summaryrefslogtreecommitdiff
path: root/src/pkg
diff options
context:
space:
mode:
Diffstat (limited to 'src/pkg')
-rw-r--r--src/pkg/archive/zip/reader.go7
-rw-r--r--src/pkg/archive/zip/reader_test.go20
-rw-r--r--src/pkg/archive/zip/struct.go9
-rw-r--r--src/pkg/archive/zip/testdata/test-trailing-junk.zipbin0 -> 1184 bytes
-rw-r--r--src/pkg/archive/zip/writer.go3
-rw-r--r--src/pkg/bufio/bufio.go1
-rw-r--r--src/pkg/bufio/bufio_test.go47
-rw-r--r--src/pkg/bufio/example_test.go4
-rw-r--r--src/pkg/bufio/scan.go34
-rw-r--r--src/pkg/bufio/scan_test.go36
-rw-r--r--src/pkg/builtin/builtin.go15
-rw-r--r--src/pkg/bytes/asm_386.s22
-rw-r--r--src/pkg/bytes/asm_amd64.s27
-rw-r--r--src/pkg/bytes/asm_arm.s14
-rw-r--r--src/pkg/bytes/buffer.go56
-rw-r--r--src/pkg/bytes/buffer_test.go50
-rw-r--r--src/pkg/bytes/bytes.go4
-rw-r--r--src/pkg/bytes/bytes_decl.go2
-rw-r--r--src/pkg/bytes/bytes_test.go76
-rw-r--r--src/pkg/bytes/equal_test.go47
-rw-r--r--src/pkg/bytes/export_test.go4
-rw-r--r--src/pkg/compress/bzip2/huffman.go2
-rw-r--r--src/pkg/compress/flate/deflate_test.go1
-rw-r--r--src/pkg/compress/flate/inflate.go3
-rw-r--r--src/pkg/compress/flate/token.go1
-rw-r--r--src/pkg/compress/gzip/gunzip.go1
-rw-r--r--src/pkg/compress/gzip/gzip.go24
-rw-r--r--src/pkg/compress/gzip/gzip_test.go40
-rw-r--r--src/pkg/compress/lzw/reader.go2
-rw-r--r--src/pkg/crypto/cipher/example_test.go4
-rw-r--r--src/pkg/crypto/dsa/dsa.go2
-rw-r--r--src/pkg/crypto/dsa/dsa_test.go5
-rw-r--r--src/pkg/crypto/ecdsa/ecdsa.go2
-rw-r--r--src/pkg/crypto/md5/gen.go19
-rw-r--r--src/pkg/crypto/md5/md5block.go5
-rw-r--r--src/pkg/crypto/md5/md5block_386.s180
-rw-r--r--src/pkg/crypto/md5/md5block_amd64.s177
-rw-r--r--src/pkg/crypto/md5/md5block_decl.go9
-rw-r--r--src/pkg/crypto/rand/util.go9
-rw-r--r--src/pkg/crypto/rc4/rc4.go6
-rw-r--r--src/pkg/crypto/rc4/rc4_386.s51
-rw-r--r--src/pkg/crypto/rc4/rc4_amd64.s202
-rw-r--r--src/pkg/crypto/rc4/rc4_arm.s10
-rw-r--r--src/pkg/crypto/rc4/rc4_asm.go4
-rw-r--r--src/pkg/crypto/rc4/rc4_ref.go2
-rw-r--r--src/pkg/crypto/rc4/rc4_test.go69
-rw-r--r--src/pkg/crypto/rsa/rsa.go4
-rw-r--r--src/pkg/crypto/rsa/rsa_test.go3
-rw-r--r--src/pkg/crypto/sha1/sha1block.go2
-rw-r--r--src/pkg/crypto/sha1/sha1block_386.s233
-rw-r--r--src/pkg/crypto/sha1/sha1block_amd64.s216
-rw-r--r--src/pkg/crypto/sha1/sha1block_decl.go9
-rw-r--r--src/pkg/crypto/tls/common.go19
-rw-r--r--src/pkg/crypto/tls/handshake_server.go17
-rw-r--r--src/pkg/crypto/x509/pkcs8.go2
-rw-r--r--src/pkg/crypto/x509/x509.go1
-rw-r--r--src/pkg/database/sql/convert.go62
-rw-r--r--src/pkg/database/sql/convert_test.go33
-rw-r--r--src/pkg/database/sql/driver/driver.go4
-rw-r--r--src/pkg/database/sql/fakedb_test.go61
-rw-r--r--src/pkg/database/sql/sql.go624
-rw-r--r--src/pkg/database/sql/sql_test.go416
-rw-r--r--src/pkg/debug/dwarf/buf.go48
-rw-r--r--src/pkg/debug/dwarf/entry.go26
-rw-r--r--src/pkg/debug/dwarf/type.go4
-rw-r--r--src/pkg/debug/dwarf/unit.go51
-rw-r--r--src/pkg/debug/elf/file.go18
-rw-r--r--src/pkg/debug/macho/file.go2
-rw-r--r--src/pkg/encoding/ascii85/ascii85.go1
-rw-r--r--src/pkg/encoding/asn1/marshal.go1
-rw-r--r--src/pkg/encoding/base32/base32.go87
-rw-r--r--src/pkg/encoding/base32/base32_test.go106
-rw-r--r--src/pkg/encoding/base64/base64.go63
-rw-r--r--src/pkg/encoding/base64/base64_test.go71
-rw-r--r--src/pkg/encoding/binary/varint.go1
-rw-r--r--src/pkg/encoding/csv/reader.go3
-rw-r--r--src/pkg/encoding/gob/codec_test.go6
-rw-r--r--src/pkg/encoding/gob/decode.go1
-rw-r--r--src/pkg/encoding/gob/timing_test.go9
-rw-r--r--src/pkg/encoding/gob/type.go1
-rw-r--r--src/pkg/encoding/json/decode.go13
-rw-r--r--src/pkg/encoding/json/decode_test.go15
-rw-r--r--src/pkg/encoding/json/encode.go98
-rw-r--r--src/pkg/encoding/json/encode_test.go104
-rw-r--r--src/pkg/encoding/xml/marshal.go75
-rw-r--r--src/pkg/encoding/xml/marshal_test.go38
-rw-r--r--src/pkg/encoding/xml/read.go6
-rw-r--r--src/pkg/encoding/xml/read_test.go222
-rw-r--r--src/pkg/encoding/xml/typeinfo.go41
-rw-r--r--src/pkg/encoding/xml/xml.go28
-rw-r--r--src/pkg/encoding/xml/xml_test.go31
-rw-r--r--src/pkg/exp/norm/Makefile30
-rw-r--r--src/pkg/exp/norm/composition.go382
-rw-r--r--src/pkg/exp/norm/composition_test.go143
-rw-r--r--src/pkg/exp/norm/example_iter_test.go81
-rw-r--r--src/pkg/exp/norm/forminfo.go229
-rw-r--r--src/pkg/exp/norm/input.go105
-rw-r--r--src/pkg/exp/norm/iter.go401
-rw-r--r--src/pkg/exp/norm/iter_test.go188
-rw-r--r--src/pkg/exp/norm/maketables.go923
-rw-r--r--src/pkg/exp/norm/maketesttables.go45
-rw-r--r--src/pkg/exp/norm/norm_test.go14
-rw-r--r--src/pkg/exp/norm/normalize.go478
-rw-r--r--src/pkg/exp/norm/normalize_test.go750
-rw-r--r--src/pkg/exp/norm/normregtest.go304
-rw-r--r--src/pkg/exp/norm/readwriter.go126
-rw-r--r--src/pkg/exp/norm/readwriter_test.go68
-rw-r--r--src/pkg/exp/norm/tables.go6779
-rw-r--r--src/pkg/exp/norm/trie.go232
-rw-r--r--src/pkg/exp/norm/trie_test.go152
-rw-r--r--src/pkg/exp/norm/triedata_test.go85
-rw-r--r--src/pkg/exp/norm/triegen.go317
-rw-r--r--src/pkg/fmt/doc.go10
-rw-r--r--src/pkg/fmt/fmt_test.go7
-rw-r--r--src/pkg/fmt/print.go7
-rw-r--r--src/pkg/go/ast/filter.go25
-rw-r--r--src/pkg/go/ast/filter_test.go86
-rw-r--r--src/pkg/go/ast/print.go2
-rw-r--r--src/pkg/go/build/build.go81
-rw-r--r--src/pkg/go/build/deps_test.go2
-rw-r--r--src/pkg/go/build/doc.go16
-rw-r--r--src/pkg/go/doc/doc.go20
-rw-r--r--src/pkg/go/doc/example.go7
-rw-r--r--src/pkg/go/doc/example_test.go80
-rw-r--r--src/pkg/go/doc/filter.go2
-rw-r--r--src/pkg/go/doc/reader.go88
-rw-r--r--src/pkg/go/doc/testdata/a.0.golden22
-rw-r--r--src/pkg/go/doc/testdata/a.1.golden22
-rw-r--r--src/pkg/go/doc/testdata/a.2.golden22
-rw-r--r--src/pkg/go/doc/testdata/a0.go23
-rw-r--r--src/pkg/go/doc/testdata/template.txt2
-rw-r--r--src/pkg/go/format/format.go9
-rw-r--r--src/pkg/go/parser/error_test.go2
-rw-r--r--src/pkg/go/parser/interface.go29
-rw-r--r--src/pkg/go/parser/parser.go55
-rw-r--r--src/pkg/go/parser/parser_test.go13
-rw-r--r--src/pkg/go/parser/short_test.go3
-rw-r--r--src/pkg/go/printer/nodes.go4
-rw-r--r--src/pkg/go/printer/printer.go31
-rw-r--r--src/pkg/go/printer/testdata/declarations.golden25
-rw-r--r--src/pkg/go/printer/testdata/declarations.input25
-rw-r--r--src/pkg/go/scanner/scanner.go13
-rw-r--r--src/pkg/go/scanner/scanner_test.go5
-rw-r--r--src/pkg/go/token/token.go4
-rw-r--r--src/pkg/go/types/api.go105
-rw-r--r--src/pkg/go/types/builtins.go455
-rw-r--r--src/pkg/go/types/check.go507
-rw-r--r--src/pkg/go/types/check_test.go259
-rw-r--r--src/pkg/go/types/const.go718
-rw-r--r--src/pkg/go/types/conversions.go129
-rw-r--r--src/pkg/go/types/errors.go335
-rw-r--r--src/pkg/go/types/exportdata.go111
-rw-r--r--src/pkg/go/types/expr.go1520
-rw-r--r--src/pkg/go/types/gcimporter.go950
-rw-r--r--src/pkg/go/types/gcimporter_test.go180
-rw-r--r--src/pkg/go/types/objects.go186
-rw-r--r--src/pkg/go/types/operand.go411
-rw-r--r--src/pkg/go/types/predicates.go303
-rw-r--r--src/pkg/go/types/resolve.go197
-rw-r--r--src/pkg/go/types/resolver_test.go167
-rw-r--r--src/pkg/go/types/scope.go78
-rw-r--r--src/pkg/go/types/sizes.go162
-rw-r--r--src/pkg/go/types/stmt.go743
-rw-r--r--src/pkg/go/types/testdata/builtins.src401
-rw-r--r--src/pkg/go/types/testdata/const0.src215
-rw-r--r--src/pkg/go/types/testdata/conversions.src18
-rw-r--r--src/pkg/go/types/testdata/decls0.src187
-rw-r--r--src/pkg/go/types/testdata/decls1.src132
-rw-r--r--src/pkg/go/types/testdata/decls2a.src67
-rw-r--r--src/pkg/go/types/testdata/decls2b.src28
-rw-r--r--src/pkg/go/types/testdata/decls3.src253
-rw-r--r--src/pkg/go/types/testdata/exports.go89
-rw-r--r--src/pkg/go/types/testdata/expr0.src161
-rw-r--r--src/pkg/go/types/testdata/expr1.src7
-rw-r--r--src/pkg/go/types/testdata/expr2.src23
-rw-r--r--src/pkg/go/types/testdata/expr3.src463
-rw-r--r--src/pkg/go/types/testdata/stmt0.src288
-rw-r--r--src/pkg/go/types/types.go236
-rw-r--r--src/pkg/go/types/types_test.go171
-rw-r--r--src/pkg/go/types/universe.go146
-rw-r--r--src/pkg/hash/crc32/crc32_amd64.s6
-rw-r--r--src/pkg/html/template/template.go22
-rw-r--r--src/pkg/html/template/transition.go3
-rw-r--r--src/pkg/image/gif/reader.go103
-rw-r--r--src/pkg/image/gif/reader_test.go138
-rw-r--r--src/pkg/image/jpeg/reader.go32
-rw-r--r--src/pkg/image/jpeg/reader_test.go63
-rw-r--r--src/pkg/image/jpeg/scan.go8
-rw-r--r--src/pkg/image/jpeg/writer_test.go39
-rw-r--r--src/pkg/image/png/writer.go2
-rw-r--r--src/pkg/io/io.go12
-rw-r--r--src/pkg/io/ioutil/ioutil.go1
-rw-r--r--src/pkg/math/abs_386.s2
-rw-r--r--src/pkg/math/abs_amd64.s2
-rw-r--r--src/pkg/math/abs_arm.s8
-rw-r--r--src/pkg/math/asin_386.s4
-rw-r--r--src/pkg/math/atan2_386.s2
-rw-r--r--src/pkg/math/atan_386.s2
-rw-r--r--src/pkg/math/big/arith_386.s18
-rw-r--r--src/pkg/math/big/arith_amd64.s18
-rw-r--r--src/pkg/math/big/arith_arm.s16
-rw-r--r--src/pkg/math/big/int.go16
-rw-r--r--src/pkg/math/big/nat.go2
-rw-r--r--src/pkg/math/big/rat.go14
-rw-r--r--src/pkg/math/big/rat_test.go10
-rw-r--r--src/pkg/math/dim_amd64.s24
-rw-r--r--src/pkg/math/exp2_386.s16
-rw-r--r--src/pkg/math/exp_386.s14
-rw-r--r--src/pkg/math/exp_amd64.s6
-rw-r--r--src/pkg/math/expm1_386.s16
-rw-r--r--src/pkg/math/floor_386.s6
-rw-r--r--src/pkg/math/floor_amd64.s12
-rw-r--r--src/pkg/math/hypot.go6
-rw-r--r--src/pkg/math/hypot_386.s24
-rw-r--r--src/pkg/math/hypot_amd64.s8
-rw-r--r--src/pkg/math/ldexp_386.s2
-rw-r--r--src/pkg/math/log10_386.s4
-rw-r--r--src/pkg/math/log1p_386.s4
-rw-r--r--src/pkg/math/log_386.s2
-rw-r--r--src/pkg/math/log_amd64.s8
-rw-r--r--src/pkg/math/mod_386.s2
-rw-r--r--src/pkg/math/rand/exp.go1
-rw-r--r--src/pkg/math/rand/normal.go1
-rw-r--r--src/pkg/math/rand/zipf.go6
-rw-r--r--src/pkg/math/remainder_386.s2
-rw-r--r--src/pkg/math/sin_386.s8
-rw-r--r--src/pkg/math/sqrt.go11
-rw-r--r--src/pkg/math/sqrt_386.s2
-rw-r--r--src/pkg/math/sqrt_amd64.s2
-rw-r--r--src/pkg/math/sqrt_arm.s2
-rw-r--r--src/pkg/math/tan_386.s4
-rw-r--r--src/pkg/math/tanh.go2
-rw-r--r--src/pkg/mime/multipart/multipart.go10
-rw-r--r--src/pkg/mime/multipart/quotedprintable.go20
-rw-r--r--src/pkg/mime/multipart/quotedprintable_test.go9
-rw-r--r--src/pkg/net/conn_test.go13
-rw-r--r--src/pkg/net/dial.go251
-rw-r--r--src/pkg/net/dial_gen.go73
-rw-r--r--src/pkg/net/dial_gen_test.go11
-rw-r--r--src/pkg/net/dial_test.go85
-rw-r--r--src/pkg/net/empty.c8
-rw-r--r--src/pkg/net/example_test.go1
-rw-r--r--src/pkg/net/fd_darwin.go126
-rw-r--r--src/pkg/net/fd_linux.go192
-rw-r--r--src/pkg/net/fd_plan9.go4
-rw-r--r--src/pkg/net/fd_poll_runtime.go119
-rw-r--r--src/pkg/net/fd_poll_unix.go360
-rw-r--r--src/pkg/net/fd_unix.go380
-rw-r--r--src/pkg/net/fd_windows.go40
-rw-r--r--src/pkg/net/file_windows.go12
-rw-r--r--src/pkg/net/http/client.go12
-rw-r--r--src/pkg/net/http/client_test.go37
-rw-r--r--src/pkg/net/http/cookiejar/jar.go3
-rw-r--r--src/pkg/net/http/example_test.go16
-rw-r--r--src/pkg/net/http/export_test.go2
-rw-r--r--src/pkg/net/http/fcgi/child.go41
-rw-r--r--src/pkg/net/http/fs_test.go28
-rw-r--r--src/pkg/net/http/header.go47
-rw-r--r--src/pkg/net/http/header_test.go12
-rw-r--r--src/pkg/net/http/httptest/example_test.go2
-rw-r--r--src/pkg/net/http/httputil/dump_test.go4
-rw-r--r--src/pkg/net/http/httputil/reverseproxy.go37
-rw-r--r--src/pkg/net/http/httputil/reverseproxy_test.go4
-rw-r--r--src/pkg/net/http/request.go46
-rw-r--r--src/pkg/net/http/request_test.go34
-rw-r--r--src/pkg/net/http/requestwrite_test.go60
-rw-r--r--src/pkg/net/http/response.go3
-rw-r--r--src/pkg/net/http/response_test.go8
-rw-r--r--src/pkg/net/http/serve_test.go488
-rw-r--r--src/pkg/net/http/server.go343
-rw-r--r--src/pkg/net/http/server_test.go35
-rw-r--r--src/pkg/net/http/sniff_test.go11
-rw-r--r--src/pkg/net/http/status.go12
-rw-r--r--src/pkg/net/http/transfer.go47
-rw-r--r--src/pkg/net/http/transport.go190
-rw-r--r--src/pkg/net/http/transport_test.go312
-rw-r--r--src/pkg/net/http/z_last_test.go62
-rw-r--r--src/pkg/net/interface_bsd.go1
-rw-r--r--src/pkg/net/interface_darwin.go3
-rw-r--r--src/pkg/net/interface_freebsd.go3
-rw-r--r--src/pkg/net/interface_linux.go6
-rw-r--r--src/pkg/net/interface_test.go34
-rw-r--r--src/pkg/net/interface_unix_test.go10
-rw-r--r--src/pkg/net/ip.go95
-rw-r--r--src/pkg/net/ip_test.go129
-rw-r--r--src/pkg/net/ipraw_test.go45
-rw-r--r--src/pkg/net/iprawsock.go11
-rw-r--r--src/pkg/net/iprawsock_plan9.go6
-rw-r--r--src/pkg/net/iprawsock_posix.go32
-rw-r--r--src/pkg/net/ipsock.go61
-rw-r--r--src/pkg/net/lookup_plan9.go22
-rw-r--r--src/pkg/net/multicast_posix_test.go180
-rw-r--r--src/pkg/net/multicast_test.go184
-rw-r--r--src/pkg/net/newpollserver_unix.go46
-rw-r--r--src/pkg/net/packetconn_test.go30
-rw-r--r--src/pkg/net/protoconn_test.go10
-rw-r--r--src/pkg/net/rpc/jsonrpc/all_test.go17
-rw-r--r--src/pkg/net/rpc/jsonrpc/client.go2
-rw-r--r--src/pkg/net/rpc/server_test.go8
-rw-r--r--src/pkg/net/sendfile_freebsd.go2
-rw-r--r--src/pkg/net/sendfile_linux.go2
-rw-r--r--src/pkg/net/server_test.go21
-rw-r--r--src/pkg/net/smtp/auth.go11
-rw-r--r--src/pkg/net/smtp/smtp_test.go35
-rw-r--r--src/pkg/net/sock_bsd.go6
-rw-r--r--src/pkg/net/sock_cloexec.go4
-rw-r--r--src/pkg/net/sock_linux.go6
-rw-r--r--src/pkg/net/sock_posix.go22
-rw-r--r--src/pkg/net/sock_windows.go1
-rw-r--r--src/pkg/net/sockopt_posix.go19
-rw-r--r--src/pkg/net/sockopt_windows.go19
-rw-r--r--src/pkg/net/tcp_test.go102
-rw-r--r--src/pkg/net/tcpsock.go16
-rw-r--r--src/pkg/net/tcpsock_plan9.go10
-rw-r--r--src/pkg/net/tcpsock_posix.go67
-rw-r--r--src/pkg/net/textproto/reader.go2
-rw-r--r--src/pkg/net/textproto/reader_test.go2
-rw-r--r--src/pkg/net/timeout_test.go60
-rw-r--r--src/pkg/net/udp_test.go139
-rw-r--r--src/pkg/net/udpsock.go16
-rw-r--r--src/pkg/net/udpsock_plan9.go17
-rw-r--r--src/pkg/net/udpsock_posix.go45
-rw-r--r--src/pkg/net/unicast_posix_test.go65
-rw-r--r--src/pkg/net/unix_test.go132
-rw-r--r--src/pkg/net/unixsock.go11
-rw-r--r--src/pkg/net/unixsock_plan9.go12
-rw-r--r--src/pkg/net/unixsock_posix.go40
-rw-r--r--src/pkg/net/url/url.go127
-rw-r--r--src/pkg/net/url/url_test.go190
-rw-r--r--src/pkg/os/exec/exec.go2
-rw-r--r--src/pkg/os/exec/exec_test.go158
-rw-r--r--src/pkg/os/file_posix.go2
-rw-r--r--src/pkg/os/file_unix.go1
-rw-r--r--src/pkg/os/file_windows.go2
-rw-r--r--src/pkg/os/getwd.go2
-rw-r--r--src/pkg/os/signal/sig.s5
-rw-r--r--src/pkg/os/signal/signal.go93
-rw-r--r--src/pkg/os/signal/signal_stub.go8
-rw-r--r--src/pkg/os/signal/signal_test.go117
-rw-r--r--src/pkg/os/signal/signal_unix.go25
-rw-r--r--src/pkg/path/filepath/path_test.go5
-rw-r--r--src/pkg/path/path_test.go6
-rw-r--r--src/pkg/reflect/all_test.go489
-rw-r--r--src/pkg/reflect/asm_386.s14
-rw-r--r--src/pkg/reflect/asm_amd64.s14
-rw-r--r--src/pkg/reflect/asm_arm.s14
-rw-r--r--src/pkg/reflect/deepequal.go2
-rw-r--r--src/pkg/reflect/makefunc.go57
-rw-r--r--src/pkg/reflect/tostring_test.go1
-rw-r--r--src/pkg/reflect/type.go175
-rw-r--r--src/pkg/reflect/value.go244
-rw-r--r--src/pkg/regexp/regexp.go18
-rw-r--r--src/pkg/regexp/syntax/doc.go6
-rw-r--r--src/pkg/runtime/alg.c65
-rw-r--r--src/pkg/runtime/arch_386.h4
-rw-r--r--src/pkg/runtime/arch_amd64.h4
-rw-r--r--src/pkg/runtime/arch_arm.h6
-rw-r--r--src/pkg/runtime/asm_386.s403
-rw-r--r--src/pkg/runtime/asm_amd64.s302
-rw-r--r--src/pkg/runtime/asm_arm.s60
-rw-r--r--src/pkg/runtime/atomic_386.c13
-rw-r--r--src/pkg/runtime/atomic_arm.c17
-rw-r--r--src/pkg/runtime/cgo/callbacks.c12
-rw-r--r--src/pkg/runtime/cgo/gcc_386.S3
-rw-r--r--src/pkg/runtime/cgo/gcc_amd64.S4
-rw-r--r--src/pkg/runtime/cgo/gcc_arm.S3
-rw-r--r--src/pkg/runtime/cgo/gcc_freebsd_386.c14
-rw-r--r--src/pkg/runtime/cgo/gcc_freebsd_amd64.c16
-rw-r--r--src/pkg/runtime/cgo/gcc_freebsd_arm.c14
-rw-r--r--src/pkg/runtime/cgo/gcc_linux_386.c17
-rw-r--r--src/pkg/runtime/cgo/gcc_linux_amd64.c15
-rw-r--r--src/pkg/runtime/cgo/gcc_netbsd_386.c14
-rw-r--r--src/pkg/runtime/cgo/gcc_netbsd_amd64.c15
-rw-r--r--src/pkg/runtime/cgo/gcc_openbsd_386.c20
-rw-r--r--src/pkg/runtime/cgo/gcc_openbsd_amd64.c21
-rw-r--r--src/pkg/runtime/cgocall.c41
-rw-r--r--src/pkg/runtime/chan.c31
-rw-r--r--src/pkg/runtime/crash_test.go46
-rw-r--r--src/pkg/runtime/debug/garbage_test.go2
-rw-r--r--src/pkg/runtime/defs2_linux.go26
-rw-r--r--src/pkg/runtime/defs_darwin.go20
-rw-r--r--src/pkg/runtime/defs_darwin_386.h30
-rw-r--r--src/pkg/runtime/defs_darwin_amd64.h30
-rw-r--r--src/pkg/runtime/defs_freebsd.go4
-rw-r--r--src/pkg/runtime/defs_freebsd_386.h4
-rw-r--r--src/pkg/runtime/defs_freebsd_amd64.h4
-rw-r--r--src/pkg/runtime/defs_freebsd_arm.h4
-rw-r--r--src/pkg/runtime/defs_linux.go21
-rw-r--r--src/pkg/runtime/defs_linux_386.h22
-rw-r--r--src/pkg/runtime/defs_linux_amd64.h24
-rw-r--r--src/pkg/runtime/defs_linux_arm.h26
-rw-r--r--src/pkg/runtime/defs_netbsd.go1
-rw-r--r--src/pkg/runtime/defs_netbsd_386.go1
-rw-r--r--src/pkg/runtime/defs_netbsd_amd64.go1
-rw-r--r--src/pkg/runtime/defs_netbsd_arm.go39
-rw-r--r--src/pkg/runtime/defs_netbsd_arm.h26
-rw-r--r--src/pkg/runtime/env_plan9.c2
-rw-r--r--src/pkg/runtime/export_futex_test.go13
-rw-r--r--src/pkg/runtime/extern.go52
-rw-r--r--src/pkg/runtime/futex_test.go31
-rw-r--r--src/pkg/runtime/gc_test.go17
-rw-r--r--src/pkg/runtime/hashmap.c1757
-rw-r--r--src/pkg/runtime/hashmap.h180
-rw-r--r--src/pkg/runtime/hashmap_fast.c219
-rw-r--r--src/pkg/runtime/lock_futex.c28
-rw-r--r--src/pkg/runtime/lock_sema.c34
-rw-r--r--src/pkg/runtime/malloc.goc15
-rw-r--r--src/pkg/runtime/malloc.h16
-rw-r--r--src/pkg/runtime/map_test.go373
-rw-r--r--src/pkg/runtime/mapspeed_test.go208
-rw-r--r--src/pkg/runtime/mcentral.c1
-rw-r--r--src/pkg/runtime/mem_darwin.c9
-rw-r--r--src/pkg/runtime/mem_freebsd.c21
-rw-r--r--src/pkg/runtime/mem_linux.c2
-rw-r--r--src/pkg/runtime/mem_netbsd.c9
-rw-r--r--src/pkg/runtime/mem_openbsd.c9
-rw-r--r--src/pkg/runtime/memmove_amd64.s5
-rw-r--r--src/pkg/runtime/memmove_linux_amd64_test.go61
-rw-r--r--src/pkg/runtime/mfixalloc.c5
-rw-r--r--src/pkg/runtime/mgc0.c396
-rw-r--r--src/pkg/runtime/mgc0.h4
-rw-r--r--src/pkg/runtime/mheap.c22
-rwxr-xr-xsrc/pkg/runtime/mkasmh.sh138
-rw-r--r--src/pkg/runtime/mprof.goc4
-rw-r--r--src/pkg/runtime/netpoll.goc351
-rw-r--r--src/pkg/runtime/netpoll_epoll.c95
-rw-r--r--src/pkg/runtime/netpoll_kqueue.c108
-rw-r--r--src/pkg/runtime/netpoll_stub.c18
-rw-r--r--src/pkg/runtime/os_darwin.c (renamed from src/pkg/runtime/thread_darwin.c)73
-rw-r--r--src/pkg/runtime/os_darwin.h6
-rw-r--r--src/pkg/runtime/os_freebsd.c (renamed from src/pkg/runtime/thread_freebsd.c)95
-rw-r--r--src/pkg/runtime/os_freebsd.h10
-rw-r--r--src/pkg/runtime/os_freebsd_arm.c23
-rw-r--r--src/pkg/runtime/os_linux.c (renamed from src/pkg/runtime/thread_linux.c)112
-rw-r--r--src/pkg/runtime/os_linux.h6
-rw-r--r--src/pkg/runtime/os_linux_386.c37
-rw-r--r--src/pkg/runtime/os_linux_arm.c82
-rw-r--r--src/pkg/runtime/os_netbsd.c (renamed from src/pkg/runtime/thread_netbsd.c)86
-rw-r--r--src/pkg/runtime/os_netbsd.h7
-rw-r--r--src/pkg/runtime/os_netbsd_386.c17
-rw-r--r--src/pkg/runtime/os_netbsd_amd64.c18
-rw-r--r--src/pkg/runtime/os_netbsd_arm.c33
-rw-r--r--src/pkg/runtime/os_openbsd.c (renamed from src/pkg/runtime/thread_openbsd.c)90
-rw-r--r--src/pkg/runtime/os_openbsd.h6
-rw-r--r--src/pkg/runtime/os_plan9.c (renamed from src/pkg/runtime/thread_plan9.c)24
-rw-r--r--src/pkg/runtime/os_plan9.h4
-rw-r--r--src/pkg/runtime/os_plan9_386.c (renamed from src/pkg/runtime/signal_plan9_386.c)13
-rw-r--r--src/pkg/runtime/os_plan9_amd64.c (renamed from src/pkg/runtime/signal_plan9_amd64.c)13
-rw-r--r--src/pkg/runtime/os_windows.c (renamed from src/pkg/runtime/thread_windows.c)56
-rw-r--r--src/pkg/runtime/os_windows_386.c (renamed from src/pkg/runtime/signal_windows_386.c)13
-rw-r--r--src/pkg/runtime/os_windows_amd64.c (renamed from src/pkg/runtime/signal_windows_amd64.c)12
-rw-r--r--src/pkg/runtime/panic.c12
-rw-r--r--src/pkg/runtime/parfor.c6
-rw-r--r--src/pkg/runtime/proc.c121
-rw-r--r--src/pkg/runtime/race.c7
-rw-r--r--src/pkg/runtime/race/doc.go9
-rw-r--r--src/pkg/runtime/race/race.go1
-rw-r--r--src/pkg/runtime/race/race_test.go2
-rw-r--r--src/pkg/runtime/race/testdata/atomic_test.go19
-rw-r--r--src/pkg/runtime/race/testdata/map_test.go6
-rw-r--r--src/pkg/runtime/race/testdata/mop_test.go240
-rw-r--r--src/pkg/runtime/race/testdata/regression_test.go12
-rw-r--r--src/pkg/runtime/race/testdata/slice_test.go24
-rw-r--r--src/pkg/runtime/race/testdata/sync_test.go19
-rw-r--r--src/pkg/runtime/rt0_darwin_386.s10
-rw-r--r--src/pkg/runtime/rt0_darwin_amd64.s9
-rw-r--r--src/pkg/runtime/rt0_freebsd_386.s11
-rw-r--r--src/pkg/runtime/rt0_freebsd_amd64.s12
-rw-r--r--src/pkg/runtime/rt0_linux_386.s14
-rw-r--r--src/pkg/runtime/rt0_linux_amd64.s9
-rw-r--r--src/pkg/runtime/rt0_netbsd_386.s12
-rw-r--r--src/pkg/runtime/rt0_netbsd_amd64.s11
-rw-r--r--src/pkg/runtime/rt0_openbsd_386.s12
-rw-r--r--src/pkg/runtime/rt0_openbsd_amd64.s11
-rw-r--r--src/pkg/runtime/rt0_plan9_386.s7
-rw-r--r--src/pkg/runtime/rt0_plan9_amd64.s5
-rw-r--r--src/pkg/runtime/rt0_windows_386.s11
-rw-r--r--src/pkg/runtime/rt0_windows_amd64.s9
-rw-r--r--src/pkg/runtime/runtime-gdb.py49
-rw-r--r--src/pkg/runtime/runtime.c28
-rw-r--r--src/pkg/runtime/runtime.h83
-rw-r--r--src/pkg/runtime/sema.goc6
-rw-r--r--src/pkg/runtime/signal_386.c123
-rw-r--r--src/pkg/runtime/signal_amd64.c133
-rw-r--r--src/pkg/runtime/signal_arm.c124
-rw-r--r--src/pkg/runtime/signal_darwin_386.c155
-rw-r--r--src/pkg/runtime/signal_darwin_386.h23
-rw-r--r--src/pkg/runtime/signal_darwin_amd64.c165
-rw-r--r--src/pkg/runtime/signal_darwin_amd64.h31
-rw-r--r--src/pkg/runtime/signal_freebsd_386.c154
-rw-r--r--src/pkg/runtime/signal_freebsd_386.h23
-rw-r--r--src/pkg/runtime/signal_freebsd_amd64.c162
-rw-r--r--src/pkg/runtime/signal_freebsd_amd64.h31
-rw-r--r--src/pkg/runtime/signal_freebsd_arm.c193
-rw-r--r--src/pkg/runtime/signal_freebsd_arm.h28
-rw-r--r--src/pkg/runtime/signal_linux_386.c175
-rw-r--r--src/pkg/runtime/signal_linux_386.h24
-rw-r--r--src/pkg/runtime/signal_linux_amd64.c162
-rw-r--r--src/pkg/runtime/signal_linux_amd64.h32
-rw-r--r--src/pkg/runtime/signal_linux_arm.c241
-rw-r--r--src/pkg/runtime/signal_linux_arm.h28
-rw-r--r--src/pkg/runtime/signal_netbsd_386.c164
-rw-r--r--src/pkg/runtime/signal_netbsd_386.h23
-rw-r--r--src/pkg/runtime/signal_netbsd_amd64.c172
-rw-r--r--src/pkg/runtime/signal_netbsd_amd64.h31
-rw-r--r--src/pkg/runtime/signal_netbsd_arm.c208
-rw-r--r--src/pkg/runtime/signal_netbsd_arm.h30
-rw-r--r--src/pkg/runtime/signal_openbsd_386.c147
-rw-r--r--src/pkg/runtime/signal_openbsd_386.h23
-rw-r--r--src/pkg/runtime/signal_openbsd_amd64.c156
-rw-r--r--src/pkg/runtime/signal_openbsd_amd64.h31
-rw-r--r--src/pkg/runtime/signal_unix.c72
-rw-r--r--src/pkg/runtime/signal_unix.h14
-rw-r--r--src/pkg/runtime/signals_plan9.h4
-rw-r--r--src/pkg/runtime/sigqueue.goc18
-rw-r--r--src/pkg/runtime/stack_test.go13
-rw-r--r--src/pkg/runtime/string.goc10
-rw-r--r--src/pkg/runtime/string_test.go32
-rw-r--r--src/pkg/runtime/symtab.c2
-rw-r--r--src/pkg/runtime/sys_darwin_386.s59
-rw-r--r--src/pkg/runtime/sys_darwin_amd64.s75
-rw-r--r--src/pkg/runtime/sys_freebsd_386.s24
-rw-r--r--src/pkg/runtime/sys_freebsd_amd64.s28
-rw-r--r--src/pkg/runtime/sys_freebsd_arm.s23
-rw-r--r--src/pkg/runtime/sys_linux_386.s49
-rw-r--r--src/pkg/runtime/sys_linux_amd64.s47
-rw-r--r--src/pkg/runtime/sys_linux_arm.s53
-rw-r--r--src/pkg/runtime/sys_netbsd_386.s22
-rw-r--r--src/pkg/runtime/sys_netbsd_amd64.s32
-rw-r--r--src/pkg/runtime/sys_netbsd_arm.s23
-rw-r--r--src/pkg/runtime/sys_openbsd_386.s22
-rw-r--r--src/pkg/runtime/sys_openbsd_amd64.s32
-rw-r--r--src/pkg/runtime/sys_plan9_386.s27
-rw-r--r--src/pkg/runtime/sys_plan9_amd64.s28
-rw-r--r--src/pkg/runtime/sys_windows_386.s43
-rw-r--r--src/pkg/runtime/sys_windows_amd64.s32
-rw-r--r--src/pkg/runtime/time.goc19
-rw-r--r--src/pkg/runtime/time_plan9_386.c2
-rw-r--r--src/pkg/runtime/traceback_arm.c34
-rw-r--r--src/pkg/runtime/traceback_x86.c37
-rw-r--r--src/pkg/runtime/vdso_linux_amd64.c10
-rw-r--r--src/pkg/sort/example_multi_test.go132
-rw-r--r--src/pkg/sort/search_test.go4
-rw-r--r--src/pkg/sort/sort.go9
-rw-r--r--src/pkg/strconv/extfloat.go1
-rw-r--r--src/pkg/strconv/strconv_test.go10
-rw-r--r--src/pkg/strings/strings.go10
-rw-r--r--src/pkg/strings/strings_test.go18
-rw-r--r--src/pkg/sync/atomic/asm_386.s28
-rw-r--r--src/pkg/sync/atomic/asm_arm.s16
-rw-r--r--src/pkg/sync/atomic/asm_linux_arm.s8
-rw-r--r--src/pkg/sync/atomic/atomic_test.go26
-rw-r--r--src/pkg/sync/atomic/race.go15
-rw-r--r--src/pkg/sync/cond.go3
-rw-r--r--src/pkg/sync/mutex.go1
-rw-r--r--src/pkg/sync/rwmutex.go4
-rw-r--r--src/pkg/sync/waitgroup.go2
-rw-r--r--src/pkg/syscall/asm_plan9_386.s4
-rw-r--r--src/pkg/syscall/asm_plan9_amd64.s4
-rw-r--r--src/pkg/syscall/exec_bsd.go14
-rw-r--r--src/pkg/syscall/exec_linux.go10
-rw-r--r--src/pkg/syscall/exec_plan9.go10
-rwxr-xr-xsrc/pkg/syscall/mkerrors.sh1
-rw-r--r--src/pkg/syscall/passfd_test.go6
-rw-r--r--src/pkg/syscall/syscall_bsd.go5
-rw-r--r--src/pkg/syscall/syscall_darwin.go2
-rw-r--r--src/pkg/syscall/syscall_freebsd.go2
-rw-r--r--src/pkg/syscall/syscall_netbsd.go2
-rw-r--r--src/pkg/syscall/syscall_openbsd.go2
-rw-r--r--src/pkg/syscall/zerrors_freebsd_386.go204
-rw-r--r--src/pkg/syscall/zerrors_freebsd_amd64.go204
-rw-r--r--src/pkg/syscall/zerrors_freebsd_arm.go44
-rw-r--r--src/pkg/syscall/zsyscall_darwin_386.go9
-rw-r--r--src/pkg/syscall/zsyscall_darwin_amd64.go9
-rw-r--r--src/pkg/syscall/zsyscall_freebsd_386.go9
-rw-r--r--src/pkg/syscall/zsyscall_freebsd_amd64.go9
-rw-r--r--src/pkg/syscall/zsyscall_netbsd_386.go9
-rw-r--r--src/pkg/syscall/zsyscall_netbsd_amd64.go9
-rw-r--r--src/pkg/syscall/zsyscall_openbsd_386.go9
-rw-r--r--src/pkg/syscall/zsyscall_openbsd_amd64.go9
-rw-r--r--src/pkg/syscall/zsysnum_freebsd_386.go4
-rw-r--r--src/pkg/syscall/zsysnum_freebsd_amd64.go4
-rw-r--r--src/pkg/syscall/zsysnum_freebsd_arm.go11
-rw-r--r--src/pkg/testing/iotest/reader.go8
-rw-r--r--src/pkg/testing/quick/quick.go2
-rw-r--r--src/pkg/testing/testing.go11
-rw-r--r--src/pkg/text/template/exec.go20
-rw-r--r--src/pkg/text/template/exec_test.go64
-rw-r--r--src/pkg/text/template/funcs.go2
-rw-r--r--src/pkg/text/template/parse/parse.go2
-rw-r--r--src/pkg/time/example_test.go11
-rw-r--r--src/pkg/time/format.go41
-rw-r--r--src/pkg/time/sleep_test.go5
-rw-r--r--src/pkg/time/time_test.go4
-rw-r--r--src/pkg/unicode/letter.go2
-rw-r--r--src/pkg/unicode/maketables.go2
-rw-r--r--src/pkg/unicode/tables.go2
-rw-r--r--src/pkg/unicode/utf8/utf8_test.go6
598 files changed, 17696 insertions, 29630 deletions
diff --git a/src/pkg/archive/zip/reader.go b/src/pkg/archive/zip/reader.go
index c10f29a83..f19cf2d1f 100644
--- a/src/pkg/archive/zip/reader.go
+++ b/src/pkg/archive/zip/reader.go
@@ -353,6 +353,11 @@ func readDirectoryEnd(r io.ReaderAt, size int64) (dir *directoryEnd, err error)
if err != nil {
return nil, err
}
+
+ // Make sure directoryOffset points to somewhere in our file.
+ if o := int64(d.directoryOffset); o < 0 || o >= size {
+ return nil, ErrFormat
+ }
return d, nil
}
@@ -407,7 +412,7 @@ func findSignatureInBlock(b []byte) int {
if b[i] == 'P' && b[i+1] == 'K' && b[i+2] == 0x05 && b[i+3] == 0x06 {
// n is length of comment
n := int(b[i+directoryEndLen-2]) | int(b[i+directoryEndLen-1])<<8
- if n+directoryEndLen+i == len(b) {
+ if n+directoryEndLen+i <= len(b) {
return i
}
}
diff --git a/src/pkg/archive/zip/reader_test.go b/src/pkg/archive/zip/reader_test.go
index cf9c59c4b..833ba28ad 100644
--- a/src/pkg/archive/zip/reader_test.go
+++ b/src/pkg/archive/zip/reader_test.go
@@ -64,6 +64,24 @@ var tests = []ZipTest{
},
},
{
+ Name: "test-trailing-junk.zip",
+ Comment: "This is a zipfile comment.",
+ File: []ZipTestFile{
+ {
+ Name: "test.txt",
+ Content: []byte("This is a test text file.\n"),
+ Mtime: "09-05-10 12:12:02",
+ Mode: 0644,
+ },
+ {
+ Name: "gophercolor16x16.png",
+ File: "gophercolor16x16.png",
+ Mtime: "09-05-10 15:52:58",
+ Mode: 0644,
+ },
+ },
+ },
+ {
Name: "r.zip",
Source: returnRecursiveZip,
File: []ZipTestFile{
@@ -262,7 +280,7 @@ func readTestZip(t *testing.T, zt ZipTest) {
}
}
if err != zt.Error {
- t.Errorf("error=%v, want %v", err, zt.Error)
+ t.Errorf("%s: error=%v, want %v", zt.Name, err, zt.Error)
return
}
diff --git a/src/pkg/archive/zip/struct.go b/src/pkg/archive/zip/struct.go
index ea067f355..73972d41c 100644
--- a/src/pkg/archive/zip/struct.go
+++ b/src/pkg/archive/zip/struct.go
@@ -64,8 +64,15 @@ const (
zip64ExtraId = 0x0001 // zip64 Extended Information Extra Field
)
+// FileHeader describes a file within a zip file.
+// See the zip spec for details.
type FileHeader struct {
- Name string
+ // Name is the name of the file.
+ // It must be a relative path: it must not start with a drive
+ // letter (e.g. C:) or leading slash, and only forward slashes
+ // are allowed.
+ Name string
+
CreatorVersion uint16
ReaderVersion uint16
Flags uint16
diff --git a/src/pkg/archive/zip/testdata/test-trailing-junk.zip b/src/pkg/archive/zip/testdata/test-trailing-junk.zip
new file mode 100644
index 000000000..42281b4e3
--- /dev/null
+++ b/src/pkg/archive/zip/testdata/test-trailing-junk.zip
Binary files differ
diff --git a/src/pkg/archive/zip/writer.go b/src/pkg/archive/zip/writer.go
index 4c696e152..e9f147cea 100644
--- a/src/pkg/archive/zip/writer.go
+++ b/src/pkg/archive/zip/writer.go
@@ -163,6 +163,9 @@ func (w *Writer) Close() error {
// Create adds a file to the zip file using the provided name.
// It returns a Writer to which the file contents should be written.
+// The name must be a relative path: it must not start with a drive
+// letter (e.g. C:) or leading slash, and only forward slashes are
+// allowed.
// The file's contents must be written to the io.Writer before the next
// call to Create, CreateHeader, or Close.
func (w *Writer) Create(name string) (io.Writer, error) {
diff --git a/src/pkg/bufio/bufio.go b/src/pkg/bufio/bufio.go
index ee69c2d31..df3501f2c 100644
--- a/src/pkg/bufio/bufio.go
+++ b/src/pkg/bufio/bufio.go
@@ -274,7 +274,6 @@ func (b *Reader) ReadSlice(delim byte) (line []byte, err error) {
return b.buf, ErrBufferFull
}
}
- panic("not reached")
}
// ReadLine is a low-level line-reading primitive. Most callers should use
diff --git a/src/pkg/bufio/bufio_test.go b/src/pkg/bufio/bufio_test.go
index b0e811443..79ed0f178 100644
--- a/src/pkg/bufio/bufio_test.go
+++ b/src/pkg/bufio/bufio_test.go
@@ -7,6 +7,7 @@ package bufio_test
import (
. "bufio"
"bytes"
+ "errors"
"fmt"
"io"
"io/ioutil"
@@ -434,9 +435,12 @@ func TestWriteErrors(t *testing.T) {
t.Errorf("Write hello to %v: %v", w, e)
continue
}
- e = buf.Flush()
- if e != w.expect {
- t.Errorf("Flush %v: got %v, wanted %v", w, e, w.expect)
+ // Two flushes, to verify the error is sticky.
+ for i := 0; i < 2; i++ {
+ e = buf.Flush()
+ if e != w.expect {
+ t.Errorf("Flush %d/2 %v: got %v, wanted %v", i+1, w, e, w.expect)
+ }
}
}
}
@@ -962,6 +966,43 @@ func TestNegativeRead(t *testing.T) {
b.Read(make([]byte, 100))
}
+var errFake = errors.New("fake error")
+
+type errorThenGoodReader struct {
+ didErr bool
+ nread int
+}
+
+func (r *errorThenGoodReader) Read(p []byte) (int, error) {
+ r.nread++
+ if !r.didErr {
+ r.didErr = true
+ return 0, errFake
+ }
+ return len(p), nil
+}
+
+func TestReaderClearError(t *testing.T) {
+ r := &errorThenGoodReader{}
+ b := NewReader(r)
+ buf := make([]byte, 1)
+ if _, err := b.Read(nil); err != nil {
+ t.Fatalf("1st nil Read = %v; want nil", err)
+ }
+ if _, err := b.Read(buf); err != errFake {
+ t.Fatalf("1st Read = %v; want errFake", err)
+ }
+ if _, err := b.Read(nil); err != nil {
+ t.Fatalf("2nd nil Read = %v; want nil", err)
+ }
+ if _, err := b.Read(buf); err != nil {
+ t.Fatalf("3rd Read with buffer = %v; want nil", err)
+ }
+ if r.nread != 2 {
+ t.Errorf("num reads = %d; want 2", r.nread)
+ }
+}
+
// An onlyReader only implements io.Reader, no matter what other methods the underlying implementation may have.
type onlyReader struct {
r io.Reader
diff --git a/src/pkg/bufio/example_test.go b/src/pkg/bufio/example_test.go
index b545ce39a..08a39441e 100644
--- a/src/pkg/bufio/example_test.go
+++ b/src/pkg/bufio/example_test.go
@@ -19,7 +19,7 @@ func ExampleScanner_lines() {
fmt.Println(scanner.Text()) // Println will add back the final '\n'
}
if err := scanner.Err(); err != nil {
- fmt.Fprintln(os.Stdout, "reading standard input:", err)
+ fmt.Fprintln(os.Stderr, "reading standard input:", err)
}
}
@@ -37,7 +37,7 @@ func ExampleScanner_words() {
count++
}
if err := scanner.Err(); err != nil {
- fmt.Fprintln(os.Stdout, "reading input:", err)
+ fmt.Fprintln(os.Stderr, "reading input:", err)
}
fmt.Printf("%d\n", count)
// Output: 15
diff --git a/src/pkg/bufio/scan.go b/src/pkg/bufio/scan.go
index 268ce6d1d..2e1a2e999 100644
--- a/src/pkg/bufio/scan.go
+++ b/src/pkg/bufio/scan.go
@@ -16,7 +16,7 @@ import (
// the Scan method will step through the 'tokens' of a file, skipping
// the bytes between the tokens. The specification of a token is
// defined by a split function of type SplitFunc; the default split
-// function breaks the input into lines with newlines stripped. Split
+// function breaks the input into lines with line termination stripped. Split
// functions are defined in this package for scanning a file into
// lines, bytes, UTF-8-encoded runes, and space-delimited words. The
// client may instead provide a custom split function.
@@ -27,8 +27,6 @@ import (
// control over error handling or large tokens, or must run sequential scans
// on a reader, should use bufio.Reader instead.
//
-// TODO(r): Provide executable examples.
-//
type Scanner struct {
r io.Reader // The reader provided by the client.
split SplitFunc // The function to split the tokens.
@@ -72,6 +70,7 @@ const (
)
// NewScanner returns a new Scanner to read from r.
+// The split function defaults to ScanLines.
func NewScanner(r io.Reader) *Scanner {
return &Scanner{
r: r,
@@ -159,17 +158,26 @@ func (s *Scanner) Scan() bool {
s.start = 0
continue
}
- // Finally we can read some input.
- n, err := s.r.Read(s.buf[s.end:len(s.buf)])
- if err != nil {
- s.setErr(err)
- }
- if n == 0 { // Don't loop forever if Reader doesn't deliver EOF.
- s.err = io.EOF
+ // 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
+ // be extra careful: Scanner is for safe, simple jobs.
+ for loop := 0; ; {
+ n, err := s.r.Read(s.buf[s.end:len(s.buf)])
+ s.end += n
+ if err != nil {
+ s.setErr(err)
+ break
+ }
+ if n > 0 {
+ break
+ }
+ loop++
+ if loop > 100 {
+ s.setErr(io.ErrNoProgress)
+ break
+ }
}
- s.end += n
}
- panic("not reached")
}
// advance consumes n bytes of the buffer. It reports whether the advance was legal.
@@ -260,7 +268,7 @@ func dropCR(data []byte) []byte {
// ScanLines is a split function for a Scanner that returns each line of
// text, stripped of any trailing end-of-line marker. The returned line may
// be empty. The end-of-line marker is one optional carriage return followed
-// by one mandatory newline. In regular expression notation, it is `\r?\n'.
+// by one mandatory newline. In regular expression notation, it is `\r?\n`.
// The last non-empty line of input will be returned even if it has no
// newline.
func ScanLines(data []byte, atEOF bool) (advance int, token []byte, err error) {
diff --git a/src/pkg/bufio/scan_test.go b/src/pkg/bufio/scan_test.go
index 48729aabb..c1483b268 100644
--- a/src/pkg/bufio/scan_test.go
+++ b/src/pkg/bufio/scan_test.go
@@ -368,3 +368,39 @@ func TestErrAtEOF(t *testing.T) {
t.Fatal("wrong error:", s.Err())
}
}
+
+// Test for issue 5268.
+type alwaysError struct{}
+
+func (alwaysError) Read(p []byte) (int, error) {
+ return 0, io.ErrUnexpectedEOF
+}
+
+func TestNonEOFWithEmptyRead(t *testing.T) {
+ scanner := NewScanner(alwaysError{})
+ for scanner.Scan() {
+ t.Fatal("read should fail")
+ }
+ err := scanner.Err()
+ if err != io.ErrUnexpectedEOF {
+ t.Errorf("unexpected error: %v", err)
+ }
+}
+
+// Test that Scan finishes if we have endless empty reads.
+type endlessZeros struct{}
+
+func (endlessZeros) Read(p []byte) (int, error) {
+ return 0, nil
+}
+
+func TestBadReader(t *testing.T) {
+ scanner := NewScanner(endlessZeros{})
+ for scanner.Scan() {
+ t.Fatal("read should fail")
+ }
+ err := scanner.Err()
+ if err != io.ErrNoProgress {
+ t.Errorf("unexpected error: %v", err)
+ }
+}
diff --git a/src/pkg/builtin/builtin.go b/src/pkg/builtin/builtin.go
index 7b5e9ab1d..128a1b5f8 100644
--- a/src/pkg/builtin/builtin.go
+++ b/src/pkg/builtin/builtin.go
@@ -13,6 +13,12 @@ package builtin
// bool is the set of boolean values, true and false.
type bool bool
+// true and false are the two untyped boolean values.
+const (
+ true = 0 == 0 // Untyped bool.
+ false = 0 != 0 // Untyped bool.
+)
+
// uint8 is the set of all unsigned 8-bit integers.
// Range: 0 through 255.
type uint8 uint8
@@ -85,6 +91,15 @@ type byte byte
// used, by convention, to distinguish character values from integer values.
type rune rune
+// iota is a predeclared identifier representing the untyped integer ordinal
+// number of the current const specification in a (usually parenthesized)
+// const declaration. It is zero-indexed.
+const iota = 0 // Untyped int.
+
+// nil is a predeclared identifier representing the zero value for a
+// pointer, channel, func, interface, map, or slice type.
+var nil Type // Type must be a pointer, channel, func, interface, map, or slice type
+
// Type is here for the purposes of documentation only. It is a stand-in
// for any Go type, but represents the same type for any given function
// invocation.
diff --git a/src/pkg/bytes/asm_386.s b/src/pkg/bytes/asm_386.s
index c444b55e1..27cd4e787 100644
--- a/src/pkg/bytes/asm_386.s
+++ b/src/pkg/bytes/asm_386.s
@@ -4,30 +4,14 @@
TEXT ·IndexByte(SB),7,$0
MOVL s+0(FP), SI
- MOVL s+4(FP), CX
+ MOVL s_len+4(FP), CX
MOVB c+12(FP), AL
MOVL SI, DI
CLD; REPN; SCASB
JZ 3(PC)
- MOVL $-1, r+16(FP)
+ MOVL $-1, ret+16(FP)
RET
SUBL SI, DI
SUBL $1, DI
- MOVL DI, r+16(FP)
- RET
-
-TEXT ·Equal(SB),7,$0
- MOVL a+4(FP), BX
- MOVL b+16(FP), CX
- MOVL $0, AX
- CMPL BX, CX
- JNE eqret
- MOVL a+0(FP), SI
- MOVL b+12(FP), DI
- CLD
- REP; CMPSB
- JNE eqret
- MOVL $1, AX
-eqret:
- MOVB AX, r+24(FP)
+ MOVL DI, ret+16(FP)
RET
diff --git a/src/pkg/bytes/asm_amd64.s b/src/pkg/bytes/asm_amd64.s
index 482422642..b84957b6d 100644
--- a/src/pkg/bytes/asm_amd64.s
+++ b/src/pkg/bytes/asm_amd64.s
@@ -4,7 +4,7 @@
TEXT ·IndexByte(SB),7,$0
MOVQ s+0(FP), SI
- MOVQ s+8(FP), BX
+ MOVQ s_len+8(FP), BX
MOVB c+24(FP), AL
MOVQ SI, DI
@@ -63,7 +63,7 @@ condition:
JZ success
failure:
- MOVQ $-1, r+32(FP)
+ MOVQ $-1, ret+32(FP)
RET
// handle for lengths < 16
@@ -71,7 +71,7 @@ small:
MOVQ BX, CX
REPN; SCASB
JZ success
- MOVQ $-1, r+32(FP)
+ MOVQ $-1, ret+32(FP)
RET
// we've found the chunk containing the byte
@@ -81,28 +81,11 @@ ssesuccess:
BSFW DX, DX
SUBQ SI, DI
ADDQ DI, DX
- MOVQ DX, r+32(FP)
+ MOVQ DX, ret+32(FP)
RET
success:
SUBQ SI, DI
SUBL $1, DI
- MOVQ DI, r+32(FP)
+ MOVQ DI, ret+32(FP)
RET
-
-TEXT ·Equal(SB),7,$0
- MOVQ a+8(FP), BX
- MOVQ b+32(FP), CX
- MOVL $0, AX
- CMPQ BX, CX
- JNE eqret
- MOVQ a+0(FP), SI
- MOVQ b+24(FP), DI
- CLD
- REP; CMPSB
- MOVL $1, DX
- CMOVLEQ DX, AX
-eqret:
- MOVB AX, r+48(FP)
- RET
-
diff --git a/src/pkg/bytes/asm_arm.s b/src/pkg/bytes/asm_arm.s
index c7685f041..2e9f805a4 100644
--- a/src/pkg/bytes/asm_arm.s
+++ b/src/pkg/bytes/asm_arm.s
@@ -4,7 +4,7 @@
TEXT ·IndexByte(SB),7,$0
MOVW s+0(FP), R0
- MOVW s+4(FP), R1
+ MOVW s_len+4(FP), R1
MOVBU c+12(FP), R2 // byte to find
MOVW R0, R4 // store base for later
ADD R0, R1 // end
@@ -18,17 +18,17 @@ _loop:
SUB $1, R0 // R0 will be one beyond the position we want
SUB R4, R0 // remove base
- MOVW R0, r+16(FP)
+ MOVW R0, ret+16(FP)
RET
_notfound:
MOVW $-1, R0
- MOVW R0, r+16(FP)
+ MOVW R0, ret+16(FP)
RET
TEXT ·Equal(SB),7,$0
- MOVW a+4(FP), R1
- MOVW b+16(FP), R3
+ MOVW a_len+4(FP), R1
+ MOVW b_len+16(FP), R3
CMP R1, R3 // unequal lengths are not equal
B.NE _notequal
@@ -47,10 +47,10 @@ _next:
_notequal:
MOVW $0, R0
- MOVBU R0, r+24(FP)
+ MOVBU R0, ret+24(FP)
RET
_equal:
MOVW $1, R0
- MOVBU R0, r+24(FP)
+ MOVBU R0, ret+24(FP)
RET
diff --git a/src/pkg/bytes/buffer.go b/src/pkg/bytes/buffer.go
index 85c157798..46ca1d5ad 100644
--- a/src/pkg/bytes/buffer.go
+++ b/src/pkg/bytes/buffer.go
@@ -87,6 +87,13 @@ func (b *Buffer) grow(n int) int {
var buf []byte
if b.buf == nil && n <= len(b.bootstrap) {
buf = b.bootstrap[0:]
+ } else if m+n <= cap(b.buf)/2 {
+ // We can slide things down instead of allocating a new
+ // slice. We only need m+n <= cap(b.buf) to slide, but
+ // we instead let capacity get twice as large so we
+ // don't spend all our time copying.
+ copy(b.buf[:], b.buf[b.off:])
+ buf = b.buf[:m]
} else {
// not enough space anywhere
buf = makeSlice(2*cap(b.buf) + n)
@@ -112,20 +119,18 @@ func (b *Buffer) Grow(n int) {
b.buf = b.buf[0:m]
}
-// Write appends the contents of p to the buffer. The return
-// value n is the length of p; err is always nil.
-// If the buffer becomes too large, Write will panic with
-// ErrTooLarge.
+// Write appends the contents of p to the buffer, growing the buffer as
+// needed. The return value n is the length of p; err is always nil. If the
+// buffer becomes too large, Write will panic with ErrTooLarge.
func (b *Buffer) Write(p []byte) (n int, err error) {
b.lastRead = opInvalid
m := b.grow(len(p))
return copy(b.buf[m:], p), nil
}
-// WriteString appends the contents of s to the buffer. The return
-// value n is the length of s; err is always nil.
-// If the buffer becomes too large, WriteString will panic with
-// ErrTooLarge.
+// WriteString appends the contents of s to the buffer, growing the buffer as
+// needed. The return value n is the length of s; err is always nil. If the
+// buffer becomes too large, WriteString will panic with ErrTooLarge.
func (b *Buffer) WriteString(s string) (n int, err error) {
b.lastRead = opInvalid
m := b.grow(len(s))
@@ -138,12 +143,10 @@ func (b *Buffer) WriteString(s string) (n int, err error) {
// underlying buffer.
const MinRead = 512
-// ReadFrom reads data from r until EOF and appends it to the buffer.
-// The return value n is the number of bytes read.
-// Any error except io.EOF encountered during the read
-// is also returned.
-// If the buffer becomes too large, ReadFrom will panic with
-// ErrTooLarge.
+// ReadFrom reads data from r until EOF and appends it to the buffer, growing
+// the buffer as needed. The return value n is the number of bytes read. Any
+// error except io.EOF encountered during the read is also returned. If the
+// buffer becomes too large, ReadFrom will panic with ErrTooLarge.
func (b *Buffer) ReadFrom(r io.Reader) (n int64, err error) {
b.lastRead = opInvalid
// If buffer is empty, reset to recover space.
@@ -188,10 +191,10 @@ func makeSlice(n int) []byte {
return make([]byte, n)
}
-// WriteTo writes data to w until the buffer is drained or an error
-// occurs. The return value n is the number of bytes written; it always
-// fits into an int, but it is int64 to match the io.WriterTo interface.
-// Any error encountered during the write is also returned.
+// WriteTo writes data to w until the buffer is drained or an error occurs.
+// The return value n is the number of bytes written; it always fits into an
+// int, but it is int64 to match the io.WriterTo interface. Any error
+// encountered during the write is also returned.
func (b *Buffer) WriteTo(w io.Writer) (n int64, err error) {
b.lastRead = opInvalid
if b.off < len(b.buf) {
@@ -216,10 +219,9 @@ func (b *Buffer) WriteTo(w io.Writer) (n int64, err error) {
return
}
-// WriteByte appends the byte c to the buffer.
-// The returned error is always nil, but is included
-// to match bufio.Writer's WriteByte.
-// If the buffer becomes too large, WriteByte will panic with
+// WriteByte appends the byte c to the buffer, growing the buffer as needed.
+// The returned error is always nil, but is included to match bufio.Writer's
+// WriteByte. If the buffer becomes too large, WriteByte will panic with
// ErrTooLarge.
func (b *Buffer) WriteByte(c byte) error {
b.lastRead = opInvalid
@@ -228,12 +230,10 @@ func (b *Buffer) WriteByte(c byte) error {
return nil
}
-// WriteRune appends the UTF-8 encoding of Unicode
-// code point r to the buffer, returning its length and
-// an error, which is always nil but is included
-// to match bufio.Writer's WriteRune.
-// If the buffer becomes too large, WriteRune will panic with
-// ErrTooLarge.
+// WriteRune appends the UTF-8 encoding of Unicode code point r to the
+// buffer, returning its length and an error, which is always nil but is
+// included to match bufio.Writer's WriteRune. The buffer is grown as needed;
+// if it becomes too large, WriteRune will panic with ErrTooLarge.
func (b *Buffer) WriteRune(r rune) (n int, err error) {
if r < utf8.RuneSelf {
b.WriteByte(byte(r))
diff --git a/src/pkg/bytes/buffer_test.go b/src/pkg/bytes/buffer_test.go
index f9fb2625a..75145b05e 100644
--- a/src/pkg/bytes/buffer_test.go
+++ b/src/pkg/bytes/buffer_test.go
@@ -475,3 +475,53 @@ func TestUnreadByte(t *testing.T) {
t.Errorf("ReadByte = %q; want %q", c, 'm')
}
}
+
+// Tests that we occasionally compact. Issue 5154.
+func TestBufferGrowth(t *testing.T) {
+ var b Buffer
+ buf := make([]byte, 1024)
+ b.Write(buf[0:1])
+ var cap0 int
+ for i := 0; i < 5<<10; i++ {
+ b.Write(buf)
+ b.Read(buf)
+ if i == 0 {
+ cap0 = b.Cap()
+ }
+ }
+ cap1 := b.Cap()
+ // (*Buffer).grow allows for 2x capacity slop before sliding,
+ // so set our error threshold at 3x.
+ if cap1 > cap0*3 {
+ t.Errorf("buffer cap = %d; too big (grew from %d)", cap1, cap0)
+ }
+}
+
+// From Issue 5154.
+func BenchmarkBufferNotEmptyWriteRead(b *testing.B) {
+ buf := make([]byte, 1024)
+ for i := 0; i < b.N; i++ {
+ var b Buffer
+ b.Write(buf[0:1])
+ for i := 0; i < 5<<10; i++ {
+ b.Write(buf)
+ b.Read(buf)
+ }
+ }
+}
+
+// Check that we don't compact too often. From Issue 5154.
+func BenchmarkBufferFullSmallReads(b *testing.B) {
+ buf := make([]byte, 1024)
+ for i := 0; i < b.N; i++ {
+ var b Buffer
+ b.Write(buf)
+ for b.Len()+20 < b.Cap() {
+ b.Write(buf[:10])
+ }
+ for i := 0; i < 5<<10; i++ {
+ b.Read(buf[:1])
+ b.Write(buf[:1])
+ }
+ }
+}
diff --git a/src/pkg/bytes/bytes.go b/src/pkg/bytes/bytes.go
index 3bab65ef9..e42f74439 100644
--- a/src/pkg/bytes/bytes.go
+++ b/src/pkg/bytes/bytes.go
@@ -461,10 +461,10 @@ func isSeparator(r rune) bool {
return unicode.IsSpace(r)
}
-// BUG(r): The rule Title uses for word boundaries does not handle Unicode punctuation properly.
-
// Title returns a copy of s with all Unicode letters that begin words
// mapped to their title case.
+//
+// BUG: The rule Title uses for word boundaries does not handle Unicode punctuation properly.
func Title(s []byte) []byte {
// Use a closure here to remember state.
// Hackish but effective. Depends on Map scanning in order and calling
diff --git a/src/pkg/bytes/bytes_decl.go b/src/pkg/bytes/bytes_decl.go
index ce78be416..fbf928275 100644
--- a/src/pkg/bytes/bytes_decl.go
+++ b/src/pkg/bytes/bytes_decl.go
@@ -13,4 +13,4 @@ func IndexByte(s []byte, c byte) int // asm_$GOARCH.s
// Equal returns a boolean reporting whether a == b.
// A nil argument is equivalent to an empty slice.
-func Equal(a, b []byte) bool // asm_$GOARCH.s
+func Equal(a, b []byte) bool // asm_arm.s or ../runtime/asm_{386,amd64}.s
diff --git a/src/pkg/bytes/bytes_test.go b/src/pkg/bytes/bytes_test.go
index 1d6274c33..d296224ac 100644
--- a/src/pkg/bytes/bytes_test.go
+++ b/src/pkg/bytes/bytes_test.go
@@ -61,6 +61,10 @@ var compareTests = []struct {
{[]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},
@@ -86,6 +90,58 @@ func TestCompare(t *testing.T) {
}
}
+func TestEqual(t *testing.T) {
+ var size = 128
+ if testing.Short() {
+ size = 32
+ }
+ a := make([]byte, size)
+ b := make([]byte, size)
+ b_init := make([]byte, size)
+ // randomish but deterministic data
+ for i := 0; i < size; i++ {
+ a[i] = byte(17 * i)
+ b_init[i] = byte(23*i + 100)
+ }
+
+ for len := 0; len <= size; len++ {
+ for x := 0; x <= size-len; x++ {
+ for y := 0; y <= size-len; y++ {
+ copy(b, b_init)
+ copy(b[y:y+len], a[x:x+len])
+ if !Equal(a[x:x+len], b[y:y+len]) || !Equal(b[y:y+len], a[x:x+len]) {
+ t.Errorf("Equal(%d, %d, %d) = false", len, x, y)
+ }
+ }
+ }
+ }
+}
+
+// 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
+ if testing.Short() {
+ size = 32
+ }
+ a := make([]byte, size)
+ b := make([]byte, size)
+
+ for len := 0; len <= size; len++ {
+ for x := 0; x <= size-len; x++ {
+ for y := 0; y <= size-len; y++ {
+ for diffpos := x; diffpos < x+len; diffpos++ {
+ a[diffpos] = 1
+ if Equal(a[x:x+len], b[y:y+len]) || Equal(b[y:y+len], a[x:x+len]) {
+ t.Errorf("NotEqual(%d, %d, %d, %d) = true", len, x, y, diffpos)
+ }
+ a[diffpos] = 0
+ }
+ }
+ }
+ }
+}
+
var indexTests = []BinOpTest{
{"", "", 0},
{"", "a", -1},
@@ -303,10 +359,30 @@ func bmIndexByte(b *testing.B, index func([]byte, byte) int, n int) {
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) }
diff --git a/src/pkg/bytes/equal_test.go b/src/pkg/bytes/equal_test.go
new file mode 100644
index 000000000..1bf19a74b
--- /dev/null
+++ b/src/pkg/bytes/equal_test.go
@@ -0,0 +1,47 @@
+// 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 bytes_test
+
+import (
+ . "bytes"
+ "syscall"
+ "testing"
+ "unsafe"
+)
+
+// This file tests the situation where memeq is checking
+// 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
+// not OS-specific, so it does not need to be tested on all
+// operating systems.
+
+func TestEqualNearPageBoundary(t *testing.T) {
+ pagesize := syscall.Getpagesize()
+ b := make([]byte, 4*pagesize)
+ i := pagesize
+ for ; uintptr(unsafe.Pointer(&b[i]))%uintptr(pagesize) != 0; i++ {
+ }
+ syscall.Mprotect(b[i-pagesize:i], 0)
+ syscall.Mprotect(b[i+pagesize:i+2*pagesize], 0)
+ defer syscall.Mprotect(b[i-pagesize:i], syscall.PROT_READ|syscall.PROT_WRITE)
+ defer syscall.Mprotect(b[i+pagesize:i+2*pagesize], syscall.PROT_READ|syscall.PROT_WRITE)
+
+ // both of these should fault
+ //pagesize += int(b[i-1])
+ //pagesize += int(b[i+pagesize])
+
+ for j := 0; j < pagesize; j++ {
+ b[i+j] = 'A'
+ }
+ for j := 0; j <= pagesize; j++ {
+ Equal(b[i:i+j], b[i+pagesize-j:i+pagesize])
+ Equal(b[i+pagesize-j:i+pagesize], b[i:i+j])
+ }
+}
diff --git a/src/pkg/bytes/export_test.go b/src/pkg/bytes/export_test.go
index f61523e60..3b915d5ea 100644
--- a/src/pkg/bytes/export_test.go
+++ b/src/pkg/bytes/export_test.go
@@ -7,3 +7,7 @@ package bytes
// Export func for testing
var IndexBytePortable = indexBytePortable
var EqualPortable = equalPortable
+
+func (b *Buffer) Cap() int {
+ return cap(b.buf)
+}
diff --git a/src/pkg/compress/bzip2/huffman.go b/src/pkg/compress/bzip2/huffman.go
index 078c1cb89..f755019bb 100644
--- a/src/pkg/compress/bzip2/huffman.go
+++ b/src/pkg/compress/bzip2/huffman.go
@@ -54,8 +54,6 @@ func (t huffmanTree) Decode(br *bitReader) (v uint16) {
nodeIndex = node.right
}
}
-
- panic("unreachable")
}
// newHuffmanTree builds a Huffman tree from a slice containing the code
diff --git a/src/pkg/compress/flate/deflate_test.go b/src/pkg/compress/flate/deflate_test.go
index 8f4e196b4..8c4a6d6b3 100644
--- a/src/pkg/compress/flate/deflate_test.go
+++ b/src/pkg/compress/flate/deflate_test.go
@@ -158,7 +158,6 @@ func (b *syncBuffer) Read(p []byte) (n int, err error) {
}
<-b.ready
}
- panic("unreachable")
}
func (b *syncBuffer) signal() {
diff --git a/src/pkg/compress/flate/inflate.go b/src/pkg/compress/flate/inflate.go
index a8d646019..beca34b4d 100644
--- a/src/pkg/compress/flate/inflate.go
+++ b/src/pkg/compress/flate/inflate.go
@@ -263,7 +263,6 @@ func (f *decompressor) Read(b []byte) (int, error) {
}
f.step(f)
}
- panic("unreachable")
}
func (f *decompressor) Close() error {
@@ -495,7 +494,6 @@ func (f *decompressor) huffmanBlock() {
return
}
}
- panic("unreached")
}
// copyHist copies f.copyLen bytes from f.hist (f.copyDist bytes ago) to itself.
@@ -642,7 +640,6 @@ func (f *decompressor) huffSym(h *huffmanDecoder) (int, error) {
return int(chunk >> huffmanValueShift), nil
}
}
- return 0, CorruptInputError(f.roffset)
}
// Flush any buffered output to the underlying writer.
diff --git a/src/pkg/compress/flate/token.go b/src/pkg/compress/flate/token.go
index 38aea5fa6..4d4917687 100644
--- a/src/pkg/compress/flate/token.go
+++ b/src/pkg/compress/flate/token.go
@@ -99,5 +99,4 @@ func offsetCode(off uint32) uint32 {
default:
return offsetCodes[off>>14] + 28
}
- panic("unreachable")
}
diff --git a/src/pkg/compress/gzip/gunzip.go b/src/pkg/compress/gzip/gunzip.go
index 33736f635..1fb9b0964 100644
--- a/src/pkg/compress/gzip/gunzip.go
+++ b/src/pkg/compress/gzip/gunzip.go
@@ -120,7 +120,6 @@ func (z *Reader) readString() (string, error) {
return string(z.buf[0:i]), nil
}
}
- panic("not reached")
}
func (z *Reader) read2() (uint32, error) {
diff --git a/src/pkg/compress/gzip/gzip.go b/src/pkg/compress/gzip/gzip.go
index 3035dfffc..45558b742 100644
--- a/src/pkg/compress/gzip/gzip.go
+++ b/src/pkg/compress/gzip/gzip.go
@@ -28,7 +28,7 @@ type Writer struct {
Header
w io.Writer
level int
- compressor io.WriteCloser
+ compressor *flate.Writer
digest hash.Hash32
size uint32
closed bool
@@ -191,6 +191,28 @@ func (z *Writer) Write(p []byte) (int, error) {
return n, z.err
}
+// Flush flushes any pending compressed 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. 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.
+func (z *Writer) Flush() error {
+ if z.err != nil {
+ return z.err
+ }
+ if z.closed {
+ return nil
+ }
+ if z.compressor == nil {
+ z.Write(nil)
+ }
+ z.err = z.compressor.Flush()
+ return z.err
+}
+
// Close closes the Writer. It does not close the underlying io.Writer.
func (z *Writer) Close() error {
if z.err != nil {
diff --git a/src/pkg/compress/gzip/gzip_test.go b/src/pkg/compress/gzip/gzip_test.go
index 6f7b59364..4d1af9438 100644
--- a/src/pkg/compress/gzip/gzip_test.go
+++ b/src/pkg/compress/gzip/gzip_test.go
@@ -157,3 +157,43 @@ func TestLatin1RoundTrip(t *testing.T) {
}
}
}
+
+func TestWriterFlush(t *testing.T) {
+ buf := new(bytes.Buffer)
+
+ w := NewWriter(buf)
+ w.Comment = "comment"
+ w.Extra = []byte("extra")
+ w.ModTime = time.Unix(1e8, 0)
+ w.Name = "name"
+
+ n0 := buf.Len()
+ if n0 != 0 {
+ t.Fatalf("buffer size = %d before writes; want 0", n0)
+ }
+
+ if err := w.Flush(); err != nil {
+ t.Fatal(err)
+ }
+
+ n1 := buf.Len()
+ if n1 == 0 {
+ t.Fatal("no data after first flush")
+ }
+
+ w.Write([]byte("x"))
+
+ n2 := buf.Len()
+ if n1 != n2 {
+ t.Fatalf("after writing a single byte, size changed from %d to %d; want no change", n1, n2)
+ }
+
+ if err := w.Flush(); err != nil {
+ t.Fatal(err)
+ }
+
+ n3 := buf.Len()
+ if n2 == n3 {
+ t.Fatal("Flush didn't flush any data")
+ }
+}
diff --git a/src/pkg/compress/lzw/reader.go b/src/pkg/compress/lzw/reader.go
index 0ed742c89..efbc758f9 100644
--- a/src/pkg/compress/lzw/reader.go
+++ b/src/pkg/compress/lzw/reader.go
@@ -121,7 +121,6 @@ func (d *decoder) Read(b []byte) (int, error) {
}
d.decode()
}
- panic("unreachable")
}
// decode decompresses bytes from r and leaves them in d.toRead.
@@ -203,7 +202,6 @@ func (d *decoder) decode() {
return
}
}
- panic("unreachable")
}
func (d *decoder) flush() {
diff --git a/src/pkg/crypto/cipher/example_test.go b/src/pkg/crypto/cipher/example_test.go
index e0027cac2..373f6791b 100644
--- a/src/pkg/crypto/cipher/example_test.go
+++ b/src/pkg/crypto/cipher/example_test.go
@@ -233,7 +233,7 @@ func ExampleStreamReader() {
}
defer outFile.Close()
- reader := &cipher.StreamReader{stream, inFile}
+ reader := &cipher.StreamReader{S: stream, R: inFile}
// Copy the input file to the output file, decrypting as we go.
if _, err := io.Copy(outFile, reader); err != nil {
panic(err)
@@ -270,7 +270,7 @@ func ExampleStreamWriter() {
}
defer outFile.Close()
- writer := &cipher.StreamWriter{stream, outFile, nil}
+ writer := &cipher.StreamWriter{S: stream, W: outFile}
// Copy the input file to the output file, encrypting as we go.
if _, err := io.Copy(writer, inFile); err != nil {
panic(err)
diff --git a/src/pkg/crypto/dsa/dsa.go b/src/pkg/crypto/dsa/dsa.go
index 05766a2f1..5a2a65744 100644
--- a/src/pkg/crypto/dsa/dsa.go
+++ b/src/pkg/crypto/dsa/dsa.go
@@ -144,8 +144,6 @@ GeneratePrimes:
params.G = g
return
}
-
- panic("unreachable")
}
// GenerateKey generates a public&private key pair. The Parameters of the
diff --git a/src/pkg/crypto/dsa/dsa_test.go b/src/pkg/crypto/dsa/dsa_test.go
index 177aa444d..568416d0d 100644
--- a/src/pkg/crypto/dsa/dsa_test.go
+++ b/src/pkg/crypto/dsa/dsa_test.go
@@ -63,8 +63,9 @@ func testParameterGeneration(t *testing.T, sizes ParameterSizes, L, N int) {
}
func TestParameterGeneration(t *testing.T) {
- // This test is too slow to run all the time.
- return
+ if testing.Short() {
+ t.Skip("skipping parameter generation test in short mode")
+ }
testParameterGeneration(t, L1024N160, 1024, 160)
testParameterGeneration(t, L2048N224, 2048, 224)
diff --git a/src/pkg/crypto/ecdsa/ecdsa.go b/src/pkg/crypto/ecdsa/ecdsa.go
index 512d20c63..255000229 100644
--- a/src/pkg/crypto/ecdsa/ecdsa.go
+++ b/src/pkg/crypto/ecdsa/ecdsa.go
@@ -49,7 +49,7 @@ func randFieldElement(c elliptic.Curve, rand io.Reader) (k *big.Int, err error)
return
}
-// GenerateKey generates a public&private key pair.
+// GenerateKey generates a public and private key pair.
func GenerateKey(c elliptic.Curve, rand io.Reader) (priv *PrivateKey, err error) {
k, err := randFieldElement(c, rand)
if err != nil {
diff --git a/src/pkg/crypto/md5/gen.go b/src/pkg/crypto/md5/gen.go
index 966bdae26..275b4aeea 100644
--- a/src/pkg/crypto/md5/gen.go
+++ b/src/pkg/crypto/md5/gen.go
@@ -161,6 +161,11 @@ var data = Data{
}
var program = `
+// DO NOT EDIT.
+// Generate with: go run gen.go{{if .Full}} -full{{end}} | gofmt >md5block.go
+
+// +build !amd64
+
package md5
import (
@@ -186,6 +191,16 @@ import (
}
{{end}}
+const x86 = runtime.GOARCH == "amd64" || runtime.GOARCH == "386"
+
+var littleEndian bool
+
+func init() {
+ x := uint32(0x04030201)
+ y := [4]byte{0x1, 0x2, 0x3, 0x4}
+ littleEndian = *(*[4]byte)(unsafe.Pointer(&x)) == y
+}
+
func block(dig *digest, p []byte) {
a := dig.s[0]
b := dig.s[1]
@@ -197,13 +212,13 @@ func block(dig *digest, p []byte) {
aa, bb, cc, dd := a, b, c, d
// This is a constant condition - it is not evaluated on each iteration.
- if runtime.GOARCH == "amd64" || runtime.GOARCH == "386" {
+ if x86 {
// MD5 was designed so that x86 processors can just iterate
// over the block data directly as uint32s, and we generate
// less code and run 1.3x faster if we take advantage of that.
// My apologies.
X = (*[16]uint32)(unsafe.Pointer(&p[0]))
- } else if uintptr(unsafe.Pointer(&p[0]))&(unsafe.Alignof(uint32(0))-1) == 0 {
+ } else if littleEndian && uintptr(unsafe.Pointer(&p[0]))&(unsafe.Alignof(uint32(0))-1) == 0 {
X = (*[16]uint32)(unsafe.Pointer(&p[0]))
} else {
X = &xbuf
diff --git a/src/pkg/crypto/md5/md5block.go b/src/pkg/crypto/md5/md5block.go
index 0ca421774..a376fbee9 100644
--- a/src/pkg/crypto/md5/md5block.go
+++ b/src/pkg/crypto/md5/md5block.go
@@ -1,3 +1,8 @@
+// DO NOT EDIT.
+// Generate with: go run gen.go -full | gofmt >md5block.go
+
+// +build !amd64,!386
+
package md5
import (
diff --git a/src/pkg/crypto/md5/md5block_386.s b/src/pkg/crypto/md5/md5block_386.s
new file mode 100644
index 000000000..3ce15e37f
--- /dev/null
+++ b/src/pkg/crypto/md5/md5block_386.s
@@ -0,0 +1,180 @@
+// Original source:
+// http://www.zorinaq.com/papers/md5-amd64.html
+// http://www.zorinaq.com/papers/md5-amd64.tar.bz2
+//
+// Translated from Perl generating GNU assembly into
+// #defines generating 8a assembly, and adjusted for 386,
+// by the Go Authors.
+
+// MD5 optimized for AMD64.
+//
+// Author: Marc Bevand <bevand_m (at) epita.fr>
+// Licence: I hereby disclaim the copyright on this code and place it
+// in the public domain.
+
+#define ROUND1(a, b, c, d, index, const, shift) \
+ XORL c, BP; \
+ LEAL const(a)(DI*1), a; \
+ ANDL b, BP; \
+ XORL d, BP; \
+ MOVL (index*4)(SI), DI; \
+ ADDL BP, a; \
+ ROLL $shift, a; \
+ MOVL c, BP; \
+ ADDL b, a
+
+#define ROUND2(a, b, c, d, index, const, shift) \
+ LEAL const(a)(DI*1),a; \
+ MOVL d, DI; \
+ ANDL b, DI; \
+ MOVL d, BP; \
+ NOTL BP; \
+ ANDL c, BP; \
+ ORL DI, BP; \
+ MOVL (index*4)(SI),DI; \
+ ADDL BP, a; \
+ ROLL $shift, a; \
+ ADDL b, a
+
+#define ROUND3(a, b, c, d, index, const, shift) \
+ LEAL const(a)(DI*1),a; \
+ MOVL (index*4)(SI),DI; \
+ XORL d, BP; \
+ XORL b, BP; \
+ ADDL BP, a; \
+ ROLL $shift, a; \
+ MOVL b, BP; \
+ ADDL b, a
+
+#define ROUND4(a, b, c, d, index, const, shift) \
+ LEAL const(a)(DI*1),a; \
+ ORL b, BP; \
+ XORL c, BP; \
+ ADDL BP, a; \
+ MOVL (index*4)(SI),DI; \
+ MOVL $0xffffffff, BP; \
+ ROLL $shift, a; \
+ XORL c, BP; \
+ ADDL b, a
+
+TEXT ·block(SB),7,$24-16
+ MOVL dig+0(FP), BP
+ MOVL p+4(FP), SI
+ MOVL p_len+8(FP), DX
+ SHRL $6, DX
+ SHLL $6, DX
+
+ LEAL (SI)(DX*1), DI
+ MOVL (0*4)(BP), AX
+ MOVL (1*4)(BP), BX
+ MOVL (2*4)(BP), CX
+ MOVL (3*4)(BP), DX
+
+ CMPL SI, DI
+ JEQ end
+
+ MOVL DI, 16(SP)
+
+loop:
+ MOVL AX, 0(SP)
+ MOVL BX, 4(SP)
+ MOVL CX, 8(SP)
+ MOVL DX, 12(SP)
+
+ MOVL (0*4)(SI), DI
+ MOVL DX, BP
+
+ ROUND1(AX,BX,CX,DX, 1,0xd76aa478, 7);
+ ROUND1(DX,AX,BX,CX, 2,0xe8c7b756,12);
+ ROUND1(CX,DX,AX,BX, 3,0x242070db,17);
+ ROUND1(BX,CX,DX,AX, 4,0xc1bdceee,22);
+ ROUND1(AX,BX,CX,DX, 5,0xf57c0faf, 7);
+ ROUND1(DX,AX,BX,CX, 6,0x4787c62a,12);
+ ROUND1(CX,DX,AX,BX, 7,0xa8304613,17);
+ ROUND1(BX,CX,DX,AX, 8,0xfd469501,22);
+ ROUND1(AX,BX,CX,DX, 9,0x698098d8, 7);
+ ROUND1(DX,AX,BX,CX,10,0x8b44f7af,12);
+ ROUND1(CX,DX,AX,BX,11,0xffff5bb1,17);
+ ROUND1(BX,CX,DX,AX,12,0x895cd7be,22);
+ ROUND1(AX,BX,CX,DX,13,0x6b901122, 7);
+ ROUND1(DX,AX,BX,CX,14,0xfd987193,12);
+ ROUND1(CX,DX,AX,BX,15,0xa679438e,17);
+ ROUND1(BX,CX,DX,AX, 0,0x49b40821,22);
+
+ MOVL (1*4)(SI), DI
+ MOVL DX, BP
+
+ ROUND2(AX,BX,CX,DX, 6,0xf61e2562, 5);
+ ROUND2(DX,AX,BX,CX,11,0xc040b340, 9);
+ ROUND2(CX,DX,AX,BX, 0,0x265e5a51,14);
+ ROUND2(BX,CX,DX,AX, 5,0xe9b6c7aa,20);
+ ROUND2(AX,BX,CX,DX,10,0xd62f105d, 5);
+ ROUND2(DX,AX,BX,CX,15, 0x2441453, 9);
+ ROUND2(CX,DX,AX,BX, 4,0xd8a1e681,14);
+ ROUND2(BX,CX,DX,AX, 9,0xe7d3fbc8,20);
+ ROUND2(AX,BX,CX,DX,14,0x21e1cde6, 5);
+ ROUND2(DX,AX,BX,CX, 3,0xc33707d6, 9);
+ ROUND2(CX,DX,AX,BX, 8,0xf4d50d87,14);
+ ROUND2(BX,CX,DX,AX,13,0x455a14ed,20);
+ ROUND2(AX,BX,CX,DX, 2,0xa9e3e905, 5);
+ ROUND2(DX,AX,BX,CX, 7,0xfcefa3f8, 9);
+ ROUND2(CX,DX,AX,BX,12,0x676f02d9,14);
+ ROUND2(BX,CX,DX,AX, 0,0x8d2a4c8a,20);
+
+ MOVL (5*4)(SI), DI
+ MOVL CX, BP
+
+ ROUND3(AX,BX,CX,DX, 8,0xfffa3942, 4);
+ ROUND3(DX,AX,BX,CX,11,0x8771f681,11);
+ ROUND3(CX,DX,AX,BX,14,0x6d9d6122,16);
+ ROUND3(BX,CX,DX,AX, 1,0xfde5380c,23);
+ ROUND3(AX,BX,CX,DX, 4,0xa4beea44, 4);
+ ROUND3(DX,AX,BX,CX, 7,0x4bdecfa9,11);
+ ROUND3(CX,DX,AX,BX,10,0xf6bb4b60,16);
+ ROUND3(BX,CX,DX,AX,13,0xbebfbc70,23);
+ ROUND3(AX,BX,CX,DX, 0,0x289b7ec6, 4);
+ ROUND3(DX,AX,BX,CX, 3,0xeaa127fa,11);
+ ROUND3(CX,DX,AX,BX, 6,0xd4ef3085,16);
+ ROUND3(BX,CX,DX,AX, 9, 0x4881d05,23);
+ ROUND3(AX,BX,CX,DX,12,0xd9d4d039, 4);
+ ROUND3(DX,AX,BX,CX,15,0xe6db99e5,11);
+ ROUND3(CX,DX,AX,BX, 2,0x1fa27cf8,16);
+ ROUND3(BX,CX,DX,AX, 0,0xc4ac5665,23);
+
+ MOVL (0*4)(SI), DI
+ MOVL $0xffffffff, BP
+ XORL DX, BP
+
+ ROUND4(AX,BX,CX,DX, 7,0xf4292244, 6);
+ ROUND4(DX,AX,BX,CX,14,0x432aff97,10);
+ ROUND4(CX,DX,AX,BX, 5,0xab9423a7,15);
+ ROUND4(BX,CX,DX,AX,12,0xfc93a039,21);
+ ROUND4(AX,BX,CX,DX, 3,0x655b59c3, 6);
+ ROUND4(DX,AX,BX,CX,10,0x8f0ccc92,10);
+ ROUND4(CX,DX,AX,BX, 1,0xffeff47d,15);
+ ROUND4(BX,CX,DX,AX, 8,0x85845dd1,21);
+ ROUND4(AX,BX,CX,DX,15,0x6fa87e4f, 6);
+ ROUND4(DX,AX,BX,CX, 6,0xfe2ce6e0,10);
+ ROUND4(CX,DX,AX,BX,13,0xa3014314,15);
+ ROUND4(BX,CX,DX,AX, 4,0x4e0811a1,21);
+ ROUND4(AX,BX,CX,DX,11,0xf7537e82, 6);
+ ROUND4(DX,AX,BX,CX, 2,0xbd3af235,10);
+ ROUND4(CX,DX,AX,BX, 9,0x2ad7d2bb,15);
+ ROUND4(BX,CX,DX,AX, 0,0xeb86d391,21);
+
+ ADDL 0(SP), AX
+ ADDL 4(SP), BX
+ ADDL 8(SP), CX
+ ADDL 12(SP), DX
+
+ ADDL $64, SI
+ CMPL SI, 16(SP)
+ JB loop
+
+end:
+ MOVL dig+0(FP), BP
+ MOVL AX, (0*4)(BP)
+ MOVL BX, (1*4)(BP)
+ MOVL CX, (2*4)(BP)
+ MOVL DX, (3*4)(BP)
+ RET
diff --git a/src/pkg/crypto/md5/md5block_amd64.s b/src/pkg/crypto/md5/md5block_amd64.s
new file mode 100644
index 000000000..e6420a28a
--- /dev/null
+++ b/src/pkg/crypto/md5/md5block_amd64.s
@@ -0,0 +1,177 @@
+// Original source:
+// http://www.zorinaq.com/papers/md5-amd64.html
+// http://www.zorinaq.com/papers/md5-amd64.tar.bz2
+//
+// Translated from Perl generating GNU assembly into
+// #defines generating 6a assembly by the Go Authors.
+
+// MD5 optimized for AMD64.
+//
+// Author: Marc Bevand <bevand_m (at) epita.fr>
+// Licence: I hereby disclaim the copyright on this code and place it
+// in the public domain.
+
+TEXT ·block(SB),7,$0-32
+ MOVQ dig+0(FP), BP
+ MOVQ p+8(FP), SI
+ MOVQ p_len+16(FP), DX
+ SHRQ $6, DX
+ SHLQ $6, DX
+
+ LEAQ (SI)(DX*1), DI
+ MOVL (0*4)(BP), AX
+ MOVL (1*4)(BP), BX
+ MOVL (2*4)(BP), CX
+ MOVL (3*4)(BP), DX
+
+ CMPQ SI, DI
+ JEQ end
+
+loop:
+ MOVL AX, R12
+ MOVL BX, R13
+ MOVL CX, R14
+ MOVL DX, R15
+
+ MOVL (0*4)(SI), R8
+ MOVL DX, R9
+
+#define ROUND1(a, b, c, d, index, const, shift) \
+ XORL c, R9; \
+ LEAL const(a)(R8*1), a; \
+ ANDL b, R9; \
+ XORL d, R9; \
+ MOVL (index*4)(SI), R8; \
+ ADDL R9, a; \
+ ROLL $shift, a; \
+ MOVL c, R9; \
+ ADDL b, a
+
+ ROUND1(AX,BX,CX,DX, 1,0xd76aa478, 7);
+ ROUND1(DX,AX,BX,CX, 2,0xe8c7b756,12);
+ ROUND1(CX,DX,AX,BX, 3,0x242070db,17);
+ ROUND1(BX,CX,DX,AX, 4,0xc1bdceee,22);
+ ROUND1(AX,BX,CX,DX, 5,0xf57c0faf, 7);
+ ROUND1(DX,AX,BX,CX, 6,0x4787c62a,12);
+ ROUND1(CX,DX,AX,BX, 7,0xa8304613,17);
+ ROUND1(BX,CX,DX,AX, 8,0xfd469501,22);
+ ROUND1(AX,BX,CX,DX, 9,0x698098d8, 7);
+ ROUND1(DX,AX,BX,CX,10,0x8b44f7af,12);
+ ROUND1(CX,DX,AX,BX,11,0xffff5bb1,17);
+ ROUND1(BX,CX,DX,AX,12,0x895cd7be,22);
+ ROUND1(AX,BX,CX,DX,13,0x6b901122, 7);
+ ROUND1(DX,AX,BX,CX,14,0xfd987193,12);
+ ROUND1(CX,DX,AX,BX,15,0xa679438e,17);
+ ROUND1(BX,CX,DX,AX, 0,0x49b40821,22);
+
+ MOVL (1*4)(SI), R8
+ MOVL DX, R9
+ MOVL DX, R10
+
+#define ROUND2(a, b, c, d, index, const, shift) \
+ NOTL R9; \
+ LEAL const(a)(R8*1),a; \
+ ANDL b, R10; \
+ ANDL c, R9; \
+ MOVL (index*4)(SI),R8; \
+ ORL R9, R10; \
+ MOVL c, R9; \
+ ADDL R10, a; \
+ MOVL c, R10; \
+ ROLL $shift, a; \
+ ADDL b, a
+
+ ROUND2(AX,BX,CX,DX, 6,0xf61e2562, 5);
+ ROUND2(DX,AX,BX,CX,11,0xc040b340, 9);
+ ROUND2(CX,DX,AX,BX, 0,0x265e5a51,14);
+ ROUND2(BX,CX,DX,AX, 5,0xe9b6c7aa,20);
+ ROUND2(AX,BX,CX,DX,10,0xd62f105d, 5);
+ ROUND2(DX,AX,BX,CX,15, 0x2441453, 9);
+ ROUND2(CX,DX,AX,BX, 4,0xd8a1e681,14);
+ ROUND2(BX,CX,DX,AX, 9,0xe7d3fbc8,20);
+ ROUND2(AX,BX,CX,DX,14,0x21e1cde6, 5);
+ ROUND2(DX,AX,BX,CX, 3,0xc33707d6, 9);
+ ROUND2(CX,DX,AX,BX, 8,0xf4d50d87,14);
+ ROUND2(BX,CX,DX,AX,13,0x455a14ed,20);
+ ROUND2(AX,BX,CX,DX, 2,0xa9e3e905, 5);
+ ROUND2(DX,AX,BX,CX, 7,0xfcefa3f8, 9);
+ ROUND2(CX,DX,AX,BX,12,0x676f02d9,14);
+ ROUND2(BX,CX,DX,AX, 0,0x8d2a4c8a,20);
+
+ MOVL (5*4)(SI), R8
+ MOVL CX, R9
+
+#define ROUND3(a, b, c, d, index, const, shift) \
+ LEAL const(a)(R8*1),a; \
+ MOVL (index*4)(SI),R8; \
+ XORL d, R9; \
+ XORL b, R9; \
+ ADDL R9, a; \
+ ROLL $shift, a; \
+ MOVL b, R9; \
+ ADDL b, a
+
+ ROUND3(AX,BX,CX,DX, 8,0xfffa3942, 4);
+ ROUND3(DX,AX,BX,CX,11,0x8771f681,11);
+ ROUND3(CX,DX,AX,BX,14,0x6d9d6122,16);
+ ROUND3(BX,CX,DX,AX, 1,0xfde5380c,23);
+ ROUND3(AX,BX,CX,DX, 4,0xa4beea44, 4);
+ ROUND3(DX,AX,BX,CX, 7,0x4bdecfa9,11);
+ ROUND3(CX,DX,AX,BX,10,0xf6bb4b60,16);
+ ROUND3(BX,CX,DX,AX,13,0xbebfbc70,23);
+ ROUND3(AX,BX,CX,DX, 0,0x289b7ec6, 4);
+ ROUND3(DX,AX,BX,CX, 3,0xeaa127fa,11);
+ ROUND3(CX,DX,AX,BX, 6,0xd4ef3085,16);
+ ROUND3(BX,CX,DX,AX, 9, 0x4881d05,23);
+ ROUND3(AX,BX,CX,DX,12,0xd9d4d039, 4);
+ ROUND3(DX,AX,BX,CX,15,0xe6db99e5,11);
+ ROUND3(CX,DX,AX,BX, 2,0x1fa27cf8,16);
+ ROUND3(BX,CX,DX,AX, 0,0xc4ac5665,23);
+
+ MOVL (0*4)(SI), R8
+ MOVL $0xffffffff, R9
+ XORL DX, R9
+
+#define ROUND4(a, b, c, d, index, const, shift) \
+ LEAL const(a)(R8*1),a; \
+ ORL b, R9; \
+ XORL c, R9; \
+ ADDL R9, a; \
+ MOVL (index*4)(SI),R8; \
+ MOVL $0xffffffff, R9; \
+ ROLL $shift, a; \
+ XORL c, R9; \
+ ADDL b, a
+
+ ROUND4(AX,BX,CX,DX, 7,0xf4292244, 6);
+ ROUND4(DX,AX,BX,CX,14,0x432aff97,10);
+ ROUND4(CX,DX,AX,BX, 5,0xab9423a7,15);
+ ROUND4(BX,CX,DX,AX,12,0xfc93a039,21);
+ ROUND4(AX,BX,CX,DX, 3,0x655b59c3, 6);
+ ROUND4(DX,AX,BX,CX,10,0x8f0ccc92,10);
+ ROUND4(CX,DX,AX,BX, 1,0xffeff47d,15);
+ ROUND4(BX,CX,DX,AX, 8,0x85845dd1,21);
+ ROUND4(AX,BX,CX,DX,15,0x6fa87e4f, 6);
+ ROUND4(DX,AX,BX,CX, 6,0xfe2ce6e0,10);
+ ROUND4(CX,DX,AX,BX,13,0xa3014314,15);
+ ROUND4(BX,CX,DX,AX, 4,0x4e0811a1,21);
+ ROUND4(AX,BX,CX,DX,11,0xf7537e82, 6);
+ ROUND4(DX,AX,BX,CX, 2,0xbd3af235,10);
+ ROUND4(CX,DX,AX,BX, 9,0x2ad7d2bb,15);
+ ROUND4(BX,CX,DX,AX, 0,0xeb86d391,21);
+
+ ADDL R12, AX
+ ADDL R13, BX
+ ADDL R14, CX
+ ADDL R15, DX
+
+ ADDQ $64, SI
+ CMPQ SI, DI
+ JB loop
+
+end:
+ MOVL AX, (0*4)(BP)
+ MOVL BX, (1*4)(BP)
+ MOVL CX, (2*4)(BP)
+ MOVL DX, (3*4)(BP)
+ RET
diff --git a/src/pkg/crypto/md5/md5block_decl.go b/src/pkg/crypto/md5/md5block_decl.go
new file mode 100644
index 000000000..14190c6ff
--- /dev/null
+++ b/src/pkg/crypto/md5/md5block_decl.go
@@ -0,0 +1,9 @@
+// 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 386
+
+package md5
+
+func block(dig *digest, p []byte)
diff --git a/src/pkg/crypto/rand/util.go b/src/pkg/crypto/rand/util.go
index 50e5b162b..0cd5e0e02 100644
--- a/src/pkg/crypto/rand/util.go
+++ b/src/pkg/crypto/rand/util.go
@@ -98,12 +98,13 @@ func Prime(rand io.Reader, bits int) (p *big.Int, err error) {
return
}
}
-
- return
}
-// Int returns a uniform random value in [0, max).
+// Int returns a uniform random value in [0, max). It panics if max <= 0.
func Int(rand io.Reader, max *big.Int) (n *big.Int, err error) {
+ if max.Sign() <= 0 {
+ panic("crypto/rand: argument to Int is <= 0")
+ }
k := (max.BitLen() + 7) / 8
// b is the number of bits in the most significant byte of max.
@@ -130,6 +131,4 @@ func Int(rand io.Reader, max *big.Int) (n *big.Int, err error) {
return
}
}
-
- return
}
diff --git a/src/pkg/crypto/rc4/rc4.go b/src/pkg/crypto/rc4/rc4.go
index e0c33fa4b..3d717c63b 100644
--- a/src/pkg/crypto/rc4/rc4.go
+++ b/src/pkg/crypto/rc4/rc4.go
@@ -13,7 +13,7 @@ import "strconv"
// A Cipher is an instance of RC4 using a particular key.
type Cipher struct {
- s [256]byte
+ s [256]uint32
i, j uint8
}
@@ -32,11 +32,11 @@ func NewCipher(key []byte) (*Cipher, error) {
}
var c Cipher
for i := 0; i < 256; i++ {
- c.s[i] = uint8(i)
+ c.s[i] = uint32(i)
}
var j uint8 = 0
for i := 0; i < 256; i++ {
- j += c.s[i] + key[i%k]
+ j += uint8(c.s[i]) + key[i%k]
c.s[i], c.s[j] = c.s[j], c.s[i]
}
return &c, nil
diff --git a/src/pkg/crypto/rc4/rc4_386.s b/src/pkg/crypto/rc4/rc4_386.s
new file mode 100644
index 000000000..c80ef2a3a
--- /dev/null
+++ b/src/pkg/crypto/rc4/rc4_386.s
@@ -0,0 +1,51 @@
+// 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.
+
+// func xorKeyStream(dst, src *byte, n int, state *[256]byte, i, j *uint8)
+TEXT ·xorKeyStream(SB),7,$0
+ MOVL dst+0(FP), DI
+ MOVL src+4(FP), SI
+ MOVL state+12(FP), BP
+
+ MOVL i+16(FP), AX
+ MOVBLZX (AX), AX
+ MOVL j+20(FP), BX
+ MOVBLZX (BX), BX
+ CMPL n+8(FP), $0
+ JEQ done
+
+loop:
+ // i += 1
+ INCB AX
+
+ // j += c.s[i]
+ MOVBLZX (BP)(AX*4), DX
+ ADDB DX, BX
+ MOVBLZX BX, BX
+
+ // c.s[i], c.s[j] = c.s[j], c.s[i]
+ MOVBLZX (BP)(BX*4), CX
+ MOVB CX, (BP)(AX*4)
+ MOVB DX, (BP)(BX*4)
+
+ // *dst = *src ^ c.s[c.s[i]+c.s[j]]
+ ADDB DX, CX
+ MOVBLZX CX, CX
+ MOVB (BP)(CX*4), CX
+ XORB (SI), CX
+ MOVBLZX CX, CX
+ MOVB CX, (DI)
+
+ INCL SI
+ INCL DI
+ DECL n+8(FP)
+ JNE loop
+
+done:
+ MOVL i+16(FP), CX
+ MOVB AX, (CX)
+ MOVL j+20(FP), CX
+ MOVB BX, (CX)
+
+ RET
diff --git a/src/pkg/crypto/rc4/rc4_amd64.s b/src/pkg/crypto/rc4/rc4_amd64.s
index ffe9ada85..353fe3720 100644
--- a/src/pkg/crypto/rc4/rc4_amd64.s
+++ b/src/pkg/crypto/rc4/rc4_amd64.s
@@ -1,53 +1,177 @@
-// 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.
+// Original source:
+// http://www.zorinaq.com/papers/rc4-amd64.html
+// http://www.zorinaq.com/papers/rc4-amd64.tar.bz2
+
+// Local modifications:
+//
+// Transliterated from GNU to 6a assembly syntax by the Go authors.
+// The comments and spacing are from the original.
+//
+// The new EXTEND macros avoid a bad stall on some systems after 8-bit math.
+//
+// The original code accumulated 64 bits of key stream in an integer
+// register and then XOR'ed the key stream into the data 8 bytes at a time.
+// Modified to accumulate 128 bits of key stream into an XMM register
+// and then XOR the key stream into the data 16 bytes at a time.
+// Approximately doubles throughput.
+
+// NOTE: Changing EXTEND to a no-op makes the code run 1.2x faster on Core i5
+// but makes the code run 2.0x slower on Xeon.
+#define EXTEND(r) MOVBLZX r, r
+
+/*
+** RC4 implementation optimized for AMD64.
+**
+** Author: Marc Bevand <bevand_m (at) epita.fr>
+** Licence: I hereby disclaim the copyright on this code and place it
+** in the public domain.
+**
+** The code has been designed to be easily integrated into openssl:
+** the exported RC4() function can replace the actual implementations
+** openssl already contains. Please note that when linking with openssl,
+** it requires that sizeof(RC4_INT) == 8. So openssl must be compiled
+** with -DRC4_INT='unsigned long'.
+**
+** The throughput achieved by this code is about 320 MBytes/sec, on
+** a 1.8 GHz AMD Opteron (rev C0) processor.
+*/
-// func xorKeyStream(dst, src *byte, n int, state *[256]byte, i, j *uint8)
TEXT ·xorKeyStream(SB),7,$0
- MOVQ dst+0(FP), DI
- MOVQ src+8(FP), SI
- MOVQ n+16(FP), CX
- MOVQ state+24(FP), R8
+ MOVQ n+16(FP), BX // rbx = ARG(len)
+ MOVQ src+8(FP), SI // in = ARG(in)
+ MOVQ dst+0(FP), DI // out = ARG(out)
+ MOVQ state+24(FP), BP // d = ARG(data)
+ MOVQ i+32(FP), AX
+ MOVBQZX 0(AX), CX // x = *xp
+ MOVQ j+40(FP), AX
+ MOVBQZX 0(AX), DX // y = *yp
+
+ LEAQ (SI)(BX*1), R9 // limit = in+len
+
+l1: CMPQ SI, R9 // cmp in with in+len
+ JGE finished // jump if (in >= in+len)
+
+ INCB CX
+ EXTEND(CX)
+ TESTL $15, CX
+ JZ wordloop
+
+ MOVBLZX (BP)(CX*4), AX
+
+ ADDB AX, DX // y += tx
+ EXTEND(DX)
+ MOVBLZX (BP)(DX*4), BX // ty = d[y]
+ MOVB BX, (BP)(CX*4) // d[x] = ty
+ ADDB AX, BX // val = ty+tx
+ EXTEND(BX)
+ MOVB AX, (BP)(DX*4) // d[y] = tx
+ MOVBLZX (BP)(BX*4), R8 // val = d[val]
+ XORB (SI), R8 // xor 1 byte
+ MOVB R8, (DI)
+ INCQ SI // in++
+ INCQ DI // out++
+ JMP l1
+
+wordloop:
+ SUBQ $16, R9
+ CMPQ SI, R9
+ JGT end
+
+start:
+ ADDQ $16, SI // increment in
+ ADDQ $16, DI // increment out
+
+ // Each KEYROUND generates one byte of key and
+ // inserts it into an XMM register at the given 16-bit index.
+ // The key state array is uint32 words only using the bottom
+ // byte of each word, so the 16-bit OR only copies 8 useful bits.
+ // We accumulate alternating bytes into X0 and X1, and then at
+ // the end we OR X1<<8 into X0 to produce the actual key.
+ //
+ // At the beginning of the loop, CX%16 == 0, so the 16 loads
+ // at state[CX], state[CX+1], ..., state[CX+15] can precompute
+ // (state+CX) as R12 and then become R12[0], R12[1], ... R12[15],
+ // without fear of the byte computation CX+15 wrapping around.
+ //
+ // The first round needs R12[0], the second needs R12[1], and so on.
+ // We can avoid memory stalls by starting the load for round n+1
+ // before the end of round n, using the LOAD macro.
+ LEAQ (BP)(CX*4), R12
- MOVQ xPtr+32(FP), AX
- MOVBQZX (AX), AX
- MOVQ yPtr+40(FP), BX
- MOVBQZX (BX), BX
+#define KEYROUND(xmm, load, off, r1, r2, index) \
+ MOVBLZX (BP)(DX*4), R8; \
+ MOVB r1, (BP)(DX*4); \
+ load((off+1), r2); \
+ MOVB R8, (off*4)(R12); \
+ ADDB r1, R8; \
+ EXTEND(R8); \
+ PINSRW $index, (BP)(R8*4), xmm
-loop:
- CMPQ CX, $0
- JE done
+#define LOAD(off, reg) \
+ MOVBLZX (off*4)(R12), reg; \
+ ADDB reg, DX; \
+ EXTEND(DX)
- // c.i += 1
- INCB AX
+#define SKIP(off, reg)
- // c.j += c.s[c.i]
- MOVB (R8)(AX*1), R9
- ADDB R9, BX
+ LOAD(0, AX)
+ KEYROUND(X0, LOAD, 0, AX, BX, 0)
+ KEYROUND(X1, LOAD, 1, BX, AX, 0)
+ KEYROUND(X0, LOAD, 2, AX, BX, 1)
+ KEYROUND(X1, LOAD, 3, BX, AX, 1)
+ KEYROUND(X0, LOAD, 4, AX, BX, 2)
+ KEYROUND(X1, LOAD, 5, BX, AX, 2)
+ KEYROUND(X0, LOAD, 6, AX, BX, 3)
+ KEYROUND(X1, LOAD, 7, BX, AX, 3)
+ KEYROUND(X0, LOAD, 8, AX, BX, 4)
+ KEYROUND(X1, LOAD, 9, BX, AX, 4)
+ KEYROUND(X0, LOAD, 10, AX, BX, 5)
+ KEYROUND(X1, LOAD, 11, BX, AX, 5)
+ KEYROUND(X0, LOAD, 12, AX, BX, 6)
+ KEYROUND(X1, LOAD, 13, BX, AX, 6)
+ KEYROUND(X0, LOAD, 14, AX, BX, 7)
+ KEYROUND(X1, SKIP, 15, BX, AX, 7)
+
+ ADDB $16, CX
- MOVBQZX (R8)(BX*1), R10
+ PSLLQ $8, X1
+ PXOR X1, X0
+ MOVOU -16(SI), X2
+ PXOR X0, X2
+ MOVOU X2, -16(DI)
- MOVB R10, (R8)(AX*1)
- MOVB R9, (R8)(BX*1)
+ CMPQ SI, R9 // cmp in with in+len-16
+ JLE start // jump if (in <= in+len-16)
- // R11 = c.s[c.i]+c.s[c.j]
- MOVQ R10, R11
- ADDB R9, R11
+end:
+ DECB CX
+ ADDQ $16, R9 // tmp = in+len
- MOVB (R8)(R11*1), R11
- MOVB (SI), R12
- XORB R11, R12
- MOVB R12, (DI)
+ // handle the last bytes, one by one
+l2: CMPQ SI, R9 // cmp in with in+len
+ JGE finished // jump if (in >= in+len)
- INCQ SI
- INCQ DI
- DECQ CX
+ INCB CX
+ EXTEND(CX)
+ MOVBLZX (BP)(CX*4), AX
- JMP loop
-done:
- MOVQ xPtr+32(FP), R8
- MOVB AX, (R8)
- MOVQ yPtr+40(FP), R8
- MOVB BX, (R8)
+ ADDB AX, DX // y += tx
+ EXTEND(DX)
+ MOVBLZX (BP)(DX*4), BX // ty = d[y]
+ MOVB BX, (BP)(CX*4) // d[x] = ty
+ ADDB AX, BX // val = ty+tx
+ EXTEND(BX)
+ MOVB AX, (BP)(DX*4) // d[y] = tx
+ MOVBLZX (BP)(BX*4), R8 // val = d[val]
+ XORB (SI), R8 // xor 1 byte
+ MOVB R8, (DI)
+ INCQ SI // in++
+ INCQ DI // out++
+ JMP l2
+finished:
+ MOVQ j+40(FP), BX
+ MOVB DX, 0(BX)
+ MOVQ i+32(FP), AX
+ MOVB CX, 0(AX)
RET
diff --git a/src/pkg/crypto/rc4/rc4_arm.s b/src/pkg/crypto/rc4/rc4_arm.s
index 51a332f62..307cb7148 100644
--- a/src/pkg/crypto/rc4/rc4_arm.s
+++ b/src/pkg/crypto/rc4/rc4_arm.s
@@ -31,19 +31,19 @@ loop:
// i += 1; j += state[i]
ADD $1, R(i)
AND $0xff, R(i)
- MOVBU R(i)<<0(R(state)), R(t)
+ MOVBU R(i)<<2(R(state)), R(t)
ADD R(t), R(j)
AND $0xff, R(j)
// swap state[i] <-> state[j]
- MOVBU R(j)<<0(R(state)), R(t2)
- MOVB R(t2), R(i)<<0(R(state))
- MOVB R(t), R(j)<<0(R(state))
+ MOVBU R(j)<<2(R(state)), R(t2)
+ MOVB R(t2), R(i)<<2(R(state))
+ MOVB R(t), R(j)<<2(R(state))
// dst[k] = src[k] ^ state[state[i] + state[j]]
ADD R(t2), R(t)
AND $0xff, R(t)
- MOVBU R(t)<<0(R(state)), R(t)
+ MOVBU R(t)<<2(R(state)), R(t)
MOVBU R(k)<<0(R(src)), R(t2)
EOR R(t), R(t2)
MOVB R(t2), R(k)<<0(R(dst))
diff --git a/src/pkg/crypto/rc4/rc4_asm.go b/src/pkg/crypto/rc4/rc4_asm.go
index 0b66e4a9e..c582a4488 100644
--- a/src/pkg/crypto/rc4/rc4_asm.go
+++ b/src/pkg/crypto/rc4/rc4_asm.go
@@ -2,11 +2,11 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// +build amd64 arm
+// +build amd64 arm 386
package rc4
-func xorKeyStream(dst, src *byte, n int, state *[256]byte, i, j *uint8)
+func xorKeyStream(dst, src *byte, n int, state *[256]uint32, i, j *uint8)
// XORKeyStream sets dst to the result of XORing src with the key stream.
// Dst and src may be the same slice but otherwise should not overlap.
diff --git a/src/pkg/crypto/rc4/rc4_ref.go b/src/pkg/crypto/rc4/rc4_ref.go
index 1018548c2..44d380436 100644
--- a/src/pkg/crypto/rc4/rc4_ref.go
+++ b/src/pkg/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,!arm
+// +build !amd64,!arm,!386
package rc4
diff --git a/src/pkg/crypto/rc4/rc4_test.go b/src/pkg/crypto/rc4/rc4_test.go
index 9e12789f7..7b4df6791 100644
--- a/src/pkg/crypto/rc4/rc4_test.go
+++ b/src/pkg/crypto/rc4/rc4_test.go
@@ -5,6 +5,8 @@
package rc4
import (
+ "bytes"
+ "fmt"
"testing"
)
@@ -72,25 +74,68 @@ var golden = []rc4Test{
},
}
+func testEncrypt(t *testing.T, desc string, c *Cipher, src, expect []byte) {
+ dst := make([]byte, len(src))
+ c.XORKeyStream(dst, src)
+ for i, v := range dst {
+ if v != expect[i] {
+ t.Fatalf("%s: mismatch at byte %d:\nhave %x\nwant %x", desc, i, dst, expect)
+ }
+ }
+}
+
func TestGolden(t *testing.T) {
- for i := 0; i < len(golden); i++ {
- g := golden[i]
- c, err := NewCipher(g.key)
- if err != nil {
- t.Errorf("Failed to create cipher at golden index %d", i)
- return
+ for gi, g := range golden {
+ data := make([]byte, len(g.keystream))
+ for i := range data {
+ data[i] = byte(i)
}
- keystream := make([]byte, len(g.keystream))
- c.XORKeyStream(keystream, keystream)
- for j, v := range keystream {
- if g.keystream[j] != v {
- t.Errorf("Failed at golden index %d:\n%x\nvs\n%x", i, keystream, g.keystream)
- break
+
+ expect := make([]byte, len(g.keystream))
+ for i := range expect {
+ expect[i] = byte(i) ^ g.keystream[i]
+ }
+
+ for size := 1; size <= len(g.keystream); size++ {
+ c, err := NewCipher(g.key)
+ if err != nil {
+ t.Fatalf("#%d: NewCipher: %v", gi, err)
+ }
+
+ off := 0
+ for off < len(g.keystream) {
+ n := len(g.keystream) - off
+ if n > size {
+ n = size
+ }
+ desc := fmt.Sprintf("#%d@[%d:%d]", gi, off, off+n)
+ testEncrypt(t, desc, c, data[off:off+n], expect[off:off+n])
+ off += n
}
}
}
}
+func TestBlock(t *testing.T) {
+ c1a, _ := NewCipher(golden[0].key)
+ c1b, _ := NewCipher(golden[1].key)
+ data1 := make([]byte, 1<<20)
+ for i := range data1 {
+ c1a.XORKeyStream(data1[i:i+1], data1[i:i+1])
+ c1b.XORKeyStream(data1[i:i+1], data1[i:i+1])
+ }
+
+ c2a, _ := NewCipher(golden[0].key)
+ c2b, _ := NewCipher(golden[1].key)
+ data2 := make([]byte, 1<<20)
+ c2a.XORKeyStream(data2, data2)
+ c2b.XORKeyStream(data2, data2)
+
+ if !bytes.Equal(data1, data2) {
+ t.Fatalf("bad block")
+ }
+}
+
func benchmark(b *testing.B, size int64) {
buf := make([]byte, size)
c, err := NewCipher(golden[0].key)
diff --git a/src/pkg/crypto/rsa/rsa.go b/src/pkg/crypto/rsa/rsa.go
index 35a5f7c3c..f56fb37ee 100644
--- a/src/pkg/crypto/rsa/rsa.go
+++ b/src/pkg/crypto/rsa/rsa.go
@@ -203,7 +203,9 @@ NextSetOfPrimes:
g.GCD(priv.D, y, e, totient)
if g.Cmp(bigOne) == 0 {
- priv.D.Add(priv.D, totient)
+ if priv.D.Sign() < 0 {
+ priv.D.Add(priv.D, totient)
+ }
priv.Primes = primes
priv.N = n
diff --git a/src/pkg/crypto/rsa/rsa_test.go b/src/pkg/crypto/rsa/rsa_test.go
index f08cfe73c..ffd96e62f 100644
--- a/src/pkg/crypto/rsa/rsa_test.go
+++ b/src/pkg/crypto/rsa/rsa_test.go
@@ -93,6 +93,9 @@ func testKeyBasics(t *testing.T, priv *PrivateKey) {
if err := priv.Validate(); err != nil {
t.Errorf("Validate() failed: %s", err)
}
+ if priv.D.Cmp(priv.N) > 0 {
+ t.Errorf("private exponent too large")
+ }
pub := &priv.PublicKey
m := big.NewInt(42)
diff --git a/src/pkg/crypto/sha1/sha1block.go b/src/pkg/crypto/sha1/sha1block.go
index 1c9507c68..92224fc0e 100644
--- a/src/pkg/crypto/sha1/sha1block.go
+++ b/src/pkg/crypto/sha1/sha1block.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 !amd64,!386
+
// SHA1 block step.
// In its own file so that a faster assembly or C version
// can be substituted easily.
diff --git a/src/pkg/crypto/sha1/sha1block_386.s b/src/pkg/crypto/sha1/sha1block_386.s
new file mode 100644
index 000000000..e60a7b9b0
--- /dev/null
+++ b/src/pkg/crypto/sha1/sha1block_386.s
@@ -0,0 +1,233 @@
+// 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.
+
+// SHA1 block routine. See sha1block.go for Go equivalent.
+//
+// There are 80 rounds of 4 types:
+// - rounds 0-15 are type 1 and load data (ROUND1 macro).
+// - rounds 16-19 are type 1 and do not load data (ROUND1x macro).
+// - rounds 20-39 are type 2 and do not load data (ROUND2 macro).
+// - rounds 40-59 are type 3 and do not load data (ROUND3 macro).
+// - rounds 60-79 are type 4 and do not load data (ROUND4 macro).
+//
+// Each round loads or shuffles the data, then computes a per-round
+// function of b, c, d, and then mixes the result into and rotates the
+// five registers a, b, c, d, e holding the intermediate results.
+//
+// The register rotation is implemented by rotating the arguments to
+// the round macros instead of by explicit move instructions.
+
+// Like sha1block_amd64.s, but we keep the data and limit pointers on the stack.
+// To free up the word pointer (R10 on amd64, DI here), we add it to e during
+// LOAD/SHUFFLE instead of during MIX.
+//
+// The stack holds the intermediate word array - 16 uint32s - at 0(SP) up to 64(SP).
+// The saved a, b, c, d, e (R11 through R15 on amd64) are at 64(SP) up to 84(SP).
+// The saved limit pointer (DI on amd64) is at 84(SP).
+// The saved data pointer (SI on amd64) is at 88(SP).
+
+#define LOAD(index, e) \
+ MOVL 88(SP), SI; \
+ MOVL (index*4)(SI), DI; \
+ BSWAPL DI; \
+ MOVL DI, (index*4)(SP); \
+ ADDL DI, e
+
+#define SHUFFLE(index, e) \
+ MOVL (((index)&0xf)*4)(SP), DI; \
+ XORL (((index-3)&0xf)*4)(SP), DI; \
+ XORL (((index-8)&0xf)*4)(SP), DI; \
+ XORL (((index-14)&0xf)*4)(SP), DI; \
+ ROLL $1, DI; \
+ MOVL DI, (((index)&0xf)*4)(SP); \
+ ADDL DI, e
+
+#define FUNC1(a, b, c, d, e) \
+ MOVL b, SI; \
+ ANDL c, SI; \
+ MOVL b, DI; \
+ NOTL DI; \
+ ANDL d, DI; \
+ ORL SI, DI
+
+#define FUNC2(a, b, c, d, e) \
+ MOVL b, DI; \
+ XORL c, DI; \
+ XORL d, DI
+
+#define FUNC3(a, b, c, d, e) \
+ MOVL b, SI; \
+ ORL c, SI; \
+ ANDL d, SI; \
+ MOVL b, DI; \
+ ANDL c, DI; \
+ ORL SI, DI
+
+#define FUNC4 FUNC2
+
+#define MIX(a, b, c, d, e, const) \
+ ROLL $30, b; \
+ ADDL DI, e; \
+ MOVL a, SI; \
+ ROLL $5, SI; \
+ LEAL const(e)(SI*1), e
+
+#define ROUND1(a, b, c, d, e, index) \
+ LOAD(index, e); \
+ FUNC1(a, b, c, d, e); \
+ MIX(a, b, c, d, e, 0x5A827999)
+
+#define ROUND1x(a, b, c, d, e, index) \
+ SHUFFLE(index, e); \
+ FUNC1(a, b, c, d, e); \
+ MIX(a, b, c, d, e, 0x5A827999)
+
+#define ROUND2(a, b, c, d, e, index) \
+ SHUFFLE(index, e); \
+ FUNC2(a, b, c, d, e); \
+ MIX(a, b, c, d, e, 0x6ED9EBA1)
+
+#define ROUND3(a, b, c, d, e, index) \
+ SHUFFLE(index, e); \
+ FUNC3(a, b, c, d, e); \
+ MIX(a, b, c, d, e, 0x8F1BBCDC)
+
+#define ROUND4(a, b, c, d, e, index) \
+ SHUFFLE(index, e); \
+ FUNC4(a, b, c, d, e); \
+ MIX(a, b, c, d, e, 0xCA62C1D6)
+
+// func block(dig *digest, p []byte)
+TEXT ·block(SB),7,$92-16
+ MOVL dig+0(FP), BP
+ MOVL p+4(FP), SI
+ MOVL p_len+8(FP), DX
+ SHRL $6, DX
+ SHLL $6, DX
+
+ LEAL (SI)(DX*1), DI
+ MOVL (0*4)(BP), AX
+ MOVL (1*4)(BP), BX
+ MOVL (2*4)(BP), CX
+ MOVL (3*4)(BP), DX
+ MOVL (4*4)(BP), BP
+
+ CMPL SI, DI
+ JEQ end
+
+ MOVL DI, 84(SP)
+
+loop:
+ MOVL SI, 88(SP)
+
+ MOVL AX, 64(SP)
+ MOVL BX, 68(SP)
+ MOVL CX, 72(SP)
+ MOVL DX, 76(SP)
+ MOVL BP, 80(SP)
+
+ ROUND1(AX, BX, CX, DX, BP, 0)
+ ROUND1(BP, AX, BX, CX, DX, 1)
+ ROUND1(DX, BP, AX, BX, CX, 2)
+ ROUND1(CX, DX, BP, AX, BX, 3)
+ ROUND1(BX, CX, DX, BP, AX, 4)
+ ROUND1(AX, BX, CX, DX, BP, 5)
+ ROUND1(BP, AX, BX, CX, DX, 6)
+ ROUND1(DX, BP, AX, BX, CX, 7)
+ ROUND1(CX, DX, BP, AX, BX, 8)
+ ROUND1(BX, CX, DX, BP, AX, 9)
+ ROUND1(AX, BX, CX, DX, BP, 10)
+ ROUND1(BP, AX, BX, CX, DX, 11)
+ ROUND1(DX, BP, AX, BX, CX, 12)
+ ROUND1(CX, DX, BP, AX, BX, 13)
+ ROUND1(BX, CX, DX, BP, AX, 14)
+ ROUND1(AX, BX, CX, DX, BP, 15)
+
+ ROUND1x(BP, AX, BX, CX, DX, 16)
+ ROUND1x(DX, BP, AX, BX, CX, 17)
+ ROUND1x(CX, DX, BP, AX, BX, 18)
+ ROUND1x(BX, CX, DX, BP, AX, 19)
+
+ ROUND2(AX, BX, CX, DX, BP, 20)
+ ROUND2(BP, AX, BX, CX, DX, 21)
+ ROUND2(DX, BP, AX, BX, CX, 22)
+ ROUND2(CX, DX, BP, AX, BX, 23)
+ ROUND2(BX, CX, DX, BP, AX, 24)
+ ROUND2(AX, BX, CX, DX, BP, 25)
+ ROUND2(BP, AX, BX, CX, DX, 26)
+ ROUND2(DX, BP, AX, BX, CX, 27)
+ ROUND2(CX, DX, BP, AX, BX, 28)
+ ROUND2(BX, CX, DX, BP, AX, 29)
+ ROUND2(AX, BX, CX, DX, BP, 30)
+ ROUND2(BP, AX, BX, CX, DX, 31)
+ ROUND2(DX, BP, AX, BX, CX, 32)
+ ROUND2(CX, DX, BP, AX, BX, 33)
+ ROUND2(BX, CX, DX, BP, AX, 34)
+ ROUND2(AX, BX, CX, DX, BP, 35)
+ ROUND2(BP, AX, BX, CX, DX, 36)
+ ROUND2(DX, BP, AX, BX, CX, 37)
+ ROUND2(CX, DX, BP, AX, BX, 38)
+ ROUND2(BX, CX, DX, BP, AX, 39)
+
+ ROUND3(AX, BX, CX, DX, BP, 40)
+ ROUND3(BP, AX, BX, CX, DX, 41)
+ ROUND3(DX, BP, AX, BX, CX, 42)
+ ROUND3(CX, DX, BP, AX, BX, 43)
+ ROUND3(BX, CX, DX, BP, AX, 44)
+ ROUND3(AX, BX, CX, DX, BP, 45)
+ ROUND3(BP, AX, BX, CX, DX, 46)
+ ROUND3(DX, BP, AX, BX, CX, 47)
+ ROUND3(CX, DX, BP, AX, BX, 48)
+ ROUND3(BX, CX, DX, BP, AX, 49)
+ ROUND3(AX, BX, CX, DX, BP, 50)
+ ROUND3(BP, AX, BX, CX, DX, 51)
+ ROUND3(DX, BP, AX, BX, CX, 52)
+ ROUND3(CX, DX, BP, AX, BX, 53)
+ ROUND3(BX, CX, DX, BP, AX, 54)
+ ROUND3(AX, BX, CX, DX, BP, 55)
+ ROUND3(BP, AX, BX, CX, DX, 56)
+ ROUND3(DX, BP, AX, BX, CX, 57)
+ ROUND3(CX, DX, BP, AX, BX, 58)
+ ROUND3(BX, CX, DX, BP, AX, 59)
+
+ ROUND4(AX, BX, CX, DX, BP, 60)
+ ROUND4(BP, AX, BX, CX, DX, 61)
+ ROUND4(DX, BP, AX, BX, CX, 62)
+ ROUND4(CX, DX, BP, AX, BX, 63)
+ ROUND4(BX, CX, DX, BP, AX, 64)
+ ROUND4(AX, BX, CX, DX, BP, 65)
+ ROUND4(BP, AX, BX, CX, DX, 66)
+ ROUND4(DX, BP, AX, BX, CX, 67)
+ ROUND4(CX, DX, BP, AX, BX, 68)
+ ROUND4(BX, CX, DX, BP, AX, 69)
+ ROUND4(AX, BX, CX, DX, BP, 70)
+ ROUND4(BP, AX, BX, CX, DX, 71)
+ ROUND4(DX, BP, AX, BX, CX, 72)
+ ROUND4(CX, DX, BP, AX, BX, 73)
+ ROUND4(BX, CX, DX, BP, AX, 74)
+ ROUND4(AX, BX, CX, DX, BP, 75)
+ ROUND4(BP, AX, BX, CX, DX, 76)
+ ROUND4(DX, BP, AX, BX, CX, 77)
+ ROUND4(CX, DX, BP, AX, BX, 78)
+ ROUND4(BX, CX, DX, BP, AX, 79)
+
+ ADDL 64(SP), AX
+ ADDL 68(SP), BX
+ ADDL 72(SP), CX
+ ADDL 76(SP), DX
+ ADDL 80(SP), BP
+
+ MOVL 88(SP), SI
+ ADDL $64, SI
+ CMPL SI, 84(SP)
+ JB loop
+
+end:
+ MOVL dig+0(FP), DI
+ MOVL AX, (0*4)(DI)
+ MOVL BX, (1*4)(DI)
+ MOVL CX, (2*4)(DI)
+ MOVL DX, (3*4)(DI)
+ MOVL BP, (4*4)(DI)
+ RET
diff --git a/src/pkg/crypto/sha1/sha1block_amd64.s b/src/pkg/crypto/sha1/sha1block_amd64.s
new file mode 100644
index 000000000..452578aa4
--- /dev/null
+++ b/src/pkg/crypto/sha1/sha1block_amd64.s
@@ -0,0 +1,216 @@
+// 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.
+
+// SHA1 block routine. See sha1block.go for Go equivalent.
+//
+// There are 80 rounds of 4 types:
+// - rounds 0-15 are type 1 and load data (ROUND1 macro).
+// - rounds 16-19 are type 1 and do not load data (ROUND1x macro).
+// - rounds 20-39 are type 2 and do not load data (ROUND2 macro).
+// - rounds 40-59 are type 3 and do not load data (ROUND3 macro).
+// - rounds 60-79 are type 4 and do not load data (ROUND4 macro).
+//
+// Each round loads or shuffles the data, then computes a per-round
+// function of b, c, d, and then mixes the result into and rotates the
+// five registers a, b, c, d, e holding the intermediate results.
+//
+// The register rotation is implemented by rotating the arguments to
+// the round macros instead of by explicit move instructions.
+
+#define LOAD(index) \
+ MOVL (index*4)(SI), R10; \
+ BSWAPL R10; \
+ MOVL R10, (index*4)(SP)
+
+#define SHUFFLE(index) \
+ MOVL (((index)&0xf)*4)(SP), R10; \
+ XORL (((index-3)&0xf)*4)(SP), R10; \
+ XORL (((index-8)&0xf)*4)(SP), R10; \
+ XORL (((index-14)&0xf)*4)(SP), R10; \
+ ROLL $1, R10; \
+ MOVL R10, (((index)&0xf)*4)(SP)
+
+#define FUNC1(a, b, c, d, e) \
+ MOVL b, R8; \
+ ANDL c, R8; \
+ MOVL b, R9; \
+ NOTL R9; \
+ ANDL d, R9; \
+ ORL R8, R9
+
+#define FUNC2(a, b, c, d, e) \
+ MOVL b, R9; \
+ XORL c, R9; \
+ XORL d, R9
+
+#define FUNC3(a, b, c, d, e) \
+ MOVL b, R8; \
+ ORL c, R8; \
+ ANDL d, R8; \
+ MOVL b, R9; \
+ ANDL c, R9; \
+ ORL R8, R9
+
+#define FUNC4 FUNC2
+
+#define MIX(a, b, c, d, e, const) \
+ ROLL $30, b; \
+ ADDL R9, e; \
+ MOVL a, R8; \
+ ROLL $5, R8; \
+ LEAL const(e)(R10*1), e; \
+ ADDL R8, e
+
+#define ROUND1(a, b, c, d, e, index) \
+ LOAD(index); \
+ FUNC1(a, b, c, d, e); \
+ MIX(a, b, c, d, e, 0x5A827999)
+
+#define ROUND1x(a, b, c, d, e, index) \
+ SHUFFLE(index); \
+ FUNC1(a, b, c, d, e); \
+ MIX(a, b, c, d, e, 0x5A827999)
+
+#define ROUND2(a, b, c, d, e, index) \
+ SHUFFLE(index); \
+ FUNC2(a, b, c, d, e); \
+ MIX(a, b, c, d, e, 0x6ED9EBA1)
+
+#define ROUND3(a, b, c, d, e, index) \
+ SHUFFLE(index); \
+ FUNC3(a, b, c, d, e); \
+ MIX(a, b, c, d, e, 0x8F1BBCDC)
+
+#define ROUND4(a, b, c, d, e, index) \
+ SHUFFLE(index); \
+ FUNC4(a, b, c, d, e); \
+ MIX(a, b, c, d, e, 0xCA62C1D6)
+
+TEXT ·block(SB),7,$64-32
+ MOVQ dig+0(FP), BP
+ MOVQ p_base+8(FP), SI
+ MOVQ p_len+16(FP), DX
+ SHRQ $6, DX
+ SHLQ $6, DX
+
+ LEAQ (SI)(DX*1), DI
+ MOVL (0*4)(BP), AX
+ MOVL (1*4)(BP), BX
+ MOVL (2*4)(BP), CX
+ MOVL (3*4)(BP), DX
+ MOVL (4*4)(BP), BP
+
+ CMPQ SI, DI
+ JEQ end
+
+loop:
+ MOVL AX, R11
+ MOVL BX, R12
+ MOVL CX, R13
+ MOVL DX, R14
+ MOVL BP, R15
+
+ ROUND1(AX, BX, CX, DX, BP, 0)
+ ROUND1(BP, AX, BX, CX, DX, 1)
+ ROUND1(DX, BP, AX, BX, CX, 2)
+ ROUND1(CX, DX, BP, AX, BX, 3)
+ ROUND1(BX, CX, DX, BP, AX, 4)
+ ROUND1(AX, BX, CX, DX, BP, 5)
+ ROUND1(BP, AX, BX, CX, DX, 6)
+ ROUND1(DX, BP, AX, BX, CX, 7)
+ ROUND1(CX, DX, BP, AX, BX, 8)
+ ROUND1(BX, CX, DX, BP, AX, 9)
+ ROUND1(AX, BX, CX, DX, BP, 10)
+ ROUND1(BP, AX, BX, CX, DX, 11)
+ ROUND1(DX, BP, AX, BX, CX, 12)
+ ROUND1(CX, DX, BP, AX, BX, 13)
+ ROUND1(BX, CX, DX, BP, AX, 14)
+ ROUND1(AX, BX, CX, DX, BP, 15)
+
+ ROUND1x(BP, AX, BX, CX, DX, 16)
+ ROUND1x(DX, BP, AX, BX, CX, 17)
+ ROUND1x(CX, DX, BP, AX, BX, 18)
+ ROUND1x(BX, CX, DX, BP, AX, 19)
+
+ ROUND2(AX, BX, CX, DX, BP, 20)
+ ROUND2(BP, AX, BX, CX, DX, 21)
+ ROUND2(DX, BP, AX, BX, CX, 22)
+ ROUND2(CX, DX, BP, AX, BX, 23)
+ ROUND2(BX, CX, DX, BP, AX, 24)
+ ROUND2(AX, BX, CX, DX, BP, 25)
+ ROUND2(BP, AX, BX, CX, DX, 26)
+ ROUND2(DX, BP, AX, BX, CX, 27)
+ ROUND2(CX, DX, BP, AX, BX, 28)
+ ROUND2(BX, CX, DX, BP, AX, 29)
+ ROUND2(AX, BX, CX, DX, BP, 30)
+ ROUND2(BP, AX, BX, CX, DX, 31)
+ ROUND2(DX, BP, AX, BX, CX, 32)
+ ROUND2(CX, DX, BP, AX, BX, 33)
+ ROUND2(BX, CX, DX, BP, AX, 34)
+ ROUND2(AX, BX, CX, DX, BP, 35)
+ ROUND2(BP, AX, BX, CX, DX, 36)
+ ROUND2(DX, BP, AX, BX, CX, 37)
+ ROUND2(CX, DX, BP, AX, BX, 38)
+ ROUND2(BX, CX, DX, BP, AX, 39)
+
+ ROUND3(AX, BX, CX, DX, BP, 40)
+ ROUND3(BP, AX, BX, CX, DX, 41)
+ ROUND3(DX, BP, AX, BX, CX, 42)
+ ROUND3(CX, DX, BP, AX, BX, 43)
+ ROUND3(BX, CX, DX, BP, AX, 44)
+ ROUND3(AX, BX, CX, DX, BP, 45)
+ ROUND3(BP, AX, BX, CX, DX, 46)
+ ROUND3(DX, BP, AX, BX, CX, 47)
+ ROUND3(CX, DX, BP, AX, BX, 48)
+ ROUND3(BX, CX, DX, BP, AX, 49)
+ ROUND3(AX, BX, CX, DX, BP, 50)
+ ROUND3(BP, AX, BX, CX, DX, 51)
+ ROUND3(DX, BP, AX, BX, CX, 52)
+ ROUND3(CX, DX, BP, AX, BX, 53)
+ ROUND3(BX, CX, DX, BP, AX, 54)
+ ROUND3(AX, BX, CX, DX, BP, 55)
+ ROUND3(BP, AX, BX, CX, DX, 56)
+ ROUND3(DX, BP, AX, BX, CX, 57)
+ ROUND3(CX, DX, BP, AX, BX, 58)
+ ROUND3(BX, CX, DX, BP, AX, 59)
+
+ ROUND4(AX, BX, CX, DX, BP, 60)
+ ROUND4(BP, AX, BX, CX, DX, 61)
+ ROUND4(DX, BP, AX, BX, CX, 62)
+ ROUND4(CX, DX, BP, AX, BX, 63)
+ ROUND4(BX, CX, DX, BP, AX, 64)
+ ROUND4(AX, BX, CX, DX, BP, 65)
+ ROUND4(BP, AX, BX, CX, DX, 66)
+ ROUND4(DX, BP, AX, BX, CX, 67)
+ ROUND4(CX, DX, BP, AX, BX, 68)
+ ROUND4(BX, CX, DX, BP, AX, 69)
+ ROUND4(AX, BX, CX, DX, BP, 70)
+ ROUND4(BP, AX, BX, CX, DX, 71)
+ ROUND4(DX, BP, AX, BX, CX, 72)
+ ROUND4(CX, DX, BP, AX, BX, 73)
+ ROUND4(BX, CX, DX, BP, AX, 74)
+ ROUND4(AX, BX, CX, DX, BP, 75)
+ ROUND4(BP, AX, BX, CX, DX, 76)
+ ROUND4(DX, BP, AX, BX, CX, 77)
+ ROUND4(CX, DX, BP, AX, BX, 78)
+ ROUND4(BX, CX, DX, BP, AX, 79)
+
+ ADDL R11, AX
+ ADDL R12, BX
+ ADDL R13, CX
+ ADDL R14, DX
+ ADDL R15, BP
+
+ ADDQ $64, SI
+ CMPQ SI, DI
+ JB loop
+
+end:
+ MOVQ dig+0(FP), DI
+ MOVL AX, (0*4)(DI)
+ MOVL BX, (1*4)(DI)
+ MOVL CX, (2*4)(DI)
+ MOVL DX, (3*4)(DI)
+ MOVL BP, (4*4)(DI)
+ RET
diff --git a/src/pkg/crypto/sha1/sha1block_decl.go b/src/pkg/crypto/sha1/sha1block_decl.go
new file mode 100644
index 000000000..3512a5829
--- /dev/null
+++ b/src/pkg/crypto/sha1/sha1block_decl.go
@@ -0,0 +1,9 @@
+// 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 386
+
+package sha1
+
+func block(dig *digest, p []byte)
diff --git a/src/pkg/crypto/tls/common.go b/src/pkg/crypto/tls/common.go
index a888df762..f86c90de7 100644
--- a/src/pkg/crypto/tls/common.go
+++ b/src/pkg/crypto/tls/common.go
@@ -204,7 +204,24 @@ type Config struct {
// connections using that key are compromised.
SessionTicketKey [32]byte
- serverInitOnce sync.Once
+ serverInitOnce sync.Once // guards calling (*Config).serverInit
+}
+
+func (c *Config) serverInit() {
+ if c.SessionTicketsDisabled {
+ return
+ }
+
+ // If the key has already been set then we have nothing to do.
+ for _, b := range c.SessionTicketKey {
+ if b != 0 {
+ return
+ }
+ }
+
+ if _, err := io.ReadFull(c.rand(), c.SessionTicketKey[:]); err != nil {
+ c.SessionTicketsDisabled = true
+ }
}
func (c *Config) rand() io.Reader {
diff --git a/src/pkg/crypto/tls/handshake_server.go b/src/pkg/crypto/tls/handshake_server.go
index 730991016..823730c60 100644
--- a/src/pkg/crypto/tls/handshake_server.go
+++ b/src/pkg/crypto/tls/handshake_server.go
@@ -33,22 +33,7 @@ func (c *Conn) serverHandshake() error {
// If this is the first server handshake, we generate a random key to
// encrypt the tickets with.
- config.serverInitOnce.Do(func() {
- if config.SessionTicketsDisabled {
- return
- }
-
- // If the key has already been set then we have nothing to do.
- for _, b := range config.SessionTicketKey {
- if b != 0 {
- return
- }
- }
-
- if _, err := io.ReadFull(config.rand(), config.SessionTicketKey[:]); err != nil {
- config.SessionTicketsDisabled = true
- }
- })
+ config.serverInitOnce.Do(config.serverInit)
hs := serverHandshakeState{
c: c,
diff --git a/src/pkg/crypto/x509/pkcs8.go b/src/pkg/crypto/x509/pkcs8.go
index 30caacb3c..8e1585e15 100644
--- a/src/pkg/crypto/x509/pkcs8.go
+++ b/src/pkg/crypto/x509/pkcs8.go
@@ -51,6 +51,4 @@ func ParsePKCS8PrivateKey(der []byte) (key interface{}, err error) {
default:
return nil, fmt.Errorf("crypto/x509: PKCS#8 wrapping contained private key with unknown algorithm: %v", privKey.Algo.Algorithm)
}
-
- panic("unreachable")
}
diff --git a/src/pkg/crypto/x509/x509.go b/src/pkg/crypto/x509/x509.go
index b802bf4eb..4dfea2c94 100644
--- a/src/pkg/crypto/x509/x509.go
+++ b/src/pkg/crypto/x509/x509.go
@@ -729,7 +729,6 @@ func parsePublicKey(algo PublicKeyAlgorithm, keyData *publicKeyInfo) (interface{
default:
return nil, nil
}
- panic("unreachable")
}
func parseCertificate(in *certificate) (*Certificate, error) {
diff --git a/src/pkg/database/sql/convert.go b/src/pkg/database/sql/convert.go
index 853a7826c..c04adde1f 100644
--- a/src/pkg/database/sql/convert.go
+++ b/src/pkg/database/sql/convert.go
@@ -19,9 +19,13 @@ var errNilPtr = errors.New("destination pointer is nil") // embedded in descript
// driverArgs converts arguments from callers of Stmt.Exec and
// Stmt.Query into driver Values.
//
-// The statement si may be nil, if no statement is available.
-func driverArgs(si driver.Stmt, args []interface{}) ([]driver.Value, error) {
+// 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))
+ var si driver.Stmt
+ if ds != nil {
+ si = ds.si
+ }
cc, ok := si.(driver.ColumnConverter)
// Normal path, for a driver.Stmt that is not a ColumnConverter.
@@ -60,7 +64,9 @@ func driverArgs(si driver.Stmt, args []interface{}) ([]driver.Value, error) {
// column before going across the network to get the
// same error.
var err error
+ ds.Lock()
dargs[n], err = cc.ColumnConverter(n).ConvertValue(arg)
+ ds.Unlock()
if err != nil {
return nil, fmt.Errorf("sql: converting argument #%d's type: %v", n, err)
}
@@ -106,25 +112,41 @@ func convertAssign(dest, src interface{}) error {
if d == nil {
return errNilPtr
}
- bcopy := make([]byte, len(s))
- copy(bcopy, s)
- *d = bcopy
+ *d = cloneBytes(s)
return nil
case *[]byte:
if d == nil {
return errNilPtr
}
+ *d = cloneBytes(s)
+ return nil
+ case *RawBytes:
+ if d == nil {
+ return errNilPtr
+ }
*d = s
return nil
}
case nil:
switch d := dest.(type) {
+ case *interface{}:
+ if d == nil {
+ return errNilPtr
+ }
+ *d = nil
+ return nil
case *[]byte:
if d == nil {
return errNilPtr
}
*d = nil
return nil
+ case *RawBytes:
+ if d == nil {
+ return errNilPtr
+ }
+ *d = nil
+ return nil
}
}
@@ -141,6 +163,26 @@ func convertAssign(dest, src interface{}) error {
*d = fmt.Sprintf("%v", src)
return nil
}
+ case *[]byte:
+ sv = reflect.ValueOf(src)
+ switch sv.Kind() {
+ case reflect.Bool,
+ reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64,
+ reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64,
+ reflect.Float32, reflect.Float64:
+ *d = []byte(fmt.Sprintf("%v", src))
+ return nil
+ }
+ case *RawBytes:
+ sv = reflect.ValueOf(src)
+ switch sv.Kind() {
+ case reflect.Bool,
+ reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64,
+ reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64,
+ reflect.Float32, reflect.Float64:
+ *d = RawBytes(fmt.Sprintf("%v", src))
+ return nil
+ }
case *bool:
bv, err := driver.Bool.ConvertValue(src)
if err == nil {
@@ -212,6 +254,16 @@ func convertAssign(dest, src interface{}) error {
return fmt.Errorf("unsupported driver -> Scan pair: %T -> %T", src, dest)
}
+func cloneBytes(b []byte) []byte {
+ if b == nil {
+ return nil
+ } else {
+ c := make([]byte, len(b))
+ copy(c, b)
+ return c
+ }
+}
+
func asString(src interface{}) string {
switch v := src.(type) {
case string:
diff --git a/src/pkg/database/sql/convert_test.go b/src/pkg/database/sql/convert_test.go
index 9c362d732..950e24fc3 100644
--- a/src/pkg/database/sql/convert_test.go
+++ b/src/pkg/database/sql/convert_test.go
@@ -22,6 +22,8 @@ type conversionTest struct {
wantint int64
wantuint uint64
wantstr string
+ wantbytes []byte
+ wantraw RawBytes
wantf32 float32
wantf64 float64
wanttime time.Time
@@ -35,6 +37,8 @@ type conversionTest struct {
// Target variables for scanning into.
var (
scanstr string
+ scanbytes []byte
+ scanraw RawBytes
scanint int
scanint8 int8
scanint16 int16
@@ -56,6 +60,7 @@ var conversionTests = []conversionTest{
{s: someTime, d: &scantime, wanttime: someTime},
// To strings
+ {s: "string", d: &scanstr, wantstr: "string"},
{s: []byte("byteslice"), d: &scanstr, wantstr: "byteslice"},
{s: 123, d: &scanstr, wantstr: "123"},
{s: int8(123), d: &scanstr, wantstr: "123"},
@@ -66,6 +71,31 @@ var conversionTests = []conversionTest{
{s: uint64(123), d: &scanstr, wantstr: "123"},
{s: 1.5, d: &scanstr, wantstr: "1.5"},
+ // To []byte
+ {s: nil, d: &scanbytes, wantbytes: nil},
+ {s: "string", d: &scanbytes, wantbytes: []byte("string")},
+ {s: []byte("byteslice"), d: &scanbytes, wantbytes: []byte("byteslice")},
+ {s: 123, d: &scanbytes, wantbytes: []byte("123")},
+ {s: int8(123), d: &scanbytes, wantbytes: []byte("123")},
+ {s: int64(123), d: &scanbytes, wantbytes: []byte("123")},
+ {s: uint8(123), d: &scanbytes, wantbytes: []byte("123")},
+ {s: uint16(123), d: &scanbytes, wantbytes: []byte("123")},
+ {s: uint32(123), d: &scanbytes, wantbytes: []byte("123")},
+ {s: uint64(123), d: &scanbytes, wantbytes: []byte("123")},
+ {s: 1.5, d: &scanbytes, wantbytes: []byte("1.5")},
+
+ // To RawBytes
+ {s: nil, d: &scanraw, wantraw: nil},
+ {s: []byte("byteslice"), d: &scanraw, wantraw: RawBytes("byteslice")},
+ {s: 123, d: &scanraw, wantraw: RawBytes("123")},
+ {s: int8(123), d: &scanraw, wantraw: RawBytes("123")},
+ {s: int64(123), d: &scanraw, wantraw: RawBytes("123")},
+ {s: uint8(123), d: &scanraw, wantraw: RawBytes("123")},
+ {s: uint16(123), d: &scanraw, wantraw: RawBytes("123")},
+ {s: uint32(123), d: &scanraw, wantraw: RawBytes("123")},
+ {s: uint64(123), d: &scanraw, wantraw: RawBytes("123")},
+ {s: 1.5, d: &scanraw, wantraw: RawBytes("1.5")},
+
// Strings to integers
{s: "255", d: &scanuint8, wantuint: 255},
{s: "256", d: &scanuint8, wanterr: `converting string "256" to a uint8: strconv.ParseUint: parsing "256": value out of range`},
@@ -113,6 +143,7 @@ var conversionTests = []conversionTest{
{s: []byte("byteslice"), d: &scaniface, wantiface: []byte("byteslice")},
{s: true, d: &scaniface, wantiface: true},
{s: nil, d: &scaniface},
+ {s: []byte(nil), d: &scaniface, wantiface: []byte(nil)},
}
func intPtrValue(intptr interface{}) interface{} {
@@ -191,7 +222,7 @@ func TestConversions(t *testing.T) {
}
if srcBytes, ok := ct.s.([]byte); ok {
dstBytes := (*ifptr).([]byte)
- if &dstBytes[0] == &srcBytes[0] {
+ if len(srcBytes) > 0 && &dstBytes[0] == &srcBytes[0] {
errf("copy into interface{} didn't copy []byte data")
}
}
diff --git a/src/pkg/database/sql/driver/driver.go b/src/pkg/database/sql/driver/driver.go
index 2434e419b..d7ca94f78 100644
--- a/src/pkg/database/sql/driver/driver.go
+++ b/src/pkg/database/sql/driver/driver.go
@@ -10,8 +10,8 @@ package driver
import "errors"
-// A driver Value is a value that drivers must be able to handle.
-// A Value is either nil or an instance of one of these types:
+// Value is a value that drivers must be able to handle.
+// It is either nil or an instance of one of these types:
//
// int64
// float64
diff --git a/src/pkg/database/sql/fakedb_test.go b/src/pkg/database/sql/fakedb_test.go
index 55597f7de..d900e2ceb 100644
--- a/src/pkg/database/sql/fakedb_test.go
+++ b/src/pkg/database/sql/fakedb_test.go
@@ -13,6 +13,7 @@ import (
"strconv"
"strings"
"sync"
+ "testing"
"time"
)
@@ -34,9 +35,10 @@ var _ = log.Printf
// When opening a fakeDriver's database, it starts empty with no
// tables. All tables and data are stored in memory only.
type fakeDriver struct {
- mu sync.Mutex
- openCount int
- dbs map[string]*fakeDB
+ mu sync.Mutex // guards 3 following fields
+ openCount int // conn opens
+ closeCount int // conn closes
+ dbs map[string]*fakeDB
}
type fakeDB struct {
@@ -229,7 +231,43 @@ func (c *fakeConn) Begin() (driver.Tx, error) {
return c.currTx, nil
}
-func (c *fakeConn) Close() error {
+var hookPostCloseConn struct {
+ sync.Mutex
+ fn func(*fakeConn, error)
+}
+
+func setHookpostCloseConn(fn func(*fakeConn, error)) {
+ hookPostCloseConn.Lock()
+ defer hookPostCloseConn.Unlock()
+ hookPostCloseConn.fn = fn
+}
+
+var testStrictClose *testing.T
+
+// setStrictFakeConnClose sets the t to Errorf on when fakeConn.Close
+// fails to close. If nil, the check is disabled.
+func setStrictFakeConnClose(t *testing.T) {
+ testStrictClose = t
+}
+
+func (c *fakeConn) Close() (err error) {
+ drv := fdriver.(*fakeDriver)
+ defer func() {
+ if err != nil && testStrictClose != nil {
+ testStrictClose.Errorf("failed to close a test fakeConn: %v", err)
+ }
+ hookPostCloseConn.Lock()
+ fn := hookPostCloseConn.fn
+ hookPostCloseConn.Unlock()
+ if fn != nil {
+ fn(c, err)
+ }
+ if err == nil {
+ drv.mu.Lock()
+ drv.closeCount++
+ drv.mu.Unlock()
+ }
+ }()
if c.currTx != nil {
return errors.New("can't close fakeConn; in a Transaction")
}
@@ -424,6 +462,12 @@ func (s *fakeStmt) ColumnConverter(idx int) driver.ValueConverter {
}
func (s *fakeStmt) Close() error {
+ if s.c == nil {
+ panic("nil conn in fakeStmt.Close")
+ }
+ if s.c.db == nil {
+ panic("in fakeStmt.Close, conn's db is nil (already closed)")
+ }
if !s.closed {
s.c.incrStat(&s.c.stmtsClosed)
s.closed = true
@@ -515,6 +559,15 @@ func (s *fakeStmt) Query(args []driver.Value) (driver.Rows, error) {
if !ok {
return nil, fmt.Errorf("fakedb: table %q doesn't exist", s.table)
}
+
+ 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)
+ }
+ }
+ }
+
t.mu.Lock()
defer t.mu.Unlock()
diff --git a/src/pkg/database/sql/sql.go b/src/pkg/database/sql/sql.go
index 4faaa11b1..a80782bfe 100644
--- a/src/pkg/database/sql/sql.go
+++ b/src/pkg/database/sql/sql.go
@@ -4,6 +4,9 @@
// Package sql provides a generic interface around SQL (or SQL-like)
// databases.
+//
+// The sql package must be used in conjunction with a database driver.
+// See http://golang.org/s/sqldrivers for a list of drivers.
package sql
import (
@@ -177,32 +180,139 @@ var ErrNoRows = errors.New("sql: no rows in result set")
// DB is a database handle. It's safe for concurrent use by multiple
// goroutines.
//
-// If the underlying database driver has the concept of a connection
-// and per-connection session state, the sql package manages creating
-// and freeing connections automatically, including maintaining a free
-// pool of idle connections. If observing session state is required,
-// either do not share a *DB between multiple concurrent goroutines or
-// create and observe all state only within a transaction. Once
-// DB.Open is called, the returned Tx is bound to a single isolated
-// connection. Once Tx.Commit or Tx.Rollback is called, that
-// connection is returned to DB's idle connection pool.
+// The sql package creates and frees connections automatically; it
+// also maintains a free pool of idle connections. If the database has
+// a concept of per-connection state, such state can only be reliably
+// observed within a transaction. Once DB.Begin is called, the
+// returned Tx is bound to a single connection. Once Commit or
+// Rollback is called on the transaction, that transaction's
+// connection is returned to DB's idle connection pool. The pool size
+// can be controlled with SetMaxIdleConns.
type DB struct {
driver driver.Driver
dsn string
- mu sync.Mutex // protects following fields
- outConn map[driver.Conn]bool // whether the conn is in use
- freeConn []driver.Conn
- closed bool
- dep map[finalCloser]depSet
- onConnPut map[driver.Conn][]func() // code (with mu held) run when conn is next returned
- lastPut map[driver.Conn]string // stacktrace of last conn's put; debug only
+ mu sync.Mutex // protects following fields
+ freeConn []*driverConn
+ closed bool
+ dep map[finalCloser]depSet
+ lastPut map[*driverConn]string // stacktrace of last conn's put; debug only
+ maxIdle int // zero means defaultMaxIdleConns; negative means 0
+}
+
+// driverConn wraps a driver.Conn with a mutex, to
+// be held during all calls into the Conn. (including any calls onto
+// interfaces returned via that Conn, such as calls on Tx, Stmt,
+// Result, Rows)
+type driverConn struct {
+ db *DB
+
+ sync.Mutex // guards following
+ ci driver.Conn
+ closed bool
+ finalClosed bool // ci.Close has been called
+ openStmt map[driver.Stmt]bool
+
+ // guarded by db.mu
+ inUse bool
+ onPut []func() // code (with db.mu held) run when conn is next returned
+ dbmuClosed bool // same as closed, but guarded by db.mu, for connIfFree
+}
+
+func (dc *driverConn) removeOpenStmt(si driver.Stmt) {
+ dc.Lock()
+ defer dc.Unlock()
+ delete(dc.openStmt, si)
+}
+
+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.1, 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
+ }
+ return si, err
+}
+
+// the dc.db's Mutex is held.
+func (dc *driverConn) closeDBLocked() error {
+ dc.Lock()
+ if dc.closed {
+ dc.Unlock()
+ return errors.New("sql: duplicate driverConn close")
+ }
+ dc.closed = true
+ dc.Unlock() // not defer; removeDep finalClose calls may need to lock
+ return dc.db.removeDepLocked(dc, dc)()
+}
+
+func (dc *driverConn) Close() error {
+ dc.Lock()
+ if dc.closed {
+ dc.Unlock()
+ return errors.New("sql: duplicate driverConn close")
+ }
+ dc.closed = true
+ dc.Unlock() // not defer; removeDep finalClose calls may need to lock
+
+ // And now updates that require holding dc.mu.Lock.
+ dc.db.mu.Lock()
+ dc.dbmuClosed = true
+ fn := dc.db.removeDepLocked(dc, dc)
+ dc.db.mu.Unlock()
+ return fn()
+}
+
+func (dc *driverConn) finalClose() error {
+ dc.Lock()
+
+ for si := range dc.openStmt {
+ si.Close()
+ }
+ dc.openStmt = nil
+
+ err := dc.ci.Close()
+ dc.ci = nil
+ dc.finalClosed = true
+
+ dc.Unlock()
+ return err
+}
+
+// driverStmt associates a driver.Stmt with the
+// *driverConn from which it came, so the driverConn's lock can be
+// held during calls.
+type driverStmt struct {
+ sync.Locker // the *driverConn
+ si driver.Stmt
+}
+
+func (ds *driverStmt) Close() error {
+ ds.Lock()
+ defer ds.Unlock()
+ return ds.si.Close()
}
// depSet is a finalCloser's outstanding dependencies
type depSet map[interface{}]bool // set of true bools
-// The finalCloser interface is used by (*DB).addDep and (*DB).get
+// The finalCloser interface is used by (*DB).addDep and related
+// dependency reference counting.
type finalCloser interface {
// finalClose is called when the reference count of an object
// goes to zero. (*DB).mu is not held while calling it.
@@ -215,6 +325,10 @@ func (db *DB) addDep(x finalCloser, dep interface{}) {
//println(fmt.Sprintf("addDep(%T %p, %T %p)", x, x, dep, dep))
db.mu.Lock()
defer db.mu.Unlock()
+ db.addDepLocked(x, dep)
+}
+
+func (db *DB) addDepLocked(x finalCloser, dep interface{}) {
if db.dep == nil {
db.dep = make(map[finalCloser]depSet)
}
@@ -231,10 +345,16 @@ func (db *DB) addDep(x finalCloser, dep interface{}) {
// If x no longer has any dependencies, its finalClose method will be
// called and its error value will be returned.
func (db *DB) removeDep(x finalCloser, dep interface{}) error {
+ db.mu.Lock()
+ fn := db.removeDepLocked(x, dep)
+ db.mu.Unlock()
+ return fn()
+}
+
+func (db *DB) removeDepLocked(x finalCloser, dep interface{}) func() error {
//println(fmt.Sprintf("removeDep(%T %p, %T %p)", x, x, dep, dep))
done := false
- db.mu.Lock()
xdep := db.dep[x]
if xdep != nil {
delete(xdep, dep)
@@ -243,13 +363,14 @@ func (db *DB) removeDep(x finalCloser, dep interface{}) error {
done = true
}
}
- db.mu.Unlock()
if !done {
- return nil
+ return func() error { return nil }
+ }
+ return func() error {
+ //println(fmt.Sprintf("calling final close on %T %v (%#v)", x, x, x))
+ return x.finalClose()
}
- //println(fmt.Sprintf("calling final close on %T %v (%#v)", x, x, x))
- return x.finalClose()
}
// Open opens a database specified by its database driver name and a
@@ -257,31 +378,47 @@ func (db *DB) removeDep(x finalCloser, dep interface{}) error {
// database name and connection information.
//
// Most users will open a database via a driver-specific connection
-// helper function that returns a *DB.
+// helper function that returns a *DB. No database drivers are included
+// in the Go standard library. See http://golang.org/s/sqldrivers for
+// a list of third-party drivers.
+//
+// Open may just validate its arguments without creating a connection
+// to the database. To verify that the data source name is valid, call
+// Ping.
func Open(driverName, dataSourceName string) (*DB, error) {
driveri, ok := drivers[driverName]
if !ok {
return nil, fmt.Errorf("sql: unknown driver %q (forgotten import?)", driverName)
}
- // TODO: optionally proactively connect to a Conn to check
- // the dataSourceName: golang.org/issue/4804
db := &DB{
- driver: driveri,
- dsn: dataSourceName,
- outConn: make(map[driver.Conn]bool),
- lastPut: make(map[driver.Conn]string),
- onConnPut: make(map[driver.Conn][]func()),
+ driver: driveri,
+ dsn: dataSourceName,
+ lastPut: make(map[*driverConn]string),
}
return db, nil
}
+// Ping 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()
+ if err != nil {
+ return err
+ }
+ db.putConn(dc, nil)
+ return nil
+}
+
// Close closes the database, releasing any open resources.
func (db *DB) Close() error {
db.mu.Lock()
defer db.mu.Unlock()
var err error
- for _, c := range db.freeConn {
- err1 := c.Close()
+ for _, dc := range db.freeConn {
+ err1 := dc.closeDBLocked()
if err1 != nil {
err = err1
}
@@ -291,15 +428,45 @@ func (db *DB) Close() error {
return err
}
-func (db *DB) maxIdleConns() int {
- const defaultMaxIdleConns = 2
- // TODO(bradfitz): ask driver, if supported, for its default preference
- // TODO(bradfitz): let users override?
- return defaultMaxIdleConns
+const defaultMaxIdleConns = 2
+
+func (db *DB) maxIdleConnsLocked() int {
+ n := db.maxIdle
+ switch {
+ case n == 0:
+ // TODO(bradfitz): ask driver, if supported, for its default preference
+ return defaultMaxIdleConns
+ case n < 0:
+ return 0
+ default:
+ return n
+ }
}
-// conn returns a newly-opened or cached driver.Conn
-func (db *DB) conn() (driver.Conn, error) {
+// SetMaxIdleConns sets the maximum number of connections in the idle
+// connection pool.
+//
+// If n <= 0, no idle connections are retained.
+func (db *DB) SetMaxIdleConns(n int) {
+ db.mu.Lock()
+ defer db.mu.Unlock()
+ if n > 0 {
+ db.maxIdle = n
+ } else {
+ // No idle connections.
+ db.maxIdle = -1
+ }
+ for len(db.freeConn) > 0 && len(db.freeConn) > n {
+ nfree := len(db.freeConn)
+ dc := db.freeConn[nfree-1]
+ db.freeConn[nfree-1] = nil
+ db.freeConn = db.freeConn[:nfree-1]
+ go dc.Close()
+ }
+}
+
+// conn returns a newly-opened or cached *driverConn
+func (db *DB) conn() (*driverConn, error) {
db.mu.Lock()
if db.closed {
db.mu.Unlock()
@@ -308,30 +475,47 @@ func (db *DB) conn() (driver.Conn, error) {
if n := len(db.freeConn); n > 0 {
conn := db.freeConn[n-1]
db.freeConn = db.freeConn[:n-1]
- db.outConn[conn] = true
+ conn.inUse = true
db.mu.Unlock()
return conn, nil
}
db.mu.Unlock()
- conn, err := db.driver.Open(db.dsn)
- if err == nil {
- db.mu.Lock()
- db.outConn[conn] = true
- db.mu.Unlock()
+
+ ci, err := db.driver.Open(db.dsn)
+ if err != nil {
+ return nil, err
+ }
+ dc := &driverConn{
+ db: db,
+ ci: ci,
}
- return conn, err
+ db.mu.Lock()
+ db.addDepLocked(dc, dc)
+ dc.inUse = true
+ db.mu.Unlock()
+ return dc, nil
}
-// connIfFree returns (wanted, true) if wanted is still a valid conn and
+var (
+ errConnClosed = errors.New("database/sql: internal sentinel error: conn is closed")
+ errConnBusy = errors.New("database/sql: internal sentinel error: conn is busy")
+)
+
+// connIfFree returns (wanted, nil) if wanted is still a valid conn and
// isn't in use.
//
-// If wanted is valid but in use, connIfFree returns (wanted, false).
-// If wanted is invalid, connIfFre returns (nil, false).
-func (db *DB) connIfFree(wanted driver.Conn) (conn driver.Conn, ok bool) {
+// The error is errConnClosed if the connection if the requested connection
+// is invalid because it's been closed.
+//
+// The error is errConnBusy if the connection is in use.
+func (db *DB) connIfFree(wanted *driverConn) (*driverConn, error) {
db.mu.Lock()
defer db.mu.Unlock()
- if db.outConn[wanted] {
- return conn, false
+ if wanted.inUse {
+ return nil, errConnBusy
+ }
+ if wanted.dbmuClosed {
+ return nil, errConnClosed
}
for i, conn := range db.freeConn {
if conn != wanted {
@@ -339,27 +523,36 @@ func (db *DB) connIfFree(wanted driver.Conn) (conn driver.Conn, ok bool) {
}
db.freeConn[i] = db.freeConn[len(db.freeConn)-1]
db.freeConn = db.freeConn[:len(db.freeConn)-1]
- db.outConn[wanted] = true
- return wanted, true
+ wanted.inUse = true
+ return wanted, nil
}
- return nil, false
+ // TODO(bradfitz): shouldn't get here. After Go 1.1, change this to:
+ // panic("connIfFree call requested a non-closed, non-busy, non-free conn")
+ // Which passes all the tests, but I'm too paranoid to include this
+ // late in Go 1.1.
+ // Instead, treat it like a busy connection:
+ return nil, errConnBusy
}
// putConnHook is a hook for testing.
-var putConnHook func(*DB, driver.Conn)
+var putConnHook func(*DB, *driverConn)
// noteUnusedDriverStatement notes that si 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 driver.Conn, si driver.Stmt) {
+func (db *DB) noteUnusedDriverStatement(c *driverConn, si driver.Stmt) {
db.mu.Lock()
defer db.mu.Unlock()
- if db.outConn[c] {
- db.onConnPut[c] = append(db.onConnPut[c], func() {
+ if c.inUse {
+ c.onPut = append(c.onPut, func() {
si.Close()
})
} else {
- si.Close()
+ c.Lock()
+ defer c.Unlock()
+ if !c.finalClosed {
+ si.Close()
+ }
}
}
@@ -369,25 +562,23 @@ const debugGetPut = false
// putConn adds a connection to the db's free pool.
// err is optionally the last error that occurred on this connection.
-func (db *DB) putConn(c driver.Conn, err error) {
+func (db *DB) putConn(dc *driverConn, err error) {
db.mu.Lock()
- if !db.outConn[c] {
+ if !dc.inUse {
if debugGetPut {
- fmt.Printf("putConn(%v) DUPLICATE was: %s\n\nPREVIOUS was: %s", c, stack(), db.lastPut[c])
+ fmt.Printf("putConn(%v) DUPLICATE was: %s\n\nPREVIOUS was: %s", dc, stack(), db.lastPut[dc])
}
panic("sql: connection returned that was never out")
}
if debugGetPut {
- db.lastPut[c] = stack()
+ db.lastPut[dc] = stack()
}
- delete(db.outConn, c)
+ dc.inUse = false
- if fns, ok := db.onConnPut[c]; ok {
- for _, fn := range fns {
- fn()
- }
- delete(db.onConnPut, c)
+ for _, fn := range dc.onPut {
+ fn()
}
+ dc.onPut = nil
if err == driver.ErrBadConn {
// Don't reuse bad connections.
@@ -395,17 +586,16 @@ func (db *DB) putConn(c driver.Conn, err error) {
return
}
if putConnHook != nil {
- putConnHook(db, c)
+ putConnHook(db, dc)
}
- if n := len(db.freeConn); !db.closed && n < db.maxIdleConns() {
- db.freeConn = append(db.freeConn, c)
+ if n := len(db.freeConn); !db.closed && n < db.maxIdleConnsLocked() {
+ db.freeConn = append(db.freeConn, dc)
db.mu.Unlock()
return
}
- // TODO: check to see if we need this Conn for any prepared
- // statements which are still active?
db.mu.Unlock()
- c.Close()
+
+ dc.Close()
}
// Prepare creates a prepared statement for later queries or executions.
@@ -430,21 +620,24 @@ func (db *DB) prepare(query string) (*Stmt, error) {
// 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.
- ci, err := db.conn()
+ dc, err := db.conn()
if err != nil {
return nil, err
}
- si, err := ci.Prepare(query)
+ dc.Lock()
+ si, err := dc.prepareLocked(query)
+ dc.Unlock()
if err != nil {
- db.putConn(ci, err)
+ db.putConn(dc, err)
return nil, err
}
stmt := &Stmt{
db: db,
query: query,
- css: []connStmt{{ci, si}},
+ css: []connStmt{{dc, si}},
}
db.addDep(stmt, stmt)
+ db.putConn(dc, nil)
return stmt, nil
}
@@ -463,35 +656,38 @@ func (db *DB) Exec(query string, args ...interface{}) (Result, error) {
}
func (db *DB) exec(query string, args []interface{}) (res Result, err error) {
- ci, err := db.conn()
+ dc, err := db.conn()
if err != nil {
return nil, err
}
defer func() {
- db.putConn(ci, err)
+ db.putConn(dc, err)
}()
- if execer, ok := ci.(driver.Execer); ok {
+ if execer, ok := dc.ci.(driver.Execer); ok {
dargs, err := driverArgs(nil, args)
if err != nil {
return nil, err
}
+ dc.Lock()
resi, err := execer.Exec(query, dargs)
+ dc.Unlock()
if err != driver.ErrSkip {
if err != nil {
return nil, err
}
- return result{resi}, nil
+ return driverResult{dc, resi}, nil
}
}
- sti, err := ci.Prepare(query)
+ dc.Lock()
+ si, err := dc.ci.Prepare(query)
+ dc.Unlock()
if err != nil {
return nil, err
}
- defer sti.Close()
-
- return resultFromStatement(sti, args...)
+ defer withLock(dc, func() { si.Close() })
+ return resultFromStatement(driverStmt{dc, si}, args...)
}
// Query executes a query that returns rows, typically a SELECT.
@@ -521,24 +717,25 @@ func (db *DB) query(query string, args []interface{}) (*Rows, error) {
// queryConn executes a query on the given connection.
// The connection gets released by the releaseConn function.
-func (db *DB) queryConn(ci driver.Conn, releaseConn func(error), query string, args []interface{}) (*Rows, error) {
- if queryer, ok := ci.(driver.Queryer); ok {
+func (db *DB) queryConn(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()
if err != driver.ErrSkip {
if err != nil {
releaseConn(err)
return nil, err
}
- // Note: ownership of ci passes to the *Rows, to be freed
+ // Note: ownership of dc passes to the *Rows, to be freed
// with releaseConn.
rows := &Rows{
- db: db,
- ci: ci,
+ dc: dc,
releaseConn: releaseConn,
rowsi: rowsi,
}
@@ -546,27 +743,31 @@ func (db *DB) queryConn(ci driver.Conn, releaseConn func(error), query string, a
}
}
- sti, err := ci.Prepare(query)
+ dc.Lock()
+ si, err := dc.ci.Prepare(query)
+ dc.Unlock()
if err != nil {
releaseConn(err)
return nil, err
}
- rowsi, err := rowsiFromStatement(sti, args...)
+ ds := driverStmt{dc, si}
+ rowsi, err := rowsiFromStatement(ds, args...)
if err != nil {
releaseConn(err)
- sti.Close()
+ dc.Lock()
+ si.Close()
+ dc.Unlock()
return nil, err
}
// Note: ownership of ci passes to the *Rows, to be freed
// with releaseConn.
rows := &Rows{
- db: db,
- ci: ci,
+ dc: dc,
releaseConn: releaseConn,
rowsi: rowsi,
- closeStmt: sti,
+ closeStmt: si,
}
return rows, nil
}
@@ -594,18 +795,20 @@ func (db *DB) Begin() (*Tx, error) {
}
func (db *DB) begin() (tx *Tx, err error) {
- ci, err := db.conn()
+ dc, err := db.conn()
if err != nil {
return nil, err
}
- txi, err := ci.Begin()
+ dc.Lock()
+ txi, err := dc.ci.Begin()
+ dc.Unlock()
if err != nil {
- db.putConn(ci, err)
+ db.putConn(dc, err)
return nil, err
}
return &Tx{
db: db,
- ci: ci,
+ dc: dc,
txi: txi,
}, nil
}
@@ -624,15 +827,11 @@ func (db *DB) Driver() driver.Driver {
type Tx struct {
db *DB
- // ci is owned exclusively until Commit or Rollback, at which point
+ // dc is owned exclusively until Commit or Rollback, at which point
// it's returned with putConn.
- ci driver.Conn
+ dc *driverConn
txi driver.Tx
- // cimu is held while somebody is using ci (between grabConn
- // and releaseConn)
- cimu sync.Mutex
-
// done transitions from false to true exactly once, on Commit
// or Rollback. once done, all operations fail with
// ErrTxDone.
@@ -646,21 +845,16 @@ func (tx *Tx) close() {
panic("double close") // internal error
}
tx.done = true
- tx.db.putConn(tx.ci, nil)
- tx.ci = nil
+ tx.db.putConn(tx.dc, nil)
+ tx.dc = nil
tx.txi = nil
}
-func (tx *Tx) grabConn() (driver.Conn, error) {
+func (tx *Tx) grabConn() (*driverConn, error) {
if tx.done {
return nil, ErrTxDone
}
- tx.cimu.Lock()
- return tx.ci, nil
-}
-
-func (tx *Tx) releaseConn() {
- tx.cimu.Unlock()
+ return tx.dc, nil
}
// Commit commits the transaction.
@@ -669,6 +863,8 @@ func (tx *Tx) Commit() error {
return ErrTxDone
}
defer tx.close()
+ tx.dc.Lock()
+ defer tx.dc.Unlock()
return tx.txi.Commit()
}
@@ -678,6 +874,8 @@ func (tx *Tx) Rollback() error {
return ErrTxDone
}
defer tx.close()
+ tx.dc.Lock()
+ defer tx.dc.Unlock()
return tx.txi.Rollback()
}
@@ -701,21 +899,25 @@ func (tx *Tx) Prepare(query string) (*Stmt, error) {
// 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.
- ci, err := tx.grabConn()
+ dc, err := tx.grabConn()
if err != nil {
return nil, err
}
- defer tx.releaseConn()
- si, err := ci.Prepare(query)
+ dc.Lock()
+ si, err := dc.ci.Prepare(query)
+ dc.Unlock()
if err != nil {
return nil, err
}
stmt := &Stmt{
- db: tx.db,
- tx: tx,
- txsi: si,
+ db: tx.db,
+ tx: tx,
+ txsi: &driverStmt{
+ Locker: dc,
+ si: si,
+ },
query: query,
}
return stmt, nil
@@ -739,16 +941,20 @@ func (tx *Tx) Stmt(stmt *Stmt) *Stmt {
if tx.db != stmt.db {
return &Stmt{stickyErr: errors.New("sql: Tx.Stmt: statement from different database used")}
}
- ci, err := tx.grabConn()
+ dc, err := tx.grabConn()
if err != nil {
return &Stmt{stickyErr: err}
}
- defer tx.releaseConn()
- si, err := ci.Prepare(stmt.query)
+ dc.Lock()
+ si, err := dc.ci.Prepare(stmt.query)
+ dc.Unlock()
return &Stmt{
- db: tx.db,
- tx: tx,
- txsi: si,
+ db: tx.db,
+ tx: tx,
+ txsi: &driverStmt{
+ Locker: dc,
+ si: si,
+ },
query: stmt.query,
stickyErr: err,
}
@@ -757,45 +963,46 @@ func (tx *Tx) Stmt(stmt *Stmt) *Stmt {
// 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) {
- ci, err := tx.grabConn()
+ dc, err := tx.grabConn()
if err != nil {
return nil, err
}
- defer tx.releaseConn()
- if execer, ok := ci.(driver.Execer); ok {
+ if execer, ok := dc.ci.(driver.Execer); ok {
dargs, err := driverArgs(nil, args)
if err != nil {
return nil, err
}
+ dc.Lock()
resi, err := execer.Exec(query, dargs)
+ dc.Unlock()
if err == nil {
- return result{resi}, nil
+ return driverResult{dc, resi}, nil
}
if err != driver.ErrSkip {
return nil, err
}
}
- sti, err := ci.Prepare(query)
+ dc.Lock()
+ si, err := dc.ci.Prepare(query)
+ dc.Unlock()
if err != nil {
return nil, err
}
- defer sti.Close()
+ defer withLock(dc, func() { si.Close() })
- return resultFromStatement(sti, args...)
+ return resultFromStatement(driverStmt{dc, si}, args...)
}
// Query executes a query that returns rows, typically a SELECT.
func (tx *Tx) Query(query string, args ...interface{}) (*Rows, error) {
- ci, err := tx.grabConn()
+ dc, err := tx.grabConn()
if err != nil {
return nil, err
}
-
- releaseConn := func(err error) { tx.releaseConn() }
-
- return tx.db.queryConn(ci, releaseConn, query, args)
+ releaseConn := func(error) {}
+ return tx.db.queryConn(dc, releaseConn, query, args)
}
// QueryRow executes a query that is expected to return at most one row.
@@ -808,7 +1015,7 @@ func (tx *Tx) QueryRow(query string, args ...interface{}) *Row {
// connStmt is a prepared statement on a particular connection.
type connStmt struct {
- ci driver.Conn
+ dc *driverConn
si driver.Stmt
}
@@ -823,7 +1030,7 @@ type Stmt struct {
// If in a transaction, else both nil:
tx *Tx
- txsi driver.Stmt
+ txsi *driverStmt
mu sync.Mutex // protects the rest of the fields
closed bool
@@ -840,39 +1047,45 @@ type Stmt struct {
func (s *Stmt) Exec(args ...interface{}) (Result, error) {
s.closemu.RLock()
defer s.closemu.RUnlock()
- _, releaseConn, si, err := s.connStmt()
+ dc, releaseConn, si, err := s.connStmt()
if err != nil {
return nil, err
}
defer releaseConn(nil)
- return resultFromStatement(si, args...)
+ return resultFromStatement(driverStmt{dc, si}, args...)
}
-func resultFromStatement(si driver.Stmt, args ...interface{}) (Result, error) {
+func resultFromStatement(ds driverStmt, args ...interface{}) (Result, error) {
+ ds.Lock()
+ want := ds.si.NumInput()
+ ds.Unlock()
+
// -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
// driver deal with errors.
- if want := si.NumInput(); want != -1 && len(args) != want {
+ if want != -1 && len(args) != want {
return nil, fmt.Errorf("sql: expected %d arguments, got %d", want, len(args))
}
- dargs, err := driverArgs(si, args)
+ dargs, err := driverArgs(&ds, args)
if err != nil {
return nil, err
}
- resi, err := si.Exec(dargs)
+ ds.Lock()
+ resi, err := ds.si.Exec(dargs)
+ ds.Unlock()
if err != nil {
return nil, err
}
- return result{resi}, nil
+ return driverResult{ds.Locker, resi}, nil
}
// 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 driver.Conn, releaseConn func(error), si driver.Stmt, err error) {
+func (s *Stmt) connStmt() (ci *driverConn, releaseConn func(error), si driver.Stmt, err error) {
if err = s.stickyErr; err != nil {
return
}
@@ -891,19 +1104,27 @@ func (s *Stmt) connStmt() (ci driver.Conn, releaseConn func(error), si driver.St
if err != nil {
return
}
- releaseConn = func(error) { s.tx.releaseConn() }
- return ci, releaseConn, s.txsi, nil
+ releaseConn = func(error) {}
+ return ci, releaseConn, s.txsi.si, nil
}
var cs connStmt
match := false
- for _, v := range s.css {
- // TODO(bradfitz): lazily clean up entries in this
- // list with dead conns while enumerating
- if _, match = s.db.connIfFree(v.ci); match {
+ for i := 0; i < len(s.css); i++ {
+ v := s.css[i]
+ _, err := s.db.connIfFree(v.dc)
+ if err == nil {
+ match = true
cs = v
break
}
+ if err == errConnClosed {
+ // Lazily remove dead conn from our freelist.
+ s.css[i] = s.css[len(s.css)-1]
+ s.css = s.css[:len(s.css)-1]
+ i--
+ }
+
}
s.mu.Unlock()
@@ -911,11 +1132,13 @@ func (s *Stmt) connStmt() (ci driver.Conn, releaseConn func(error), si driver.St
// TODO(bradfitz): or wait for one? make configurable later?
if !match {
for i := 0; ; i++ {
- ci, err := s.db.conn()
+ dc, err := s.db.conn()
if err != nil {
return nil, nil, nil, err
}
- si, err := ci.Prepare(s.query)
+ dc.Lock()
+ si, err := dc.prepareLocked(s.query)
+ dc.Unlock()
if err == driver.ErrBadConn && i < 10 {
continue
}
@@ -923,14 +1146,14 @@ func (s *Stmt) connStmt() (ci driver.Conn, releaseConn func(error), si driver.St
return nil, nil, nil, err
}
s.mu.Lock()
- cs = connStmt{ci, si}
+ cs = connStmt{dc, si}
s.css = append(s.css, cs)
s.mu.Unlock()
break
}
}
- conn := cs.ci
+ conn := cs.dc
releaseConn = func(err error) { s.db.putConn(conn, err) }
return conn, releaseConn, cs.si, nil
}
@@ -941,12 +1164,13 @@ func (s *Stmt) Query(args ...interface{}) (*Rows, error) {
s.closemu.RLock()
defer s.closemu.RUnlock()
- ci, releaseConn, si, err := s.connStmt()
+ dc, releaseConn, si, err := s.connStmt()
if err != nil {
return nil, err
}
- rowsi, err := rowsiFromStatement(si, args...)
+ ds := driverStmt{dc, si}
+ rowsi, err := rowsiFromStatement(ds, args...)
if err != nil {
releaseConn(err)
return nil, err
@@ -955,8 +1179,7 @@ func (s *Stmt) Query(args ...interface{}) (*Rows, error) {
// Note: ownership of ci passes to the *Rows, to be freed
// with releaseConn.
rows := &Rows{
- db: s.db,
- ci: ci,
+ dc: dc,
rowsi: rowsi,
// releaseConn set below
}
@@ -968,20 +1191,26 @@ func (s *Stmt) Query(args ...interface{}) (*Rows, error) {
return rows, nil
}
-func rowsiFromStatement(si driver.Stmt, args ...interface{}) (driver.Rows, error) {
+func rowsiFromStatement(ds driverStmt, args ...interface{}) (driver.Rows, error) {
+ ds.Lock()
+ want := ds.si.NumInput()
+ ds.Unlock()
+
// -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
// driver deal with errors.
- if want := si.NumInput(); want != -1 && len(args) != want {
- return nil, fmt.Errorf("sql: statement expects %d inputs; got %d", si.NumInput(), len(args))
+ if want != -1 && len(args) != want {
+ return nil, fmt.Errorf("sql: statement expects %d inputs; got %d", want, len(args))
}
- dargs, err := driverArgs(si, args)
+ dargs, err := driverArgs(&ds, args)
if err != nil {
return nil, err
}
- rowsi, err := si.Query(dargs)
+ ds.Lock()
+ rowsi, err := ds.si.Query(dargs)
+ ds.Unlock()
if err != nil {
return nil, err
}
@@ -1032,7 +1261,9 @@ func (s *Stmt) Close() error {
func (s *Stmt) finalClose() error {
for _, v := range s.css {
- s.db.noteUnusedDriverStatement(v.ci, v.si)
+ s.db.noteUnusedDriverStatement(v.dc, v.si)
+ v.dc.removeOpenStmt(v.si)
+ s.db.removeDep(v.dc, s)
}
s.css = nil
return nil
@@ -1052,8 +1283,7 @@ func (s *Stmt) finalClose() error {
// err = rows.Err() // get any error encountered during iteration
// ...
type Rows struct {
- db *DB
- ci driver.Conn // owned; must call releaseConn when closed to release
+ dc *driverConn // owned; must call releaseConn when closed to release
releaseConn func(error)
rowsi driver.Rows
@@ -1136,24 +1366,6 @@ func (rs *Rows) Scan(dest ...interface{}) error {
return fmt.Errorf("sql: Scan error on column index %d: %v", i, err)
}
}
- for _, dp := range dest {
- b, ok := dp.(*[]byte)
- if !ok {
- continue
- }
- if *b == nil {
- // If the []byte is now nil (for a NULL value),
- // don't fall through to below which would
- // turn it into a non-nil 0-length byte slice
- continue
- }
- if _, ok = dp.(*RawBytes); ok {
- continue
- }
- clone := make([]byte, len(*b))
- copy(clone, *b)
- *b = clone
- }
return nil
}
@@ -1166,10 +1378,10 @@ func (rs *Rows) Close() error {
}
rs.closed = true
err := rs.rowsi.Close()
- rs.releaseConn(err)
if rs.closeStmt != nil {
rs.closeStmt.Close()
}
+ rs.releaseConn(err)
return err
}
@@ -1226,11 +1438,31 @@ type Result interface {
RowsAffected() (int64, error)
}
-type result struct {
- driver.Result
+type driverResult struct {
+ sync.Locker // the *driverConn
+ resi driver.Result
+}
+
+func (dr driverResult) LastInsertId() (int64, error) {
+ dr.Lock()
+ defer dr.Unlock()
+ return dr.resi.LastInsertId()
+}
+
+func (dr driverResult) RowsAffected() (int64, error) {
+ dr.Lock()
+ defer dr.Unlock()
+ return dr.resi.RowsAffected()
}
func stack() string {
- var buf [1024]byte
+ var buf [2 << 10]byte
return string(buf[:runtime.Stack(buf[:], false)])
}
+
+// withLock runs while holding lk.
+func withLock(lk sync.Locker, fn func()) {
+ lk.Lock()
+ fn()
+ lk.Unlock()
+}
diff --git a/src/pkg/database/sql/sql_test.go b/src/pkg/database/sql/sql_test.go
index 53b229600..e6cc667fa 100644
--- a/src/pkg/database/sql/sql_test.go
+++ b/src/pkg/database/sql/sql_test.go
@@ -5,10 +5,11 @@
package sql
import (
- "database/sql/driver"
"fmt"
"reflect"
+ "runtime"
"strings"
+ "sync"
"testing"
"time"
)
@@ -16,10 +17,10 @@ import (
func init() {
type dbConn struct {
db *DB
- c driver.Conn
+ c *driverConn
}
freedFrom := make(map[dbConn]string)
- putConnHook = func(db *DB, c driver.Conn) {
+ putConnHook = func(db *DB, c *driverConn) {
for _, oc := range db.freeConn {
if oc == c {
// print before panic, as panic may get lost due to conflicting panic
@@ -37,7 +38,15 @@ const fakeDBName = "foo"
var chrisBirthday = time.Unix(123456789, 0)
-func newTestDB(t *testing.T, name string) *DB {
+type testOrBench interface {
+ Fatalf(string, ...interface{})
+ Errorf(string, ...interface{})
+ Fatal(...interface{})
+ Error(...interface{})
+ Logf(string, ...interface{})
+}
+
+func newTestDB(t testOrBench, name string) *DB {
db, err := Open("test", fakeDBName)
if err != nil {
t.Fatalf("Open: %v", err)
@@ -51,21 +60,42 @@ func newTestDB(t *testing.T, name string) *DB {
exec(t, db, "INSERT|people|name=Bob,age=?,photo=BPHOTO", 2)
exec(t, db, "INSERT|people|name=Chris,age=?,photo=CPHOTO,bdate=?", 3, chrisBirthday)
}
+ if name == "magicquery" {
+ // Magic table name and column, known by fakedb_test.go.
+ exec(t, db, "CREATE|magicquery|op=string,millis=int32")
+ exec(t, db, "INSERT|magicquery|op=sleep,millis=10")
+ }
return db
}
-func exec(t *testing.T, db *DB, query string, args ...interface{}) {
+func exec(t testOrBench, db *DB, query string, args ...interface{}) {
_, err := db.Exec(query, args...)
if err != nil {
t.Fatalf("Exec of %q: %v", query, err)
}
}
-func closeDB(t *testing.T, db *DB) {
+func closeDB(t testOrBench, db *DB) {
if e := recover(); e != nil {
fmt.Printf("Panic: %v\n", e)
panic(e)
}
+ defer setHookpostCloseConn(nil)
+ setHookpostCloseConn(func(_ *fakeConn, err error) {
+ if err != nil {
+ t.Errorf("Error closing fakeConn: %v", err)
+ }
+ })
+ for i, dc := range db.freeConn {
+ if n := len(dc.openStmt); n > 0 {
+ // Just a sanity check. This is legal in
+ // general, but if we make the tests clean up
+ // their statements first, then we can safely
+ // verify this is always zero here, and any
+ // other value is a leak.
+ t.Errorf("while closing db, freeConn %d/%d had %d open stmts; want 0", i, len(db.freeConn), n)
+ }
+ }
err := db.Close()
if err != nil {
t.Fatalf("error closing DB: %v", err)
@@ -78,7 +108,52 @@ func numPrepares(t *testing.T, db *DB) int {
if n := len(db.freeConn); n != 1 {
t.Fatalf("free conns = %d; want 1", n)
}
- return db.freeConn[0].(*fakeConn).numPrepare
+ return db.freeConn[0].ci.(*fakeConn).numPrepare
+}
+
+func (db *DB) numDeps() int {
+ db.mu.Lock()
+ defer db.mu.Unlock()
+ return len(db.dep)
+}
+
+// Dependencies are closed via a goroutine, so this polls waiting for
+// numDeps to fall to want, waiting up to d.
+func (db *DB) numDepsPollUntil(want int, d time.Duration) int {
+ deadline := time.Now().Add(d)
+ for {
+ n := db.numDeps()
+ if n <= want || time.Now().After(deadline) {
+ return n
+ }
+ time.Sleep(50 * time.Millisecond)
+ }
+}
+
+func (db *DB) numFreeConns() int {
+ db.mu.Lock()
+ defer db.mu.Unlock()
+ return len(db.freeConn)
+}
+
+func (db *DB) dumpDeps(t *testing.T) {
+ for fc := range db.dep {
+ db.dumpDep(t, 0, fc, map[finalCloser]bool{})
+ }
+}
+
+func (db *DB) dumpDep(t *testing.T, depth int, dep finalCloser, seen map[finalCloser]bool) {
+ seen[dep] = true
+ indent := strings.Repeat(" ", depth)
+ ds := db.dep[dep]
+ for k := range ds {
+ t.Logf("%s%T (%p) waiting for -> %T (%p)", indent, dep, dep, k, k)
+ if fc, ok := k.(finalCloser); ok {
+ if !seen[fc] {
+ db.dumpDep(t, depth+1, fc, seen)
+ }
+ }
+ }
}
func TestQuery(t *testing.T) {
@@ -117,7 +192,7 @@ func TestQuery(t *testing.T) {
// And verify that the final rows.Next() call, which hit EOF,
// also closed the rows connection.
- if n := len(db.freeConn); n != 1 {
+ 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 {
@@ -576,7 +651,7 @@ func TestQueryRowClosingStmt(t *testing.T) {
if len(db.freeConn) != 1 {
t.Fatalf("expected 1 free conn")
}
- fakeConn := db.freeConn[0].(*fakeConn)
+ fakeConn := db.freeConn[0].ci.(*fakeConn)
if made, closed := fakeConn.stmtsMade, fakeConn.stmtsClosed; made != closed {
t.Errorf("statement close mismatch: made %d, closed %d", made, closed)
}
@@ -708,3 +783,326 @@ func TestQueryRowNilScanDest(t *testing.T) {
t.Errorf("error = %q; want %q", err.Error(), want)
}
}
+
+func TestIssue4902(t *testing.T) {
+ db := newTestDB(t, "people")
+ defer closeDB(t, db)
+
+ driver := db.driver.(*fakeDriver)
+ opens0 := driver.openCount
+
+ var stmt *Stmt
+ var err error
+ for i := 0; i < 10; i++ {
+ stmt, err = db.Prepare("SELECT|people|name|")
+ if err != nil {
+ t.Fatal(err)
+ }
+ err = stmt.Close()
+ if err != nil {
+ t.Fatal(err)
+ }
+ }
+
+ opens := driver.openCount - opens0
+ if opens > 1 {
+ t.Errorf("opens = %d; want <= 1", opens)
+ t.Logf("db = %#v", db)
+ t.Logf("driver = %#v", driver)
+ t.Logf("stmt = %#v", stmt)
+ }
+}
+
+// Issue 3857
+// This used to deadlock.
+func TestSimultaneousQueries(t *testing.T) {
+ db := newTestDB(t, "people")
+ defer closeDB(t, db)
+
+ tx, err := db.Begin()
+ if err != nil {
+ t.Fatal(err)
+ }
+ defer tx.Rollback()
+
+ r1, err := tx.Query("SELECT|people|name|")
+ if err != nil {
+ t.Fatal(err)
+ }
+ defer r1.Close()
+
+ r2, err := tx.Query("SELECT|people|name|")
+ if err != nil {
+ t.Fatal(err)
+ }
+ defer r2.Close()
+}
+
+func TestMaxIdleConns(t *testing.T) {
+ db := newTestDB(t, "people")
+ defer closeDB(t, db)
+
+ tx, err := db.Begin()
+ if err != nil {
+ t.Fatal(err)
+ }
+ tx.Commit()
+ if got := len(db.freeConn); got != 1 {
+ t.Errorf("freeConns = %d; want 1", got)
+ }
+
+ db.SetMaxIdleConns(0)
+
+ if got := len(db.freeConn); got != 0 {
+ t.Errorf("freeConns after set to zero = %d; want 0", got)
+ }
+
+ tx, err = db.Begin()
+ if err != nil {
+ t.Fatal(err)
+ }
+ tx.Commit()
+ if got := len(db.freeConn); got != 0 {
+ t.Errorf("freeConns = %d; want 0", got)
+ }
+}
+
+// golang.org/issue/5323
+func TestStmtCloseDeps(t *testing.T) {
+ if testing.Short() {
+ t.Skip("skipping in short mode")
+ }
+ defer setHookpostCloseConn(nil)
+ setHookpostCloseConn(func(_ *fakeConn, err error) {
+ if err != nil {
+ t.Errorf("Error closing fakeConn: %v", err)
+ }
+ })
+
+ db := newTestDB(t, "magicquery")
+ defer closeDB(t, db)
+
+ driver := db.driver.(*fakeDriver)
+
+ driver.mu.Lock()
+ opens0 := driver.openCount
+ closes0 := driver.closeCount
+ driver.mu.Unlock()
+ openDelta0 := opens0 - closes0
+
+ stmt, err := db.Prepare("SELECT|magicquery|op|op=?,millis=?")
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ // Start 50 parallel slow queries.
+ const (
+ nquery = 50
+ sleepMillis = 25
+ nbatch = 2
+ )
+ var wg sync.WaitGroup
+ for batch := 0; batch < nbatch; batch++ {
+ for i := 0; i < nquery; i++ {
+ wg.Add(1)
+ go func() {
+ defer wg.Done()
+ var op string
+ if err := stmt.QueryRow("sleep", sleepMillis).Scan(&op); err != nil && err != ErrNoRows {
+ t.Error(err)
+ }
+ }()
+ }
+ // Sleep for twice the expected length of time for the
+ // batch of 50 queries above to finish before starting
+ // the next round.
+ time.Sleep(2 * sleepMillis * time.Millisecond)
+ }
+ wg.Wait()
+
+ if g, w := db.numFreeConns(), 2; g != w {
+ t.Errorf("free conns = %d; want %d", g, w)
+ }
+
+ if n := db.numDepsPollUntil(4, time.Second); n > 4 {
+ t.Errorf("number of dependencies = %d; expected <= 4", n)
+ db.dumpDeps(t)
+ }
+
+ driver.mu.Lock()
+ opens := driver.openCount - opens0
+ closes := driver.closeCount - closes0
+ driver.mu.Unlock()
+ openDelta := (driver.openCount - driver.closeCount) - openDelta0
+
+ if openDelta > 2 {
+ t.Logf("open calls = %d", opens)
+ t.Logf("close calls = %d", closes)
+ t.Logf("open delta = %d", openDelta)
+ t.Errorf("db connections opened = %d; want <= 2", openDelta)
+ db.dumpDeps(t)
+ }
+
+ if len(stmt.css) > nquery {
+ t.Errorf("len(stmt.css) = %d; want <= %d", len(stmt.css), nquery)
+ }
+
+ if err := stmt.Close(); err != nil {
+ t.Fatal(err)
+ }
+
+ if g, w := db.numFreeConns(), 2; g != w {
+ t.Errorf("free conns = %d; want %d", g, w)
+ }
+
+ if n := db.numDepsPollUntil(2, time.Second); n > 2 {
+ t.Errorf("number of dependencies = %d; expected <= 2", n)
+ db.dumpDeps(t)
+ }
+
+ db.SetMaxIdleConns(0)
+
+ if g, w := db.numFreeConns(), 0; g != w {
+ t.Errorf("free conns = %d; want %d", g, w)
+ }
+
+ if n := db.numDepsPollUntil(0, time.Second); n > 0 {
+ t.Errorf("number of dependencies = %d; expected 0", n)
+ db.dumpDeps(t)
+ }
+}
+
+// golang.org/issue/5046
+func TestCloseConnBeforeStmts(t *testing.T) {
+ db := newTestDB(t, "people")
+ defer closeDB(t, db)
+
+ defer setHookpostCloseConn(nil)
+ setHookpostCloseConn(func(_ *fakeConn, err error) {
+ if err != nil {
+ t.Errorf("Error closing fakeConn: %v; from %s", err, stack())
+ db.dumpDeps(t)
+ t.Errorf("DB = %#v", db)
+ }
+ })
+
+ stmt, err := db.Prepare("SELECT|people|name|")
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ if len(db.freeConn) != 1 {
+ t.Fatalf("expected 1 freeConn; got %d", len(db.freeConn))
+ }
+ dc := db.freeConn[0]
+ if dc.closed {
+ t.Errorf("conn shouldn't be closed")
+ }
+
+ if n := len(dc.openStmt); n != 1 {
+ t.Errorf("driverConn num openStmt = %d; want 1", n)
+ }
+ err = db.Close()
+ if err != nil {
+ t.Errorf("db Close = %v", err)
+ }
+ if !dc.closed {
+ t.Errorf("after db.Close, driverConn should be closed")
+ }
+ if n := len(dc.openStmt); n != 0 {
+ t.Errorf("driverConn num openStmt = %d; want 0", n)
+ }
+
+ err = stmt.Close()
+ if err != nil {
+ t.Errorf("Stmt close = %v", err)
+ }
+
+ if !dc.closed {
+ t.Errorf("conn should be closed")
+ }
+ if dc.ci != nil {
+ t.Errorf("after Stmt Close, driverConn's Conn interface should be nil")
+ }
+}
+
+// golang.org/issue/5283: don't release the Rows' connection in Close
+// before calling Stmt.Close.
+func TestRowsCloseOrder(t *testing.T) {
+ db := newTestDB(t, "people")
+ defer closeDB(t, db)
+
+ db.SetMaxIdleConns(0)
+ setStrictFakeConnClose(t)
+ defer setStrictFakeConnClose(nil)
+
+ rows, err := db.Query("SELECT|people|age,name|")
+ if err != nil {
+ t.Fatal(err)
+ }
+ err = rows.Close()
+ if err != nil {
+ t.Fatal(err)
+ }
+}
+
+func manyConcurrentQueries(t testOrBench) {
+ maxProcs, numReqs := 16, 500
+ if testing.Short() {
+ maxProcs, numReqs = 4, 50
+ }
+ defer runtime.GOMAXPROCS(runtime.GOMAXPROCS(maxProcs))
+
+ db := newTestDB(t, "people")
+ defer closeDB(t, db)
+
+ stmt, err := db.Prepare("SELECT|people|name|")
+ if err != nil {
+ t.Fatal(err)
+ }
+ defer stmt.Close()
+
+ var wg sync.WaitGroup
+ wg.Add(numReqs)
+
+ reqs := make(chan bool)
+ defer close(reqs)
+
+ for i := 0; i < maxProcs*2; i++ {
+ go func() {
+ for _ = range reqs {
+ rows, err := stmt.Query()
+ if err != nil {
+ t.Errorf("error on query: %v", err)
+ wg.Done()
+ continue
+ }
+
+ var name string
+ for rows.Next() {
+ rows.Scan(&name)
+ }
+ rows.Close()
+
+ wg.Done()
+ }
+ }()
+ }
+
+ for i := 0; i < numReqs; i++ {
+ reqs <- true
+ }
+
+ wg.Wait()
+}
+
+func TestConcurrency(t *testing.T) {
+ manyConcurrentQueries(t)
+}
+
+func BenchmarkConcurrency(b *testing.B) {
+ b.ReportAllocs()
+ for i := 0; i < b.N; i++ {
+ manyConcurrentQueries(b)
+ }
+}
diff --git a/src/pkg/debug/dwarf/buf.go b/src/pkg/debug/dwarf/buf.go
index 6dc28d256..53c46eb4b 100644
--- a/src/pkg/debug/dwarf/buf.go
+++ b/src/pkg/debug/dwarf/buf.go
@@ -13,17 +13,45 @@ import (
// Data buffer being decoded.
type buf struct {
- dwarf *Data
- order binary.ByteOrder
- name string
- off Offset
- data []byte
- addrsize int
- err error
+ dwarf *Data
+ order binary.ByteOrder
+ format dataFormat
+ name string
+ off Offset
+ data []byte
+ err error
}
-func makeBuf(d *Data, name string, off Offset, data []byte, addrsize int) buf {
- return buf{d, d.order, name, off, data, addrsize, nil}
+// Data format, other than byte order. This affects the handling of
+// certain field formats.
+type dataFormat interface {
+ // 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.
+ addrsize() int
+}
+
+// Some parts of DWARF have no data format, e.g., abbrevs.
+type unknownFormat struct{}
+
+func (u unknownFormat) version() int {
+ return 0
+}
+
+func (u unknownFormat) dwarf64() (bool, bool) {
+ return false, false
+}
+
+func (u unknownFormat) addrsize() int {
+ return 0
+}
+
+func makeBuf(d *Data, format dataFormat, name string, off Offset, data []byte) buf {
+ return buf{d, d.order, format, name, off, data, nil}
}
func (b *buf) uint8() uint8 {
@@ -121,7 +149,7 @@ func (b *buf) int() int64 {
// Address-sized uint.
func (b *buf) addr() uint64 {
- switch b.addrsize {
+ switch b.format.addrsize() {
case 1:
return uint64(b.uint8())
case 2:
diff --git a/src/pkg/debug/dwarf/entry.go b/src/pkg/debug/dwarf/entry.go
index f376e4088..13d8d5ecf 100644
--- a/src/pkg/debug/dwarf/entry.go
+++ b/src/pkg/debug/dwarf/entry.go
@@ -40,7 +40,7 @@ func (d *Data) parseAbbrev(off uint32) (abbrevTable, error) {
} else {
data = data[off:]
}
- b := makeBuf(d, "abbrev", 0, data, 0)
+ b := makeBuf(d, unknownFormat{}, "abbrev", 0, data)
// Error handling is simplified by the buf getters
// returning an endless stream of 0s after an error.
@@ -192,7 +192,21 @@ func (b *buf) entry(atab abbrevTable, ubase Offset) *Entry {
// reference to other entry
case formRefAddr:
- val = Offset(b.addr())
+ vers := b.format.version()
+ if vers == 0 {
+ b.error("unknown version for DW_FORM_ref_addr")
+ } else if vers == 2 {
+ val = Offset(b.addr())
+ } else {
+ is64, known := b.format.dwarf64()
+ if !known {
+ b.error("unknown size for DW_FORM_ref_addr")
+ } else if is64 {
+ val = Offset(b.uint64())
+ } else {
+ val = Offset(b.uint32())
+ }
+ }
case formRef1:
val = Offset(b.uint8()) + ubase
case formRef2:
@@ -212,7 +226,7 @@ func (b *buf) entry(atab abbrevTable, ubase Offset) *Entry {
if b.err != nil {
return nil
}
- b1 := makeBuf(b.dwarf, "str", 0, b.dwarf.str, 0)
+ b1 := makeBuf(b.dwarf, unknownFormat{}, "str", 0, b.dwarf.str)
b1.skip(int(off))
val = b1.string()
if b1.err != nil {
@@ -262,7 +276,7 @@ func (r *Reader) Seek(off Offset) {
}
u := &d.unit[0]
r.unit = 0
- r.b = makeBuf(r.d, "info", u.off, u.data, u.addrsize)
+ r.b = makeBuf(r.d, u, "info", u.off, u.data)
return
}
@@ -273,7 +287,7 @@ func (r *Reader) Seek(off Offset) {
u = &d.unit[i]
if u.off <= off && off < u.off+Offset(len(u.data)) {
r.unit = i
- r.b = makeBuf(r.d, "info", off, u.data[off-u.off:], u.addrsize)
+ r.b = makeBuf(r.d, u, "info", off, u.data[off-u.off:])
return
}
}
@@ -285,7 +299,7 @@ func (r *Reader) maybeNextUnit() {
for len(r.b.data) == 0 && r.unit+1 < len(r.d.unit) {
r.unit++
u := &r.d.unit[r.unit]
- r.b = makeBuf(r.d, "info", u.off, u.data, u.addrsize)
+ r.b = makeBuf(r.d, u, "info", u.off, u.data)
}
}
diff --git a/src/pkg/debug/dwarf/type.go b/src/pkg/debug/dwarf/type.go
index 450235502..54000fbd7 100644
--- a/src/pkg/debug/dwarf/type.go
+++ b/src/pkg/debug/dwarf/type.go
@@ -435,7 +435,9 @@ func (d *Data) Type(off Offset) (Type, error) {
goto Error
}
if loc, ok := kid.Val(AttrDataMemberLoc).([]byte); ok {
- b := makeBuf(d, "location", 0, loc, d.addrsize)
+ // TODO: Should have original compilation
+ // unit here, not unknownFormat.
+ b := makeBuf(d, unknownFormat{}, "location", 0, loc)
if b.uint8() != opPlusUconst {
err = DecodeError{"info", kid.Offset, "unexpected opcode"}
goto Error
diff --git a/src/pkg/debug/dwarf/unit.go b/src/pkg/debug/dwarf/unit.go
index c10d75dbd..270cd2e33 100644
--- a/src/pkg/debug/dwarf/unit.go
+++ b/src/pkg/debug/dwarf/unit.go
@@ -10,19 +10,44 @@ import "strconv"
// Each unit has its own abbreviation table and address size.
type unit struct {
- base Offset // byte offset of header within the aggregate info
- off Offset // byte offset of data within the aggregate info
- data []byte
- atable abbrevTable
- addrsize int
+ base Offset // byte offset of header within the aggregate info
+ off Offset // byte offset of data within the aggregate info
+ data []byte
+ atable abbrevTable
+ asize int
+ vers int
+ is64 bool // True for 64-bit DWARF format
+}
+
+// Implement the dataFormat interface.
+
+func (u *unit) version() int {
+ return u.vers
+}
+
+func (u *unit) dwarf64() (bool, bool) {
+ return u.is64, true
+}
+
+func (u *unit) addrsize() int {
+ return u.asize
}
func (d *Data) parseUnits() ([]unit, error) {
// Count units.
nunit := 0
- b := makeBuf(d, "info", 0, d.info, 0)
+ b := makeBuf(d, unknownFormat{}, "info", 0, d.info)
for len(b.data) > 0 {
- b.skip(int(b.uint32()))
+ len := b.uint32()
+ if len == 0xffffffff {
+ len64 := b.uint64()
+ if len64 != uint64(uint32(len64)) {
+ b.error("unit length overflow")
+ break
+ }
+ len = uint32(len64)
+ }
+ b.skip(int(len))
nunit++
}
if b.err != nil {
@@ -30,16 +55,22 @@ func (d *Data) parseUnits() ([]unit, error) {
}
// Again, this time writing them down.
- b = makeBuf(d, "info", 0, d.info, 0)
+ b = makeBuf(d, unknownFormat{}, "info", 0, d.info)
units := make([]unit, nunit)
for i := range units {
u := &units[i]
u.base = b.off
n := b.uint32()
- if vers := b.uint16(); vers != 2 {
+ if n == 0xffffffff {
+ u.is64 = true
+ n = uint32(b.uint64())
+ }
+ vers := b.uint16()
+ if vers != 2 && vers != 3 {
b.error("unsupported DWARF version " + strconv.Itoa(int(vers)))
break
}
+ u.vers = int(vers)
atable, err := d.parseAbbrev(b.uint32())
if err != nil {
if b.err == nil {
@@ -48,7 +79,7 @@ func (d *Data) parseUnits() ([]unit, error) {
break
}
u.atable = atable
- u.addrsize = int(b.uint8())
+ u.asize = int(b.uint8())
u.off = b.off
u.data = b.bytes(int(n - (2 + 4 + 1)))
}
diff --git a/src/pkg/debug/elf/file.go b/src/pkg/debug/elf/file.go
index acb9817af..a55c37ea9 100644
--- a/src/pkg/debug/elf/file.go
+++ b/src/pkg/debug/elf/file.go
@@ -422,6 +422,10 @@ func (f *File) getSymbols32(typ SectionType) ([]Symbol, []byte, error) {
return nil, nil, errors.New("cannot load string table section")
}
+ // The first entry is all zeros.
+ var skip [Sym32Size]byte
+ symtab.Read(skip[:])
+
symbols := make([]Symbol, symtab.Len()/Sym32Size)
i := 0
@@ -461,6 +465,10 @@ func (f *File) getSymbols64(typ SectionType) ([]Symbol, []byte, error) {
return nil, nil, errors.New("cannot load string table section")
}
+ // The first entry is all zeros.
+ var skip [Sym64Size]byte
+ symtab.Read(skip[:])
+
symbols := make([]Symbol, symtab.Len()/Sym64Size)
i := 0
@@ -533,10 +541,10 @@ func (f *File) applyRelocationsAMD64(dst []byte, rels []byte) error {
symNo := rela.Info >> 32
t := R_X86_64(rela.Info & 0xffff)
- if symNo >= uint64(len(symbols)) {
+ if symNo == 0 || symNo > uint64(len(symbols)) {
continue
}
- sym := &symbols[symNo]
+ sym := &symbols[symNo-1]
if SymType(sym.Info&0xf) != STT_SECTION {
// We don't handle non-section relocations for now.
continue
@@ -597,6 +605,10 @@ func (f *File) DWARF() (*dwarf.Data, error) {
}
// Symbols returns the symbol table for f.
+//
+// For compatibility with Go 1.0, Symbols omits the null symbol at index 0.
+// After retrieving the symbols as symtab, an externally supplied index x
+// corresponds to symtab[x-1], not symtab[x].
func (f *File) Symbols() ([]Symbol, error) {
sym, _, err := f.getSymbols(SHT_SYMTAB)
return sym, err
@@ -706,7 +718,7 @@ func (f *File) gnuVersionInit(str []byte) {
// which came from offset i of the symbol table.
func (f *File) gnuVersion(i int, sym *ImportedSymbol) {
// Each entry is two bytes.
- i = i * 2
+ i = (i + 1) * 2
if i >= len(f.gnuVersym) {
return
}
diff --git a/src/pkg/debug/macho/file.go b/src/pkg/debug/macho/file.go
index fa73a315c..f5f0dedb7 100644
--- a/src/pkg/debug/macho/file.go
+++ b/src/pkg/debug/macho/file.go
@@ -142,6 +142,8 @@ type Dysymtab struct {
* Mach-O reader
*/
+// FormatError is returned by some operations if the data does
+// not have the correct format for an object file.
type FormatError struct {
off int64
msg string
diff --git a/src/pkg/encoding/ascii85/ascii85.go b/src/pkg/encoding/ascii85/ascii85.go
index 705022792..e2afc5871 100644
--- a/src/pkg/encoding/ascii85/ascii85.go
+++ b/src/pkg/encoding/ascii85/ascii85.go
@@ -296,5 +296,4 @@ func (d *decoder) Read(p []byte) (n int, err error) {
nn, d.readErr = d.r.Read(d.buf[d.nbuf:])
d.nbuf += nn
}
- panic("unreachable")
}
diff --git a/src/pkg/encoding/asn1/marshal.go b/src/pkg/encoding/asn1/marshal.go
index 0c216fdb3..adaf80dcd 100644
--- a/src/pkg/encoding/asn1/marshal.go
+++ b/src/pkg/encoding/asn1/marshal.go
@@ -460,7 +460,6 @@ func marshalBody(out *forkableWriter, value reflect.Value, params fieldParameter
default:
return marshalUTF8String(out, v.String())
}
- return
}
return StructuralError{"unknown Go type"}
diff --git a/src/pkg/encoding/base32/base32.go b/src/pkg/encoding/base32/base32.go
index dbefc48fa..fe17b7322 100644
--- a/src/pkg/encoding/base32/base32.go
+++ b/src/pkg/encoding/base32/base32.go
@@ -6,8 +6,10 @@
package base32
import (
+ "bytes"
"io"
"strconv"
+ "strings"
)
/*
@@ -48,6 +50,13 @@ var StdEncoding = NewEncoding(encodeStd)
// It is typically used in DNS.
var HexEncoding = NewEncoding(encodeHex)
+var removeNewlinesMapper = func(r rune) rune {
+ if r == '\r' || r == '\n' {
+ return -1
+ }
+ return r
+}
+
/*
* Encoder
*/
@@ -228,40 +237,47 @@ func (e CorruptInputError) Error() string {
// decode is like Decode but returns an additional 'end' value, which
// indicates if end-of-message padding was encountered and thus any
-// additional data is an error.
+// additional data is an error. This method assumes that src has been
+// stripped of all supported whitespace ('\r' and '\n').
func (enc *Encoding) decode(dst, src []byte) (n int, end bool, err error) {
- osrc := src
+ olen := len(src)
for len(src) > 0 && !end {
// Decode quantum using the base32 alphabet
var dbuf [8]byte
dlen := 8
- // do the top bytes contain any data?
for j := 0; j < 8; {
if len(src) == 0 {
- return n, false, CorruptInputError(len(osrc) - len(src) - j)
+ return n, false, CorruptInputError(olen - len(src) - j)
}
in := src[0]
src = src[1:]
- if in == '\r' || in == '\n' {
- // Ignore this character.
- continue
- }
if in == '=' && j >= 2 && len(src) < 8 {
- // We've reached the end and there's
- // padding, the rest should be padded
- for k := 0; k < 8-j-1; k++ {
+ // We've reached the end and there's padding
+ if len(src)+j < 8-1 {
+ // not enough padding
+ return n, false, CorruptInputError(olen)
+ }
+ for k := 0; k < 8-1-j; k++ {
if len(src) > k && src[k] != '=' {
- return n, false, CorruptInputError(len(osrc) - len(src) + k - 1)
+ // incorrect padding
+ return n, false, CorruptInputError(olen - len(src) + k - 1)
}
}
- dlen = j
- end = true
+ dlen, end = j, true
+ // 7, 5 and 2 are not valid padding lengths, and so 1, 3 and 6 are not
+ // valid dlen values. See RFC 4648 Section 6 "Base 32 Encoding" listing
+ // the five valid padding lengths, and Section 9 "Illustrations and
+ // Examples" for an illustration for how the the 1st, 3rd and 6th base32
+ // src bytes do not yield enough information to decode a dst byte.
+ if dlen == 1 || dlen == 3 || dlen == 6 {
+ return n, false, CorruptInputError(olen - len(src) - 1)
+ }
break
}
dbuf[j] = enc.decodeMap[in]
if dbuf[j] == 0xFF {
- return n, false, CorruptInputError(len(osrc) - len(src) - 1)
+ return n, false, CorruptInputError(olen - len(src) - 1)
}
j++
}
@@ -269,16 +285,16 @@ func (enc *Encoding) decode(dst, src []byte) (n int, end bool, err error) {
// Pack 8x 5-bit source blocks into 5 byte destination
// quantum
switch dlen {
- case 7, 8:
+ case 8:
dst[4] = dbuf[6]<<5 | dbuf[7]
fallthrough
- case 6, 5:
+ case 7:
dst[3] = dbuf[4]<<7 | dbuf[5]<<2 | dbuf[6]>>3
fallthrough
- case 4:
+ case 5:
dst[2] = dbuf[3]<<4 | dbuf[4]>>1
fallthrough
- case 3:
+ case 4:
dst[1] = dbuf[1]<<6 | dbuf[2]<<1 | dbuf[3]>>4
fallthrough
case 2:
@@ -288,11 +304,11 @@ func (enc *Encoding) decode(dst, src []byte) (n int, end bool, err error) {
switch dlen {
case 2:
n += 1
- case 3, 4:
+ case 4:
n += 2
case 5:
n += 3
- case 6, 7:
+ case 7:
n += 4
case 8:
n += 5
@@ -307,12 +323,14 @@ func (enc *Encoding) decode(dst, src []byte) (n int, end bool, err error) {
// 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) {
+ src = bytes.Map(removeNewlinesMapper, src)
n, _, err = enc.decode(dst, src)
return
}
// DecodeString returns the bytes represented by the base32 string s.
func (enc *Encoding) DecodeString(s string) ([]byte, error) {
+ s = strings.Map(removeNewlinesMapper, s)
dbuf := make([]byte, enc.DecodedLen(len(s)))
n, err := enc.Decode(dbuf, []byte(s))
return dbuf[:n], err
@@ -377,9 +395,34 @@ func (d *decoder) Read(p []byte) (n int, err error) {
return n, d.err
}
+type newlineFilteringReader struct {
+ wrapped io.Reader
+}
+
+func (r *newlineFilteringReader) Read(p []byte) (int, error) {
+ n, err := r.wrapped.Read(p)
+ for n > 0 {
+ offset := 0
+ for i, b := range p[0:n] {
+ if b != '\r' && b != '\n' {
+ if i != offset {
+ p[offset] = b
+ }
+ offset++
+ }
+ }
+ if offset > 0 {
+ return offset, err
+ }
+ // Previous buffer entirely whitespace, read again
+ n, err = r.wrapped.Read(p)
+ }
+ return n, err
+}
+
// NewDecoder constructs a new base32 stream decoder.
func NewDecoder(enc *Encoding, r io.Reader) io.Reader {
- return &decoder{enc: enc, r: r}
+ return &decoder{enc: enc, r: &newlineFilteringReader{r}}
}
// DecodedLen returns the maximum length in bytes of the decoded data
diff --git a/src/pkg/encoding/base32/base32_test.go b/src/pkg/encoding/base32/base32_test.go
index 98365e18c..63298d1c9 100644
--- a/src/pkg/encoding/base32/base32_test.go
+++ b/src/pkg/encoding/base32/base32_test.go
@@ -8,6 +8,7 @@ import (
"bytes"
"io"
"io/ioutil"
+ "strings"
"testing"
)
@@ -137,27 +138,48 @@ func TestDecoderBuffering(t *testing.T) {
}
func TestDecodeCorrupt(t *testing.T) {
- type corrupt struct {
- e string
- p int
- }
- examples := []corrupt{
+ testCases := []struct {
+ input string
+ offset int // -1 means no corruption.
+ }{
+ {"", -1},
{"!!!!", 0},
{"x===", 0},
{"AA=A====", 2},
{"AAA=AAAA", 3},
{"MMMMMMMMM", 8},
{"MMMMMM", 0},
+ {"A=", 1},
+ {"AA=", 3},
+ {"AA==", 4},
+ {"AA===", 5},
+ {"AAAA=", 5},
+ {"AAAA==", 6},
+ {"AAAAA=", 6},
+ {"AAAAA==", 7},
+ {"A=======", 1},
+ {"AA======", -1},
+ {"AAA=====", 3},
+ {"AAAA====", -1},
+ {"AAAAA===", -1},
+ {"AAAAAA==", 6},
+ {"AAAAAAA=", -1},
+ {"AAAAAAAA", -1},
}
-
- for _, e := range examples {
- dbuf := make([]byte, StdEncoding.DecodedLen(len(e.e)))
- _, err := StdEncoding.Decode(dbuf, []byte(e.e))
+ for _, tc := range testCases {
+ dbuf := make([]byte, StdEncoding.DecodedLen(len(tc.input)))
+ _, err := StdEncoding.Decode(dbuf, []byte(tc.input))
+ if tc.offset == -1 {
+ if err != nil {
+ t.Error("Decoder wrongly detected coruption in", tc.input)
+ }
+ continue
+ }
switch err := err.(type) {
case CorruptInputError:
- testEqual(t, "Corruption in %q at offset %v, want %v", e.e, int(err), e.p)
+ testEqual(t, "Corruption in %q at offset %v, want %v", tc.input, int(err), tc.offset)
default:
- t.Error("Decoder failed to detect corruption in", e)
+ t.Error("Decoder failed to detect corruption in", tc)
}
}
}
@@ -195,9 +217,21 @@ func TestBig(t *testing.T) {
}
}
+func testStringEncoding(t *testing.T, expected string, examples []string) {
+ for _, e := range examples {
+ buf, err := StdEncoding.DecodeString(e)
+ if err != nil {
+ t.Errorf("Decode(%q) failed: %v", e, err)
+ continue
+ }
+ if s := string(buf); s != expected {
+ t.Errorf("Decode(%q) = %q, want %q", e, s, expected)
+ }
+ }
+}
+
func TestNewLineCharacters(t *testing.T) {
// Each of these should decode to the string "sure", without errors.
- const expected = "sure"
examples := []string{
"ON2XEZI=",
"ON2XEZI=\r",
@@ -209,14 +243,44 @@ func TestNewLineCharacters(t *testing.T) {
"ON2XEZ\nI=",
"ON2XEZI\n=",
}
- for _, e := range examples {
- buf, err := StdEncoding.DecodeString(e)
- if err != nil {
- t.Errorf("Decode(%q) failed: %v", e, err)
- continue
- }
- if s := string(buf); s != expected {
- t.Errorf("Decode(%q) = %q, want %q", e, s, expected)
- }
+ testStringEncoding(t, "sure", examples)
+
+ // Each of these should decode to the string "foobar", without errors.
+ examples = []string{
+ "MZXW6YTBOI======",
+ "MZXW6YTBOI=\r\n=====",
+ }
+ testStringEncoding(t, "foobar", examples)
+}
+
+func TestDecoderIssue4779(t *testing.T) {
+ encoded := `JRXXEZLNEBUXA43VNUQGI33MN5ZCA43JOQQGC3LFOQWCAY3PNZZWKY3UMV2HK4
+RAMFSGS4DJONUWG2LOM4QGK3DJOQWCA43FMQQGI3YKMVUXK43NN5SCA5DFNVYG64RANFXGG2LENFSH
+K3TUEB2XIIDMMFRG64TFEBSXIIDEN5WG64TFEBWWCZ3OMEQGC3DJOF2WCLRAKV2CAZLONFWQUYLEEB
+WWS3TJNUQHMZLONFQW2LBAOF2WS4ZANZXXG5DSOVSCAZLYMVZGG2LUMF2GS33OEB2WY3DBNVRW6IDM
+MFRG64TJOMQG42LTNEQHK5AKMFWGS4LVNFYCAZLYEBSWCIDDN5WW233EN4QGG33OONSXC5LBOQXCAR
+DVNFZSAYLVORSSA2LSOVZGKIDEN5WG64RANFXAU4TFOBZGK2DFNZSGK4TJOQQGS3RAOZXWY5LQORQX
+IZJAOZSWY2LUEBSXG43FEBRWS3DMOVWSAZDPNRXXEZJAMV2SAZTVM5UWC5BANZ2WY3DBBJYGC4TJMF
+2HK4ROEBCXQY3FOB2GK5LSEBZWS3TUEBXWGY3BMVRWC5BAMN2XA2LEMF2GC5BANZXW4IDQOJXWSZDF
+NZ2CYIDTOVXHIIDJNYFGG5LMOBQSA4LVNEQG6ZTGNFRWSYJAMRSXGZLSOVXHIIDNN5WGY2LUEBQW42
+LNEBUWIIDFON2CA3DBMJXXE5LNFY==
+====`
+ encodedShort := strings.Replace(encoded, "\n", "", -1)
+
+ dec := NewDecoder(StdEncoding, bytes.NewBufferString(encoded))
+ res1, err := ioutil.ReadAll(dec)
+ if err != nil {
+ t.Errorf("ReadAll failed: %v", err)
+ }
+
+ dec = NewDecoder(StdEncoding, bytes.NewBufferString(encodedShort))
+ var res2 []byte
+ res2, err = ioutil.ReadAll(dec)
+ if err != nil {
+ t.Errorf("ReadAll failed: %v", err)
+ }
+
+ if !bytes.Equal(res1, res2) {
+ t.Error("Decoded results not equal")
}
}
diff --git a/src/pkg/encoding/base64/base64.go b/src/pkg/encoding/base64/base64.go
index e66672a1c..85e398fd0 100644
--- a/src/pkg/encoding/base64/base64.go
+++ b/src/pkg/encoding/base64/base64.go
@@ -6,8 +6,10 @@
package base64
import (
+ "bytes"
"io"
"strconv"
+ "strings"
)
/*
@@ -49,6 +51,13 @@ var StdEncoding = NewEncoding(encodeStd)
// It is typically used in URLs and file names.
var URLEncoding = NewEncoding(encodeURL)
+var removeNewlinesMapper = func(r rune) rune {
+ if r == '\r' || r == '\n' {
+ return -1
+ }
+ return r
+}
+
/*
* Encoder
*/
@@ -208,9 +217,10 @@ func (e CorruptInputError) Error() string {
// decode is like Decode but returns an additional 'end' value, which
// indicates if end-of-message padding was encountered and thus any
-// additional data is an error.
+// additional data is an error. This method assumes that src has been
+// stripped of all supported whitespace ('\r' and '\n').
func (enc *Encoding) decode(dst, src []byte) (n int, end bool, err error) {
- osrc := src
+ olen := len(src)
for len(src) > 0 && !end {
// Decode quantum using the base64 alphabet
var dbuf [4]byte
@@ -218,32 +228,26 @@ func (enc *Encoding) decode(dst, src []byte) (n int, end bool, err error) {
for j := 0; j < 4; {
if len(src) == 0 {
- return n, false, CorruptInputError(len(osrc) - len(src) - j)
+ return n, false, CorruptInputError(olen - len(src) - j)
}
in := src[0]
src = src[1:]
- if in == '\r' || in == '\n' {
- // Ignore this character.
- continue
- }
if in == '=' && j >= 2 && len(src) < 4 {
- // We've reached the end and there's
- // padding
- if len(src) == 0 && j == 2 {
+ // We've reached the end and there's padding
+ if len(src)+j < 4-1 {
// not enough padding
- return n, false, CorruptInputError(len(osrc))
+ return n, false, CorruptInputError(olen)
}
if len(src) > 0 && src[0] != '=' {
// incorrect padding
- return n, false, CorruptInputError(len(osrc) - len(src) - 1)
+ return n, false, CorruptInputError(olen - len(src) - 1)
}
- dlen = j
- end = true
+ dlen, end = j, true
break
}
dbuf[j] = enc.decodeMap[in]
if dbuf[j] == 0xFF {
- return n, false, CorruptInputError(len(osrc) - len(src) - 1)
+ return n, false, CorruptInputError(olen - len(src) - 1)
}
j++
}
@@ -273,12 +277,14 @@ func (enc *Encoding) decode(dst, src []byte) (n int, end bool, err error) {
// 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) {
+ src = bytes.Map(removeNewlinesMapper, src)
n, _, err = enc.decode(dst, src)
return
}
// DecodeString returns the bytes represented by the base64 string s.
func (enc *Encoding) DecodeString(s string) ([]byte, error) {
+ s = strings.Map(removeNewlinesMapper, s)
dbuf := make([]byte, enc.DecodedLen(len(s)))
n, err := enc.Decode(dbuf, []byte(s))
return dbuf[:n], err
@@ -343,9 +349,34 @@ func (d *decoder) Read(p []byte) (n int, err error) {
return n, d.err
}
+type newlineFilteringReader struct {
+ wrapped io.Reader
+}
+
+func (r *newlineFilteringReader) Read(p []byte) (int, error) {
+ n, err := r.wrapped.Read(p)
+ for n > 0 {
+ offset := 0
+ for i, b := range p[0:n] {
+ if b != '\r' && b != '\n' {
+ if i != offset {
+ p[offset] = b
+ }
+ offset++
+ }
+ }
+ if offset > 0 {
+ return offset, err
+ }
+ // Previous buffer entirely whitespace, read again
+ n, err = r.wrapped.Read(p)
+ }
+ return n, err
+}
+
// NewDecoder constructs a new base64 stream decoder.
func NewDecoder(enc *Encoding, r io.Reader) io.Reader {
- return &decoder{enc: enc, r: r}
+ return &decoder{enc: enc, r: &newlineFilteringReader{r}}
}
// DecodedLen returns the maximum length in bytes of the decoded data
diff --git a/src/pkg/encoding/base64/base64_test.go b/src/pkg/encoding/base64/base64_test.go
index 2166abd7a..579591a88 100644
--- a/src/pkg/encoding/base64/base64_test.go
+++ b/src/pkg/encoding/base64/base64_test.go
@@ -9,6 +9,7 @@ import (
"errors"
"io"
"io/ioutil"
+ "strings"
"testing"
"time"
)
@@ -142,11 +143,11 @@ func TestDecoderBuffering(t *testing.T) {
}
func TestDecodeCorrupt(t *testing.T) {
- type corrupt struct {
- e string
- p int
- }
- examples := []corrupt{
+ testCases := []struct {
+ input string
+ offset int // -1 means no corruption.
+ }{
+ {"", -1},
{"!!!!", 0},
{"x===", 1},
{"AA=A", 2},
@@ -154,18 +155,27 @@ func TestDecodeCorrupt(t *testing.T) {
{"AAAAA", 4},
{"AAAAAA", 4},
{"A=", 1},
+ {"A==", 1},
{"AA=", 3},
+ {"AA==", -1},
+ {"AAA=", -1},
+ {"AAAA", -1},
{"AAAAAA=", 7},
}
-
- for _, e := range examples {
- dbuf := make([]byte, StdEncoding.DecodedLen(len(e.e)))
- _, err := StdEncoding.Decode(dbuf, []byte(e.e))
+ for _, tc := range testCases {
+ dbuf := make([]byte, StdEncoding.DecodedLen(len(tc.input)))
+ _, err := StdEncoding.Decode(dbuf, []byte(tc.input))
+ if tc.offset == -1 {
+ if err != nil {
+ t.Error("Decoder wrongly detected coruption in", tc.input)
+ }
+ continue
+ }
switch err := err.(type) {
case CorruptInputError:
- testEqual(t, "Corruption in %q at offset %v, want %v", e.e, int(err), e.p)
+ testEqual(t, "Corruption in %q at offset %v, want %v", tc.input, int(err), tc.offset)
default:
- t.Error("Decoder failed to detect corruption in", e)
+ t.Error("Decoder failed to detect corruption in", tc)
}
}
}
@@ -216,6 +226,8 @@ func TestNewLineCharacters(t *testing.T) {
"c3V\nyZ\rQ==",
"c3VyZ\nQ==",
"c3VyZQ\n==",
+ "c3VyZQ=\n=",
+ "c3VyZQ=\r\n\r\n=",
}
for _, e := range examples {
buf, err := StdEncoding.DecodeString(e)
@@ -276,3 +288,40 @@ func TestDecoderIssue3577(t *testing.T) {
t.Errorf("timeout; Decoder blocked without returning an error")
}
}
+
+func TestDecoderIssue4779(t *testing.T) {
+ encoded := `CP/EAT8AAAEF
+AQEBAQEBAAAAAAAAAAMAAQIEBQYHCAkKCwEAAQUBAQEBAQEAAAAAAAAAAQACAwQFBgcICQoLEAAB
+BAEDAgQCBQcGCAUDDDMBAAIRAwQhEjEFQVFhEyJxgTIGFJGhsUIjJBVSwWIzNHKC0UMHJZJT8OHx
+Y3M1FqKygyZEk1RkRcKjdDYX0lXiZfKzhMPTdePzRieUpIW0lcTU5PSltcXV5fVWZnaGlqa2xtbm
+9jdHV2d3h5ent8fX5/cRAAICAQIEBAMEBQYHBwYFNQEAAhEDITESBEFRYXEiEwUygZEUobFCI8FS
+0fAzJGLhcoKSQ1MVY3M08SUGFqKygwcmNcLSRJNUoxdkRVU2dGXi8rOEw9N14/NGlKSFtJXE1OT0
+pbXF1eX1VmZ2hpamtsbW5vYnN0dXZ3eHl6e3x//aAAwDAQACEQMRAD8A9VSSSSUpJJJJSkkkJ+Tj
+1kiy1jCJJDnAcCTykpKkuQ6p/jN6FgmxlNduXawwAzaGH+V6jn/R/wCt71zdn+N/qL3kVYFNYB4N
+ji6PDVjWpKp9TSXnvTf8bFNjg3qOEa2n6VlLpj/rT/pf567DpX1i6L1hs9Py67X8mqdtg/rUWbbf
++gkp0kkkklKSSSSUpJJJJT//0PVUkkklKVLq3WMDpGI7KzrNjADtYNXvI/Mqr/Pd/q9W3vaxjnvM
+NaCXE9gNSvGPrf8AWS3qmba5jjsJhoB0DAf0NDf6sevf+/lf8Hj0JJATfWT6/dV6oXU1uOLQeKKn
+EQP+Hubtfe/+R7Mf/g7f5xcocp++Z11JMCJPgFBxOg7/AOuqDx8I/ikpkXkmSdU8mJIJA/O8EMAy
+j+mSARB/17pKVXYWHXjsj7yIex0PadzXMO1zT5KHoNA3HT8ietoGhgjsfA+CSnvvqh/jJtqsrwOv
+2b6NGNzXfTYexzJ+nU7/ALkf4P8Awv6P9KvTQQ4AgyDqCF85Pho3CTB7eHwXoH+LT65uZbX9X+o2
+bqbPb06551Y4
+`
+ encodedShort := strings.Replace(encoded, "\n", "", -1)
+
+ dec := NewDecoder(StdEncoding, bytes.NewBufferString(encoded))
+ res1, err := ioutil.ReadAll(dec)
+ if err != nil {
+ t.Errorf("ReadAll failed: %v", err)
+ }
+
+ dec = NewDecoder(StdEncoding, bytes.NewBufferString(encodedShort))
+ var res2 []byte
+ res2, err = ioutil.ReadAll(dec)
+ if err != nil {
+ t.Errorf("ReadAll failed: %v", err)
+ }
+
+ if !bytes.Equal(res1, res2) {
+ t.Error("Decoded results not equal")
+ }
+}
diff --git a/src/pkg/encoding/binary/varint.go b/src/pkg/encoding/binary/varint.go
index 7035529f2..3a2dfa3c7 100644
--- a/src/pkg/encoding/binary/varint.go
+++ b/src/pkg/encoding/binary/varint.go
@@ -120,7 +120,6 @@ func ReadUvarint(r io.ByteReader) (uint64, error) {
x |= uint64(b&0x7f) << s
s += 7
}
- panic("unreachable")
}
// ReadVarint reads an encoded signed integer from r and returns it as an int64.
diff --git a/src/pkg/encoding/csv/reader.go b/src/pkg/encoding/csv/reader.go
index db4d98852..b099caf60 100644
--- a/src/pkg/encoding/csv/reader.go
+++ b/src/pkg/encoding/csv/reader.go
@@ -171,7 +171,6 @@ func (r *Reader) ReadAll() (records [][]string, err error) {
}
records = append(records, record)
}
- panic("unreachable")
}
// readRune reads one rune from r, folding \r\n to \n and keeping track
@@ -213,7 +212,6 @@ func (r *Reader) skip(delim rune) error {
return nil
}
}
- panic("unreachable")
}
// parseRecord reads and parses a single csv record from r.
@@ -250,7 +248,6 @@ func (r *Reader) parseRecord() (fields []string, err error) {
return nil, err
}
}
- panic("unreachable")
}
// parseField parses the next field in the record. The read field is
diff --git a/src/pkg/encoding/gob/codec_test.go b/src/pkg/encoding/gob/codec_test.go
index 482212b74..9e38e31d5 100644
--- a/src/pkg/encoding/gob/codec_test.go
+++ b/src/pkg/encoding/gob/codec_test.go
@@ -1191,10 +1191,8 @@ func TestInterface(t *testing.T) {
if v1 != nil || v2 != nil {
t.Errorf("item %d inconsistent nils", i)
}
- continue
- if v1.Square() != v2.Square() {
- t.Errorf("item %d inconsistent values: %v %v", i, v1, v2)
- }
+ } else if v1.Square() != v2.Square() {
+ t.Errorf("item %d inconsistent values: %v %v", i, v1, v2)
}
}
}
diff --git a/src/pkg/encoding/gob/decode.go b/src/pkg/encoding/gob/decode.go
index a80d9f919..7cc756540 100644
--- a/src/pkg/encoding/gob/decode.go
+++ b/src/pkg/encoding/gob/decode.go
@@ -1066,7 +1066,6 @@ func (dec *Decoder) compatibleType(fr reflect.Type, fw typeId, inProgress map[re
case reflect.Struct:
return true
}
- return true
}
// typeString returns a human-readable description of the type identified by remoteId.
diff --git a/src/pkg/encoding/gob/timing_test.go b/src/pkg/encoding/gob/timing_test.go
index 13eb11925..f589675dd 100644
--- a/src/pkg/encoding/gob/timing_test.go
+++ b/src/pkg/encoding/gob/timing_test.go
@@ -9,6 +9,7 @@ import (
"fmt"
"io"
"os"
+ "runtime"
"testing"
)
@@ -49,6 +50,10 @@ func BenchmarkEndToEndByteBuffer(b *testing.B) {
}
func TestCountEncodeMallocs(t *testing.T) {
+ if runtime.GOMAXPROCS(0) > 1 {
+ t.Skip("skipping; GOMAXPROCS>1")
+ }
+
const N = 1000
var buf bytes.Buffer
@@ -65,6 +70,10 @@ func TestCountEncodeMallocs(t *testing.T) {
}
func TestCountDecodeMallocs(t *testing.T) {
+ if runtime.GOMAXPROCS(0) > 1 {
+ t.Skip("skipping; GOMAXPROCS>1")
+ }
+
const N = 1000
var buf bytes.Buffer
diff --git a/src/pkg/encoding/gob/type.go b/src/pkg/encoding/gob/type.go
index ea0db4eac..7fa0b499f 100644
--- a/src/pkg/encoding/gob/type.go
+++ b/src/pkg/encoding/gob/type.go
@@ -526,7 +526,6 @@ func newTypeObject(name string, ut *userTypeInfo, rt reflect.Type) (gobType, err
default:
return nil, errors.New("gob NewTypeObject can't handle type: " + rt.String())
}
- return nil, nil
}
// isExported reports whether this is an exported - upper case - name.
diff --git a/src/pkg/encoding/json/decode.go b/src/pkg/encoding/json/decode.go
index f2ec9cb67..62ac294b8 100644
--- a/src/pkg/encoding/json/decode.go
+++ b/src/pkg/encoding/json/decode.go
@@ -261,6 +261,16 @@ func (d *decodeState) value(v reflect.Value) {
}
d.scan.step(&d.scan, '"')
d.scan.step(&d.scan, '"')
+
+ n := len(d.scan.parseState)
+ if n > 0 && d.scan.parseState[n-1] == parseObjectKey {
+ // d.scan thinks we just read an object key; finish the object
+ d.scan.step(&d.scan, ':')
+ d.scan.step(&d.scan, '"')
+ d.scan.step(&d.scan, '"')
+ d.scan.step(&d.scan, '}')
+ }
+
return
}
@@ -739,6 +749,7 @@ func (d *decodeState) valueInterface() interface{} {
switch d.scanWhile(scanSkipSpace) {
default:
d.error(errPhase)
+ panic("unreachable")
case scanBeginArray:
return d.arrayInterface()
case scanBeginObject:
@@ -746,7 +757,6 @@ func (d *decodeState) valueInterface() interface{} {
case scanBeginLiteral:
return d.literalInterface()
}
- panic("unreachable")
}
// arrayInterface is like array but returns []interface{}.
@@ -858,7 +868,6 @@ func (d *decodeState) literalInterface() interface{} {
}
return n
}
- panic("unreachable")
}
// getu4 decodes \uXXXX from the beginning of s, returning the hex value,
diff --git a/src/pkg/encoding/json/decode_test.go b/src/pkg/encoding/json/decode_test.go
index e1bd918dd..f845f69ab 100644
--- a/src/pkg/encoding/json/decode_test.go
+++ b/src/pkg/encoding/json/decode_test.go
@@ -30,7 +30,7 @@ type V struct {
F3 Number
}
-// ifaceNumAsFloat64/ifaceNumAsNumber are used to test unmarshalling with and
+// ifaceNumAsFloat64/ifaceNumAsNumber are used to test unmarshaling with and
// without UseNumber
var ifaceNumAsFloat64 = map[string]interface{}{
"k1": float64(1),
@@ -1178,3 +1178,16 @@ func TestUnmarshalJSONLiteralError(t *testing.T) {
t.Errorf("got err = %v; want out of range error", err)
}
}
+
+// Test that extra object elements in an array do not result in a
+// "data changing underfoot" error.
+// Issue 3717
+func TestSkipArrayObjects(t *testing.T) {
+ json := `[{}]`
+ var dest [0]interface{}
+
+ err := Unmarshal([]byte(json), &dest)
+ if err != nil {
+ t.Errorf("got error %q, want nil", err)
+ }
+}
diff --git a/src/pkg/encoding/json/encode.go b/src/pkg/encoding/json/encode.go
index fb57f1d51..85727ba61 100644
--- a/src/pkg/encoding/json/encode.go
+++ b/src/pkg/encoding/json/encode.go
@@ -3,7 +3,8 @@
// license that can be found in the LICENSE file.
// Package json implements encoding and decoding of JSON objects as defined in
-// RFC 4627.
+// RFC 4627. The mapping between JSON objects and Go values is described
+// in the documentation for the Marshal and Unmarshal functions.
//
// See "JSON and Go" for an introduction to this package:
// http://golang.org/doc/articles/json_and_go.html
@@ -38,8 +39,8 @@ import (
//
// Floating point, integer, and Number values encode as JSON numbers.
//
-// String values encode as JSON strings, with each invalid UTF-8 sequence
-// replaced by the encoding of the Unicode replacement character U+FFFD.
+// String values encode as JSON strings. InvalidUTF8Error will be returned
+// if an invalid UTF-8 sequence is encountered.
// The angle brackets "<" and ">" are escaped to "\u003c" and "\u003e"
// to keep some browsers from misinterpreting JSON output as HTML.
//
@@ -86,9 +87,21 @@ import (
// underscores and slashes.
//
// 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.
+// were fields in the outer struct, subject to the usual Go visibility rules amended
+// as described in the next paragraph.
// An anonymous struct field with a name given in its JSON tag is treated as
-// having that name instead of as anonymous.
+// having that name, rather than being anonymous.
+//
+// The Go visibility rules for struct fields are amended for JSON when
+// deciding which field to marshal or unmarshal. If there are
+// multiple fields at the same level, and that level is the least
+// nested (and would therefore be the nesting level selected by the
+// usual Go rules), the following extra rules apply:
+//
+// 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.
// Prior to Go 1.1, anonymous struct fields were ignored. To force ignoring of
@@ -187,8 +200,10 @@ func (e *UnsupportedValueError) Error() string {
return "json: unsupported value: " + e.Str
}
+// An InvalidUTF8Error is returned by Marshal when attempting
+// to encode a string value with invalid UTF-8 sequences.
type InvalidUTF8Error struct {
- S string
+ S string // the whole string value that caused the error
}
func (e *InvalidUTF8Error) Error() string {
@@ -654,27 +669,78 @@ func typeFields(t reflect.Type) []field {
sort.Sort(byName(fields))
- // Remove fields with annihilating name collisions
- // and also fields shadowed by fields with explicit JSON tags.
- name := ""
+ // Delete all fields that are hidden by the Go rules for embedded fields,
+ // except that fields with JSON tags are promoted.
+
+ // The fields are sorted in primary order of name, secondary order
+ // of field index length. Loop over names; for each name, delete
+ // hidden fields by choosing the one dominant field that survives.
out := fields[:0]
- for _, f := range fields {
- if f.name != name {
- name = f.name
- out = append(out, f)
+ for advance, i := 0, 0; i < len(fields); i += advance {
+ // One iteration per name.
+ // Find the sequence of fields with the name of this first field.
+ fi := fields[i]
+ name := fi.name
+ for advance = 1; i+advance < len(fields); advance++ {
+ fj := fields[i+advance]
+ if fj.name != name {
+ break
+ }
+ }
+ if advance == 1 { // Only one field with this name
+ out = append(out, fi)
continue
}
- if n := len(out); n > 0 && out[n-1].name == name && (!out[n-1].tag || f.tag) {
- out = out[:n-1]
+ dominant, ok := dominantField(fields[i : i+advance])
+ if ok {
+ out = append(out, dominant)
}
}
- fields = out
+ fields = out
sort.Sort(byIndex(fields))
return fields
}
+// dominantField looks through the fields, all of which are known to
+// have the same name, to find the single field that dominates the
+// others using Go's embedding rules, modified by the presence of
+// JSON tags. If there are multiple top-level fields, the boolean
+// will be false: This condition is an error in Go and we skip all
+// the fields.
+func dominantField(fields []field) (field, bool) {
+ // The fields are sorted in increasing index-length order. The winner
+ // must therefore be one with the shortest index length. Drop all
+ // longer entries, which is easy: just truncate the slice.
+ length := len(fields[0].index)
+ tagged := -1 // Index of first tagged field.
+ for i, f := range fields {
+ if len(f.index) > length {
+ fields = fields[:i]
+ break
+ }
+ if f.tag {
+ if tagged >= 0 {
+ // Multiple tagged fields at the same level: conflict.
+ // Return no field.
+ return field{}, false
+ }
+ tagged = i
+ }
+ }
+ if tagged >= 0 {
+ return fields[tagged], true
+ }
+ // All remaining fields have the same length. If there's more than one,
+ // we have a conflict (two fields named "X" at the same level) and we
+ // return no field.
+ if len(fields) > 1 {
+ return field{}, false
+ }
+ return fields[0], true
+}
+
var fieldCache struct {
sync.RWMutex
m map[reflect.Type][]field
diff --git a/src/pkg/encoding/json/encode_test.go b/src/pkg/encoding/json/encode_test.go
index be74c997c..5be0a992e 100644
--- a/src/pkg/encoding/json/encode_test.go
+++ b/src/pkg/encoding/json/encode_test.go
@@ -206,3 +206,107 @@ func TestAnonymousNonstruct(t *testing.T) {
t.Errorf("got %q, want %q", got, want)
}
}
+
+type BugA struct {
+ S string
+}
+
+type BugB struct {
+ BugA
+ S string
+}
+
+type BugC struct {
+ S string
+}
+
+// Legal Go: We never use the repeated embedded field (S).
+type BugX struct {
+ A int
+ BugA
+ BugB
+}
+
+// Issue 5245.
+func TestEmbeddedBug(t *testing.T) {
+ v := BugB{
+ BugA{"A"},
+ "B",
+ }
+ b, err := Marshal(v)
+ if err != nil {
+ t.Fatal("Marshal:", err)
+ }
+ want := `{"S":"B"}`
+ got := string(b)
+ if got != want {
+ t.Fatalf("Marshal: got %s want %s", got, want)
+ }
+ // Now check that the duplicate field, S, does not appear.
+ x := BugX{
+ A: 23,
+ }
+ b, err = Marshal(x)
+ if err != nil {
+ t.Fatal("Marshal:", err)
+ }
+ want = `{"A":23}`
+ got = string(b)
+ if got != want {
+ t.Fatalf("Marshal: got %s want %s", got, want)
+ }
+}
+
+type BugD struct { // Same as BugA after tagging.
+ XXX string `json:"S"`
+}
+
+// BugD's tagged S field should dominate BugA's.
+type BugY struct {
+ BugA
+ BugD
+}
+
+// Test that a field with a tag dominates untagged fields.
+func TestTaggedFieldDominates(t *testing.T) {
+ v := BugY{
+ BugA{"BugA"},
+ BugD{"BugD"},
+ }
+ b, err := Marshal(v)
+ if err != nil {
+ t.Fatal("Marshal:", err)
+ }
+ want := `{"S":"BugD"}`
+ got := string(b)
+ if got != want {
+ t.Fatalf("Marshal: got %s want %s", got, want)
+ }
+}
+
+// There are no tags here, so S should not appear.
+type BugZ struct {
+ BugA
+ BugC
+ BugY // Contains a tagged S field through BugD; should not dominate.
+}
+
+func TestDuplicatedFieldDisappears(t *testing.T) {
+ v := BugZ{
+ BugA{"BugA"},
+ BugC{"BugC"},
+ BugY{
+ BugA{"nested BugA"},
+ BugD{"nested BugD"},
+ },
+ }
+ b, err := Marshal(v)
+ if err != nil {
+ t.Fatal("Marshal:", err)
+ }
+ want := `{}`
+ got := string(b)
+ if got != want {
+ t.Fatalf("Marshal: got %s want %s", got, want)
+ }
+}
diff --git a/src/pkg/encoding/xml/marshal.go b/src/pkg/encoding/xml/marshal.go
index ea58ce254..47b001763 100644
--- a/src/pkg/encoding/xml/marshal.go
+++ b/src/pkg/encoding/xml/marshal.go
@@ -120,11 +120,76 @@ func (enc *Encoder) Encode(v interface{}) error {
type printer struct {
*bufio.Writer
+ seq int
indent string
prefix string
depth int
indentedIn bool
putNewline bool
+ attrNS map[string]string // map prefix -> name space
+ attrPrefix map[string]string // map name space -> prefix
+}
+
+// createAttrPrefix finds the name space prefix attribute to use for the given name space,
+// defining a new prefix if necessary. It returns the prefix and whether it is new.
+func (p *printer) createAttrPrefix(url string) (prefix string, isNew bool) {
+ if prefix = p.attrPrefix[url]; prefix != "" {
+ return prefix, false
+ }
+
+ // The "http://www.w3.org/XML/1998/namespace" name space is predefined as "xml"
+ // and must be referred to that way.
+ // (The "http://www.w3.org/2000/xmlns/" name space is also predefined as "xmlns",
+ // but users should not be trying to use that one directly - that's our job.)
+ if url == xmlURL {
+ return "xml", false
+ }
+
+ // Need to define a new name space.
+ if p.attrPrefix == nil {
+ p.attrPrefix = make(map[string]string)
+ p.attrNS = make(map[string]string)
+ }
+
+ // Pick a name. We try to use the final element of the path
+ // but fall back to _.
+ prefix = strings.TrimRight(url, "/")
+ if i := strings.LastIndex(prefix, "/"); i >= 0 {
+ prefix = prefix[i+1:]
+ }
+ if prefix == "" || !isName([]byte(prefix)) || strings.Contains(prefix, ":") {
+ prefix = "_"
+ }
+ if strings.HasPrefix(prefix, "xml") {
+ // xmlanything is reserved.
+ prefix = "_" + prefix
+ }
+ if p.attrNS[prefix] != "" {
+ // Name is taken. Find a better one.
+ for p.seq++; ; p.seq++ {
+ if id := prefix + "_" + strconv.Itoa(p.seq); p.attrNS[id] == "" {
+ prefix = id
+ break
+ }
+ }
+ }
+
+ p.attrPrefix[url] = prefix
+ p.attrNS[prefix] = url
+
+ p.WriteString(`xmlns:`)
+ p.WriteString(prefix)
+ p.WriteString(`="`)
+ EscapeText(p, []byte(url))
+ p.WriteString(`" `)
+
+ return prefix, true
+}
+
+// deleteAttrPrefix removes an attribute name space prefix.
+func (p *printer) deleteAttrPrefix(prefix string) {
+ delete(p.attrPrefix, p.attrNS[prefix])
+ delete(p.attrNS, prefix)
}
// marshalValue writes one or more XML elements representing val.
@@ -210,6 +275,14 @@ func (p *printer) marshalValue(val reflect.Value, finfo *fieldInfo) error {
continue
}
p.WriteByte(' ')
+ if finfo.xmlns != "" {
+ prefix, created := p.createAttrPrefix(finfo.xmlns)
+ if created {
+ defer p.deleteAttrPrefix(prefix)
+ }
+ p.WriteString(prefix)
+ p.WriteByte(':')
+ }
p.WriteString(finfo.name)
p.WriteString(`="`)
if err := p.marshalSimple(fv.Type(), fv); err != nil {
@@ -286,7 +359,7 @@ func (p *printer) marshalStruct(tinfo *typeInfo, val reflect.Value) error {
s := parentStack{printer: p}
for i := range tinfo.fields {
finfo := &tinfo.fields[i]
- if finfo.flags&(fAttr) != 0 {
+ if finfo.flags&fAttr != 0 {
continue
}
vf := finfo.value(val)
diff --git a/src/pkg/encoding/xml/marshal_test.go b/src/pkg/encoding/xml/marshal_test.go
index 3a190def6..ca14a1e53 100644
--- a/src/pkg/encoding/xml/marshal_test.go
+++ b/src/pkg/encoding/xml/marshal_test.go
@@ -266,6 +266,16 @@ type Plain struct {
V interface{}
}
+type MyInt int
+
+type EmbedInt struct {
+ MyInt
+}
+
+type Strings struct {
+ X []string `xml:"A>B,omitempty"`
+}
+
// 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
@@ -790,6 +800,17 @@ var marshalTests = []struct {
},
UnmarshalOnly: true,
},
+ {
+ ExpectXML: `<EmbedInt><MyInt>42</MyInt></EmbedInt>`,
+ Value: &EmbedInt{
+ MyInt: 42,
+ },
+ },
+ // Test omitempty with parent chain; see golang.org/issue/4168.
+ {
+ ExpectXML: `<Strings><A></A></Strings>`,
+ Value: &Strings{},
+ },
}
func TestMarshal(t *testing.T) {
@@ -812,6 +833,10 @@ func TestMarshal(t *testing.T) {
}
}
+type AttrParent struct {
+ X string `xml:"X>Y,attr"`
+}
+
var marshalErrorTests = []struct {
Value interface{}
Err string
@@ -839,6 +864,11 @@ var marshalErrorTests = []struct {
Value: &Domain{Comment: []byte("f--bar")},
Err: `xml: comments must not contain "--"`,
},
+ // Reject parent chain with attr, never worked; see golang.org/issue/5033.
+ {
+ Value: &AttrParent{},
+ Err: `xml: X>Y chain not valid with attr flag`,
+ },
}
var marshalIndentTests = []struct {
@@ -861,8 +891,12 @@ var marshalIndentTests = []struct {
func TestMarshalErrors(t *testing.T) {
for idx, test := range marshalErrorTests {
- _, err := Marshal(test.Value)
- if err == nil || err.Error() != test.Err {
+ data, err := Marshal(test.Value)
+ if err == nil {
+ t.Errorf("#%d: marshal(%#v) = [success] %q, want error %v", idx, test.Value, data, test.Err)
+ continue
+ }
+ if err.Error() != test.Err {
t.Errorf("#%d: marshal(%#v) = [error] %v, want %v", idx, test.Value, err, test.Err)
}
if test.Kind != reflect.Invalid {
diff --git a/src/pkg/encoding/xml/read.go b/src/pkg/encoding/xml/read.go
index 344ab514e..a7a2a9655 100644
--- a/src/pkg/encoding/xml/read.go
+++ b/src/pkg/encoding/xml/read.go
@@ -263,7 +263,7 @@ func (p *Decoder) unmarshal(val reflect.Value, start *StartElement) error {
strv := finfo.value(sv)
// Look for attribute.
for _, a := range start.Attr {
- if a.Name.Local == finfo.name {
+ if a.Name.Local == finfo.name && (finfo.xmlns == "" || finfo.xmlns == a.Name.Space) {
copyValue(strv, []byte(a.Value))
break
}
@@ -441,7 +441,7 @@ func (p *Decoder) unmarshalPath(tinfo *typeInfo, sv reflect.Value, parents []str
Loop:
for i := range tinfo.fields {
finfo := &tinfo.fields[i]
- if finfo.flags&fElement == 0 || len(finfo.parents) < len(parents) {
+ if finfo.flags&fElement == 0 || len(finfo.parents) < len(parents) || finfo.xmlns != "" && finfo.xmlns != start.Name.Space {
continue
}
for j := range parents {
@@ -493,7 +493,6 @@ Loop:
return true, nil
}
}
- panic("unreachable")
}
// Skip reads tokens until it has consumed the end element
@@ -517,5 +516,4 @@ func (d *Decoder) Skip() error {
return nil
}
}
- panic("unreachable")
}
diff --git a/src/pkg/encoding/xml/read_test.go b/src/pkg/encoding/xml/read_test.go
index b45e2f0e6..7d28c5d7d 100644
--- a/src/pkg/encoding/xml/read_test.go
+++ b/src/pkg/encoding/xml/read_test.go
@@ -6,6 +6,7 @@ package xml
import (
"reflect"
+ "strings"
"testing"
"time"
)
@@ -399,3 +400,224 @@ func TestUnmarshalAttr(t *testing.T) {
t.Fatalf("Unmarshal with %s failed:\nhave %#v,\n want %#v", x, p3.Int, 1)
}
}
+
+type Tables struct {
+ HTable string `xml:"http://www.w3.org/TR/html4/ table"`
+ FTable string `xml:"http://www.w3schools.com/furniture table"`
+}
+
+var tables = []struct {
+ xml string
+ tab Tables
+ ns string
+}{
+ {
+ xml: `<Tables>` +
+ `<table xmlns="http://www.w3.org/TR/html4/">hello</table>` +
+ `<table xmlns="http://www.w3schools.com/furniture">world</table>` +
+ `</Tables>`,
+ tab: Tables{"hello", "world"},
+ },
+ {
+ xml: `<Tables>` +
+ `<table xmlns="http://www.w3schools.com/furniture">world</table>` +
+ `<table xmlns="http://www.w3.org/TR/html4/">hello</table>` +
+ `</Tables>`,
+ tab: Tables{"hello", "world"},
+ },
+ {
+ xml: `<Tables xmlns:f="http://www.w3schools.com/furniture" xmlns:h="http://www.w3.org/TR/html4/">` +
+ `<f:table>world</f:table>` +
+ `<h:table>hello</h:table>` +
+ `</Tables>`,
+ tab: Tables{"hello", "world"},
+ },
+ {
+ xml: `<Tables>` +
+ `<table>bogus</table>` +
+ `</Tables>`,
+ tab: Tables{},
+ },
+ {
+ xml: `<Tables>` +
+ `<table>only</table>` +
+ `</Tables>`,
+ tab: Tables{HTable: "only"},
+ ns: "http://www.w3.org/TR/html4/",
+ },
+ {
+ xml: `<Tables>` +
+ `<table>only</table>` +
+ `</Tables>`,
+ tab: Tables{FTable: "only"},
+ ns: "http://www.w3schools.com/furniture",
+ },
+ {
+ xml: `<Tables>` +
+ `<table>only</table>` +
+ `</Tables>`,
+ tab: Tables{},
+ ns: "something else entirely",
+ },
+}
+
+func TestUnmarshalNS(t *testing.T) {
+ for i, tt := range tables {
+ var dst Tables
+ var err error
+ if tt.ns != "" {
+ d := NewDecoder(strings.NewReader(tt.xml))
+ d.DefaultSpace = tt.ns
+ err = d.Decode(&dst)
+ } else {
+ err = Unmarshal([]byte(tt.xml), &dst)
+ }
+ if err != nil {
+ t.Errorf("#%d: Unmarshal: %v", i, err)
+ continue
+ }
+ want := tt.tab
+ if dst != want {
+ t.Errorf("#%d: dst=%+v, want %+v", i, dst, want)
+ }
+ }
+}
+
+func TestMarshalNS(t *testing.T) {
+ dst := Tables{"hello", "world"}
+ data, err := Marshal(&dst)
+ if err != nil {
+ t.Fatalf("Marshal: %v", err)
+ }
+ want := `<Tables><table xmlns="http://www.w3.org/TR/html4/">hello</table><table xmlns="http://www.w3schools.com/furniture">world</table></Tables>`
+ str := string(data)
+ if str != want {
+ t.Errorf("have: %q\nwant: %q\n", str, want)
+ }
+}
+
+type TableAttrs struct {
+ TAttr TAttr
+}
+
+type TAttr struct {
+ HTable string `xml:"http://www.w3.org/TR/html4/ table,attr"`
+ FTable string `xml:"http://www.w3schools.com/furniture table,attr"`
+ Lang string `xml:"http://www.w3.org/XML/1998/namespace lang,attr,omitempty"`
+ Other1 string `xml:"http://golang.org/xml/ other,attr,omitempty"`
+ Other2 string `xml:"http://golang.org/xmlfoo/ other,attr,omitempty"`
+ Other3 string `xml:"http://golang.org/json/ other,attr,omitempty"`
+ Other4 string `xml:"http://golang.org/2/json/ other,attr,omitempty"`
+}
+
+var tableAttrs = []struct {
+ xml string
+ tab TableAttrs
+ ns string
+}{
+ {
+ xml: `<TableAttrs xmlns:f="http://www.w3schools.com/furniture" xmlns:h="http://www.w3.org/TR/html4/"><TAttr ` +
+ `h:table="hello" f:table="world" ` +
+ `/></TableAttrs>`,
+ tab: TableAttrs{TAttr{HTable: "hello", FTable: "world"}},
+ },
+ {
+ xml: `<TableAttrs><TAttr xmlns:f="http://www.w3schools.com/furniture" xmlns:h="http://www.w3.org/TR/html4/" ` +
+ `h:table="hello" f:table="world" ` +
+ `/></TableAttrs>`,
+ tab: TableAttrs{TAttr{HTable: "hello", FTable: "world"}},
+ },
+ {
+ xml: `<TableAttrs><TAttr ` +
+ `h:table="hello" f:table="world" xmlns:f="http://www.w3schools.com/furniture" xmlns:h="http://www.w3.org/TR/html4/" ` +
+ `/></TableAttrs>`,
+ tab: TableAttrs{TAttr{HTable: "hello", FTable: "world"}},
+ },
+ {
+ // Default space does not apply to attribute names.
+ xml: `<TableAttrs xmlns="http://www.w3schools.com/furniture" xmlns:h="http://www.w3.org/TR/html4/"><TAttr ` +
+ `h:table="hello" table="world" ` +
+ `/></TableAttrs>`,
+ tab: TableAttrs{TAttr{HTable: "hello", FTable: ""}},
+ },
+ {
+ // Default space does not apply to attribute names.
+ xml: `<TableAttrs xmlns:f="http://www.w3schools.com/furniture"><TAttr xmlns="http://www.w3.org/TR/html4/" ` +
+ `table="hello" f:table="world" ` +
+ `/></TableAttrs>`,
+ tab: TableAttrs{TAttr{HTable: "", FTable: "world"}},
+ },
+ {
+ xml: `<TableAttrs><TAttr ` +
+ `table="bogus" ` +
+ `/></TableAttrs>`,
+ tab: TableAttrs{},
+ },
+ {
+ // Default space does not apply to attribute names.
+ xml: `<TableAttrs xmlns:h="http://www.w3.org/TR/html4/"><TAttr ` +
+ `h:table="hello" table="world" ` +
+ `/></TableAttrs>`,
+ tab: TableAttrs{TAttr{HTable: "hello", FTable: ""}},
+ ns: "http://www.w3schools.com/furniture",
+ },
+ {
+ // Default space does not apply to attribute names.
+ xml: `<TableAttrs xmlns:f="http://www.w3schools.com/furniture"><TAttr ` +
+ `table="hello" f:table="world" ` +
+ `/></TableAttrs>`,
+ tab: TableAttrs{TAttr{HTable: "", FTable: "world"}},
+ ns: "http://www.w3.org/TR/html4/",
+ },
+ {
+ xml: `<TableAttrs><TAttr ` +
+ `table="bogus" ` +
+ `/></TableAttrs>`,
+ tab: TableAttrs{},
+ ns: "something else entirely",
+ },
+}
+
+func TestUnmarshalNSAttr(t *testing.T) {
+ for i, tt := range tableAttrs {
+ var dst TableAttrs
+ var err error
+ if tt.ns != "" {
+ d := NewDecoder(strings.NewReader(tt.xml))
+ d.DefaultSpace = tt.ns
+ err = d.Decode(&dst)
+ } else {
+ err = Unmarshal([]byte(tt.xml), &dst)
+ }
+ if err != nil {
+ t.Errorf("#%d: Unmarshal: %v", i, err)
+ continue
+ }
+ want := tt.tab
+ if dst != want {
+ t.Errorf("#%d: dst=%+v, want %+v", i, dst, want)
+ }
+ }
+}
+
+func TestMarshalNSAttr(t *testing.T) {
+ src := TableAttrs{TAttr{"hello", "world", "en_US", "other1", "other2", "other3", "other4"}}
+ data, err := Marshal(&src)
+ if err != nil {
+ t.Fatalf("Marshal: %v", err)
+ }
+ want := `<TableAttrs><TAttr xmlns:html4="http://www.w3.org/TR/html4/" html4:table="hello" xmlns:furniture="http://www.w3schools.com/furniture" furniture:table="world" xml:lang="en_US" xmlns:_xml="http://golang.org/xml/" _xml:other="other1" xmlns:_xmlfoo="http://golang.org/xmlfoo/" _xmlfoo:other="other2" xmlns:json="http://golang.org/json/" json:other="other3" xmlns:json_1="http://golang.org/2/json/" json_1:other="other4"></TAttr></TableAttrs>`
+ str := string(data)
+ if str != want {
+ t.Errorf("Marshal:\nhave: %#q\nwant: %#q\n", str, want)
+ }
+
+ var dst TableAttrs
+ if err := Unmarshal(data, &dst); err != nil {
+ t.Errorf("Unmarshal: %v", err)
+ }
+
+ if dst != src {
+ t.Errorf("Unmarshal = %q, want %q", dst, src)
+ }
+}
diff --git a/src/pkg/encoding/xml/typeinfo.go b/src/pkg/encoding/xml/typeinfo.go
index bbeb28d87..83e65402c 100644
--- a/src/pkg/encoding/xml/typeinfo.go
+++ b/src/pkg/encoding/xml/typeinfo.go
@@ -70,20 +70,19 @@ func getTypeInfo(typ reflect.Type) (*typeInfo, error) {
if t.Kind() == reflect.Ptr {
t = t.Elem()
}
- if t.Kind() != reflect.Struct {
- continue
- }
- inner, err := getTypeInfo(t)
- if err != nil {
- return nil, err
- }
- for _, finfo := range inner.fields {
- finfo.idx = append([]int{i}, finfo.idx...)
- if err := addFieldInfo(typ, tinfo, &finfo); err != nil {
+ if t.Kind() == reflect.Struct {
+ inner, err := getTypeInfo(t)
+ if err != nil {
return nil, err
}
+ for _, finfo := range inner.fields {
+ finfo.idx = append([]int{i}, finfo.idx...)
+ if err := addFieldInfo(typ, tinfo, &finfo); err != nil {
+ return nil, err
+ }
+ }
+ continue
}
- continue
}
finfo, err := structFieldInfo(typ, &f)
@@ -193,16 +192,19 @@ func structFieldInfo(typ reflect.Type, f *reflect.StructField) (*fieldInfo, erro
}
// Prepare field name and parents.
- tokens = strings.Split(tag, ">")
- if tokens[0] == "" {
- tokens[0] = f.Name
+ parents := strings.Split(tag, ">")
+ if parents[0] == "" {
+ parents[0] = f.Name
}
- if tokens[len(tokens)-1] == "" {
+ if parents[len(parents)-1] == "" {
return nil, fmt.Errorf("xml: trailing '>' in field %s of type %s", f.Name, typ)
}
- finfo.name = tokens[len(tokens)-1]
- if len(tokens) > 1 {
- finfo.parents = tokens[:len(tokens)-1]
+ finfo.name = parents[len(parents)-1]
+ if len(parents) > 1 {
+ if (finfo.flags & fElement) == 0 {
+ return nil, fmt.Errorf("xml: %s chain not valid with %s flag", tag, strings.Join(tokens[1:], ","))
+ }
+ finfo.parents = parents[:len(parents)-1]
}
// If the field type has an XMLName field, the names must match
@@ -268,6 +270,9 @@ Loop:
if oldf.flags&fMode != newf.flags&fMode {
continue
}
+ if oldf.xmlns != "" && newf.xmlns != "" && oldf.xmlns != newf.xmlns {
+ continue
+ }
minl := min(len(newf.parents), len(oldf.parents))
for p := 0; p < minl; p++ {
if oldf.parents[p] != newf.parents[p] {
diff --git a/src/pkg/encoding/xml/xml.go b/src/pkg/encoding/xml/xml.go
index 143fec554..021f7e47d 100644
--- a/src/pkg/encoding/xml/xml.go
+++ b/src/pkg/encoding/xml/xml.go
@@ -169,6 +169,11 @@ type Decoder struct {
// the CharsetReader's result values must be non-nil.
CharsetReader func(charset string, input io.Reader) (io.Reader, error)
+ // DefaultSpace sets the default name space used for unadorned tags,
+ // as if the entire XML stream were wrapped in an element containing
+ // the attribute xmlns="DefaultSpace".
+ DefaultSpace string
+
r io.ByteReader
buf bytes.Buffer
saved *bytes.Buffer
@@ -268,6 +273,8 @@ func (d *Decoder) Token() (t Token, err error) {
return
}
+const xmlURL = "http://www.w3.org/XML/1998/namespace"
+
// Apply name space translation to name n.
// The default name space (for Space=="")
// applies only to element names, not to attribute names.
@@ -277,11 +284,15 @@ func (d *Decoder) translate(n *Name, isElementName bool) {
return
case n.Space == "" && !isElementName:
return
+ case n.Space == "xml":
+ n.Space = xmlURL
case n.Space == "" && n.Local == "xmlns":
return
}
if v, ok := d.ns[n.Space]; ok {
n.Space = v
+ } else if n.Space == "" {
+ n.Space = d.DefaultSpace
}
}
@@ -956,7 +967,7 @@ Input:
b0, b1 = 0, 0
continue Input
}
- ent := string(d.buf.Bytes()[before])
+ ent := string(d.buf.Bytes()[before:])
if ent[len(ent)-1] != ';' {
ent += " (no semicolon)"
}
@@ -1718,6 +1729,7 @@ var (
esc_tab = []byte("&#x9;")
esc_nl = []byte("&#xA;")
esc_cr = []byte("&#xD;")
+ esc_fffd = []byte("\uFFFD") // Unicode replacement character
)
// EscapeText writes to w the properly escaped XML equivalent
@@ -1725,8 +1737,10 @@ var (
func EscapeText(w io.Writer, s []byte) error {
var esc []byte
last := 0
- for i, c := range s {
- switch c {
+ for i := 0; i < len(s); {
+ r, width := utf8.DecodeRune(s[i:])
+ i += width
+ switch r {
case '"':
esc = esc_quot
case '\'':
@@ -1744,15 +1758,19 @@ func EscapeText(w io.Writer, s []byte) error {
case '\r':
esc = esc_cr
default:
+ if !isInCharacterRange(r) {
+ esc = esc_fffd
+ break
+ }
continue
}
- if _, err := w.Write(s[last:i]); err != nil {
+ if _, err := w.Write(s[last : i-width]); err != nil {
return err
}
if _, err := w.Write(esc); err != nil {
return err
}
- last = i + 1
+ last = i
}
if _, err := w.Write(s[last:]); err != nil {
return err
diff --git a/src/pkg/encoding/xml/xml_test.go b/src/pkg/encoding/xml/xml_test.go
index 54dab5484..eeedbe575 100644
--- a/src/pkg/encoding/xml/xml_test.go
+++ b/src/pkg/encoding/xml/xml_test.go
@@ -5,6 +5,7 @@
package xml
import (
+ "bytes"
"fmt"
"io"
"reflect"
@@ -595,13 +596,6 @@ func TestEntityInsideCDATA(t *testing.T) {
}
}
-// The last three tests (respectively one for characters in attribute
-// names and two for character entities) pass not because of code
-// changed for issue 1259, but instead pass with the given messages
-// from other parts of xml.Decoder. I provide these to note the
-// current behavior of situations where one might think that character
-// range checking would detect the error, but it does not in fact.
-
var characterTests = []struct {
in string
err string
@@ -611,8 +605,10 @@ var characterTests = []struct {
{"\xef\xbf\xbe<doc/>", "illegal character code U+FFFE"},
{"<?xml version=\"1.0\"?><doc>\r\n<hiya/>\x07<toots/></doc>", "illegal character code U+0007"},
{"<?xml version=\"1.0\"?><doc \x12='value'>what's up</doc>", "expected attribute name in element"},
+ {"<doc>&abc\x01;</doc>", "invalid character entity &abc (no semicolon)"},
{"<doc>&\x01;</doc>", "invalid character entity & (no semicolon)"},
- {"<doc>&\xef\xbf\xbe;</doc>", "invalid character entity & (no semicolon)"},
+ {"<doc>&\xef\xbf\xbe;</doc>", "invalid character entity &\uFFFE;"},
+ {"<doc>&hello;</doc>", "invalid character entity &hello;"},
}
func TestDisallowedCharacters(t *testing.T) {
@@ -629,7 +625,7 @@ func TestDisallowedCharacters(t *testing.T) {
t.Fatalf("input %d d.Token() = _, %v, want _, *SyntaxError", i, err)
}
if synerr.Msg != tt.err {
- t.Fatalf("input %d synerr.Msg wrong: want '%s', got '%s'", i, tt.err, synerr.Msg)
+ t.Fatalf("input %d synerr.Msg wrong: want %q, got %q", i, tt.err, synerr.Msg)
}
}
}
@@ -700,6 +696,21 @@ func TestEscapeTextIOErrors(t *testing.T) {
err := EscapeText(errWriter{}, []byte{'A'})
if err == nil || err.Error() != expectErr {
- t.Errorf("EscapeTest = [error] %v, want %v", err, expectErr)
+ t.Errorf("have %v, want %v", err, expectErr)
+ }
+}
+
+func TestEscapeTextInvalidChar(t *testing.T) {
+ input := []byte("A \x00 terminated string.")
+ expected := "A \uFFFD terminated string."
+
+ buff := new(bytes.Buffer)
+ if err := EscapeText(buff, input); err != nil {
+ t.Fatalf("have %v, want nil", err)
+ }
+ text := buff.String()
+
+ if text != expected {
+ t.Errorf("have %v, want %v", text, expected)
}
}
diff --git a/src/pkg/exp/norm/Makefile b/src/pkg/exp/norm/Makefile
deleted file mode 100644
index f278eb02f..000000000
--- a/src/pkg/exp/norm/Makefile
+++ /dev/null
@@ -1,30 +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.
-
-maketables: maketables.go triegen.go
- go build $^
-
-maketesttables: maketesttables.go triegen.go
- go build $^
-
-normregtest: normregtest.go
- go build $^
-
-tables: maketables
- ./maketables > tables.go
- gofmt -w tables.go
-
-trietesttables: maketesttables
- ./maketesttables > triedata_test.go
- gofmt -w triedata_test.go
-
-# Downloads from www.unicode.org, so not part
-# of standard test scripts.
-test: testtables regtest
-
-testtables: maketables
- ./maketables -test -tables=
-
-regtest: normregtest
- ./normregtest
diff --git a/src/pkg/exp/norm/composition.go b/src/pkg/exp/norm/composition.go
deleted file mode 100644
index 2d52f99dc..000000000
--- a/src/pkg/exp/norm/composition.go
+++ /dev/null
@@ -1,382 +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 norm
-
-import "unicode/utf8"
-
-const (
- maxCombiningChars = 30
- maxBufferSize = maxCombiningChars + 2 // +1 to hold starter +1 to hold CGJ
- maxBackRunes = maxCombiningChars - 1
- maxNFCExpansion = 3 // NFC(0x1D160)
- maxNFKCExpansion = 18 // NFKC(0xFDFA)
-
- maxByteBufferSize = utf8.UTFMax * maxBufferSize // 128
-)
-
-// 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.
- nrune int // Number of runeInfos.
- nbyte uint8 // Number or bytes.
- f formInfo
-
- src input
- nsrc int
- tmpBytes input
-}
-
-func (rb *reorderBuffer) init(f Form, src []byte) {
- rb.f = *formTable[f]
- rb.src.setBytes(src)
- rb.nsrc = len(src)
-}
-
-func (rb *reorderBuffer) initString(f Form, src string) {
- rb.f = *formTable[f]
- rb.src.setString(src)
- rb.nsrc = len(src)
-}
-
-// reset discards all characters from the buffer.
-func (rb *reorderBuffer) reset() {
- rb.nrune = 0
- rb.nbyte = 0
-}
-
-// 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) bool {
- n := rb.nrune
- if n >= maxCombiningChars+1 {
- return false
- }
- 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
- return true
-}
-
-// insert inserts the given rune in the buffer ordered by CCC.
-// It returns true if the buffer was large enough to hold the decomposed rune.
-func (rb *reorderBuffer) insert(src input, i int, info Properties) bool {
- if rune := src.hangul(i); rune != 0 {
- return rb.decomposeHangul(rune)
- }
- if info.hasDecomposition() {
- return rb.insertDecomposed(info.Decomposition())
- }
- return 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.
-func (rb *reorderBuffer) insertDecomposed(dcomp []byte) bool {
- saveNrune, saveNbyte := rb.nrune, rb.nbyte
- rb.tmpBytes.setBytes(dcomp)
- for i := 0; i < len(dcomp); {
- info := rb.f.info(rb.tmpBytes, i)
- pos := rb.nbyte
- if !rb.insertOrdered(info) {
- rb.nrune, rb.nbyte = saveNrune, saveNbyte
- return false
- }
- i += copy(rb.byte[pos:], dcomp[i:i+int(info.size)])
- }
- return true
-}
-
-// 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) bool {
- // insertOrder changes nbyte
- pos := rb.nbyte
- if !rb.insertOrdered(info) {
- return false
- }
- src.copySlice(rb.byte[pos:], i, i+int(info.size))
- return true
-}
-
-// 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) bool {
- b := rb.rune[:]
- n := rb.nrune
- if n+3 > len(b) {
- return false
- }
- r -= hangulBase
- x := r % jamoTCount
- r /= jamoTCount
- rb.appendRune(jamoLBase + r/jamoVCount)
- rb.appendRune(jamoVBase + r%jamoVCount)
- if x != 0 {
- rb.appendRune(jamoTBase + x)
- }
- return true
-}
-
-// 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/src/pkg/exp/norm/composition_test.go b/src/pkg/exp/norm/composition_test.go
deleted file mode 100644
index 976aa21ed..000000000
--- a/src/pkg/exp/norm/composition_test.go
+++ /dev/null
@@ -1,143 +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 norm
-
-import "testing"
-
-// TestCase is used for most tests.
-type TestCase struct {
- in []rune
- out []rune
-}
-
-type insertFunc func(rb *reorderBuffer, r rune) bool
-
-func insert(rb *reorderBuffer, r rune) bool {
- src := inputString(string(r))
- return rb.insert(src, 0, rb.f.info(src, 0))
-}
-
-func runTests(t *testing.T, name string, fm Form, f insertFunc, tests []TestCase) {
- rb := reorderBuffer{}
- rb.init(fm, nil)
- for i, test := range tests {
- rb.reset()
- for j, rune := range test.in {
- b := []byte(string(rune))
- src := inputBytes(b)
- if !rb.insert(src, 0, rb.f.info(src, 0)) {
- t.Errorf("%s:%d: insert failed for rune %d", name, i, j)
- }
- }
- if rb.f.composing {
- rb.compose()
- }
- if rb.nrune != len(test.out) {
- t.Errorf("%s:%d: length = %d; want %d", name, i, rb.nrune, len(test.out))
- continue
- }
- for j, want := range test.out {
- found := rune(rb.runeAt(j))
- if found != want {
- t.Errorf("%s:%d: runeAt(%d) = %U; want %U", name, i, j, found, want)
- }
- }
- }
-}
-
-type flushFunc func(rb *reorderBuffer) []byte
-
-func testFlush(t *testing.T, name string, fn flushFunc) {
- rb := reorderBuffer{}
- rb.init(NFC, nil)
- out := fn(&rb)
- if len(out) != 0 {
- t.Errorf("%s: wrote bytes on flush of empty buffer. (len(out) = %d)", name, len(out))
- }
-
- for _, r := range []rune("world!") {
- insert(&rb, r)
- }
-
- out = []byte("Hello ")
- out = rb.flush(out)
- want := "Hello world!"
- if string(out) != want {
- t.Errorf(`%s: output after flush was "%s"; want "%s"`, name, string(out), want)
- }
- if rb.nrune != 0 {
- t.Errorf("%s: non-null size of info buffer (rb.nrune == %d)", name, rb.nrune)
- }
- if rb.nbyte != 0 {
- t.Errorf("%s: non-null size of byte buffer (rb.nbyte == %d)", name, rb.nbyte)
- }
-}
-
-func flushF(rb *reorderBuffer) []byte {
- out := make([]byte, 0)
- return rb.flush(out)
-}
-
-func flushCopyF(rb *reorderBuffer) []byte {
- out := make([]byte, maxByteBufferSize)
- n := rb.flushCopy(out)
- return out[:n]
-}
-
-func TestFlush(t *testing.T) {
- testFlush(t, "flush", flushF)
- testFlush(t, "flushCopy", flushCopyF)
-}
-
-var insertTests = []TestCase{
- {[]rune{'a'}, []rune{'a'}},
- {[]rune{0x300}, []rune{0x300}},
- {[]rune{0x300, 0x316}, []rune{0x316, 0x300}}, // CCC(0x300)==230; CCC(0x316)==220
- {[]rune{0x316, 0x300}, []rune{0x316, 0x300}},
- {[]rune{0x41, 0x316, 0x300}, []rune{0x41, 0x316, 0x300}},
- {[]rune{0x41, 0x300, 0x316}, []rune{0x41, 0x316, 0x300}},
- {[]rune{0x300, 0x316, 0x41}, []rune{0x316, 0x300, 0x41}},
- {[]rune{0x41, 0x300, 0x40, 0x316}, []rune{0x41, 0x300, 0x40, 0x316}},
-}
-
-func TestInsert(t *testing.T) {
- runTests(t, "TestInsert", NFD, insert, insertTests)
-}
-
-var decompositionNFDTest = []TestCase{
- {[]rune{0xC0}, []rune{0x41, 0x300}},
- {[]rune{0xAC00}, []rune{0x1100, 0x1161}},
- {[]rune{0x01C4}, []rune{0x01C4}},
- {[]rune{0x320E}, []rune{0x320E}},
- {[]rune("음ẻ과"), []rune{0x110B, 0x1173, 0x11B7, 0x65, 0x309, 0x1100, 0x116A}},
-}
-
-var decompositionNFKDTest = []TestCase{
- {[]rune{0xC0}, []rune{0x41, 0x300}},
- {[]rune{0xAC00}, []rune{0x1100, 0x1161}},
- {[]rune{0x01C4}, []rune{0x44, 0x5A, 0x030C}},
- {[]rune{0x320E}, []rune{0x28, 0x1100, 0x1161, 0x29}},
-}
-
-func TestDecomposition(t *testing.T) {
- runTests(t, "TestDecompositionNFD", NFD, insert, decompositionNFDTest)
- runTests(t, "TestDecompositionNFKD", NFKD, insert, decompositionNFKDTest)
-}
-
-var compositionTest = []TestCase{
- {[]rune{0x41, 0x300}, []rune{0xC0}},
- {[]rune{0x41, 0x316}, []rune{0x41, 0x316}},
- {[]rune{0x41, 0x300, 0x35D}, []rune{0xC0, 0x35D}},
- {[]rune{0x41, 0x316, 0x300}, []rune{0xC0, 0x316}},
- // blocking starter
- {[]rune{0x41, 0x316, 0x40, 0x300}, []rune{0x41, 0x316, 0x40, 0x300}},
- {[]rune{0x1100, 0x1161}, []rune{0xAC00}},
- // parenthesized Hangul, alternate between ASCII and Hangul.
- {[]rune{0x28, 0x1100, 0x1161, 0x29}, []rune{0x28, 0xAC00, 0x29}},
-}
-
-func TestComposition(t *testing.T) {
- runTests(t, "TestComposition", NFC, insert, compositionTest)
-}
diff --git a/src/pkg/exp/norm/example_iter_test.go b/src/pkg/exp/norm/example_iter_test.go
deleted file mode 100644
index edb9fcf55..000000000
--- a/src/pkg/exp/norm/example_iter_test.go
+++ /dev/null
@@ -1,81 +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 norm_test
-
-import (
- "bytes"
- "exp/norm"
- "fmt"
- "unicode/utf8"
-)
-
-// EqualSimple uses a norm.Iter to compare two non-normalized
-// strings for equivalence.
-func EqualSimple(a, b string) bool {
- var ia, ib norm.Iter
- ia.InitString(norm.NFKD, a)
- ib.InitString(norm.NFKD, b)
- for !ia.Done() && !ib.Done() {
- if !bytes.Equal(ia.Next(), ib.Next()) {
- return false
- }
- }
- return ia.Done() && ib.Done()
-}
-
-// FindPrefix finds the longest common prefix of ASCII characters
-// of a and b.
-func FindPrefix(a, b string) int {
- i := 0
- for ; i < len(a) && i < len(b) && a[i] < utf8.RuneSelf && a[i] == b[i]; i++ {
- }
- return i
-}
-
-// EqualOpt is like EqualSimple, but optimizes the special
-// case for ASCII characters.
-func EqualOpt(a, b string) bool {
- n := FindPrefix(a, b)
- a, b = a[n:], b[n:]
- var ia, ib norm.Iter
- ia.InitString(norm.NFKD, a)
- ib.InitString(norm.NFKD, b)
- for !ia.Done() && !ib.Done() {
- if !bytes.Equal(ia.Next(), ib.Next()) {
- return false
- }
- if n := int64(FindPrefix(a[ia.Pos():], b[ib.Pos():])); n != 0 {
- ia.Seek(n, 1)
- ib.Seek(n, 1)
- }
- }
- return ia.Done() && ib.Done()
-}
-
-var compareTests = []struct{ a, b string }{
- {"aaa", "aaa"},
- {"aaa", "aab"},
- {"a\u0300a", "\u00E0a"},
- {"a\u0300\u0320b", "a\u0320\u0300b"},
- {"\u1E0A\u0323", "\x44\u0323\u0307"},
- // A character that decomposes into multiple segments
- // spans several iterations.
- {"\u3304", "\u30A4\u30CB\u30F3\u30AF\u3099"},
-}
-
-func ExampleIter() {
- for i, t := range compareTests {
- r0 := EqualSimple(t.a, t.b)
- r1 := EqualOpt(t.a, t.b)
- fmt.Printf("%d: %v %v\n", i, r0, r1)
- }
- // Output:
- // 0: true true
- // 1: false false
- // 2: true true
- // 3: true true
- // 4: true true
- // 5: true true
-}
diff --git a/src/pkg/exp/norm/forminfo.go b/src/pkg/exp/norm/forminfo.go
deleted file mode 100644
index 7f7ee72e8..000000000
--- a/src/pkg/exp/norm/forminfo.go
+++ /dev/null
@@ -1,229 +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 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
-// 0..8: ccc
-// 9..12: qcInfo (see below). isYesD is always true (no decompostion).
-// 16: 1
-// 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 2 and 3 of qcIfo (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.
-
-const (
- qcInfoMask = 0xF // 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)
- 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 this rune cannot combine with runes to the right
-// and always denotes the end of a segment.
-func (p Properties) BoundaryAfter() bool {
- return p.isInert()
-}
-
-// We pack quick check data in 4 bits:
-// 0: NFD_QC Yes (0) or No (1). No also means there is a decomposition.
-// 1..2: NFC_QC Yes(00), No (10), or Maybe (11)
-// 3: Combines forward (0 == false, 1 == true)
-//
-// 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&0x4 == 0 }
-func (p Properties) isYesD() bool { return p.flags&0x1 == 0 }
-
-func (p Properties) combinesForward() bool { return p.flags&0x8 != 0 }
-func (p Properties) combinesBackward() bool { return p.flags&0x2 != 0 } // == isMaybe
-func (p Properties) hasDecomposition() bool { return p.flags&0x1 != 0 } // == isNoD
-
-func (p Properties) isInert() bool {
- return p.flags&0xf == 0 && p.ccc == 0
-}
-
-func (p Properties) multiSegment() bool {
- return p.index >= firstMulti && p.index < endMulti
-}
-
-// Decomposition returns the decomposition for the underlying rune
-// or nil if there is none.
-func (p Properties) Decomposition() []byte {
- 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 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 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 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(nfcTrie.lookup(s))
- }
- return compInfo(nfkcTrie.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(nfcTrie.lookupString(s))
- }
- return compInfo(nfkcTrie.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 {
- return Properties{
- size: uint8(sz),
- ccc: uint8(v),
- tccc: uint8(v),
- flags: qcInfo(v>>8) & qcInfoMask,
- }
- }
- // has decomposition
- h := decomps[v]
- f := (qcInfo(h&headerFlagsMask) >> 4) | 0x1
- ri := Properties{size: uint8(sz), flags: f, index: v}
- if v >= firstCCC {
- v += uint16(h&headerLenMask) + 1
- ri.tccc = decomps[v]
- if v >= firstLeadingCCC {
- ri.ccc = decomps[v+1]
- }
- }
- return ri
-}
diff --git a/src/pkg/exp/norm/input.go b/src/pkg/exp/norm/input.go
deleted file mode 100644
index d0177a14a..000000000
--- a/src/pkg/exp/norm/input.go
+++ /dev/null
@@ -1,105 +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 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) skipNonStarter(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 nfcTrie.lookupString(in.str[p:])
- }
- return nfcTrie.lookup(in.bytes[p:])
-}
-
-func (in *input) charinfoNFKC(p int) (uint16, int) {
- if in.bytes == nil {
- return nfkcTrie.lookupString(in.str[p:])
- }
- return nfkcTrie.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/src/pkg/exp/norm/iter.go b/src/pkg/exp/norm/iter.go
deleted file mode 100644
index a9546247c..000000000
--- a/src/pkg/exp/norm/iter.go
+++ /dev/null
@@ -1,401 +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 norm
-
-import (
- "fmt"
- "unicode/utf8"
-)
-
-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 {
- if r := i.rb.src.hangul(i.p); r != 0 {
- i.p += hangulUTF8Size
- if i.p >= i.rb.nsrc {
- i.setDone()
- }
- return i.buf[:decomposeHangul(i.buf[:], r)]
- }
- i.info = i.rb.f.info(i.rb.src, i.p)
- i.next = i.rb.f.nextMain
- return i.next(i)
-}
-
-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.ccc == 0 {
- 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
- // 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.ccc == 0 {
- i.multiSeg = d[j:]
- return d[:j]
- }
- j += int(info.size)
- }
- i.multiSeg = nil
- i.next = nextComposed
- i.p++ // restore old valud of i.p. See nextComposed.
- if i.p >= i.rb.nsrc {
- i.setDone()
- }
- return d
-}
-
-// nextDecomposed is the implementation of Next for forms NFD and NFKD.
-func nextDecomposed(i *Iter) (next []byte) {
- startp, outp := i.p, 0
- inCopyStart, outCopyStart := i.p, 0
- 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)
- }
- if i.info.BoundaryBefore() {
- 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 {
- i.next = nextHangul
- i.p += hangulUTF8Size
- if i.p >= i.rb.nsrc {
- i.setDone()
- }
- return i.buf[:decomposeHangul(i.buf[:], r)]
- } 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 i.info.BoundaryBefore() {
- break
- } else 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)
- if !i.rb.insertDecomposed(i.buf[0:outp]) {
- // Start over to prevent decompositions from crossing segment boundaries.
- // This is a rare occurrence.
- i.p = startp
- i.info = i.rb.f.info(i.rb.src, i.p)
- }
- for {
- if !i.rb.insert(i.rb.src, i.p, i.info) {
- break
- }
- 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[:])]
-}
-
-// nextComposed is the implementation of Next for forms NFC and NFKC.
-func nextComposed(i *Iter) []byte {
- outp, startp := 0, i.p
- var prevCC uint8
- for {
- if !i.info.isYesC() {
- goto doNorm
- }
- if cc := i.info.ccc; cc == 0 && outp > 0 {
- break
- } else if cc < prevCC {
- 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)
- }
- return i.returnSlice(startp, i.p)
-doNorm:
- multi := false
- i.p = startp
- i.info = i.rb.f.info(i.rb.src, i.p)
- for {
- if !i.rb.insert(i.rb.src, i.p, i.info) {
- break
- }
- multi = multi || i.info.multiSegment()
- 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.BoundaryBefore() {
- break
- }
- }
- i.rb.compose()
- seg := i.buf[:i.rb.flushCopy(i.buf[:])]
- if multi {
- i.p-- // fake not being done yet
- i.multiSeg = seg
- i.next = nextMultiNorm
- return nextMultiNorm(i)
- }
- return seg
-}
diff --git a/src/pkg/exp/norm/iter_test.go b/src/pkg/exp/norm/iter_test.go
deleted file mode 100644
index 826119362..000000000
--- a/src/pkg/exp/norm/iter_test.go
+++ /dev/null
@@ -1,188 +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 norm
-
-import (
- "strings"
- "testing"
-)
-
-func doIterNorm(f Form, s string) []byte {
- acc := []byte{}
- i := Iter{}
- i.InitString(f, s)
- for !i.Done() {
- acc = append(acc, i.Next()...)
- }
- return acc
-}
-
-func runIterTests(t *testing.T, name string, f Form, tests []AppendTest, norm bool) {
- for i, test := range tests {
- in := test.left + test.right
- gold := test.out
- if norm {
- gold = string(f.AppendString(nil, test.out))
- }
- out := string(doIterNorm(f, in))
- if len(out) != len(gold) {
- const msg = "%s:%d: length is %d; want %d"
- t.Errorf(msg, name, i, len(out), len(gold))
- }
- if out != gold {
- // Find first rune that differs and show context.
- ir := []rune(out)
- ig := []rune(gold)
- t.Errorf("\n%X != \n%X", ir, ig)
- for j := 0; j < len(ir) && j < len(ig); j++ {
- if ir[j] == ig[j] {
- continue
- }
- if j -= 3; j < 0 {
- j = 0
- }
- for e := j + 7; j < e && j < len(ir) && j < len(ig); j++ {
- const msg = "%s:%d: runeAt(%d) = %U; want %U"
- t.Errorf(msg, name, i, j, ir[j], ig[j])
- }
- break
- }
- }
- }
-}
-
-func rep(r rune, n int) string {
- return strings.Repeat(string(r), n)
-}
-
-const segSize = maxByteBufferSize
-
-var iterTests = []AppendTest{
- {"", ascii, ascii},
- {"", txt_all, txt_all},
- {"", "a" + rep(0x0300, segSize/2), "a" + rep(0x0300, segSize/2)},
-}
-
-var iterTestsD = []AppendTest{
- { // segment overflow on unchanged character
- "",
- "a" + rep(0x0300, segSize/2) + "\u0316",
- "a" + rep(0x0300, segSize/2-1) + "\u0316\u0300",
- },
- { // segment overflow on unchanged character + start value
- "",
- "a" + rep(0x0300, segSize/2+maxCombiningChars+4) + "\u0316",
- "a" + rep(0x0300, segSize/2+maxCombiningChars) + "\u0316" + rep(0x300, 4),
- },
- { // segment overflow on decomposition
- "",
- "a" + rep(0x0300, segSize/2-1) + "\u0340",
- "a" + rep(0x0300, segSize/2),
- },
- { // segment overflow on decomposition + start value
- "",
- "a" + rep(0x0300, segSize/2-1) + "\u0340" + rep(0x300, maxCombiningChars+4) + "\u0320",
- "a" + rep(0x0300, segSize/2-1) + rep(0x300, maxCombiningChars+1) + "\u0320" + rep(0x300, 4),
- },
- { // start value after ASCII overflow
- "",
- rep('a', segSize) + rep(0x300, maxCombiningChars+2) + "\u0320",
- rep('a', segSize) + rep(0x300, maxCombiningChars) + "\u0320\u0300\u0300",
- },
- { // start value after Hangul overflow
- "",
- rep(0xAC00, segSize/6) + rep(0x300, maxCombiningChars+2) + "\u0320",
- strings.Repeat("\u1100\u1161", segSize/6) + rep(0x300, maxCombiningChars+1) + "\u0320" + rep(0x300, 1),
- },
- { // start value after cc=0
- "",
- "您您" + rep(0x300, maxCombiningChars+4) + "\u0320",
- "您您" + rep(0x300, maxCombiningChars) + "\u0320" + rep(0x300, 4),
- },
- { // start value after normalization
- "",
- "\u0300\u0320a" + rep(0x300, maxCombiningChars+4) + "\u0320",
- "\u0320\u0300a" + rep(0x300, maxCombiningChars) + "\u0320" + rep(0x300, 4),
- },
-}
-
-var iterTestsC = []AppendTest{
- { // ordering of non-composing combining characters
- "",
- "\u0305\u0316",
- "\u0316\u0305",
- },
- { // segment overflow
- "",
- "a" + rep(0x0305, segSize/2+4) + "\u0316",
- "a" + rep(0x0305, segSize/2-1) + "\u0316" + rep(0x305, 5),
- },
-}
-
-func TestIterNextD(t *testing.T) {
- runIterTests(t, "IterNextD1", NFKD, appendTests, true)
- runIterTests(t, "IterNextD2", NFKD, iterTests, true)
- runIterTests(t, "IterNextD3", NFKD, iterTestsD, false)
-}
-
-func TestIterNextC(t *testing.T) {
- runIterTests(t, "IterNextC1", NFKC, appendTests, true)
- runIterTests(t, "IterNextC2", NFKC, iterTests, true)
- runIterTests(t, "IterNextC3", NFKC, iterTestsC, false)
-}
-
-type SegmentTest struct {
- in string
- out []string
-}
-
-var segmentTests = []SegmentTest{
- {"\u1E0A\u0323a", []string{"\x44\u0323\u0307", "a", ""}},
- {rep('a', segSize), append(strings.Split(rep('a', segSize), ""), "")},
- {rep('a', segSize+2), append(strings.Split(rep('a', segSize+2), ""), "")},
- {rep('a', segSize) + "\u0300aa",
- append(strings.Split(rep('a', segSize-1), ""), "a\u0300", "a", "a", "")},
-}
-
-var segmentTestsK = []SegmentTest{
- {"\u3332", []string{"\u30D5", "\u30A1", "\u30E9", "\u30C3", "\u30C8\u3099", ""}},
- // last segment of multi-segment decomposition needs normalization
- {"\u3332\u093C", []string{"\u30D5", "\u30A1", "\u30E9", "\u30C3", "\u30C8\u093C\u3099", ""}},
- // Hangul and Jamo are grouped togeter.
- {"\uAC00", []string{"\u1100\u1161", ""}},
- {"\uAC01", []string{"\u1100\u1161\u11A8", ""}},
- {"\u1100\u1161", []string{"\u1100\u1161", ""}},
-}
-
-// Note that, by design, segmentation is equal for composing and decomposing forms.
-func TestIterSegmentation(t *testing.T) {
- segmentTest(t, "SegmentTestD", NFD, segmentTests)
- segmentTest(t, "SegmentTestC", NFC, segmentTests)
- segmentTest(t, "SegmentTestD", NFKD, segmentTestsK)
- segmentTest(t, "SegmentTestC", NFKC, segmentTestsK)
-}
-
-func segmentTest(t *testing.T, name string, f Form, tests []SegmentTest) {
- iter := Iter{}
- for i, tt := range tests {
- iter.InitString(f, tt.in)
- for j, seg := range tt.out {
- if seg == "" {
- if !iter.Done() {
- res := string(iter.Next())
- t.Errorf(`%s:%d:%d: expected Done()==true, found segment "%s"`, name, i, j, res)
- }
- continue
- }
- if iter.Done() {
- t.Errorf("%s:%d:%d: Done()==true, want false", name, i, j)
- }
- seg = f.String(seg)
- if res := string(iter.Next()); res != seg {
- t.Errorf(`%s:%d:%d" segment was "%s" (%d); want "%s" (%d) %X %X`, name, i, j, res, len(res), seg, len(seg), []rune(res), []rune(seg))
- }
- }
- }
-}
diff --git a/src/pkg/exp/norm/maketables.go b/src/pkg/exp/norm/maketables.go
deleted file mode 100644
index 50c0c310a..000000000
--- a/src/pkg/exp/norm/maketables.go
+++ /dev/null
@@ -1,923 +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 ignore
-
-// Normalization table generator.
-// Data read from the web.
-// See forminfo.go for a description of the trie values associated with each rune.
-
-package main
-
-import (
- "bufio"
- "bytes"
- "flag"
- "fmt"
- "io"
- "log"
- "net/http"
- "os"
- "regexp"
- "sort"
- "strconv"
- "strings"
- "unicode"
-)
-
-func main() {
- flag.Parse()
- loadUnicodeData()
- loadCompositionExclusions()
- completeCharFields(FCanonical)
- completeCharFields(FCompatibility)
- verifyComputed()
- printChars()
- makeTables()
- testDerived()
-}
-
-var url = flag.String("url",
- "http://www.unicode.org/Public/"+unicode.Version+"/ucd/",
- "URL of Unicode database directory")
-var tablelist = flag.String("tables",
- "all",
- "comma-separated list of which tables to generate; "+
- "can be 'decomp', 'recomp', 'info' and 'all'")
-var test = flag.Bool("test",
- false,
- "test existing tables; can be used to compare web data with package data")
-var verbose = flag.Bool("verbose",
- false,
- "write data to stdout as it is parsed")
-var localFiles = flag.Bool("local",
- false,
- "data files have been copied to the current directory; for debugging only")
-
-var logger = log.New(os.Stderr, "", log.Lshortfile)
-
-// UnicodeData.txt has form:
-// 0037;DIGIT SEVEN;Nd;0;EN;;7;7;7;N;;;;;
-// 007A;LATIN SMALL LETTER Z;Ll;0;L;;;;;N;;;005A;;005A
-// See http://unicode.org/reports/tr44/ for full explanation
-// The fields:
-const (
- FCodePoint = iota
- FName
- FGeneralCategory
- FCanonicalCombiningClass
- FBidiClass
- FDecompMapping
- FDecimalValue
- FDigitValue
- FNumericValue
- FBidiMirrored
- FUnicode1Name
- FISOComment
- FSimpleUppercaseMapping
- FSimpleLowercaseMapping
- FSimpleTitlecaseMapping
- NumField
-
- MaxChar = 0x10FFFF // anything above this shouldn't exist
-)
-
-// Quick Check properties of runes allow us to quickly
-// determine whether a rune may occur in a normal form.
-// For a given normal form, a rune may be guaranteed to occur
-// verbatim (QC=Yes), may or may not combine with another
-// rune (QC=Maybe), or may not occur (QC=No).
-type QCResult int
-
-const (
- QCUnknown QCResult = iota
- QCYes
- QCNo
- QCMaybe
-)
-
-func (r QCResult) String() string {
- switch r {
- case QCYes:
- return "Yes"
- case QCNo:
- return "No"
- case QCMaybe:
- return "Maybe"
- }
- return "***UNKNOWN***"
-}
-
-const (
- FCanonical = iota // NFC or NFD
- FCompatibility // NFKC or NFKD
- FNumberOfFormTypes
-)
-
-const (
- MComposed = iota // NFC or NFKC
- MDecomposed // NFD or NFKD
- MNumberOfModes
-)
-
-// This contains only the properties we're interested in.
-type Char struct {
- name string
- codePoint rune // if zero, this index is not a valid code point.
- ccc uint8 // canonical combining class
- excludeInComp bool // from CompositionExclusions.txt
- compatDecomp bool // it has a compatibility expansion
-
- forms [FNumberOfFormTypes]FormInfo // For FCanonical and FCompatibility
-
- state State
-}
-
-var chars = make([]Char, MaxChar+1)
-
-func (c Char) String() string {
- buf := new(bytes.Buffer)
-
- fmt.Fprintf(buf, "%U [%s]:\n", c.codePoint, c.name)
- fmt.Fprintf(buf, " ccc: %v\n", c.ccc)
- fmt.Fprintf(buf, " excludeInComp: %v\n", c.excludeInComp)
- fmt.Fprintf(buf, " compatDecomp: %v\n", c.compatDecomp)
- fmt.Fprintf(buf, " state: %v\n", c.state)
- fmt.Fprintf(buf, " NFC:\n")
- fmt.Fprint(buf, c.forms[FCanonical])
- fmt.Fprintf(buf, " NFKC:\n")
- fmt.Fprint(buf, c.forms[FCompatibility])
-
- return buf.String()
-}
-
-// In UnicodeData.txt, some ranges are marked like this:
-// 3400;<CJK Ideograph Extension A, First>;Lo;0;L;;;;;N;;;;;
-// 4DB5;<CJK Ideograph Extension A, Last>;Lo;0;L;;;;;N;;;;;
-// parseCharacter keeps a state variable indicating the weirdness.
-type State int
-
-const (
- SNormal State = iota // known to be zero for the type
- SFirst
- SLast
- SMissing
-)
-
-var lastChar = rune('\u0000')
-
-func (c Char) isValid() bool {
- return c.codePoint != 0 && c.state != SMissing
-}
-
-type FormInfo struct {
- quickCheck [MNumberOfModes]QCResult // index: MComposed or MDecomposed
- verified [MNumberOfModes]bool // index: MComposed or MDecomposed
-
- combinesForward bool // May combine with rune on the right
- combinesBackward bool // May combine with rune on the left
- isOneWay bool // Never appears in result
- inDecomp bool // Some decompositions result in this char.
- decomp Decomposition
- expandedDecomp Decomposition
-}
-
-func (f FormInfo) String() string {
- buf := bytes.NewBuffer(make([]byte, 0))
-
- fmt.Fprintf(buf, " quickCheck[C]: %v\n", f.quickCheck[MComposed])
- fmt.Fprintf(buf, " quickCheck[D]: %v\n", f.quickCheck[MDecomposed])
- fmt.Fprintf(buf, " cmbForward: %v\n", f.combinesForward)
- fmt.Fprintf(buf, " cmbBackward: %v\n", f.combinesBackward)
- fmt.Fprintf(buf, " isOneWay: %v\n", f.isOneWay)
- fmt.Fprintf(buf, " inDecomp: %v\n", f.inDecomp)
- fmt.Fprintf(buf, " decomposition: %X\n", f.decomp)
- fmt.Fprintf(buf, " expandedDecomp: %X\n", f.expandedDecomp)
-
- return buf.String()
-}
-
-type Decomposition []rune
-
-func openReader(file string) (input io.ReadCloser) {
- if *localFiles {
- f, err := os.Open(file)
- if err != nil {
- logger.Fatal(err)
- }
- input = f
- } else {
- path := *url + file
- resp, err := http.Get(path)
- if err != nil {
- logger.Fatal(err)
- }
- if resp.StatusCode != 200 {
- logger.Fatal("bad GET status for "+file, resp.Status)
- }
- input = resp.Body
- }
- return
-}
-
-func parseDecomposition(s string, skipfirst bool) (a []rune, e error) {
- decomp := strings.Split(s, " ")
- if len(decomp) > 0 && skipfirst {
- decomp = decomp[1:]
- }
- for _, d := range decomp {
- point, err := strconv.ParseUint(d, 16, 64)
- if err != nil {
- return a, err
- }
- a = append(a, rune(point))
- }
- return a, nil
-}
-
-func parseCharacter(line string) {
- field := strings.Split(line, ";")
- if len(field) != NumField {
- logger.Fatalf("%5s: %d fields (expected %d)\n", line, len(field), NumField)
- }
- x, err := strconv.ParseUint(field[FCodePoint], 16, 64)
- point := int(x)
- if err != nil {
- logger.Fatalf("%.5s...: %s", line, err)
- }
- if point == 0 {
- return // not interesting and we use 0 as unset
- }
- if point > MaxChar {
- logger.Fatalf("%5s: Rune %X > MaxChar (%X)", line, point, MaxChar)
- return
- }
- state := SNormal
- switch {
- case strings.Index(field[FName], ", First>") > 0:
- state = SFirst
- case strings.Index(field[FName], ", Last>") > 0:
- state = SLast
- }
- firstChar := lastChar + 1
- lastChar = rune(point)
- if state != SLast {
- firstChar = lastChar
- }
- x, err = strconv.ParseUint(field[FCanonicalCombiningClass], 10, 64)
- if err != nil {
- logger.Fatalf("%U: bad ccc field: %s", int(x), err)
- }
- ccc := uint8(x)
- decmap := field[FDecompMapping]
- exp, e := parseDecomposition(decmap, false)
- isCompat := false
- if e != nil {
- if len(decmap) > 0 {
- exp, e = parseDecomposition(decmap, true)
- if e != nil {
- logger.Fatalf(`%U: bad decomp |%v|: "%s"`, int(x), decmap, e)
- }
- isCompat = true
- }
- }
- for i := firstChar; i <= lastChar; i++ {
- char := &chars[i]
- char.name = field[FName]
- char.codePoint = i
- char.forms[FCompatibility].decomp = exp
- if !isCompat {
- char.forms[FCanonical].decomp = exp
- } else {
- char.compatDecomp = true
- }
- if len(decmap) > 0 {
- char.forms[FCompatibility].decomp = exp
- }
- char.ccc = ccc
- char.state = SMissing
- if i == lastChar {
- char.state = state
- }
- }
- return
-}
-
-func loadUnicodeData() {
- f := openReader("UnicodeData.txt")
- defer f.Close()
- scanner := bufio.NewScanner(f)
- for scanner.Scan() {
- parseCharacter(scanner.Text())
- }
- if scanner.Err() != nil {
- logger.Fatal(scanner.Err())
- }
-}
-
-var singlePointRe = regexp.MustCompile(`^([0-9A-F]+) *$`)
-
-// CompositionExclusions.txt has form:
-// 0958 # ...
-// See http://unicode.org/reports/tr44/ for full explanation
-func parseExclusion(line string) int {
- comment := strings.Index(line, "#")
- if comment >= 0 {
- line = line[0:comment]
- }
- if len(line) == 0 {
- return 0
- }
- matches := singlePointRe.FindStringSubmatch(line)
- if len(matches) != 2 {
- logger.Fatalf("%s: %d matches (expected 1)\n", line, len(matches))
- }
- point, err := strconv.ParseUint(matches[1], 16, 64)
- if err != nil {
- logger.Fatalf("%.5s...: %s", line, err)
- }
- return int(point)
-}
-
-func loadCompositionExclusions() {
- f := openReader("CompositionExclusions.txt")
- defer f.Close()
- scanner := bufio.NewScanner(f)
- for scanner.Scan() {
- point := parseExclusion(scanner.Text())
- if point == 0 {
- continue
- }
- c := &chars[point]
- if c.excludeInComp {
- logger.Fatalf("%U: Duplicate entry in exclusions.", c.codePoint)
- }
- c.excludeInComp = true
- }
- if scanner.Err() != nil {
- log.Fatal(scanner.Err())
- }
-}
-
-// hasCompatDecomp returns true if any of the recursive
-// decompositions contains a compatibility expansion.
-// In this case, the character may not occur in NFK*.
-func hasCompatDecomp(r rune) bool {
- c := &chars[r]
- if c.compatDecomp {
- return true
- }
- for _, d := range c.forms[FCompatibility].decomp {
- if hasCompatDecomp(d) {
- return true
- }
- }
- return false
-}
-
-// Hangul related constants.
-const (
- HangulBase = 0xAC00
- HangulEnd = 0xD7A4 // hangulBase + Jamo combinations (19 * 21 * 28)
-
- JamoLBase = 0x1100
- JamoLEnd = 0x1113
- JamoVBase = 0x1161
- JamoVEnd = 0x1176
- JamoTBase = 0x11A8
- JamoTEnd = 0x11C3
-)
-
-func isHangul(r rune) bool {
- return HangulBase <= r && r < HangulEnd
-}
-
-func ccc(r rune) uint8 {
- return chars[r].ccc
-}
-
-// Insert a rune in a buffer, ordered by Canonical Combining Class.
-func insertOrdered(b Decomposition, r rune) Decomposition {
- n := len(b)
- b = append(b, 0)
- cc := ccc(r)
- if cc > 0 {
- // Use bubble sort.
- for ; n > 0; n-- {
- if ccc(b[n-1]) <= cc {
- break
- }
- b[n] = b[n-1]
- }
- }
- b[n] = r
- return b
-}
-
-// Recursively decompose.
-func decomposeRecursive(form int, r rune, d Decomposition) Decomposition {
- if isHangul(r) {
- return d
- }
- dcomp := chars[r].forms[form].decomp
- if len(dcomp) == 0 {
- return insertOrdered(d, r)
- }
- for _, c := range dcomp {
- d = decomposeRecursive(form, c, d)
- }
- return d
-}
-
-func completeCharFields(form int) {
- // Phase 0: pre-expand decomposition.
- for i := range chars {
- f := &chars[i].forms[form]
- if len(f.decomp) == 0 {
- continue
- }
- exp := make(Decomposition, 0)
- for _, c := range f.decomp {
- exp = decomposeRecursive(form, c, exp)
- }
- f.expandedDecomp = exp
- }
-
- // Phase 1: composition exclusion, mark decomposition.
- for i := range chars {
- c := &chars[i]
- f := &c.forms[form]
-
- // Marks script-specific exclusions and version restricted.
- f.isOneWay = c.excludeInComp
-
- // Singletons
- f.isOneWay = f.isOneWay || len(f.decomp) == 1
-
- // Non-starter decompositions
- if len(f.decomp) > 1 {
- chk := c.ccc != 0 || chars[f.decomp[0]].ccc != 0
- f.isOneWay = f.isOneWay || chk
- }
-
- // Runes that decompose into more than two runes.
- f.isOneWay = f.isOneWay || len(f.decomp) > 2
-
- if form == FCompatibility {
- f.isOneWay = f.isOneWay || hasCompatDecomp(c.codePoint)
- }
-
- for _, r := range f.decomp {
- chars[r].forms[form].inDecomp = true
- }
- }
-
- // Phase 2: forward and backward combining.
- for i := range chars {
- c := &chars[i]
- f := &c.forms[form]
-
- if !f.isOneWay && len(f.decomp) == 2 {
- f0 := &chars[f.decomp[0]].forms[form]
- f1 := &chars[f.decomp[1]].forms[form]
- if !f0.isOneWay {
- f0.combinesForward = true
- }
- if !f1.isOneWay {
- f1.combinesBackward = true
- }
- }
- }
-
- // Phase 3: quick check values.
- for i := range chars {
- c := &chars[i]
- f := &c.forms[form]
-
- switch {
- case len(f.decomp) > 0:
- f.quickCheck[MDecomposed] = QCNo
- case isHangul(rune(i)):
- f.quickCheck[MDecomposed] = QCNo
- default:
- f.quickCheck[MDecomposed] = QCYes
- }
- switch {
- case f.isOneWay:
- f.quickCheck[MComposed] = QCNo
- case (i & 0xffff00) == JamoLBase:
- f.quickCheck[MComposed] = QCYes
- if JamoLBase <= i && i < JamoLEnd {
- f.combinesForward = true
- }
- if JamoVBase <= i && i < JamoVEnd {
- f.quickCheck[MComposed] = QCMaybe
- f.combinesBackward = true
- f.combinesForward = true
- }
- if JamoTBase <= i && i < JamoTEnd {
- f.quickCheck[MComposed] = QCMaybe
- f.combinesBackward = true
- }
- case !f.combinesBackward:
- f.quickCheck[MComposed] = QCYes
- default:
- f.quickCheck[MComposed] = QCMaybe
- }
- }
-}
-
-func printBytes(b []byte, name string) {
- fmt.Printf("// %s: %d bytes\n", name, len(b))
- fmt.Printf("var %s = [...]byte {", name)
- for i, c := range b {
- switch {
- case i%64 == 0:
- fmt.Printf("\n// Bytes %x - %x\n", i, i+63)
- case i%8 == 0:
- fmt.Printf("\n")
- }
- fmt.Printf("0x%.2X, ", c)
- }
- fmt.Print("\n}\n\n")
-}
-
-// See forminfo.go for format.
-func makeEntry(f *FormInfo) uint16 {
- e := uint16(0)
- if f.combinesForward {
- e |= 0x8
- }
- if f.quickCheck[MDecomposed] == QCNo {
- e |= 0x1
- }
- switch f.quickCheck[MComposed] {
- case QCYes:
- case QCNo:
- e |= 0x4
- case QCMaybe:
- e |= 0x6
- default:
- log.Fatalf("Illegal quickcheck value %v.", f.quickCheck[MComposed])
- }
- return e
-}
-
-// decompSet keeps track of unique decompositions, grouped by whether
-// the decomposition is followed by a trailing and/or leading CCC.
-type decompSet [6]map[string]bool
-
-const (
- normalDecomp = iota
- firstMulti
- firstCCC
- endMulti
- firstLeadingCCC
- firstCCCZeroExcept
- lastDecomp
-)
-
-var cname = []string{"firstMulti", "firstCCC", "endMulti", "firstLeadingCCC", "firstCCCZeroExcept", "lastDecomp"}
-
-func makeDecompSet() decompSet {
- m := decompSet{}
- for i := range m {
- m[i] = make(map[string]bool)
- }
- return m
-}
-func (m *decompSet) insert(key int, s string) {
- m[key][s] = true
-}
-
-func printCharInfoTables() int {
- mkstr := func(r rune, f *FormInfo) (int, string) {
- d := f.expandedDecomp
- s := string([]rune(d))
- if max := 1 << 6; len(s) >= max {
- const msg = "%U: too many bytes in decomposition: %d >= %d"
- logger.Fatalf(msg, r, len(s), max)
- }
- head := uint8(len(s))
- if f.quickCheck[MComposed] != QCYes {
- head |= 0x40
- }
- if f.combinesForward {
- head |= 0x80
- }
- s = string([]byte{head}) + s
-
- lccc := ccc(d[0])
- tccc := ccc(d[len(d)-1])
- cc := ccc(r)
- if cc != 0 && lccc == 0 && tccc == 0 {
- logger.Fatalf("%U: trailing and leading ccc are 0 for non-zero ccc %d", r, cc)
- }
- if tccc < lccc && lccc != 0 {
- const msg = "%U: lccc (%d) must be <= tcc (%d)"
- logger.Fatalf(msg, r, lccc, tccc)
- }
- index := normalDecomp
- if tccc > 0 || lccc > 0 {
- s += string([]byte{tccc})
- index = endMulti
- for _, r := range d[1:] {
- if ccc(r) == 0 {
- index = firstCCC
- }
- }
- if lccc > 0 {
- s += string([]byte{lccc})
- if index == firstCCC {
- logger.Fatalf("%U: multi-segment decomposition not supported for decompositions with leading CCC != 0", r)
- }
- index = firstLeadingCCC
- }
- if cc != lccc {
- if cc != 0 {
- logger.Fatalf("%U: for lccc != ccc, expected ccc to be 0; was %d", r, cc)
- }
- index = firstCCCZeroExcept
- }
- } else if len(d) > 1 {
- index = firstMulti
- }
- return index, s
- }
-
- decompSet := makeDecompSet()
-
- // Store the uniqued decompositions in a byte buffer,
- // preceded by their byte length.
- for _, c := range chars {
- for _, f := range c.forms {
- if len(f.expandedDecomp) == 0 {
- continue
- }
- if f.combinesBackward {
- logger.Fatalf("%U: combinesBackward and decompose", c.codePoint)
- }
- index, s := mkstr(c.codePoint, &f)
- decompSet.insert(index, s)
- }
- }
-
- decompositions := bytes.NewBuffer(make([]byte, 0, 10000))
- size := 0
- positionMap := make(map[string]uint16)
- decompositions.WriteString("\000")
- fmt.Println("const (")
- for i, m := range decompSet {
- sa := []string{}
- for s := range m {
- sa = append(sa, s)
- }
- sort.Strings(sa)
- for _, s := range sa {
- p := decompositions.Len()
- decompositions.WriteString(s)
- positionMap[s] = uint16(p)
- }
- if cname[i] != "" {
- fmt.Printf("%s = 0x%X\n", cname[i], decompositions.Len())
- }
- }
- fmt.Println("maxDecomp = 0x8000")
- fmt.Println(")")
- b := decompositions.Bytes()
- printBytes(b, "decomps")
- size += len(b)
-
- varnames := []string{"nfc", "nfkc"}
- for i := 0; i < FNumberOfFormTypes; i++ {
- trie := newNode()
- for r, c := range chars {
- f := c.forms[i]
- d := f.expandedDecomp
- if len(d) != 0 {
- _, key := mkstr(c.codePoint, &f)
- trie.insert(rune(r), positionMap[key])
- if c.ccc != ccc(d[0]) {
- // We assume the lead ccc of a decomposition !=0 in this case.
- if ccc(d[0]) == 0 {
- logger.Fatalf("Expected leading CCC to be non-zero; ccc is %d", c.ccc)
- }
- }
- } else if v := makeEntry(&f)<<8 | uint16(c.ccc); v != 0 {
- trie.insert(c.codePoint, 0x8000|v)
- }
- }
- size += trie.printTables(varnames[i])
- }
- return size
-}
-
-func contains(sa []string, s string) bool {
- for _, a := range sa {
- if a == s {
- return true
- }
- }
- return false
-}
-
-// Extract the version number from the URL.
-func version() string {
- // From http://www.unicode.org/standard/versions/#Version_Numbering:
- // for the later Unicode versions, data files are located in
- // versioned directories.
- fields := strings.Split(*url, "/")
- for _, f := range fields {
- if match, _ := regexp.MatchString(`[0-9]\.[0-9]\.[0-9]`, f); match {
- return f
- }
- }
- logger.Fatal("unknown version")
- return "Unknown"
-}
-
-const fileHeader = `// Generated by running
-// maketables --tables=%s --url=%s
-// DO NOT EDIT
-
-package norm
-
-`
-
-func makeTables() {
- size := 0
- if *tablelist == "" {
- return
- }
- list := strings.Split(*tablelist, ",")
- if *tablelist == "all" {
- list = []string{"recomp", "info"}
- }
- fmt.Printf(fileHeader, *tablelist, *url)
-
- fmt.Println("// Version is the Unicode edition from which the tables are derived.")
- fmt.Printf("const Version = %q\n\n", version())
-
- if contains(list, "info") {
- size += printCharInfoTables()
- }
-
- if contains(list, "recomp") {
- // Note that we use 32 bit keys, instead of 64 bit.
- // This clips the bits of three entries, but we know
- // this won't cause a collision. The compiler will catch
- // any changes made to UnicodeData.txt that introduces
- // a collision.
- // Note that the recomposition map for NFC and NFKC
- // are identical.
-
- // Recomposition map
- nrentries := 0
- for _, c := range chars {
- f := c.forms[FCanonical]
- if !f.isOneWay && len(f.decomp) > 0 {
- nrentries++
- }
- }
- sz := nrentries * 8
- size += sz
- fmt.Printf("// recompMap: %d bytes (entries only)\n", sz)
- fmt.Println("var recompMap = map[uint32]rune{")
- for i, c := range chars {
- f := c.forms[FCanonical]
- d := f.decomp
- if !f.isOneWay && len(d) > 0 {
- key := uint32(uint16(d[0]))<<16 + uint32(uint16(d[1]))
- fmt.Printf("0x%.8X: 0x%.4X,\n", key, i)
- }
- }
- fmt.Printf("}\n\n")
- }
-
- fmt.Printf("// Total size of tables: %dKB (%d bytes)\n", (size+512)/1024, size)
-}
-
-func printChars() {
- if *verbose {
- for _, c := range chars {
- if !c.isValid() || c.state == SMissing {
- continue
- }
- fmt.Println(c)
- }
- }
-}
-
-// verifyComputed does various consistency tests.
-func verifyComputed() {
- for i, c := range chars {
- for _, f := range c.forms {
- isNo := (f.quickCheck[MDecomposed] == QCNo)
- if (len(f.decomp) > 0) != isNo && !isHangul(rune(i)) {
- log.Fatalf("%U: NF*D must be no if rune decomposes", i)
- }
-
- isMaybe := f.quickCheck[MComposed] == QCMaybe
- if f.combinesBackward != isMaybe {
- log.Fatalf("%U: NF*C must be maybe if combinesBackward", i)
- }
- }
- nfc := c.forms[FCanonical]
- nfkc := c.forms[FCompatibility]
- if nfc.combinesBackward != nfkc.combinesBackward {
- logger.Fatalf("%U: Cannot combine combinesBackward\n", c.codePoint)
- }
- }
-}
-
-var qcRe = regexp.MustCompile(`([0-9A-F\.]+) *; (NF.*_QC); ([YNM]) #.*`)
-
-// Use values in DerivedNormalizationProps.txt to compare against the
-// values we computed.
-// DerivedNormalizationProps.txt has form:
-// 00C0..00C5 ; NFD_QC; N # ...
-// 0374 ; NFD_QC; N # ...
-// See http://unicode.org/reports/tr44/ for full explanation
-func testDerived() {
- if !*test {
- return
- }
- f := openReader("DerivedNormalizationProps.txt")
- defer f.Close()
- scanner := bufio.NewScanner(f)
- for scanner.Scan() {
- line := scanner.Text()
- qc := qcRe.FindStringSubmatch(line)
- if qc == nil {
- continue
- }
- rng := strings.Split(qc[1], "..")
- i, err := strconv.ParseUint(rng[0], 16, 64)
- if err != nil {
- log.Fatal(err)
- }
- j := i
- if len(rng) > 1 {
- j, err = strconv.ParseUint(rng[1], 16, 64)
- if err != nil {
- log.Fatal(err)
- }
- }
- var ftype, mode int
- qt := strings.TrimSpace(qc[2])
- switch qt {
- case "NFC_QC":
- ftype, mode = FCanonical, MComposed
- case "NFD_QC":
- ftype, mode = FCanonical, MDecomposed
- case "NFKC_QC":
- ftype, mode = FCompatibility, MComposed
- case "NFKD_QC":
- ftype, mode = FCompatibility, MDecomposed
- default:
- log.Fatalf(`Unexpected quick check type "%s"`, qt)
- }
- var qr QCResult
- switch qc[3] {
- case "Y":
- qr = QCYes
- case "N":
- qr = QCNo
- case "M":
- qr = QCMaybe
- default:
- log.Fatalf(`Unexpected quick check value "%s"`, qc[3])
- }
- var lastFailed bool
- // Verify current
- for ; i <= j; i++ {
- c := &chars[int(i)]
- c.forms[ftype].verified[mode] = true
- curqr := c.forms[ftype].quickCheck[mode]
- if curqr != qr {
- if !lastFailed {
- logger.Printf("%s: %.4X..%.4X -- %s\n",
- qt, int(i), int(j), line[0:50])
- }
- logger.Printf("%U: FAILED %s (was %v need %v)\n",
- int(i), qt, curqr, qr)
- lastFailed = true
- }
- }
- }
- if scanner.Err() != nil {
- logger.Fatal(scanner.Err())
- }
- // Any unspecified value must be QCYes. Verify this.
- for i, c := range chars {
- for j, fd := range c.forms {
- for k, qr := range fd.quickCheck {
- if !fd.verified[k] && qr != QCYes {
- m := "%U: FAIL F:%d M:%d (was %v need Yes) %s\n"
- logger.Printf(m, i, j, k, qr, c.name)
- }
- }
- }
- }
-}
diff --git a/src/pkg/exp/norm/maketesttables.go b/src/pkg/exp/norm/maketesttables.go
deleted file mode 100644
index 6d11ec069..000000000
--- a/src/pkg/exp/norm/maketesttables.go
+++ /dev/null
@@ -1,45 +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 ignore
-
-// Generate test data for trie code.
-
-package main
-
-import (
- "fmt"
-)
-
-func main() {
- printTestTables()
-}
-
-// We take the smallest, largest and an arbitrary value for each
-// of the UTF-8 sequence lengths.
-var testRunes = []rune{
- 0x01, 0x0C, 0x7F, // 1-byte sequences
- 0x80, 0x100, 0x7FF, // 2-byte sequences
- 0x800, 0x999, 0xFFFF, // 3-byte sequences
- 0x10000, 0x10101, 0x10FFFF, // 4-byte sequences
- 0x200, 0x201, 0x202, 0x210, 0x215, // five entries in one sparse block
-}
-
-const fileHeader = `// Generated by running
-// maketesttables
-// DO NOT EDIT
-
-package norm
-
-`
-
-func printTestTables() {
- fmt.Print(fileHeader)
- fmt.Printf("var testRunes = %#v\n\n", testRunes)
- t := newNode()
- for i, r := range testRunes {
- t.insert(r, uint16(i))
- }
- t.printTables("testdata")
-}
diff --git a/src/pkg/exp/norm/norm_test.go b/src/pkg/exp/norm/norm_test.go
deleted file mode 100644
index 12dacfcf3..000000000
--- a/src/pkg/exp/norm/norm_test.go
+++ /dev/null
@@ -1,14 +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 norm_test
-
-import (
- "testing"
-)
-
-func TestPlaceHolder(t *testing.T) {
- // Does nothing, just allows the Makefile to be canonical
- // while waiting for the package itself to be written.
-}
diff --git a/src/pkg/exp/norm/normalize.go b/src/pkg/exp/norm/normalize.go
deleted file mode 100644
index 1c3e49b77..000000000
--- a/src/pkg/exp/norm/normalize.go
+++ /dev/null
@@ -1,478 +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 norm contains types and functions for normalizing Unicode strings.
-package norm
-
-import "unicode/utf8"
-
-// 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 {
- rb := reorderBuffer{}
- rb.init(f, b)
- n := quickSpan(&rb, 0)
- if n == len(b) {
- return b
- }
- out := make([]byte, n, len(b))
- copy(out, b[0:n])
- return doAppend(&rb, out, n)
-}
-
-// String returns f(s).
-func (f Form) String(s string) string {
- rb := reorderBuffer{}
- rb.initString(f, s)
- n := quickSpan(&rb, 0)
- if n == len(s) {
- return s
- }
- out := make([]byte, n, len(s))
- copy(out, s[0:n])
- return string(doAppend(&rb, out, n))
-}
-
-// IsNormal returns true if b == f(b).
-func (f Form) IsNormal(b []byte) bool {
- rb := reorderBuffer{}
- rb.init(f, b)
- bp := quickSpan(&rb, 0)
- if bp == len(b) {
- return true
- }
- for bp < len(b) {
- decomposeSegment(&rb, bp)
- if rb.f.composing {
- rb.compose()
- }
- for i := 0; i < rb.nrune; i++ {
- info := rb.rune[i]
- if bp+int(info.size) > len(b) {
- return false
- }
- p := info.pos
- pe := p + info.size
- for ; p < pe; p++ {
- if b[bp] != rb.byte[p] {
- return false
- }
- bp++
- }
- }
- rb.reset()
- bp = quickSpan(&rb, bp)
- }
- return true
-}
-
-// IsNormalString returns true if s == f(s).
-func (f Form) IsNormalString(s string) bool {
- rb := reorderBuffer{}
- rb.initString(f, s)
- bp := quickSpan(&rb, 0)
- if bp == len(s) {
- return true
- }
- for bp < len(s) {
- decomposeSegment(&rb, bp)
- if rb.f.composing {
- rb.compose()
- }
- 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++
- }
- }
- rb.reset()
- bp = quickSpan(&rb, bp)
- }
- 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 there were trailing continuation bytes.
-func patchTail(rb *reorderBuffer, buf []byte) ([]byte, bool) {
- info, p := lastRuneStart(&rb.f, buf)
- if p == -1 || info.size == 0 {
- return buf, false
- }
- end := p + int(info.size)
- extra := len(buf) - end
- if extra > 0 {
- // Potentially allocating memory. However, this only
- // happens with ill-formed UTF-8.
- x := make([]byte, 0)
- x = append(x, buf[len(buf)-extra:]...)
- buf = decomposeToLastBoundary(rb, buf[:end])
- if rb.f.composing {
- rb.compose()
- }
- buf = rb.flush(buf)
- return append(buf, x...), true
- }
- return buf, false
-}
-
-func appendQuick(rb *reorderBuffer, dst []byte, i int) ([]byte, int) {
- if rb.nsrc == i {
- return dst, i
- }
- end := quickSpan(rb, i)
- return rb.src.appendSlice(dst, i, end), 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 {
- if len(src) == 0 {
- return out
- }
- rb := reorderBuffer{}
- rb.init(f, src)
- return doAppend(&rb, out, 0)
-}
-
-func doAppend(rb *reorderBuffer, out []byte, p int) []byte {
- src, n := rb.src, rb.nsrc
- doMerge := len(out) > 0
- if q := src.skipNonStarter(p); q > p {
- // Move leading non-starters to destination.
- out = src.appendSlice(out, p, q)
- buf, endsInError := patchTail(rb, out)
- if endsInError {
- out = buf
- doMerge = false // no need to merge, ends with illegal UTF-8
- } else {
- out = decomposeToLastBoundary(rb, buf) // force decomposition
- }
- p = q
- }
- fd := &rb.f
- if doMerge {
- var info Properties
- if p < n {
- info = fd.info(src, p)
- if p == 0 && !info.BoundaryBefore() {
- out = decomposeToLastBoundary(rb, out)
- }
- }
- if info.size == 0 || info.BoundaryBefore() {
- if fd.composing {
- rb.compose()
- }
- out = rb.flush(out)
- if info.size == 0 {
- // Append incomplete UTF-8 encoding.
- return src.appendSlice(out, p, n)
- }
- }
- }
- if rb.nrune == 0 {
- out, p = appendQuick(rb, out, p)
- }
- for p < n {
- p = decomposeSegment(rb, p)
- if fd.composing {
- rb.compose()
- }
- out = rb.flush(out)
- out, p = appendQuick(rb, out, p)
- }
- return 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 {
- if len(src) == 0 {
- return out
- }
- rb := reorderBuffer{}
- rb.initString(f, src)
- return doAppend(&rb, out, 0)
-}
-
-// 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 {
- rb := reorderBuffer{}
- rb.init(f, b)
- n := quickSpan(&rb, 0)
- return n
-}
-
-func quickSpan(rb *reorderBuffer, i int) int {
- var lastCC uint8
- var nc int
- lastSegStart := i
- src, n := rb.src, rb.nsrc
- for i < n {
- if j := src.skipASCII(i, n); i != j {
- i = j
- lastSegStart = i - 1
- lastCC = 0
- nc = 0
- continue
- }
- info := rb.f.info(src, i)
- if info.size == 0 {
- // include incomplete runes
- return n
- }
- cc := info.ccc
- if rb.f.composing {
- if !info.isYesC() {
- break
- }
- } else {
- if !info.isYesD() {
- break
- }
- }
- if cc == 0 {
- lastSegStart = i
- nc = 0
- } else {
- if nc >= maxCombiningChars {
- lastSegStart = i
- lastCC = cc
- nc = 1
- } else {
- if lastCC > cc {
- return lastSegStart
- }
- nc++
- }
- }
- lastCC = cc
- i += int(info.size)
- }
- if i == n {
- return n
- }
- if rb.f.composing {
- return lastSegStart
- }
- return i
-}
-
-// QuickSpanString returns a boundary n such that b[0:n] == f(s[0:n]).
-// It is not guaranteed to return the largest such n.
-func (f Form) QuickSpanString(s string) int {
- rb := reorderBuffer{}
- rb.initString(f, s)
- return quickSpan(&rb, 0)
-}
-
-// 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 {
- rb := reorderBuffer{}
- rb.init(f, b)
- return firstBoundary(&rb)
-}
-
-func firstBoundary(rb *reorderBuffer) int {
- src, nsrc := rb.src, rb.nsrc
- i := src.skipNonStarter(0)
- if i >= nsrc {
- return -1
- }
- fd := &rb.f
- info := fd.info(src, i)
- for n := 0; info.size != 0 && !info.BoundaryBefore(); {
- i += int(info.size)
- if n++; n >= maxCombiningChars {
- return i
- }
- if i >= nsrc {
- if !info.BoundaryAfter() {
- return -1
- }
- return nsrc
- }
- info = fd.info(src, i)
- }
- if info.size == 0 {
- return -1
- }
- return i
-}
-
-// 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 {
- rb := reorderBuffer{}
- rb.initString(f, s)
- return firstBoundary(&rb)
-}
-
-// 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
- }
- i = p
- for n := 0; i >= 0 && !info.BoundaryBefore(); {
- info, p = lastRuneStart(fd, b[:i])
- if n++; n >= maxCombiningChars {
- return len(b)
- }
- if p+int(info.size) != i {
- if p == -1 { // no boundary found
- return -1
- }
- return i // boundary after an illegal UTF-8 encoding
- }
- i = p
- }
- return i
-}
-
-// decomposeSegment scans the first segment in src into rb.
-// It returns the number of bytes consumed from src.
-// TODO(mpvl): consider inserting U+034f (Combining Grapheme Joiner)
-// when we detect a sequence of 30+ non-starter chars.
-func decomposeSegment(rb *reorderBuffer, sp int) int {
- // Force one character to be consumed.
- info := rb.f.info(rb.src, sp)
- if info.size == 0 {
- return 0
- }
- for rb.insert(rb.src, sp, info) {
- sp += int(info.size)
- if sp >= rb.nsrc {
- break
- }
- info = rb.f.info(rb.src, sp)
- bound := info.BoundaryBefore()
- if bound || info.size == 0 {
- break
- }
- }
- 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, buf []byte) []byte {
- fd := &rb.f
- info, i := lastRuneStart(fd, buf)
- if int(info.size) != len(buf)-i {
- // illegal trailing continuation bytes
- return buf
- }
- if info.BoundaryAfter() {
- return buf
- }
- var add [maxBackRunes]Properties // stores runeInfo in reverse order
- add[0] = info
- padd := 1
- n := 1
- p := len(buf) - int(info.size)
- for ; p >= 0 && !info.BoundaryBefore(); p -= int(info.size) {
- info, i = lastRuneStart(fd, buf[:p])
- if int(info.size) != p-i {
- break
- }
- // Check that decomposition doesn't result in overflow.
- if info.hasDecomposition() {
- if isHangul(buf) {
- i += int(info.size)
- n++
- } else {
- dcomp := info.Decomposition()
- for i := 0; i < len(dcomp); {
- inf := rb.f.info(inputBytes(dcomp), i)
- i += int(inf.size)
- n++
- }
- }
- } else {
- n++
- }
- if n > maxBackRunes {
- break
- }
- add[padd] = info
- padd++
- }
- pp := p
- for padd--; padd >= 0; padd-- {
- info = add[padd]
- rb.insert(inputBytes(buf), pp, info)
- pp += int(info.size)
- }
- return buf[:p]
-}
diff --git a/src/pkg/exp/norm/normalize_test.go b/src/pkg/exp/norm/normalize_test.go
deleted file mode 100644
index 9a6b46e41..000000000
--- a/src/pkg/exp/norm/normalize_test.go
+++ /dev/null
@@ -1,750 +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 norm
-
-import (
- "bytes"
- "io"
- "strings"
- "testing"
-)
-
-type PositionTest struct {
- input string
- pos int
- buffer string // expected contents of reorderBuffer, if applicable
-}
-
-type positionFunc func(rb *reorderBuffer, s string) int
-
-func runPosTests(t *testing.T, name string, f Form, fn positionFunc, tests []PositionTest) {
- rb := reorderBuffer{}
- rb.init(f, nil)
- for i, test := range tests {
- rb.reset()
- rb.src = inputString(test.input)
- rb.nsrc = len(test.input)
- pos := fn(&rb, test.input)
- if pos != test.pos {
- t.Errorf("%s:%d: position is %d; want %d", name, i, pos, test.pos)
- }
- runes := []rune(test.buffer)
- if rb.nrune != len(runes) {
- t.Errorf("%s:%d: reorder buffer length is %d; want %d", name, i, rb.nrune, len(runes))
- continue
- }
- for j, want := range runes {
- found := rune(rb.runeAt(j))
- if found != want {
- t.Errorf("%s:%d: rune at %d is %U; want %U", name, i, j, found, want)
- }
- }
- }
-}
-
-var decomposeSegmentTests = []PositionTest{
- // illegal runes
- {"\xC0", 0, ""},
- {"\u00E0\x80", 2, "\u0061\u0300"},
- // starter
- {"a", 1, "a"},
- {"ab", 1, "a"},
- // starter + composing
- {"a\u0300", 3, "a\u0300"},
- {"a\u0300b", 3, "a\u0300"},
- // with decomposition
- {"\u00C0", 2, "A\u0300"},
- {"\u00C0b", 2, "A\u0300"},
- // long
- {strings.Repeat("\u0300", 31), 62, strings.Repeat("\u0300", 31)},
- // ends with incomplete UTF-8 encoding
- {"\xCC", 0, ""},
- {"\u0300\xCC", 2, "\u0300"},
-}
-
-func decomposeSegmentF(rb *reorderBuffer, s string) int {
- rb.src = inputString(s)
- rb.nsrc = len(s)
- return decomposeSegment(rb, 0)
-}
-
-func TestDecomposeSegment(t *testing.T) {
- runPosTests(t, "TestDecomposeSegment", NFC, decomposeSegmentF, decomposeSegmentTests)
-}
-
-var firstBoundaryTests = []PositionTest{
- // no boundary
- {"", -1, ""},
- {"\u0300", -1, ""},
- {"\x80\x80", -1, ""},
- // illegal runes
- {"\xff", 0, ""},
- {"\u0300\xff", 2, ""},
- {"\u0300\xc0\x80\x80", 2, ""},
- // boundaries
- {"a", 0, ""},
- {"\u0300a", 2, ""},
- // Hangul
- {"\u1103\u1161", 0, ""},
- {"\u110B\u1173\u11B7", 0, ""},
- {"\u1161\u110B\u1173\u11B7", 3, ""},
- {"\u1173\u11B7\u1103\u1161", 6, ""},
- // too many combining characters.
- {strings.Repeat("\u0300", maxCombiningChars-1), -1, ""},
- {strings.Repeat("\u0300", maxCombiningChars), 60, ""},
- {strings.Repeat("\u0300", maxCombiningChars+1), 60, ""},
-}
-
-func firstBoundaryF(rb *reorderBuffer, s string) int {
- return rb.f.form.FirstBoundary([]byte(s))
-}
-
-func firstBoundaryStringF(rb *reorderBuffer, s string) int {
- return rb.f.form.FirstBoundaryInString(s)
-}
-
-func TestFirstBoundary(t *testing.T) {
- runPosTests(t, "TestFirstBoundary", NFC, firstBoundaryF, firstBoundaryTests)
- runPosTests(t, "TestFirstBoundaryInString", NFC, firstBoundaryStringF, firstBoundaryTests)
-}
-
-var decomposeToLastTests = []PositionTest{
- // ends with inert character
- {"Hello!", 6, ""},
- {"\u0632", 2, ""},
- {"a\u0301\u0635", 5, ""},
- // ends with non-inert starter
- {"a", 0, "a"},
- {"a\u0301a", 3, "a"},
- {"a\u0301\u03B9", 3, "\u03B9"},
- {"a\u0327", 0, "a\u0327"},
- // illegal runes
- {"\xFF", 1, ""},
- {"aa\xFF", 3, ""},
- {"\xC0\x80\x80", 3, ""},
- {"\xCC\x80\x80", 3, ""},
- // ends with incomplete UTF-8 encoding
- {"a\xCC", 2, ""},
- // ends with combining characters
- {"\u0300\u0301", 0, "\u0300\u0301"},
- {"a\u0300\u0301", 0, "a\u0300\u0301"},
- {"a\u0301\u0308", 0, "a\u0301\u0308"},
- {"a\u0308\u0301", 0, "a\u0308\u0301"},
- {"aaaa\u0300\u0301", 3, "a\u0300\u0301"},
- {"\u0300a\u0300\u0301", 2, "a\u0300\u0301"},
- {"\u00C0", 0, "A\u0300"},
- {"a\u00C0", 1, "A\u0300"},
- // decomposing
- {"a\u0300\uFDC0", 3, "\u0645\u062C\u064A"},
- {"\uFDC0" + strings.Repeat("\u0300", 26), 0, "\u0645\u062C\u064A" + strings.Repeat("\u0300", 26)},
- // Hangul
- {"a\u1103", 1, "\u1103"},
- {"a\u110B", 1, "\u110B"},
- {"a\u110B\u1173", 1, "\u110B\u1173"},
- // See comment in composition.go:compBoundaryAfter.
- {"a\u110B\u1173\u11B7", 1, "\u110B\u1173\u11B7"},
- {"a\uC73C", 1, "\u110B\u1173"},
- {"다음", 3, "\u110B\u1173\u11B7"},
- {"다", 0, "\u1103\u1161"},
- {"\u1103\u1161\u110B\u1173\u11B7", 6, "\u110B\u1173\u11B7"},
- {"\u110B\u1173\u11B7\u1103\u1161", 9, "\u1103\u1161"},
- {"다음음", 6, "\u110B\u1173\u11B7"},
- {"음다다", 6, "\u1103\u1161"},
- // buffer overflow
- {"a" + strings.Repeat("\u0300", 30), 3, strings.Repeat("\u0300", 29)},
- {"\uFDFA" + strings.Repeat("\u0300", 14), 3, strings.Repeat("\u0300", 14)},
- // weird UTF-8
- {"a\u0300\u11B7", 0, "a\u0300\u11B7"},
-}
-
-func decomposeToLast(rb *reorderBuffer, s string) int {
- buf := decomposeToLastBoundary(rb, []byte(s))
- return len(buf)
-}
-
-func TestDecomposeToLastBoundary(t *testing.T) {
- runPosTests(t, "TestDecomposeToLastBoundary", NFKC, decomposeToLast, decomposeToLastTests)
-}
-
-var lastBoundaryTests = []PositionTest{
- // ends with inert character
- {"Hello!", 6, ""},
- {"\u0632", 2, ""},
- // ends with non-inert starter
- {"a", 0, ""},
- // illegal runes
- {"\xff", 1, ""},
- {"aa\xff", 3, ""},
- {"a\xff\u0300", 1, ""},
- {"\xc0\x80\x80", 3, ""},
- {"\xc0\x80\x80\u0300", 3, ""},
- // ends with incomplete UTF-8 encoding
- {"\xCC", -1, ""},
- {"\xE0\x80", -1, ""},
- {"\xF0\x80\x80", -1, ""},
- {"a\xCC", 0, ""},
- {"\x80\xCC", 1, ""},
- {"\xCC\xCC", 1, ""},
- // ends with combining characters
- {"a\u0300\u0301", 0, ""},
- {"aaaa\u0300\u0301", 3, ""},
- {"\u0300a\u0300\u0301", 2, ""},
- {"\u00C0", 0, ""},
- {"a\u00C0", 1, ""},
- // decomposition may recombine
- {"\u0226", 0, ""},
- // no boundary
- {"", -1, ""},
- {"\u0300\u0301", -1, ""},
- {"\u0300", -1, ""},
- {"\x80\x80", -1, ""},
- {"\x80\x80\u0301", -1, ""},
- // Hangul
- {"다음", 3, ""},
- {"다", 0, ""},
- {"\u1103\u1161\u110B\u1173\u11B7", 6, ""},
- {"\u110B\u1173\u11B7\u1103\u1161", 9, ""},
- // too many combining characters.
- {strings.Repeat("\u0300", maxCombiningChars-1), -1, ""},
- {strings.Repeat("\u0300", maxCombiningChars), 60, ""},
- {strings.Repeat("\u0300", maxCombiningChars+1), 62, ""},
-}
-
-func lastBoundaryF(rb *reorderBuffer, s string) int {
- return rb.f.form.LastBoundary([]byte(s))
-}
-
-func TestLastBoundary(t *testing.T) {
- runPosTests(t, "TestLastBoundary", NFC, lastBoundaryF, lastBoundaryTests)
-}
-
-var quickSpanTests = []PositionTest{
- {"", 0, ""},
- // starters
- {"a", 1, ""},
- {"abc", 3, ""},
- {"\u043Eb", 3, ""},
- // incomplete last rune.
- {"\xCC", 1, ""},
- {"a\xCC", 2, ""},
- // incorrectly ordered combining characters
- {"\u0300\u0316", 0, ""},
- {"\u0300\u0316cd", 0, ""},
- // have a maximum number of combining characters.
- {strings.Repeat("\u035D", 30) + "\u035B", 62, ""},
- {"a" + strings.Repeat("\u035D", 30) + "\u035B", 63, ""},
- {"Ɵ" + strings.Repeat("\u035D", 30) + "\u035B", 64, ""},
- {"aa" + strings.Repeat("\u035D", 30) + "\u035B", 64, ""},
-}
-
-var quickSpanNFDTests = []PositionTest{
- // needs decomposing
- {"\u00C0", 0, ""},
- {"abc\u00C0", 3, ""},
- // correctly ordered combining characters
- {"\u0300", 2, ""},
- {"ab\u0300", 4, ""},
- {"ab\u0300cd", 6, ""},
- {"\u0300cd", 4, ""},
- {"\u0316\u0300", 4, ""},
- {"ab\u0316\u0300", 6, ""},
- {"ab\u0316\u0300cd", 8, ""},
- {"ab\u0316\u0300\u00C0", 6, ""},
- {"\u0316\u0300cd", 6, ""},
- {"\u043E\u0308b", 5, ""},
- // incorrectly ordered combining characters
- {"ab\u0300\u0316", 1, ""}, // TODO: we could skip 'b' as well.
- {"ab\u0300\u0316cd", 1, ""},
- // Hangul
- {"같은", 0, ""},
-}
-
-var quickSpanNFCTests = []PositionTest{
- // okay composed
- {"\u00C0", 2, ""},
- {"abc\u00C0", 5, ""},
- // correctly ordered combining characters
- {"ab\u0300", 1, ""},
- {"ab\u0300cd", 1, ""},
- {"ab\u0316\u0300", 1, ""},
- {"ab\u0316\u0300cd", 1, ""},
- {"\u00C0\u035D", 4, ""},
- // we do not special case leading combining characters
- {"\u0300cd", 0, ""},
- {"\u0300", 0, ""},
- {"\u0316\u0300", 0, ""},
- {"\u0316\u0300cd", 0, ""},
- // incorrectly ordered combining characters
- {"ab\u0300\u0316", 1, ""},
- {"ab\u0300\u0316cd", 1, ""},
- // Hangul
- {"같은", 6, ""},
-}
-
-func doQuickSpan(rb *reorderBuffer, s string) int {
- return rb.f.form.QuickSpan([]byte(s))
-}
-
-func doQuickSpanString(rb *reorderBuffer, s string) int {
- return rb.f.form.QuickSpanString(s)
-}
-
-func TestQuickSpan(t *testing.T) {
- runPosTests(t, "TestQuickSpanNFD1", NFD, doQuickSpan, quickSpanTests)
- runPosTests(t, "TestQuickSpanNFD2", NFD, doQuickSpan, quickSpanNFDTests)
- runPosTests(t, "TestQuickSpanNFC1", NFC, doQuickSpan, quickSpanTests)
- runPosTests(t, "TestQuickSpanNFC2", NFC, doQuickSpan, quickSpanNFCTests)
-
- runPosTests(t, "TestQuickSpanStringNFD1", NFD, doQuickSpanString, quickSpanTests)
- runPosTests(t, "TestQuickSpanStringNFD2", NFD, doQuickSpanString, quickSpanNFDTests)
- runPosTests(t, "TestQuickSpanStringNFC1", NFC, doQuickSpanString, quickSpanTests)
- runPosTests(t, "TestQuickSpanStringNFC2", NFC, doQuickSpanString, quickSpanNFCTests)
-}
-
-var isNormalTests = []PositionTest{
- {"", 1, ""},
- // illegal runes
- {"\xff", 1, ""},
- // starters
- {"a", 1, ""},
- {"abc", 1, ""},
- {"\u043Eb", 1, ""},
- // incorrectly ordered combining characters
- {"\u0300\u0316", 0, ""},
- {"ab\u0300\u0316", 0, ""},
- {"ab\u0300\u0316cd", 0, ""},
- {"\u0300\u0316cd", 0, ""},
-}
-var isNormalNFDTests = []PositionTest{
- // needs decomposing
- {"\u00C0", 0, ""},
- {"abc\u00C0", 0, ""},
- // correctly ordered combining characters
- {"\u0300", 1, ""},
- {"ab\u0300", 1, ""},
- {"ab\u0300cd", 1, ""},
- {"\u0300cd", 1, ""},
- {"\u0316\u0300", 1, ""},
- {"ab\u0316\u0300", 1, ""},
- {"ab\u0316\u0300cd", 1, ""},
- {"\u0316\u0300cd", 1, ""},
- {"\u043E\u0308b", 1, ""},
- // Hangul
- {"같은", 0, ""},
-}
-var isNormalNFCTests = []PositionTest{
- // okay composed
- {"\u00C0", 1, ""},
- {"abc\u00C0", 1, ""},
- // need reordering
- {"a\u0300", 0, ""},
- {"a\u0300cd", 0, ""},
- {"a\u0316\u0300", 0, ""},
- {"a\u0316\u0300cd", 0, ""},
- // correctly ordered combining characters
- {"ab\u0300", 1, ""},
- {"ab\u0300cd", 1, ""},
- {"ab\u0316\u0300", 1, ""},
- {"ab\u0316\u0300cd", 1, ""},
- {"\u00C0\u035D", 1, ""},
- {"\u0300", 1, ""},
- {"\u0316\u0300cd", 1, ""},
- // Hangul
- {"같은", 1, ""},
-}
-
-func isNormalF(rb *reorderBuffer, s string) int {
- if rb.f.form.IsNormal([]byte(s)) {
- return 1
- }
- return 0
-}
-
-func TestIsNormal(t *testing.T) {
- runPosTests(t, "TestIsNormalNFD1", NFD, isNormalF, isNormalTests)
- runPosTests(t, "TestIsNormalNFD2", NFD, isNormalF, isNormalNFDTests)
- runPosTests(t, "TestIsNormalNFC1", NFC, isNormalF, isNormalTests)
- runPosTests(t, "TestIsNormalNFC2", NFC, isNormalF, isNormalNFCTests)
-}
-
-type AppendTest struct {
- left string
- right string
- out string
-}
-
-type appendFunc func(f Form, out []byte, s string) []byte
-
-func runAppendTests(t *testing.T, name string, f Form, fn appendFunc, tests []AppendTest) {
- for i, test := range tests {
- out := []byte(test.left)
- out = fn(f, out, test.right)
- outs := string(out)
- if len(outs) != len(test.out) {
- t.Errorf("%s:%d: length is %d; want %d", name, i, len(outs), len(test.out))
- }
- if outs != test.out {
- // Find first rune that differs and show context.
- ir := []rune(outs)
- ig := []rune(test.out)
- for j := 0; j < len(ir) && j < len(ig); j++ {
- if ir[j] == ig[j] {
- continue
- }
- if j -= 3; j < 0 {
- j = 0
- }
- for e := j + 7; j < e && j < len(ir) && j < len(ig); j++ {
- t.Errorf("%s:%d: runeAt(%d) = %U; want %U", name, i, j, ir[j], ig[j])
- }
- break
- }
- }
- }
-}
-
-var appendTests = []AppendTest{
- // empty buffers
- {"", "", ""},
- {"a", "", "a"},
- {"", "a", "a"},
- {"", "\u0041\u0307\u0304", "\u01E0"},
- // segment split across buffers
- {"", "a\u0300b", "\u00E0b"},
- {"a", "\u0300b", "\u00E0b"},
- {"a", "\u0300\u0316", "\u00E0\u0316"},
- {"a", "\u0316\u0300", "\u00E0\u0316"},
- {"a", "\u0300a\u0300", "\u00E0\u00E0"},
- {"a", "\u0300a\u0300a\u0300", "\u00E0\u00E0\u00E0"},
- {"a", "\u0300aaa\u0300aaa\u0300", "\u00E0aa\u00E0aa\u00E0"},
- {"a\u0300", "\u0327", "\u00E0\u0327"},
- {"a\u0327", "\u0300", "\u00E0\u0327"},
- {"a\u0316", "\u0300", "\u00E0\u0316"},
- {"\u0041\u0307", "\u0304", "\u01E0"},
- // Hangul
- {"", "\u110B\u1173", "\uC73C"},
- {"", "\u1103\u1161", "\uB2E4"},
- {"", "\u110B\u1173\u11B7", "\uC74C"},
- {"", "\u320E", "\x28\uAC00\x29"},
- {"", "\x28\u1100\u1161\x29", "\x28\uAC00\x29"},
- {"\u1103", "\u1161", "\uB2E4"},
- {"\u110B", "\u1173\u11B7", "\uC74C"},
- {"\u110B\u1173", "\u11B7", "\uC74C"},
- {"\uC73C", "\u11B7", "\uC74C"},
- // UTF-8 encoding split across buffers
- {"a\xCC", "\x80", "\u00E0"},
- {"a\xCC", "\x80b", "\u00E0b"},
- {"a\xCC", "\x80a\u0300", "\u00E0\u00E0"},
- {"a\xCC", "\x80\x80", "\u00E0\x80"},
- {"a\xCC", "\x80\xCC", "\u00E0\xCC"},
- {"a\u0316\xCC", "\x80a\u0316\u0300", "\u00E0\u0316\u00E0\u0316"},
- // ending in incomplete UTF-8 encoding
- {"", "\xCC", "\xCC"},
- {"a", "\xCC", "a\xCC"},
- {"a", "b\xCC", "ab\xCC"},
- {"\u0226", "\xCC", "\u0226\xCC"},
- // illegal runes
- {"", "\x80", "\x80"},
- {"", "\x80\x80\x80", "\x80\x80\x80"},
- {"", "\xCC\x80\x80\x80", "\xCC\x80\x80\x80"},
- {"", "a\x80", "a\x80"},
- {"", "a\x80\x80\x80", "a\x80\x80\x80"},
- {"", "a\x80\x80\x80\x80\x80\x80", "a\x80\x80\x80\x80\x80\x80"},
- {"a", "\x80\x80\x80", "a\x80\x80\x80"},
- // overflow
- {"", strings.Repeat("\x80", 33), strings.Repeat("\x80", 33)},
- {strings.Repeat("\x80", 33), "", strings.Repeat("\x80", 33)},
- {strings.Repeat("\x80", 33), strings.Repeat("\x80", 33), strings.Repeat("\x80", 66)},
- // overflow of combining characters
- {strings.Repeat("\u0300", 33), "", strings.Repeat("\u0300", 33)},
- // weird UTF-8
- {"\u00E0\xE1", "\x86", "\u00E0\xE1\x86"},
- {"a\u0300\u11B7", "\u0300", "\u00E0\u11B7\u0300"},
- {"a\u0300\u11B7\u0300", "\u0300", "\u00E0\u11B7\u0300\u0300"},
- {"\u0300", "\xF8\x80\x80\x80\x80\u0300", "\u0300\xF8\x80\x80\x80\x80\u0300"},
- {"\u0300", "\xFC\x80\x80\x80\x80\x80\u0300", "\u0300\xFC\x80\x80\x80\x80\x80\u0300"},
- {"\xF8\x80\x80\x80\x80\u0300", "\u0300", "\xF8\x80\x80\x80\x80\u0300\u0300"},
- {"\xFC\x80\x80\x80\x80\x80\u0300", "\u0300", "\xFC\x80\x80\x80\x80\x80\u0300\u0300"},
- {"\xF8\x80\x80\x80", "\x80\u0300\u0300", "\xF8\x80\x80\x80\x80\u0300\u0300"},
-}
-
-func appendF(f Form, out []byte, s string) []byte {
- return f.Append(out, []byte(s)...)
-}
-
-func appendStringF(f Form, out []byte, s string) []byte {
- return f.AppendString(out, s)
-}
-
-func bytesF(f Form, out []byte, s string) []byte {
- buf := []byte{}
- buf = append(buf, out...)
- buf = append(buf, s...)
- return f.Bytes(buf)
-}
-
-func stringF(f Form, out []byte, s string) []byte {
- outs := string(out) + s
- return []byte(f.String(outs))
-}
-
-func TestAppend(t *testing.T) {
- runAppendTests(t, "TestAppend", NFKC, appendF, appendTests)
- runAppendTests(t, "TestAppendString", NFKC, appendStringF, appendTests)
- runAppendTests(t, "TestBytes", NFKC, bytesF, appendTests)
- runAppendTests(t, "TestString", NFKC, stringF, appendTests)
-}
-
-func appendBench(f Form, in []byte) func() {
- buf := make([]byte, 0, 4*len(in))
- return func() {
- f.Append(buf, in...)
- }
-}
-
-func iterBench(f Form, in []byte) func() {
- iter := Iter{}
- return func() {
- iter.Init(f, in)
- for !iter.Done() {
- iter.Next()
- }
- }
-}
-
-func readerBench(f Form, in []byte) func() {
- buf := make([]byte, 4*len(in))
- return func() {
- r := f.Reader(bytes.NewReader(in))
- var err error
- for err == nil {
- _, err = r.Read(buf)
- }
- if err != io.EOF {
- panic("")
- }
- }
-}
-
-func writerBench(f Form, in []byte) func() {
- buf := make([]byte, 0, 4*len(in))
- return func() {
- r := f.Writer(bytes.NewBuffer(buf))
- if _, err := r.Write(in); err != nil {
- panic("")
- }
- }
-}
-
-func appendBenchmarks(bm []func(), f Form, in []byte) []func() {
- //bm = append(bm, appendBench(f, in))
- bm = append(bm, iterBench(f, in))
- //bm = append(bm, readerBench(f, in))
- //bm = append(bm, writerBench(f, in))
- return bm
-}
-
-func doFormBenchmark(b *testing.B, inf, f Form, s string) {
- b.StopTimer()
- in := inf.Bytes([]byte(s))
- bm := appendBenchmarks(nil, f, in)
- b.SetBytes(int64(len(in) * len(bm)))
- b.StartTimer()
- for i := 0; i < b.N; i++ {
- for _, fn := range bm {
- fn()
- }
- }
-}
-
-var ascii = strings.Repeat("There is nothing to change here! ", 500)
-
-func BenchmarkNormalizeAsciiNFC(b *testing.B) {
- doFormBenchmark(b, NFC, NFC, ascii)
-}
-func BenchmarkNormalizeAsciiNFD(b *testing.B) {
- doFormBenchmark(b, NFC, NFD, ascii)
-}
-func BenchmarkNormalizeAsciiNFKC(b *testing.B) {
- doFormBenchmark(b, NFC, NFKC, ascii)
-}
-func BenchmarkNormalizeAsciiNFKD(b *testing.B) {
- doFormBenchmark(b, NFC, NFKD, ascii)
-}
-
-func BenchmarkNormalizeNFC2NFC(b *testing.B) {
- doFormBenchmark(b, NFC, NFC, txt_all)
-}
-func BenchmarkNormalizeNFC2NFD(b *testing.B) {
- doFormBenchmark(b, NFC, NFD, txt_all)
-}
-func BenchmarkNormalizeNFD2NFC(b *testing.B) {
- doFormBenchmark(b, NFD, NFC, txt_all)
-}
-func BenchmarkNormalizeNFD2NFD(b *testing.B) {
- doFormBenchmark(b, NFD, NFD, txt_all)
-}
-
-// Hangul is often special-cased, so we test it separately.
-func BenchmarkNormalizeHangulNFC2NFC(b *testing.B) {
- doFormBenchmark(b, NFC, NFC, txt_kr)
-}
-func BenchmarkNormalizeHangulNFC2NFD(b *testing.B) {
- doFormBenchmark(b, NFC, NFD, txt_kr)
-}
-func BenchmarkNormalizeHangulNFD2NFC(b *testing.B) {
- doFormBenchmark(b, NFD, NFC, txt_kr)
-}
-func BenchmarkNormalizeHangulNFD2NFD(b *testing.B) {
- doFormBenchmark(b, NFD, NFD, txt_kr)
-}
-
-var forms = []Form{NFC, NFD, NFKC, NFKD}
-
-func doTextBenchmark(b *testing.B, s string) {
- b.StopTimer()
- in := []byte(s)
- bm := []func(){}
- for _, f := range forms {
- bm = appendBenchmarks(bm, f, in)
- }
- b.SetBytes(int64(len(s) * len(bm)))
- b.StartTimer()
- for i := 0; i < b.N; i++ {
- for _, f := range bm {
- f()
- }
- }
-}
-
-func BenchmarkCanonicalOrdering(b *testing.B) {
- doTextBenchmark(b, txt_canon)
-}
-func BenchmarkExtendedLatin(b *testing.B) {
- doTextBenchmark(b, txt_vn)
-}
-func BenchmarkMiscTwoByteUtf8(b *testing.B) {
- doTextBenchmark(b, twoByteUtf8)
-}
-func BenchmarkMiscThreeByteUtf8(b *testing.B) {
- doTextBenchmark(b, threeByteUtf8)
-}
-func BenchmarkHangul(b *testing.B) {
- doTextBenchmark(b, txt_kr)
-}
-func BenchmarkJapanese(b *testing.B) {
- doTextBenchmark(b, txt_jp)
-}
-func BenchmarkChinese(b *testing.B) {
- doTextBenchmark(b, txt_cn)
-}
-func BenchmarkOverflow(b *testing.B) {
- doTextBenchmark(b, overflow)
-}
-
-var overflow = string(bytes.Repeat([]byte("\u035D"), 4096)) + "\u035B"
-
-// Tests sampled from the Canonical ordering tests (Part 2) of
-// http://unicode.org/Public/UNIDATA/NormalizationTest.txt
-const txt_canon = `\u0061\u0315\u0300\u05AE\u0300\u0062 \u0061\u0300\u0315\u0300\u05AE\u0062
-\u0061\u0302\u0315\u0300\u05AE\u0062 \u0061\u0307\u0315\u0300\u05AE\u0062
-\u0061\u0315\u0300\u05AE\u030A\u0062 \u0061\u059A\u0316\u302A\u031C\u0062
-\u0061\u032E\u059A\u0316\u302A\u0062 \u0061\u0338\u093C\u0334\u0062
-\u0061\u059A\u0316\u302A\u0339 \u0061\u0341\u0315\u0300\u05AE\u0062
-\u0061\u0348\u059A\u0316\u302A\u0062 \u0061\u0361\u0345\u035D\u035C\u0062
-\u0061\u0366\u0315\u0300\u05AE\u0062 \u0061\u0315\u0300\u05AE\u0486\u0062
-\u0061\u05A4\u059A\u0316\u302A\u0062 \u0061\u0315\u0300\u05AE\u0613\u0062
-\u0061\u0315\u0300\u05AE\u0615\u0062 \u0061\u0617\u0315\u0300\u05AE\u0062
-\u0061\u0619\u0618\u064D\u064E\u0062 \u0061\u0315\u0300\u05AE\u0654\u0062
-\u0061\u0315\u0300\u05AE\u06DC\u0062 \u0061\u0733\u0315\u0300\u05AE\u0062
-\u0061\u0744\u059A\u0316\u302A\u0062 \u0061\u0315\u0300\u05AE\u0745\u0062
-\u0061\u09CD\u05B0\u094D\u3099\u0062 \u0061\u0E38\u0E48\u0E38\u0C56\u0062
-\u0061\u0EB8\u0E48\u0E38\u0E49\u0062 \u0061\u0F72\u0F71\u0EC8\u0F71\u0062
-\u0061\u1039\u05B0\u094D\u3099\u0062 \u0061\u05B0\u094D\u3099\u1A60\u0062
-\u0061\u3099\u093C\u0334\u1BE6\u0062 \u0061\u3099\u093C\u0334\u1C37\u0062
-\u0061\u1CD9\u059A\u0316\u302A\u0062 \u0061\u2DED\u0315\u0300\u05AE\u0062
-\u0061\u2DEF\u0315\u0300\u05AE\u0062 \u0061\u302D\u302E\u059A\u0316\u0062`
-
-// Taken from http://creativecommons.org/licenses/by-sa/3.0/vn/
-const txt_vn = `Với các điều kiện sau: Ghi nhận công của tác giả.
-Nếu bạn sử dụng, chuyển đổi, hoặc xây dựng dự án từ
-nội dung được chia sẻ này, bạn phải áp dụng giấy phép này hoặc
-một giấy phép khác có các điều khoản tương tự như giấy phép này
-cho dự án của bạn. Hiểu rằng: Miễn — Bất kỳ các điều kiện nào
-trên đây cũng có thể được miễn bỏ nếu bạn được sự cho phép của
-người sở hữu bản quyền. Phạm vi công chúng — Khi tác phẩm hoặc
-bất kỳ chương nào của tác phẩm đã trong vùng dành cho công
-chúng theo quy định của pháp luật thì tình trạng của nó không
-bị ảnh hưởng bởi giấy phép trong bất kỳ trường hợp nào.`
-
-// Taken from http://creativecommons.org/licenses/by-sa/1.0/deed.ru
-const txt_ru = `При обязательном соблюдении следующих условий:
-Attribution — Вы должны атрибутировать произведение (указывать
-автора и источник) в порядке, предусмотренном автором или
-лицензиаром (но только так, чтобы никоим образом не подразумевалось,
-что они поддерживают вас или использование вами данного произведения).
-Υπό τις ακόλουθες προϋποθέσεις:`
-
-// Taken from http://creativecommons.org/licenses/by-sa/3.0/gr/
-const txt_gr = `Αναφορά Δημιουργού — Θα πρέπει να κάνετε την αναφορά στο έργο με τον
-τρόπο που έχει οριστεί από το δημιουργό ή το χορηγούντο την άδεια
-(χωρίς όμως να εννοείται με οποιονδήποτε τρόπο ότι εγκρίνουν εσάς ή
-τη χρήση του έργου από εσάς). Παρόμοια Διανομή — Εάν αλλοιώσετε,
-τροποποιήσετε ή δημιουργήσετε περαιτέρω βασισμένοι στο έργο θα
-μπορείτε να διανέμετε το έργο που θα προκύψει μόνο με την ίδια ή
-παρόμοια άδεια.`
-
-// Taken from http://creativecommons.org/licenses/by-sa/3.0/deed.ar
-const txt_ar = `بموجب الشروط التالية نسب المصنف — يجب عليك أن
-تنسب العمل بالطريقة التي تحددها المؤلف أو المرخص (ولكن ليس بأي حال من
-الأحوال أن توحي وتقترح بتحول أو استخدامك للعمل).
-المشاركة على قدم المساواة — إذا كنت يعدل ، والتغيير ، أو الاستفادة
-من هذا العمل ، قد ينتج عن توزيع العمل إلا في ظل تشابه او تطابق فى واحد
-لهذا الترخيص.`
-
-// Taken from http://creativecommons.org/licenses/by-sa/1.0/il/
-const txt_il = `בכפוף לתנאים הבאים: ייחוס — עליך לייחס את היצירה (לתת קרדיט) באופן
-המצויין על-ידי היוצר או מעניק הרישיון (אך לא בשום אופן המרמז על כך
-שהם תומכים בך או בשימוש שלך ביצירה). שיתוף זהה — אם תחליט/י לשנות,
-לעבד או ליצור יצירה נגזרת בהסתמך על יצירה זו, תוכל/י להפיץ את יצירתך
-החדשה רק תחת אותו הרישיון או רישיון דומה לרישיון זה.`
-
-const twoByteUtf8 = txt_ru + txt_gr + txt_ar + txt_il
-
-// Taken from http://creativecommons.org/licenses/by-sa/2.0/kr/
-const txt_kr = `다음과 같은 조건을 따라야 합니다: 저작자표시
-(Attribution) — 저작자나 이용허락자가 정한 방법으로 저작물의
-원저작자를 표시하여야 합니다(그러나 원저작자가 이용자나 이용자의
-이용을 보증하거나 추천한다는 의미로 표시해서는 안됩니다).
-동일조건변경허락 — 이 저작물을 이용하여 만든 이차적 저작물에는 본
-라이선스와 동일한 라이선스를 적용해야 합니다.`
-
-// Taken from http://creativecommons.org/licenses/by-sa/3.0/th/
-const txt_th = `ภายใต้เงื่อนไข ดังต่อไปนี้ : แสดงที่มา — คุณต้องแสดงที่
-มาของงานดังกล่าว ตามรูปแบบที่ผู้สร้างสรรค์หรือผู้อนุญาตกำหนด (แต่
-ไม่ใช่ในลักษณะที่ว่า พวกเขาสนับสนุนคุณหรือสนับสนุนการที่
-คุณนำงานไปใช้) อนุญาตแบบเดียวกัน — หากคุณดัดแปลง เปลี่ยนรูป หรื
-อต่อเติมงานนี้ คุณต้องใช้สัญญาอนุญาตแบบเดียวกันหรือแบบที่เหมื
-อนกับสัญญาอนุญาตที่ใช้กับงานนี้เท่านั้น`
-
-const threeByteUtf8 = txt_th
-
-// Taken from http://creativecommons.org/licenses/by-sa/2.0/jp/
-const txt_jp = `あなたの従うべき条件は以下の通りです。
-表示 — あなたは原著作者のクレジットを表示しなければなりません。
-継承 — もしあなたがこの作品を改変、変形または加工した場合、
-あなたはその結果生じた作品をこの作品と同一の許諾条件の下でのみ
-頒布することができます。`
-
-// http://creativecommons.org/licenses/by-sa/2.5/cn/
-const txt_cn = `您可以自由: 复制、发行、展览、表演、放映、
-广播或通过信息网络传播本作品 创作演绎作品
-对本作品进行商业性使用 惟须遵守下列条件:
-署名 — 您必须按照作者或者许可人指定的方式对作品进行署名。
-相同方式共享 — 如果您改变、转换本作品或者以本作品为基础进行创作,
-您只能采用与本协议相同的许可协议发布基于本作品的演绎作品。`
-
-const txt_cjk = txt_cn + txt_jp + txt_kr
-const txt_all = txt_vn + twoByteUtf8 + threeByteUtf8 + txt_cjk
diff --git a/src/pkg/exp/norm/normregtest.go b/src/pkg/exp/norm/normregtest.go
deleted file mode 100644
index b77b5b545..000000000
--- a/src/pkg/exp/norm/normregtest.go
+++ /dev/null
@@ -1,304 +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 ignore
-
-package main
-
-import (
- "bufio"
- "bytes"
- "exp/norm"
- "flag"
- "fmt"
- "log"
- "net/http"
- "os"
- "path"
- "regexp"
- "runtime"
- "strconv"
- "strings"
- "time"
- "unicode"
- "unicode/utf8"
-)
-
-func main() {
- flag.Parse()
- loadTestData()
- CharacterByCharacterTests()
- StandardTests()
- PerformanceTest()
- if errorCount == 0 {
- fmt.Println("PASS")
- }
-}
-
-const file = "NormalizationTest.txt"
-
-var url = flag.String("url",
- "http://www.unicode.org/Public/"+unicode.Version+"/ucd/"+file,
- "URL of Unicode database directory")
-var localFiles = flag.Bool("local",
- false,
- "data files have been copied to the current directory; for debugging only")
-
-var logger = log.New(os.Stderr, "", log.Lshortfile)
-
-// This regression test runs the test set in NormalizationTest.txt
-// (taken from http://www.unicode.org/Public/<unicode.Version>/ucd/).
-//
-// NormalizationTest.txt has form:
-// @Part0 # Specific cases
-// #
-// 1E0A;1E0A;0044 0307;1E0A;0044 0307; # (Ḋ; Ḋ; D◌̇; Ḋ; D◌̇; ) LATIN CAPITAL LETTER D WITH DOT ABOVE
-// 1E0C;1E0C;0044 0323;1E0C;0044 0323; # (Ḍ; Ḍ; D◌̣; Ḍ; D◌̣; ) LATIN CAPITAL LETTER D WITH DOT BELOW
-//
-// Each test has 5 columns (c1, c2, c3, c4, c5), where
-// (c1, c2, c3, c4, c5) == (c1, NFC(c1), NFD(c1), NFKC(c1), NFKD(c1))
-//
-// CONFORMANCE:
-// 1. The following invariants must be true for all conformant implementations
-//
-// NFC
-// c2 == NFC(c1) == NFC(c2) == NFC(c3)
-// c4 == NFC(c4) == NFC(c5)
-//
-// NFD
-// c3 == NFD(c1) == NFD(c2) == NFD(c3)
-// c5 == NFD(c4) == NFD(c5)
-//
-// NFKC
-// c4 == NFKC(c1) == NFKC(c2) == NFKC(c3) == NFKC(c4) == NFKC(c5)
-//
-// NFKD
-// c5 == NFKD(c1) == NFKD(c2) == NFKD(c3) == NFKD(c4) == NFKD(c5)
-//
-// 2. For every code point X assigned in this version of Unicode that is not
-// specifically listed in Part 1, the following invariants must be true
-// for all conformant implementations:
-//
-// X == NFC(X) == NFD(X) == NFKC(X) == NFKD(X)
-//
-
-// Column types.
-const (
- cRaw = iota
- cNFC
- cNFD
- cNFKC
- cNFKD
- cMaxColumns
-)
-
-// Holds data from NormalizationTest.txt
-var part []Part
-
-type Part struct {
- name string
- number int
- tests []Test
-}
-
-type Test struct {
- name string
- partnr int
- number int
- r rune // used for character by character test
- cols [cMaxColumns]string // Each has 5 entries, see below.
-}
-
-func (t Test) Name() string {
- if t.number < 0 {
- return part[t.partnr].name
- }
- return fmt.Sprintf("%s:%d", part[t.partnr].name, t.number)
-}
-
-var partRe = regexp.MustCompile(`@Part(\d) # (.*)$`)
-var testRe = regexp.MustCompile(`^` + strings.Repeat(`([\dA-F ]+);`, 5) + ` # (.*)$`)
-
-var counter int
-
-// Load the data form NormalizationTest.txt
-func loadTestData() {
- if *localFiles {
- pwd, _ := os.Getwd()
- *url = "file://" + path.Join(pwd, file)
- }
- t := &http.Transport{}
- t.RegisterProtocol("file", http.NewFileTransport(http.Dir("/")))
- c := &http.Client{Transport: t}
- resp, err := c.Get(*url)
- if err != nil {
- logger.Fatal(err)
- }
- if resp.StatusCode != 200 {
- logger.Fatal("bad GET status for "+file, resp.Status)
- }
- f := resp.Body
- defer f.Close()
- scanner := bufio.NewScanner(f)
- for scanner.Scan() {
- line := scanner.Text()
- if len(line) == 0 || line[0] == '#' {
- continue
- }
- m := partRe.FindStringSubmatch(line)
- if m != nil {
- if len(m) < 3 {
- logger.Fatal("Failed to parse Part: ", line)
- }
- i, err := strconv.Atoi(m[1])
- if err != nil {
- logger.Fatal(err)
- }
- name := m[2]
- part = append(part, Part{name: name[:len(name)-1], number: i})
- continue
- }
- m = testRe.FindStringSubmatch(line)
- if m == nil || len(m) < 7 {
- logger.Fatalf(`Failed to parse: "%s" result: %#v`, line, m)
- }
- test := Test{name: m[6], partnr: len(part) - 1, number: counter}
- counter++
- for j := 1; j < len(m)-1; j++ {
- for _, split := range strings.Split(m[j], " ") {
- r, err := strconv.ParseUint(split, 16, 64)
- if err != nil {
- logger.Fatal(err)
- }
- if test.r == 0 {
- // save for CharacterByCharacterTests
- test.r = rune(r)
- }
- var buf [utf8.UTFMax]byte
- sz := utf8.EncodeRune(buf[:], rune(r))
- test.cols[j-1] += string(buf[:sz])
- }
- }
- part := &part[len(part)-1]
- part.tests = append(part.tests, test)
- }
- if scanner.Err() != nil {
- logger.Fatal(scanner.Err())
- }
-}
-
-var fstr = []string{"NFC", "NFD", "NFKC", "NFKD"}
-
-var errorCount int
-
-func cmpResult(t *Test, name string, f norm.Form, gold, test, result string) {
- if gold != result {
- errorCount++
- if errorCount > 20 {
- return
- }
- st, sr, sg := []rune(test), []rune(result), []rune(gold)
- logger.Printf("%s:%s: %s(%X)=%X; want:%X: %s",
- t.Name(), name, fstr[f], st, sr, sg, t.name)
- }
-}
-
-func cmpIsNormal(t *Test, name string, f norm.Form, test string, result, want bool) {
- if result != want {
- errorCount++
- if errorCount > 20 {
- return
- }
- logger.Printf("%s:%s: %s(%X)=%v; want: %v", t.Name(), name, fstr[f], []rune(test), result, want)
- }
-}
-
-func doTest(t *Test, f norm.Form, gold, test string) {
- result := f.Bytes([]byte(test))
- cmpResult(t, "Bytes", f, gold, test, string(result))
- sresult := f.String(test)
- cmpResult(t, "String", f, gold, test, sresult)
- acc := []byte{}
- i := norm.Iter{}
- i.InitString(f, test)
- for !i.Done() {
- acc = append(acc, i.Next()...)
- }
- cmpResult(t, "Iter.Next", f, gold, test, string(acc))
- for i := range test {
- out := f.Append(f.Bytes([]byte(test[:i])), []byte(test[i:])...)
- cmpResult(t, fmt.Sprintf(":Append:%d", i), f, gold, test, string(out))
- }
- cmpIsNormal(t, "IsNormal", f, test, f.IsNormal([]byte(test)), test == gold)
-}
-
-func doConformanceTests(t *Test, partn int) {
- for i := 0; i <= 2; i++ {
- doTest(t, norm.NFC, t.cols[1], t.cols[i])
- doTest(t, norm.NFD, t.cols[2], t.cols[i])
- doTest(t, norm.NFKC, t.cols[3], t.cols[i])
- doTest(t, norm.NFKD, t.cols[4], t.cols[i])
- }
- for i := 3; i <= 4; i++ {
- doTest(t, norm.NFC, t.cols[3], t.cols[i])
- doTest(t, norm.NFD, t.cols[4], t.cols[i])
- doTest(t, norm.NFKC, t.cols[3], t.cols[i])
- doTest(t, norm.NFKD, t.cols[4], t.cols[i])
- }
-}
-
-func CharacterByCharacterTests() {
- tests := part[1].tests
- var last rune = 0
- for i := 0; i <= len(tests); i++ { // last one is special case
- var r rune
- if i == len(tests) {
- r = 0x2FA1E // Don't have to go to 0x10FFFF
- } else {
- r = tests[i].r
- }
- for last++; last < r; last++ {
- // Check all characters that were not explicitly listed in the test.
- t := &Test{partnr: 1, number: -1}
- char := string(last)
- doTest(t, norm.NFC, char, char)
- doTest(t, norm.NFD, char, char)
- doTest(t, norm.NFKC, char, char)
- doTest(t, norm.NFKD, char, char)
- }
- if i < len(tests) {
- doConformanceTests(&tests[i], 1)
- }
- }
-}
-
-func StandardTests() {
- for _, j := range []int{0, 2, 3} {
- for _, test := range part[j].tests {
- doConformanceTests(&test, j)
- }
- }
-}
-
-// PerformanceTest verifies that normalization is O(n). If any of the
-// code does not properly check for maxCombiningChars, normalization
-// may exhibit O(n**2) behavior.
-func PerformanceTest() {
- runtime.GOMAXPROCS(2)
- success := make(chan bool, 1)
- go func() {
- buf := bytes.Repeat([]byte("\u035D"), 1024*1024)
- buf = append(buf, "\u035B"...)
- norm.NFC.Append(nil, buf...)
- success <- true
- }()
- timeout := time.After(1 * time.Second)
- select {
- case <-success:
- // test completed before the timeout
- case <-timeout:
- errorCount++
- logger.Printf(`unexpectedly long time to complete PerformanceTest`)
- }
-}
diff --git a/src/pkg/exp/norm/readwriter.go b/src/pkg/exp/norm/readwriter.go
deleted file mode 100644
index 2682894de..000000000
--- a/src/pkg/exp/norm/readwriter.go
+++ /dev/null
@@ -1,126 +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 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 30 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
- }
- }
- }
- panic("should not reach here")
-}
-
-// 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/src/pkg/exp/norm/readwriter_test.go b/src/pkg/exp/norm/readwriter_test.go
deleted file mode 100644
index 3b49eb0a2..000000000
--- a/src/pkg/exp/norm/readwriter_test.go
+++ /dev/null
@@ -1,68 +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 norm
-
-import (
- "bytes"
- "fmt"
- "strings"
- "testing"
-)
-
-var ioTests = []AppendTest{
- {"", strings.Repeat("a\u0316\u0300", 6), strings.Repeat("\u00E0\u0316", 6)},
- {"", strings.Repeat("a\u0300\u0316", 4000), strings.Repeat("\u00E0\u0316", 4000)},
- {"", strings.Repeat("\x80\x80", 4000), strings.Repeat("\x80\x80", 4000)},
- {"", "\u0041\u0307\u0304", "\u01E0"},
-}
-
-var bufSizes = []int{1, 2, 3, 4, 5, 6, 7, 8, 100, 101, 102, 103, 4000, 4001, 4002, 4003}
-
-func readFunc(size int) appendFunc {
- return func(f Form, out []byte, s string) []byte {
- out = append(out, s...)
- r := f.Reader(bytes.NewBuffer(out))
- buf := make([]byte, size)
- result := []byte{}
- for n, err := 0, error(nil); err == nil; {
- n, err = r.Read(buf)
- result = append(result, buf[:n]...)
- }
- return result
- }
-}
-
-func TestReader(t *testing.T) {
- for _, s := range bufSizes {
- name := fmt.Sprintf("TestReader%da", s)
- runAppendTests(t, name, NFKC, readFunc(s), appendTests)
- name = fmt.Sprintf("TestReader%db", s)
- runAppendTests(t, name, NFKC, readFunc(s), ioTests)
- }
-}
-
-func writeFunc(size int) appendFunc {
- return func(f Form, out []byte, s string) []byte {
- in := append(out, s...)
- result := new(bytes.Buffer)
- w := f.Writer(result)
- buf := make([]byte, size)
- for n := 0; len(in) > 0; in = in[n:] {
- n = copy(buf, in)
- _, _ = w.Write(buf[:n])
- }
- w.Close()
- return result.Bytes()
- }
-}
-
-func TestWriter(t *testing.T) {
- for _, s := range bufSizes {
- name := fmt.Sprintf("TestWriter%da", s)
- runAppendTests(t, name, NFKC, writeFunc(s), appendTests)
- name = fmt.Sprintf("TestWriter%db", s)
- runAppendTests(t, name, NFKC, writeFunc(s), ioTests)
- }
-}
diff --git a/src/pkg/exp/norm/tables.go b/src/pkg/exp/norm/tables.go
deleted file mode 100644
index fa33a34a1..000000000
--- a/src/pkg/exp/norm/tables.go
+++ /dev/null
@@ -1,6779 +0,0 @@
-// Generated by running
-// maketables --tables=all --url=http://www.unicode.org/Public/6.2.0/ucd/
-// DO NOT EDIT
-
-package norm
-
-// Version is the Unicode edition from which the tables are derived.
-const Version = "6.2.0"
-
-const (
- firstMulti = 0x18CF
- firstCCC = 0x2E74
- endMulti = 0x2F4A
- firstLeadingCCC = 0x4994
- firstCCCZeroExcept = 0x49AA
- lastDecomp = 0x49D1
- maxDecomp = 0x8000
-)
-
-// decomps: 18897 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,
- 0xB4, 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,
- // Bytes 100 - 13f
- 0x92, 0x42, 0xC9, 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, 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,
- 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, 0xD8, 0xA9, 0x42, 0xD8, 0xAA, 0x42,
- // Bytes 240 - 27f
- 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, 0x84, 0x42, 0xD9, 0x85, 0x42, 0xD9,
- // Bytes 280 - 2bf
- 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, 0x42, 0xDA, 0x8D, 0x42, 0xDA, 0x8E,
- // Bytes 2c0 - 2ff
- 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, 0xDB, 0x8B, 0x42, 0xDB, 0x8C, 0x42,
- // Bytes 300 - 33f
- 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, 0xE1, 0x84, 0x8B, 0x43, 0xE1, 0x84,
- // Bytes 340 - 37f
- 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, 0xE1, 0x84, 0xA2, 0x43, 0xE1, 0x84,
- // Bytes 380 - 3bf
- 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, 0xE1, 0x85, 0x99, 0x43, 0xE1, 0x85,
- // Bytes 3c0 - 3ff
- 0xA0, 0x43, 0xE1, 0x85, 0xA1, 0x43, 0xE1, 0x85,
- 0xA2, 0x43, 0xE1, 0x85, 0xA3, 0x43, 0xE1, 0x85,
- 0xA4, 0x43, 0xE1, 0x85, 0xA5, 0x43, 0xE1, 0x85,
- 0xA6, 0x43, 0xE1, 0x85, 0xA7, 0x43, 0xE1, 0x85,
- 0xA8, 0x43, 0xE1, 0x85, 0xA9, 0x43, 0xE1, 0x85,
- 0xAA, 0x43, 0xE1, 0x85, 0xAB, 0x43, 0xE1, 0x85,
- 0xAC, 0x43, 0xE1, 0x85, 0xAD, 0x43, 0xE1, 0x85,
- 0xAE, 0x43, 0xE1, 0x85, 0xAF, 0x43, 0xE1, 0x85,
- // Bytes 400 - 43f
- 0xB0, 0x43, 0xE1, 0x85, 0xB1, 0x43, 0xE1, 0x85,
- 0xB2, 0x43, 0xE1, 0x85, 0xB3, 0x43, 0xE1, 0x85,
- 0xB4, 0x43, 0xE1, 0x85, 0xB5, 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, 0x86,
- 0xAA, 0x43, 0xE1, 0x86, 0xAC, 0x43, 0xE1, 0x86,
- // Bytes 440 - 47f
- 0xAD, 0x43, 0xE1, 0x86, 0xB0, 0x43, 0xE1, 0x86,
- 0xB1, 0x43, 0xE1, 0x86, 0xB2, 0x43, 0xE1, 0x86,
- 0xB3, 0x43, 0xE1, 0x86, 0xB4, 0x43, 0xE1, 0x86,
- 0xB5, 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, 0xE1, 0x87, 0x99, 0x43, 0xE1, 0x87,
- 0x9D, 0x43, 0xE1, 0x87, 0x9F, 0x43, 0xE1, 0x87,
- // Bytes 480 - 4bf
- 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, 0xE2, 0x80, 0x93, 0x43, 0xE2, 0x80,
- 0x94, 0x43, 0xE2, 0x82, 0xA9, 0x43, 0xE2, 0x86,
- // Bytes 4c0 - 4ff
- 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, 0xE2, 0xB5, 0xA1, 0x43, 0xE3, 0x80,
- 0x81, 0x43, 0xE3, 0x80, 0x82, 0x43, 0xE3, 0x80,
- // Bytes 500 - 53f
- 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, 0xE3, 0x80, 0x96, 0x43, 0xE3, 0x80,
- 0x97, 0x43, 0xE3, 0x82, 0xA1, 0x43, 0xE3, 0x82,
- // Bytes 540 - 57f
- 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, 0xE3, 0x82, 0xB3, 0x43, 0xE3, 0x82,
- 0xB5, 0x43, 0xE3, 0x82, 0xB7, 0x43, 0xE3, 0x82,
- // Bytes 580 - 5bf
- 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, 0xE3, 0x83, 0x8E, 0x43, 0xE3, 0x83,
- 0x8F, 0x43, 0xE3, 0x83, 0x92, 0x43, 0xE3, 0x83,
- // Bytes 5c0 - 5ff
- 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, 0xE3, 0x83, 0xA8, 0x43, 0xE3, 0x83,
- 0xA9, 0x43, 0xE3, 0x83, 0xAA, 0x43, 0xE3, 0x83,
- // Bytes 600 - 63f
- 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, 0xE3, 0x93, 0x9F, 0x43, 0xE3, 0x94,
- 0x95, 0x43, 0xE3, 0x9B, 0xAE, 0x43, 0xE3, 0x9B,
- // Bytes 640 - 67f
- 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, 0xE3, 0xAC, 0x99, 0x43, 0xE3, 0xAD,
- 0x89, 0x43, 0xE3, 0xAE, 0x9D, 0x43, 0xE3, 0xB0,
- // Bytes 680 - 6bf
- 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, 0xE4, 0x83, 0xA3, 0x43, 0xE4, 0x84,
- 0xAF, 0x43, 0xE4, 0x88, 0x82, 0x43, 0xE4, 0x88,
- // Bytes 6c0 - 6ff
- 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, 0xE4, 0x97, 0x97, 0x43, 0xE4, 0x97,
- 0xB9, 0x43, 0xE4, 0x98, 0xB5, 0x43, 0xE4, 0x9A,
- // Bytes 700 - 73f
- 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, 0xE4, 0xB8, 0x80, 0x43, 0xE4, 0xB8,
- 0x81, 0x43, 0xE4, 0xB8, 0x83, 0x43, 0xE4, 0xB8,
- // Bytes 740 - 77f
- 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, 0xE4, 0xB8, 0xBF, 0x43, 0xE4, 0xB9,
- 0x81, 0x43, 0xE4, 0xB9, 0x99, 0x43, 0xE4, 0xB9,
- // Bytes 780 - 7bf
- 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, 0xE4, 0xBC, 0x81, 0x43, 0xE4, 0xBC,
- 0x91, 0x43, 0xE4, 0xBD, 0xA0, 0x43, 0xE4, 0xBE,
- // Bytes 7c0 - 7ff
- 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, 0xE5, 0x84, 0xAA, 0x43, 0xE5, 0x84,
- 0xBF, 0x43, 0xE5, 0x85, 0x80, 0x43, 0xE5, 0x85,
- // Bytes 800 - 83f
- 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, 0xE5, 0x86, 0x8D, 0x43, 0xE5, 0x86,
- 0x92, 0x43, 0xE5, 0x86, 0x95, 0x43, 0xE5, 0x86,
- // Bytes 840 - 87f
- 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, 0xE5, 0x87, 0xB5, 0x43, 0xE5, 0x88,
- 0x80, 0x43, 0xE5, 0x88, 0x83, 0x43, 0xE5, 0x88,
- // Bytes 880 - 8bf
- 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, 0xE5, 0x8A, 0xB3, 0x43, 0xE5, 0x8A,
- 0xB4, 0x43, 0xE5, 0x8B, 0x87, 0x43, 0xE5, 0x8B,
- // Bytes 8c0 - 8ff
- 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, 0xE5, 0x8C, 0xBB, 0x43, 0xE5, 0x8C,
- 0xBF, 0x43, 0xE5, 0x8D, 0x81, 0x43, 0xE5, 0x8D,
- // Bytes 900 - 93f
- 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, 0xE5, 0x8E, 0x82, 0x43, 0xE5, 0x8E,
- 0xB6, 0x43, 0xE5, 0x8F, 0x83, 0x43, 0xE5, 0x8F,
- // Bytes 940 - 97f
- 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, 0xE5, 0x90, 0x8F, 0x43, 0xE5, 0x90,
- 0x9D, 0x43, 0xE5, 0x90, 0xB8, 0x43, 0xE5, 0x90,
- // Bytes 980 - 9bf
- 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, 0xE5, 0x96, 0x84, 0x43, 0xE5, 0x96,
- 0x87, 0x43, 0xE5, 0x96, 0x99, 0x43, 0xE5, 0x96,
- // Bytes 9c0 - 9ff
- 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, 0xE5, 0x9B, 0xB9, 0x43, 0xE5, 0x9C,
- 0x96, 0x43, 0xE5, 0x9C, 0x97, 0x43, 0xE5, 0x9C,
- // Bytes a00 - a3f
- 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, 0xE5, 0xA2, 0xB3, 0x43, 0xE5, 0xA3,
- 0x98, 0x43, 0xE5, 0xA3, 0x9F, 0x43, 0xE5, 0xA3,
- // Bytes a40 - a7f
- 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, 0xE5, 0xA4, 0xA9, 0x43, 0xE5, 0xA5,
- 0x84, 0x43, 0xE5, 0xA5, 0x88, 0x43, 0xE5, 0xA5,
- // Bytes a80 - abf
- 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, 0xE5, 0xAC, 0xBE, 0x43, 0xE5, 0xAD,
- 0x90, 0x43, 0xE5, 0xAD, 0x97, 0x43, 0xE5, 0xAD,
- // Bytes ac0 - aff
- 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, 0xE5, 0xB0, 0xA2, 0x43, 0xE5, 0xB0,
- 0xB8, 0x43, 0xE5, 0xB0, 0xBF, 0x43, 0xE5, 0xB1,
- // Bytes b00 - b3f
- 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, 0xE5, 0xB5, 0xBC, 0x43, 0xE5, 0xB6,
- 0xB2, 0x43, 0xE5, 0xB6, 0xBA, 0x43, 0xE5, 0xB7,
- // Bytes b40 - b7f
- 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, 0xE5, 0xB9, 0xBA, 0x43, 0xE5, 0xB9,
- 0xBC, 0x43, 0xE5, 0xB9, 0xBF, 0x43, 0xE5, 0xBA,
- // Bytes b80 - bbf
- 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, 0xE5, 0xBC, 0x8B, 0x43, 0xE5, 0xBC,
- 0x93, 0x43, 0xE5, 0xBC, 0xA2, 0x43, 0xE5, 0xBD,
- // Bytes bc0 - bff
- 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, 0xE5, 0xBF, 0x83, 0x43, 0xE5, 0xBF,
- 0x8D, 0x43, 0xE5, 0xBF, 0x97, 0x43, 0xE5, 0xBF,
- // Bytes c00 - c3f
- 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, 0xE6, 0x85, 0x8C, 0x43, 0xE6, 0x85,
- 0x8E, 0x43, 0xE6, 0x85, 0xA0, 0x43, 0xE6, 0x85,
- // Bytes c40 - c7f
- 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, 0xE6, 0x88, 0x9B, 0x43, 0xE6, 0x88,
- 0xAE, 0x43, 0xE6, 0x88, 0xB4, 0x43, 0xE6, 0x88,
- // Bytes c80 - cbf
- 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, 0xE6, 0x8C, 0xBD, 0x43, 0xE6, 0x8D,
- 0x90, 0x43, 0xE6, 0x8D, 0x95, 0x43, 0xE6, 0x8D,
- // Bytes cc0 - cff
- 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, 0xE6, 0x91, 0xBE, 0x43, 0xE6, 0x92,
- 0x9A, 0x43, 0xE6, 0x92, 0x9D, 0x43, 0xE6, 0x93,
- // Bytes d00 - d3f
- 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, 0xE6, 0x97, 0x85, 0x43, 0xE6, 0x97,
- 0xA0, 0x43, 0xE6, 0x97, 0xA2, 0x43, 0xE6, 0x97,
- // Bytes d40 - d7f
- 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, 0xE6, 0x9B, 0xB8, 0x43, 0xE6, 0x9C,
- 0x80, 0x43, 0xE6, 0x9C, 0x88, 0x43, 0xE6, 0x9C,
- // Bytes d80 - dbf
- 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, 0xE6, 0x9F, 0xBA, 0x43, 0xE6, 0xA0,
- 0x97, 0x43, 0xE6, 0xA0, 0x9F, 0x43, 0xE6, 0xA0,
- // Bytes dc0 - dff
- 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, 0xE6, 0xAB, 0x93, 0x43, 0xE6, 0xAB,
- 0x9B, 0x43, 0xE6, 0xAC, 0x84, 0x43, 0xE6, 0xAC,
- // Bytes e00 - e3f
- 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, 0xE6, 0xAF, 0x8B, 0x43, 0xE6, 0xAF,
- 0x8D, 0x43, 0xE6, 0xAF, 0x94, 0x43, 0xE6, 0xAF,
- // Bytes e40 - e7f
- 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, 0xE6, 0xB4, 0x9B, 0x43, 0xE6, 0xB4,
- 0x9E, 0x43, 0xE6, 0xB4, 0xB4, 0x43, 0xE6, 0xB4,
- // Bytes e80 - ebf
- 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, 0xE6, 0xB9, 0xAE, 0x43, 0xE6, 0xBA,
- 0x80, 0x43, 0xE6, 0xBA, 0x9C, 0x43, 0xE6, 0xBA,
- // Bytes ec0 - eff
- 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, 0xE7, 0x80, 0x9B, 0x43, 0xE7, 0x80,
- 0x9E, 0x43, 0xE7, 0x80, 0xB9, 0x43, 0xE7, 0x81,
- // Bytes f00 - f3f
- 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, 0xE7, 0x86, 0x9C, 0x43, 0xE7, 0x87,
- 0x8E, 0x43, 0xE7, 0x87, 0x90, 0x43, 0xE7, 0x88,
- // Bytes f40 - f7f
- 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, 0xE7, 0x89, 0xA2, 0x43, 0xE7, 0x89,
- 0xB9, 0x43, 0xE7, 0x8A, 0x80, 0x43, 0xE7, 0x8A,
- // Bytes f80 - fbf
- 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, 0xE7, 0x8E, 0xB2, 0x43, 0xE7, 0x8F,
- 0x9E, 0x43, 0xE7, 0x90, 0x86, 0x43, 0xE7, 0x90,
- // Bytes fc0 - fff
- 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, 0xE7, 0x94, 0x98, 0x43, 0xE7, 0x94,
- 0x9F, 0x43, 0xE7, 0x94, 0xA4, 0x43, 0xE7, 0x94,
- // Bytes 1000 - 103f
- 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, 0xE7, 0x98, 0x90, 0x43, 0xE7, 0x98,
- 0x9D, 0x43, 0xE7, 0x98, 0x9F, 0x43, 0xE7, 0x99,
- // Bytes 1040 - 107f
- 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, 0xE7, 0x9C, 0x9E, 0x43, 0xE7, 0x9C,
- 0x9F, 0x43, 0xE7, 0x9D, 0x80, 0x43, 0xE7, 0x9D,
- // Bytes 1080 - 10bf
- 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, 0xE7, 0xA4, 0xAA, 0x43, 0xE7, 0xA4,
- 0xBA, 0x43, 0xE7, 0xA4, 0xBC, 0x43, 0xE7, 0xA4,
- // Bytes 10c0 - 10ff
- 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, 0xE7, 0xA6, 0xAE, 0x43, 0xE7, 0xA6,
- 0xB8, 0x43, 0xE7, 0xA6, 0xBE, 0x43, 0xE7, 0xA7,
- // Bytes 1100 - 113f
- 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, 0xE7, 0xAB, 0xB9, 0x43, 0xE7, 0xAC,
- 0xA0, 0x43, 0xE7, 0xAE, 0x8F, 0x43, 0xE7, 0xAF,
- // Bytes 1140 - 117f
- 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, 0xE7, 0xB3, 0xA8, 0x43, 0xE7, 0xB3,
- 0xB8, 0x43, 0xE7, 0xB4, 0x80, 0x43, 0xE7, 0xB4,
- // Bytes 1180 - 11bf
- 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, 0xE7, 0xB9, 0x81, 0x43, 0xE7, 0xB9,
- 0x85, 0x43, 0xE7, 0xBC, 0xB6, 0x43, 0xE7, 0xBC,
- // Bytes 11c0 - 11ff
- 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, 0xE8, 0x80, 0x8C, 0x43, 0xE8, 0x80,
- 0x92, 0x43, 0xE8, 0x80, 0xB3, 0x43, 0xE8, 0x81,
- // Bytes 1200 - 123f
- 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, 0xE8, 0x87, 0xA3, 0x43, 0xE8, 0x87,
- 0xA8, 0x43, 0xE8, 0x87, 0xAA, 0x43, 0xE8, 0x87,
- // Bytes 1240 - 127f
- 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, 0xE8, 0x89, 0xB9, 0x43, 0xE8, 0x8A,
- 0x8B, 0x43, 0xE8, 0x8A, 0x91, 0x43, 0xE8, 0x8A,
- // Bytes 1280 - 12bf
- 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, 0xE8, 0x8E, 0xBD, 0x43, 0xE8, 0x8F,
- 0x89, 0x43, 0xE8, 0x8F, 0x8A, 0x43, 0xE8, 0x8F,
- // Bytes 12c0 - 12ff
- 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, 0xE8, 0x95, 0xA4, 0x43, 0xE8, 0x97,
- 0x8D, 0x43, 0xE8, 0x97, 0xBA, 0x43, 0xE8, 0x98,
- // Bytes 1300 - 133f
- 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, 0xE8, 0x9C, 0x8E, 0x43, 0xE8, 0x9C,
- 0xA8, 0x43, 0xE8, 0x9D, 0xAB, 0x43, 0xE8, 0x9D,
- // Bytes 1340 - 137f
- 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, 0xE8, 0xA3, 0x9E, 0x43, 0xE8, 0xA3,
- 0xA1, 0x43, 0xE8, 0xA3, 0xB8, 0x43, 0xE8, 0xA3,
- // Bytes 1380 - 13bf
- 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, 0xE8, 0xAA, 0xBF, 0x43, 0xE8, 0xAB,
- 0x8B, 0x43, 0xE8, 0xAB, 0x92, 0x43, 0xE8, 0xAB,
- // Bytes 13c0 - 13ff
- 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, 0xE8, 0xB1, 0xB8, 0x43, 0xE8, 0xB2,
- 0x9D, 0x43, 0xE8, 0xB2, 0xA1, 0x43, 0xE8, 0xB2,
- // Bytes 1400 - 143f
- 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, 0xE8, 0xB6, 0xBC, 0x43, 0xE8, 0xB7,
- 0x8B, 0x43, 0xE8, 0xB7, 0xAF, 0x43, 0xE8, 0xB7,
- // Bytes 1440 - 147f
- 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, 0xE8, 0xBE, 0xB6, 0x43, 0xE9, 0x80,
- 0xA3, 0x43, 0xE9, 0x80, 0xB8, 0x43, 0xE9, 0x81,
- // Bytes 1480 - 14bf
- 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, 0xE9, 0x85, 0x89, 0x43, 0xE9, 0x85,
- 0xAA, 0x43, 0xE9, 0x86, 0x99, 0x43, 0xE9, 0x86,
- // Bytes 14c0 - 14ff
- 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, 0xE9, 0x8D,
- 0x8A, 0x43, 0xE9, 0x8F, 0xB9, 0x43, 0xE9, 0x90,
- 0x95, 0x43, 0xE9, 0x95, 0xB7, 0x43, 0xE9, 0x96,
- // Bytes 1500 - 153f
- 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, 0xE9, 0x9A,
- 0xA3, 0x43, 0xE9, 0x9A, 0xB6, 0x43, 0xE9, 0x9A,
- 0xB7, 0x43, 0xE9, 0x9A, 0xB8, 0x43, 0xE9, 0x9A,
- // Bytes 1540 - 157f
- 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, 0xE9, 0x9D,
- 0x9E, 0x43, 0xE9, 0x9D, 0xA2, 0x43, 0xE9, 0x9D,
- 0xA9, 0x43, 0xE9, 0x9F, 0x8B, 0x43, 0xE9, 0x9F,
- // Bytes 1580 - 15bf
- 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, 0xE9, 0xA2,
- 0xA8, 0x43, 0xE9, 0xA3, 0x9B, 0x43, 0xE9, 0xA3,
- 0x9F, 0x43, 0xE9, 0xA3, 0xA2, 0x43, 0xE9, 0xA3,
- // Bytes 15c0 - 15ff
- 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, 0xE9, 0xAA,
- 0xA8, 0x43, 0xE9, 0xAB, 0x98, 0x43, 0xE9, 0xAB,
- 0x9F, 0x43, 0xE9, 0xAC, 0x92, 0x43, 0xE9, 0xAC,
- // Bytes 1600 - 163f
- 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, 0xE9, 0xB7,
- 0xBA, 0x43, 0xE9, 0xB8, 0x9E, 0x43, 0xE9, 0xB9,
- 0xB5, 0x43, 0xE9, 0xB9, 0xBF, 0x43, 0xE9, 0xBA,
- // Bytes 1640 - 167f
- 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, 0xE9, 0xBC,
- 0x8E, 0x43, 0xE9, 0xBC, 0x8F, 0x43, 0xE9, 0xBC,
- 0x93, 0x43, 0xE9, 0xBC, 0x96, 0x43, 0xE9, 0xBC,
- // Bytes 1680 - 16bf
- 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, 0x9D,
- 0xAF, 0x44, 0xF0, 0xA0, 0x84, 0xA2, 0x44, 0xF0,
- 0xA0, 0x94, 0x9C, 0x44, 0xF0, 0xA0, 0x94, 0xA5,
- 0x44, 0xF0, 0xA0, 0x95, 0x8B, 0x44, 0xF0, 0xA0,
- // Bytes 16c0 - 16ff
- 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, 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,
- // Bytes 1700 - 173f
- 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, 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,
- // Bytes 1740 - 177f
- 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, 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,
- // Bytes 1780 - 17bf
- 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, 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,
- // Bytes 17c0 - 17ff
- 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, 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,
- // Bytes 1800 - 183f
- 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, 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,
- // Bytes 1840 - 187f
- 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, 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,
- // Bytes 1880 - 18bf
- 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, 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,
- // Bytes 18c0 - 18ff
- 0x44, 0xF0, 0xAA, 0x8A, 0x91, 0x44, 0xF0, 0xAA,
- 0x8E, 0x92, 0x44, 0xF0, 0xAA, 0x98, 0x80, 0x06,
- 0xE0, 0xA7, 0x87, 0xE0, 0xA6, 0xBE, 0x06, 0xE0,
- 0xA7, 0x87, 0xE0, 0xA7, 0x97, 0x06, 0xE0, 0xAD,
- 0x87, 0xE0, 0xAC, 0xBE, 0x06, 0xE0, 0xAD, 0x87,
- 0xE0, 0xAD, 0x96, 0x06, 0xE0, 0xAD, 0x87, 0xE0,
- 0xAD, 0x97, 0x06, 0xE0, 0xAE, 0x92, 0xE0, 0xAF,
- 0x97, 0x06, 0xE0, 0xAF, 0x86, 0xE0, 0xAE, 0xBE,
- // Bytes 1900 - 193f
- 0x06, 0xE0, 0xAF, 0x86, 0xE0, 0xAF, 0x97, 0x06,
- 0xE0, 0xAF, 0x87, 0xE0, 0xAE, 0xBE, 0x06, 0xE0,
- 0xB2, 0xBF, 0xE0, 0xB3, 0x95, 0x06, 0xE0, 0xB3,
- 0x86, 0xE0, 0xB3, 0x95, 0x06, 0xE0, 0xB3, 0x86,
- 0xE0, 0xB3, 0x96, 0x06, 0xE0, 0xB5, 0x86, 0xE0,
- 0xB4, 0xBE, 0x06, 0xE0, 0xB5, 0x86, 0xE0, 0xB5,
- 0x97, 0x06, 0xE0, 0xB5, 0x87, 0xE0, 0xB4, 0xBE,
- 0x06, 0xE0, 0xB7, 0x99, 0xE0, 0xB7, 0x9F, 0x06,
- // Bytes 1940 - 197f
- 0xE1, 0x80, 0xA5, 0xE1, 0x80, 0xAE, 0x06, 0xE1,
- 0xAC, 0x85, 0xE1, 0xAC, 0xB5, 0x06, 0xE1, 0xAC,
- 0x87, 0xE1, 0xAC, 0xB5, 0x06, 0xE1, 0xAC, 0x89,
- 0xE1, 0xAC, 0xB5, 0x06, 0xE1, 0xAC, 0x8B, 0xE1,
- 0xAC, 0xB5, 0x06, 0xE1, 0xAC, 0x8D, 0xE1, 0xAC,
- 0xB5, 0x06, 0xE1, 0xAC, 0x91, 0xE1, 0xAC, 0xB5,
- 0x06, 0xE1, 0xAC, 0xBA, 0xE1, 0xAC, 0xB5, 0x06,
- 0xE1, 0xAC, 0xBC, 0xE1, 0xAC, 0xB5, 0x06, 0xE1,
- // Bytes 1980 - 19bf
- 0xAC, 0xBE, 0xE1, 0xAC, 0xB5, 0x06, 0xE1, 0xAC,
- 0xBF, 0xE1, 0xAC, 0xB5, 0x06, 0xE1, 0xAD, 0x82,
- 0xE1, 0xAC, 0xB5, 0x08, 0xF0, 0x91, 0x84, 0xB1,
- 0xF0, 0x91, 0x84, 0xA7, 0x08, 0xF0, 0x91, 0x84,
- 0xB2, 0xF0, 0x91, 0x84, 0xA7, 0x09, 0xE0, 0xB3,
- 0x86, 0xE0, 0xB3, 0x82, 0xE0, 0xB3, 0x95, 0x42,
- 0x21, 0x21, 0x42, 0x21, 0x3F, 0x42, 0x2E, 0x2E,
- 0x42, 0x30, 0x2C, 0x42, 0x30, 0x2E, 0x42, 0x31,
- // Bytes 19c0 - 19ff
- 0x2C, 0x42, 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,
- // Bytes 1a00 - 1a3f
- 0x42, 0x32, 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,
- // Bytes 1a40 - 1a7f
- 0x34, 0x35, 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,
- // Bytes 1a80 - 1abf
- 0x44, 0x42, 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,
- // Bytes 1ac0 - 1aff
- 0x42, 0x4D, 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,
- // Bytes 1b00 - 1b3f
- 0x63, 0x64, 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,
- // Bytes 1b40 - 1b7f
- 0x67, 0x42, 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,
- // Bytes 1b80 - 1bbf
- 0x42, 0x6E, 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,
- // Bytes 1bc0 - 1bff
- 0x36, 0x29, 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,
- // Bytes 1c00 - 1c3f
- 0x4D, 0x29, 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,
- // Bytes 1c40 - 1c7f
- 0x63, 0x29, 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,
- // Bytes 1c80 - 1cbf
- 0x73, 0x29, 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,
- // Bytes 1cc0 - 1cff
- 0x37, 0x2E, 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,
- // Bytes 1d00 - 1d3f
- 0x50, 0x4D, 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,
- // Bytes 1d40 - 1d7f
- 0x6D, 0x32, 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,
- // Bytes 1d80 - 1dbf
- 0x6D, 0x32, 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,
- // Bytes 1dc0 - 1dff
- 0xBC, 0x73, 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,
- // Bytes 1e00 - 1e3f
- 0xE2, 0x81, 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,
- // Bytes 1e40 - 1e7f
- 0x35, 0xE6, 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,
- // Bytes 1e80 - 1ebf
- 0x44, 0x39, 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,
- // Bytes 1ec0 - 1eff
- 0xB6, 0x44, 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,
- // Bytes 1f00 - 1f3f
- 0xD8, 0xAC, 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,
- // Bytes 1f40 - 1f7f
- 0xAB, 0xD9, 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,
- // Bytes 1f80 - 1fbf
- 0xD8, 0xAE, 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,
- // Bytes 1fc0 - 1fff
- 0x44, 0xD8, 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,
- // Bytes 2000 - 203f
- 0x89, 0x44, 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,
- // Bytes 2040 - 207f
- 0xD9, 0x85, 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,
- // Bytes 2080 - 20bf
- 0x81, 0xD9, 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,
- // Bytes 20c0 - 20ff
- 0xD9, 0x83, 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,
- // Bytes 2100 - 213f
- 0x44, 0xD9, 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,
- // Bytes 2140 - 217f
- 0x8A, 0x44, 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,
- // Bytes 2180 - 21bf
- 0xD9, 0x87, 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,
- // Bytes 21c0 - 21ff
- 0x45, 0x28, 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,
- // Bytes 2200 - 223f
- 0x9D, 0x29, 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,
- // Bytes 2240 - 227f
- 0xE5, 0x90, 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,
- // Bytes 2280 - 22bf
- 0x45, 0x28, 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,
- // Bytes 22c0 - 22ff
- 0x91, 0x29, 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,
- // Bytes 2300 - 233f
- 0x33, 0xE6, 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,
- // Bytes 2340 - 237f
- 0x45, 0x31, 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,
- // Bytes 2380 - 23bf
- 0x84, 0x39, 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,
- // Bytes 23c0 - 23ff
- 0x35, 0xE6, 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,
- // Bytes 2400 - 243f
- 0x45, 0x33, 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,
- // Bytes 2440 - 247f
- 0xE2, 0x88, 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,
- // Bytes 2480 - 24bf
- 0xD8, 0xAE, 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,
- // Bytes 24c0 - 24ff
- 0x85, 0xD8, 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,
- // Bytes 2500 - 253f
- 0xD9, 0x89, 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,
- // Bytes 2540 - 257f
- 0x85, 0x46, 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,
- // Bytes 2580 - 25bf
- 0x46, 0xD8, 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,
- // Bytes 25c0 - 25ff
- 0xD9, 0x81, 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,
- // Bytes 2600 - 263f
- 0x84, 0xD8, 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,
- // Bytes 2640 - 267f
- 0xD8, 0xAC, 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,
- // Bytes 2680 - 26bf
- 0x85, 0xD9, 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,
- // Bytes 26c0 - 26ff
- 0xD9, 0x8A, 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,
- // Bytes 2700 - 273f
- 0xAD, 0x46, 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,
- // Bytes 2740 - 277f
- 0x46, 0xD9, 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,
- // Bytes 2780 - 27bf
- 0xE0, 0xBD, 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,
- // Bytes 27c0 - 27ff
- 0xBE, 0xA1, 0xE0, 0xBE, 0xB7, 0x46, 0xE0, 0xBE,
- 0xA6, 0xE0, 0xBE, 0xB7, 0x46, 0xE0, 0xBE, 0xAB,
- 0xE0, 0xBE, 0xB7, 0x46, 0xE1, 0x84, 0x80, 0xE1,
- 0x85, 0xA1, 0x46, 0xE1, 0x84, 0x82, 0xE1, 0x85,
- 0xA1, 0x46, 0xE1, 0x84, 0x83, 0xE1, 0x85, 0xA1,
- 0x46, 0xE1, 0x84, 0x85, 0xE1, 0x85, 0xA1, 0x46,
- 0xE1, 0x84, 0x86, 0xE1, 0x85, 0xA1, 0x46, 0xE1,
- 0x84, 0x87, 0xE1, 0x85, 0xA1, 0x46, 0xE1, 0x84,
- // Bytes 2800 - 283f
- 0x89, 0xE1, 0x85, 0xA1, 0x46, 0xE1, 0x84, 0x8B,
- 0xE1, 0x85, 0xA1, 0x46, 0xE1, 0x84, 0x8B, 0xE1,
- 0x85, 0xAE, 0x46, 0xE1, 0x84, 0x8C, 0xE1, 0x85,
- 0xA1, 0x46, 0xE1, 0x84, 0x8E, 0xE1, 0x85, 0xA1,
- 0x46, 0xE1, 0x84, 0x8F, 0xE1, 0x85, 0xA1, 0x46,
- 0xE1, 0x84, 0x90, 0xE1, 0x85, 0xA1, 0x46, 0xE1,
- 0x84, 0x91, 0xE1, 0x85, 0xA1, 0x46, 0xE1, 0x84,
- 0x92, 0xE1, 0x85, 0xA1, 0x46, 0xE2, 0x80, 0xB2,
- // Bytes 2840 - 287f
- 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, 0x83, 0xAD, 0x46, 0xE3, 0x82,
- 0xB3, 0xE3, 0x82, 0xB3, 0x46, 0xE3, 0x82, 0xB3,
- 0xE3, 0x83, 0x88, 0x46, 0xE3, 0x83, 0x88, 0xE3,
- // Bytes 2880 - 28bf
- 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, 0xA3, 0x46, 0xE5, 0xB9, 0xB3,
- 0xE6, 0x88, 0x90, 0x46, 0xE6, 0x98, 0x8E, 0xE6,
- 0xB2, 0xBB, 0x46, 0xE6, 0x98, 0xAD, 0xE5, 0x92,
- // Bytes 28c0 - 28ff
- 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, 0x29, 0x48, 0x28, 0xE1, 0x84,
- 0x85, 0xE1, 0x85, 0xA1, 0x29, 0x48, 0x28, 0xE1,
- 0x84, 0x86, 0xE1, 0x85, 0xA1, 0x29, 0x48, 0x28,
- // Bytes 2900 - 293f
- 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, 0x48, 0x28, 0xE1, 0x84, 0x8E,
- 0xE1, 0x85, 0xA1, 0x29, 0x48, 0x28, 0xE1, 0x84,
- 0x8F, 0xE1, 0x85, 0xA1, 0x29, 0x48, 0x28, 0xE1,
- // Bytes 2940 - 297f
- 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, 0xD8, 0xA7, 0xD9, 0x84, 0xD9,
- 0x84, 0xD9, 0x87, 0x48, 0xD8, 0xB1, 0xD8, 0xB3,
- 0xD9, 0x88, 0xD9, 0x84, 0x48, 0xD8, 0xB1, 0xDB,
- // Bytes 2980 - 29bf
- 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, 0x80, 0xB2, 0xE2, 0x80, 0xB2,
- 0xE2, 0x80, 0xB2, 0x49, 0xE2, 0x80, 0xB5, 0xE2,
- 0x80, 0xB5, 0xE2, 0x80, 0xB5, 0x49, 0xE2, 0x88,
- // Bytes 29c0 - 29ff
- 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, 0x9D, 0xE3, 0x80, 0x95, 0x49,
- 0xE3, 0x80, 0x94, 0xE5, 0xAE, 0x89, 0xE3, 0x80,
- 0x95, 0x49, 0xE3, 0x80, 0x94, 0xE6, 0x89, 0x93,
- // Bytes 2a00 - 2a3f
- 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, 0x49, 0xE3, 0x82, 0xA2, 0xE3,
- 0x83, 0xBC, 0xE3, 0x83, 0xAB, 0x49, 0xE3, 0x82,
- 0xA4, 0xE3, 0x83, 0xB3, 0xE3, 0x83, 0x81, 0x49,
- // Bytes 2a40 - 2a7f
- 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, 0xE3, 0x83, 0xBC, 0xE3, 0x82,
- 0xB9, 0x49, 0xE3, 0x82, 0xB3, 0xE3, 0x83, 0xAB,
- 0xE3, 0x83, 0x8A, 0x49, 0xE3, 0x82, 0xBB, 0xE3,
- // Bytes 2a80 - 2abf
- 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, 0x83, 0x88, 0x49, 0xE3, 0x83,
- 0x8F, 0xE3, 0x82, 0xA4, 0xE3, 0x83, 0x84, 0x49,
- 0xE3, 0x83, 0x92, 0xE3, 0x82, 0x99, 0xE3, 0x83,
- // Bytes 2ac0 - 2aff
- 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, 0x83, 0x9B, 0xE3, 0x83, 0xBC,
- 0xE3, 0x83, 0xAB, 0x49, 0xE3, 0x83, 0x9B, 0xE3,
- 0x83, 0xBC, 0xE3, 0x83, 0xB3, 0x49, 0xE3, 0x83,
- // Bytes 2b00 - 2b3f
- 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, 0xA2, 0xE3, 0x83, 0xB3, 0x49,
- 0xE3, 0x83, 0xAF, 0xE3, 0x83, 0x83, 0xE3, 0x83,
- 0x88, 0x4C, 0xE1, 0x84, 0x8C, 0xE1, 0x85, 0xAE,
- // Bytes 2b40 - 2b7f
- 0xE1, 0x84, 0x8B, 0xE1, 0x85, 0xB4, 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,
- 0x83, 0xBC, 0x4C, 0xE3, 0x82, 0xAB, 0xE3, 0x82,
- // Bytes 2b80 - 2bbf
- 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,
- 0xE3, 0x83, 0xBC, 0x4C, 0xE3, 0x82, 0xAD, 0xE3,
- // Bytes 2bc0 - 2bff
- 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,
- 0xBC, 0xE3, 0x82, 0xB9, 0x4C, 0xE3, 0x83, 0x8F,
- // Bytes 2c00 - 2c3f
- 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,
- 0x83, 0x8B, 0xE3, 0x83, 0x92, 0x4C, 0xE3, 0x83,
- // Bytes 2c40 - 2c7f
- 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,
- 0xE3, 0x83, 0x88, 0xE3, 0x83, 0xAB, 0x4C, 0xE3,
- // Bytes 2c80 - 2cbf
- 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,
- 0x84, 0x20, 0xD8, 0xAC, 0xD9, 0x84, 0xD8, 0xA7,
- // Bytes 2cc0 - 2cff
- 0xD9, 0x84, 0xD9, 0x87, 0x4F, 0xE1, 0x84, 0x8E,
- 0xE1, 0x85, 0xA1, 0xE1, 0x86, 0xB7, 0xE1, 0x84,
- 0x80, 0xE1, 0x85, 0xA9, 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,
- // Bytes 2d00 - 2d3f
- 0x83, 0xE3, 0x83, 0x88, 0x4F, 0xE3, 0x82, 0xB5,
- 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,
- // Bytes 2d40 - 2d7f
- 0xB3, 0xE3, 0x83, 0x88, 0x4F, 0xE3, 0x83, 0x9E,
- 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,
- // Bytes 2d80 - 2dbf
- 0x85, 0xA5, 0xE1, 0x86, 0xAB, 0x29, 0x52, 0xE3,
- 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,
- // Bytes 2dc0 - 2dff
- 0xE3, 0x82, 0xAF, 0xE3, 0x82, 0x99, 0xE3, 0x83,
- 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,
- // Bytes 2e00 - 2e3f
- 0x82, 0xA2, 0xE3, 0x82, 0xB9, 0xE3, 0x83, 0x88,
- 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,
- // Bytes 2e40 - 2e7f
- 0x99, 0xE3, 0x83, 0xB3, 0x61, 0xD8, 0xB5, 0xD9,
- 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, 0x86, 0xE0,
- 0xB3, 0x86, 0xE0, 0xB3, 0x82, 0x86, 0xE0, 0xB7,
- 0x99, 0xE0, 0xB7, 0x8F, 0x09, 0xE0, 0xB7, 0x99,
- 0xE0, 0xB7, 0x8F, 0xE0, 0xB7, 0x8A, 0x09, 0x44,
- // Bytes 2e80 - 2ebf
- 0x44, 0x5A, 0xCC, 0x8C, 0xE6, 0x44, 0x44, 0x7A,
- 0xCC, 0x8C, 0xE6, 0x44, 0x64, 0x7A, 0xCC, 0x8C,
- 0xE6, 0x46, 0xD9, 0x84, 0xD8, 0xA7, 0xD9, 0x93,
- 0xE6, 0x46, 0xD9, 0x84, 0xD8, 0xA7, 0xD9, 0x94,
- 0xE6, 0x46, 0xD9, 0x84, 0xD8, 0xA7, 0xD9, 0x95,
- 0xDC, 0x49, 0xE3, 0x83, 0xA1, 0xE3, 0x82, 0xAB,
- 0xE3, 0x82, 0x99, 0x08, 0x4C, 0xE3, 0x82, 0xAD,
- 0xE3, 0x82, 0x99, 0xE3, 0x82, 0xAB, 0xE3, 0x82,
- // Bytes 2ec0 - 2eff
- 0x99, 0x08, 0x4C, 0xE3, 0x82, 0xB3, 0xE3, 0x83,
- 0xBC, 0xE3, 0x83, 0x9B, 0xE3, 0x82, 0x9A, 0x08,
- 0x4C, 0xE3, 0x83, 0xA4, 0xE3, 0x83, 0xBC, 0xE3,
- 0x83, 0x88, 0xE3, 0x82, 0x99, 0x08, 0x4F, 0xE3,
- 0x82, 0xA4, 0xE3, 0x83, 0x8B, 0xE3, 0x83, 0xB3,
- 0xE3, 0x82, 0xAF, 0xE3, 0x82, 0x99, 0x08, 0x4F,
- 0xE3, 0x82, 0xB7, 0xE3, 0x83, 0xAA, 0xE3, 0x83,
- 0xB3, 0xE3, 0x82, 0xAF, 0xE3, 0x82, 0x99, 0x08,
- // Bytes 2f00 - 2f3f
- 0x4F, 0xE3, 0x83, 0x98, 0xE3, 0x82, 0x9A, 0xE3,
- 0x83, 0xBC, 0xE3, 0x82, 0xB7, 0xE3, 0x82, 0x99,
- 0x08, 0x4F, 0xE3, 0x83, 0x9B, 0xE3, 0x82, 0x9A,
- 0xE3, 0x83, 0xB3, 0xE3, 0x83, 0x88, 0xE3, 0x82,
- 0x99, 0x08, 0x52, 0xE3, 0x82, 0xA8, 0xE3, 0x82,
- 0xB9, 0xE3, 0x82, 0xAF, 0xE3, 0x83, 0xBC, 0xE3,
- 0x83, 0x88, 0xE3, 0x82, 0x99, 0x08, 0x52, 0xE3,
- 0x83, 0x95, 0xE3, 0x82, 0xA1, 0xE3, 0x83, 0xA9,
- // Bytes 2f40 - 2f7f
- 0xE3, 0x83, 0x83, 0xE3, 0x83, 0x88, 0xE3, 0x82,
- 0x99, 0x08, 0x03, 0x3C, 0xCC, 0xB8, 0x01, 0x03,
- 0x3D, 0xCC, 0xB8, 0x01, 0x03, 0x3E, 0xCC, 0xB8,
- 0x01, 0x03, 0x41, 0xCC, 0x80, 0xE6, 0x03, 0x41,
- 0xCC, 0x81, 0xE6, 0x03, 0x41, 0xCC, 0x83, 0xE6,
- 0x03, 0x41, 0xCC, 0x84, 0xE6, 0x03, 0x41, 0xCC,
- 0x89, 0xE6, 0x03, 0x41, 0xCC, 0x8C, 0xE6, 0x03,
- 0x41, 0xCC, 0x8F, 0xE6, 0x03, 0x41, 0xCC, 0x91,
- // Bytes 2f80 - 2fbf
- 0xE6, 0x03, 0x41, 0xCC, 0xA5, 0xDC, 0x03, 0x41,
- 0xCC, 0xA8, 0xCA, 0x03, 0x42, 0xCC, 0x87, 0xE6,
- 0x03, 0x42, 0xCC, 0xA3, 0xDC, 0x03, 0x42, 0xCC,
- 0xB1, 0xDC, 0x03, 0x43, 0xCC, 0x81, 0xE6, 0x03,
- 0x43, 0xCC, 0x82, 0xE6, 0x03, 0x43, 0xCC, 0x87,
- 0xE6, 0x03, 0x43, 0xCC, 0x8C, 0xE6, 0x03, 0x44,
- 0xCC, 0x87, 0xE6, 0x03, 0x44, 0xCC, 0x8C, 0xE6,
- 0x03, 0x44, 0xCC, 0xA3, 0xDC, 0x03, 0x44, 0xCC,
- // Bytes 2fc0 - 2fff
- 0xA7, 0xCA, 0x03, 0x44, 0xCC, 0xAD, 0xDC, 0x03,
- 0x44, 0xCC, 0xB1, 0xDC, 0x03, 0x45, 0xCC, 0x80,
- 0xE6, 0x03, 0x45, 0xCC, 0x81, 0xE6, 0x03, 0x45,
- 0xCC, 0x83, 0xE6, 0x03, 0x45, 0xCC, 0x86, 0xE6,
- 0x03, 0x45, 0xCC, 0x87, 0xE6, 0x03, 0x45, 0xCC,
- 0x88, 0xE6, 0x03, 0x45, 0xCC, 0x89, 0xE6, 0x03,
- 0x45, 0xCC, 0x8C, 0xE6, 0x03, 0x45, 0xCC, 0x8F,
- 0xE6, 0x03, 0x45, 0xCC, 0x91, 0xE6, 0x03, 0x45,
- // Bytes 3000 - 303f
- 0xCC, 0xA8, 0xCA, 0x03, 0x45, 0xCC, 0xAD, 0xDC,
- 0x03, 0x45, 0xCC, 0xB0, 0xDC, 0x03, 0x46, 0xCC,
- 0x87, 0xE6, 0x03, 0x47, 0xCC, 0x81, 0xE6, 0x03,
- 0x47, 0xCC, 0x82, 0xE6, 0x03, 0x47, 0xCC, 0x84,
- 0xE6, 0x03, 0x47, 0xCC, 0x86, 0xE6, 0x03, 0x47,
- 0xCC, 0x87, 0xE6, 0x03, 0x47, 0xCC, 0x8C, 0xE6,
- 0x03, 0x47, 0xCC, 0xA7, 0xCA, 0x03, 0x48, 0xCC,
- 0x82, 0xE6, 0x03, 0x48, 0xCC, 0x87, 0xE6, 0x03,
- // Bytes 3040 - 307f
- 0x48, 0xCC, 0x88, 0xE6, 0x03, 0x48, 0xCC, 0x8C,
- 0xE6, 0x03, 0x48, 0xCC, 0xA3, 0xDC, 0x03, 0x48,
- 0xCC, 0xA7, 0xCA, 0x03, 0x48, 0xCC, 0xAE, 0xDC,
- 0x03, 0x49, 0xCC, 0x80, 0xE6, 0x03, 0x49, 0xCC,
- 0x81, 0xE6, 0x03, 0x49, 0xCC, 0x82, 0xE6, 0x03,
- 0x49, 0xCC, 0x83, 0xE6, 0x03, 0x49, 0xCC, 0x84,
- 0xE6, 0x03, 0x49, 0xCC, 0x86, 0xE6, 0x03, 0x49,
- 0xCC, 0x87, 0xE6, 0x03, 0x49, 0xCC, 0x89, 0xE6,
- // Bytes 3080 - 30bf
- 0x03, 0x49, 0xCC, 0x8C, 0xE6, 0x03, 0x49, 0xCC,
- 0x8F, 0xE6, 0x03, 0x49, 0xCC, 0x91, 0xE6, 0x03,
- 0x49, 0xCC, 0xA3, 0xDC, 0x03, 0x49, 0xCC, 0xA8,
- 0xCA, 0x03, 0x49, 0xCC, 0xB0, 0xDC, 0x03, 0x4A,
- 0xCC, 0x82, 0xE6, 0x03, 0x4B, 0xCC, 0x81, 0xE6,
- 0x03, 0x4B, 0xCC, 0x8C, 0xE6, 0x03, 0x4B, 0xCC,
- 0xA3, 0xDC, 0x03, 0x4B, 0xCC, 0xA7, 0xCA, 0x03,
- 0x4B, 0xCC, 0xB1, 0xDC, 0x03, 0x4C, 0xCC, 0x81,
- // Bytes 30c0 - 30ff
- 0xE6, 0x03, 0x4C, 0xCC, 0x8C, 0xE6, 0x03, 0x4C,
- 0xCC, 0xA7, 0xCA, 0x03, 0x4C, 0xCC, 0xAD, 0xDC,
- 0x03, 0x4C, 0xCC, 0xB1, 0xDC, 0x03, 0x4D, 0xCC,
- 0x81, 0xE6, 0x03, 0x4D, 0xCC, 0x87, 0xE6, 0x03,
- 0x4D, 0xCC, 0xA3, 0xDC, 0x03, 0x4E, 0xCC, 0x80,
- 0xE6, 0x03, 0x4E, 0xCC, 0x81, 0xE6, 0x03, 0x4E,
- 0xCC, 0x83, 0xE6, 0x03, 0x4E, 0xCC, 0x87, 0xE6,
- 0x03, 0x4E, 0xCC, 0x8C, 0xE6, 0x03, 0x4E, 0xCC,
- // Bytes 3100 - 313f
- 0xA3, 0xDC, 0x03, 0x4E, 0xCC, 0xA7, 0xCA, 0x03,
- 0x4E, 0xCC, 0xAD, 0xDC, 0x03, 0x4E, 0xCC, 0xB1,
- 0xDC, 0x03, 0x4F, 0xCC, 0x80, 0xE6, 0x03, 0x4F,
- 0xCC, 0x81, 0xE6, 0x03, 0x4F, 0xCC, 0x86, 0xE6,
- 0x03, 0x4F, 0xCC, 0x89, 0xE6, 0x03, 0x4F, 0xCC,
- 0x8B, 0xE6, 0x03, 0x4F, 0xCC, 0x8C, 0xE6, 0x03,
- 0x4F, 0xCC, 0x8F, 0xE6, 0x03, 0x4F, 0xCC, 0x91,
- 0xE6, 0x03, 0x50, 0xCC, 0x81, 0xE6, 0x03, 0x50,
- // Bytes 3140 - 317f
- 0xCC, 0x87, 0xE6, 0x03, 0x52, 0xCC, 0x81, 0xE6,
- 0x03, 0x52, 0xCC, 0x87, 0xE6, 0x03, 0x52, 0xCC,
- 0x8C, 0xE6, 0x03, 0x52, 0xCC, 0x8F, 0xE6, 0x03,
- 0x52, 0xCC, 0x91, 0xE6, 0x03, 0x52, 0xCC, 0xA7,
- 0xCA, 0x03, 0x52, 0xCC, 0xB1, 0xDC, 0x03, 0x53,
- 0xCC, 0x82, 0xE6, 0x03, 0x53, 0xCC, 0x87, 0xE6,
- 0x03, 0x53, 0xCC, 0xA6, 0xDC, 0x03, 0x53, 0xCC,
- 0xA7, 0xCA, 0x03, 0x54, 0xCC, 0x87, 0xE6, 0x03,
- // Bytes 3180 - 31bf
- 0x54, 0xCC, 0x8C, 0xE6, 0x03, 0x54, 0xCC, 0xA3,
- 0xDC, 0x03, 0x54, 0xCC, 0xA6, 0xDC, 0x03, 0x54,
- 0xCC, 0xA7, 0xCA, 0x03, 0x54, 0xCC, 0xAD, 0xDC,
- 0x03, 0x54, 0xCC, 0xB1, 0xDC, 0x03, 0x55, 0xCC,
- 0x80, 0xE6, 0x03, 0x55, 0xCC, 0x81, 0xE6, 0x03,
- 0x55, 0xCC, 0x82, 0xE6, 0x03, 0x55, 0xCC, 0x86,
- 0xE6, 0x03, 0x55, 0xCC, 0x89, 0xE6, 0x03, 0x55,
- 0xCC, 0x8A, 0xE6, 0x03, 0x55, 0xCC, 0x8B, 0xE6,
- // Bytes 31c0 - 31ff
- 0x03, 0x55, 0xCC, 0x8C, 0xE6, 0x03, 0x55, 0xCC,
- 0x8F, 0xE6, 0x03, 0x55, 0xCC, 0x91, 0xE6, 0x03,
- 0x55, 0xCC, 0xA3, 0xDC, 0x03, 0x55, 0xCC, 0xA4,
- 0xDC, 0x03, 0x55, 0xCC, 0xA8, 0xCA, 0x03, 0x55,
- 0xCC, 0xAD, 0xDC, 0x03, 0x55, 0xCC, 0xB0, 0xDC,
- 0x03, 0x56, 0xCC, 0x83, 0xE6, 0x03, 0x56, 0xCC,
- 0xA3, 0xDC, 0x03, 0x57, 0xCC, 0x80, 0xE6, 0x03,
- 0x57, 0xCC, 0x81, 0xE6, 0x03, 0x57, 0xCC, 0x82,
- // Bytes 3200 - 323f
- 0xE6, 0x03, 0x57, 0xCC, 0x87, 0xE6, 0x03, 0x57,
- 0xCC, 0x88, 0xE6, 0x03, 0x57, 0xCC, 0xA3, 0xDC,
- 0x03, 0x58, 0xCC, 0x87, 0xE6, 0x03, 0x58, 0xCC,
- 0x88, 0xE6, 0x03, 0x59, 0xCC, 0x80, 0xE6, 0x03,
- 0x59, 0xCC, 0x81, 0xE6, 0x03, 0x59, 0xCC, 0x82,
- 0xE6, 0x03, 0x59, 0xCC, 0x83, 0xE6, 0x03, 0x59,
- 0xCC, 0x84, 0xE6, 0x03, 0x59, 0xCC, 0x87, 0xE6,
- 0x03, 0x59, 0xCC, 0x88, 0xE6, 0x03, 0x59, 0xCC,
- // Bytes 3240 - 327f
- 0x89, 0xE6, 0x03, 0x59, 0xCC, 0xA3, 0xDC, 0x03,
- 0x5A, 0xCC, 0x81, 0xE6, 0x03, 0x5A, 0xCC, 0x82,
- 0xE6, 0x03, 0x5A, 0xCC, 0x87, 0xE6, 0x03, 0x5A,
- 0xCC, 0x8C, 0xE6, 0x03, 0x5A, 0xCC, 0xA3, 0xDC,
- 0x03, 0x5A, 0xCC, 0xB1, 0xDC, 0x03, 0x61, 0xCC,
- 0x80, 0xE6, 0x03, 0x61, 0xCC, 0x81, 0xE6, 0x03,
- 0x61, 0xCC, 0x83, 0xE6, 0x03, 0x61, 0xCC, 0x84,
- 0xE6, 0x03, 0x61, 0xCC, 0x89, 0xE6, 0x03, 0x61,
- // Bytes 3280 - 32bf
- 0xCC, 0x8C, 0xE6, 0x03, 0x61, 0xCC, 0x8F, 0xE6,
- 0x03, 0x61, 0xCC, 0x91, 0xE6, 0x03, 0x61, 0xCC,
- 0xA5, 0xDC, 0x03, 0x61, 0xCC, 0xA8, 0xCA, 0x03,
- 0x62, 0xCC, 0x87, 0xE6, 0x03, 0x62, 0xCC, 0xA3,
- 0xDC, 0x03, 0x62, 0xCC, 0xB1, 0xDC, 0x03, 0x63,
- 0xCC, 0x81, 0xE6, 0x03, 0x63, 0xCC, 0x82, 0xE6,
- 0x03, 0x63, 0xCC, 0x87, 0xE6, 0x03, 0x63, 0xCC,
- 0x8C, 0xE6, 0x03, 0x64, 0xCC, 0x87, 0xE6, 0x03,
- // Bytes 32c0 - 32ff
- 0x64, 0xCC, 0x8C, 0xE6, 0x03, 0x64, 0xCC, 0xA3,
- 0xDC, 0x03, 0x64, 0xCC, 0xA7, 0xCA, 0x03, 0x64,
- 0xCC, 0xAD, 0xDC, 0x03, 0x64, 0xCC, 0xB1, 0xDC,
- 0x03, 0x65, 0xCC, 0x80, 0xE6, 0x03, 0x65, 0xCC,
- 0x81, 0xE6, 0x03, 0x65, 0xCC, 0x83, 0xE6, 0x03,
- 0x65, 0xCC, 0x86, 0xE6, 0x03, 0x65, 0xCC, 0x87,
- 0xE6, 0x03, 0x65, 0xCC, 0x88, 0xE6, 0x03, 0x65,
- 0xCC, 0x89, 0xE6, 0x03, 0x65, 0xCC, 0x8C, 0xE6,
- // Bytes 3300 - 333f
- 0x03, 0x65, 0xCC, 0x8F, 0xE6, 0x03, 0x65, 0xCC,
- 0x91, 0xE6, 0x03, 0x65, 0xCC, 0xA8, 0xCA, 0x03,
- 0x65, 0xCC, 0xAD, 0xDC, 0x03, 0x65, 0xCC, 0xB0,
- 0xDC, 0x03, 0x66, 0xCC, 0x87, 0xE6, 0x03, 0x67,
- 0xCC, 0x81, 0xE6, 0x03, 0x67, 0xCC, 0x82, 0xE6,
- 0x03, 0x67, 0xCC, 0x84, 0xE6, 0x03, 0x67, 0xCC,
- 0x86, 0xE6, 0x03, 0x67, 0xCC, 0x87, 0xE6, 0x03,
- 0x67, 0xCC, 0x8C, 0xE6, 0x03, 0x67, 0xCC, 0xA7,
- // Bytes 3340 - 337f
- 0xCA, 0x03, 0x68, 0xCC, 0x82, 0xE6, 0x03, 0x68,
- 0xCC, 0x87, 0xE6, 0x03, 0x68, 0xCC, 0x88, 0xE6,
- 0x03, 0x68, 0xCC, 0x8C, 0xE6, 0x03, 0x68, 0xCC,
- 0xA3, 0xDC, 0x03, 0x68, 0xCC, 0xA7, 0xCA, 0x03,
- 0x68, 0xCC, 0xAE, 0xDC, 0x03, 0x68, 0xCC, 0xB1,
- 0xDC, 0x03, 0x69, 0xCC, 0x80, 0xE6, 0x03, 0x69,
- 0xCC, 0x81, 0xE6, 0x03, 0x69, 0xCC, 0x82, 0xE6,
- 0x03, 0x69, 0xCC, 0x83, 0xE6, 0x03, 0x69, 0xCC,
- // Bytes 3380 - 33bf
- 0x84, 0xE6, 0x03, 0x69, 0xCC, 0x86, 0xE6, 0x03,
- 0x69, 0xCC, 0x89, 0xE6, 0x03, 0x69, 0xCC, 0x8C,
- 0xE6, 0x03, 0x69, 0xCC, 0x8F, 0xE6, 0x03, 0x69,
- 0xCC, 0x91, 0xE6, 0x03, 0x69, 0xCC, 0xA3, 0xDC,
- 0x03, 0x69, 0xCC, 0xA8, 0xCA, 0x03, 0x69, 0xCC,
- 0xB0, 0xDC, 0x03, 0x6A, 0xCC, 0x82, 0xE6, 0x03,
- 0x6A, 0xCC, 0x8C, 0xE6, 0x03, 0x6B, 0xCC, 0x81,
- 0xE6, 0x03, 0x6B, 0xCC, 0x8C, 0xE6, 0x03, 0x6B,
- // Bytes 33c0 - 33ff
- 0xCC, 0xA3, 0xDC, 0x03, 0x6B, 0xCC, 0xA7, 0xCA,
- 0x03, 0x6B, 0xCC, 0xB1, 0xDC, 0x03, 0x6C, 0xCC,
- 0x81, 0xE6, 0x03, 0x6C, 0xCC, 0x8C, 0xE6, 0x03,
- 0x6C, 0xCC, 0xA7, 0xCA, 0x03, 0x6C, 0xCC, 0xAD,
- 0xDC, 0x03, 0x6C, 0xCC, 0xB1, 0xDC, 0x03, 0x6D,
- 0xCC, 0x81, 0xE6, 0x03, 0x6D, 0xCC, 0x87, 0xE6,
- 0x03, 0x6D, 0xCC, 0xA3, 0xDC, 0x03, 0x6E, 0xCC,
- 0x80, 0xE6, 0x03, 0x6E, 0xCC, 0x81, 0xE6, 0x03,
- // Bytes 3400 - 343f
- 0x6E, 0xCC, 0x83, 0xE6, 0x03, 0x6E, 0xCC, 0x87,
- 0xE6, 0x03, 0x6E, 0xCC, 0x8C, 0xE6, 0x03, 0x6E,
- 0xCC, 0xA3, 0xDC, 0x03, 0x6E, 0xCC, 0xA7, 0xCA,
- 0x03, 0x6E, 0xCC, 0xAD, 0xDC, 0x03, 0x6E, 0xCC,
- 0xB1, 0xDC, 0x03, 0x6F, 0xCC, 0x80, 0xE6, 0x03,
- 0x6F, 0xCC, 0x81, 0xE6, 0x03, 0x6F, 0xCC, 0x86,
- 0xE6, 0x03, 0x6F, 0xCC, 0x89, 0xE6, 0x03, 0x6F,
- 0xCC, 0x8B, 0xE6, 0x03, 0x6F, 0xCC, 0x8C, 0xE6,
- // Bytes 3440 - 347f
- 0x03, 0x6F, 0xCC, 0x8F, 0xE6, 0x03, 0x6F, 0xCC,
- 0x91, 0xE6, 0x03, 0x70, 0xCC, 0x81, 0xE6, 0x03,
- 0x70, 0xCC, 0x87, 0xE6, 0x03, 0x72, 0xCC, 0x81,
- 0xE6, 0x03, 0x72, 0xCC, 0x87, 0xE6, 0x03, 0x72,
- 0xCC, 0x8C, 0xE6, 0x03, 0x72, 0xCC, 0x8F, 0xE6,
- 0x03, 0x72, 0xCC, 0x91, 0xE6, 0x03, 0x72, 0xCC,
- 0xA7, 0xCA, 0x03, 0x72, 0xCC, 0xB1, 0xDC, 0x03,
- 0x73, 0xCC, 0x82, 0xE6, 0x03, 0x73, 0xCC, 0x87,
- // Bytes 3480 - 34bf
- 0xE6, 0x03, 0x73, 0xCC, 0xA6, 0xDC, 0x03, 0x73,
- 0xCC, 0xA7, 0xCA, 0x03, 0x74, 0xCC, 0x87, 0xE6,
- 0x03, 0x74, 0xCC, 0x88, 0xE6, 0x03, 0x74, 0xCC,
- 0x8C, 0xE6, 0x03, 0x74, 0xCC, 0xA3, 0xDC, 0x03,
- 0x74, 0xCC, 0xA6, 0xDC, 0x03, 0x74, 0xCC, 0xA7,
- 0xCA, 0x03, 0x74, 0xCC, 0xAD, 0xDC, 0x03, 0x74,
- 0xCC, 0xB1, 0xDC, 0x03, 0x75, 0xCC, 0x80, 0xE6,
- 0x03, 0x75, 0xCC, 0x81, 0xE6, 0x03, 0x75, 0xCC,
- // Bytes 34c0 - 34ff
- 0x82, 0xE6, 0x03, 0x75, 0xCC, 0x86, 0xE6, 0x03,
- 0x75, 0xCC, 0x89, 0xE6, 0x03, 0x75, 0xCC, 0x8A,
- 0xE6, 0x03, 0x75, 0xCC, 0x8B, 0xE6, 0x03, 0x75,
- 0xCC, 0x8C, 0xE6, 0x03, 0x75, 0xCC, 0x8F, 0xE6,
- 0x03, 0x75, 0xCC, 0x91, 0xE6, 0x03, 0x75, 0xCC,
- 0xA3, 0xDC, 0x03, 0x75, 0xCC, 0xA4, 0xDC, 0x03,
- 0x75, 0xCC, 0xA8, 0xCA, 0x03, 0x75, 0xCC, 0xAD,
- 0xDC, 0x03, 0x75, 0xCC, 0xB0, 0xDC, 0x03, 0x76,
- // Bytes 3500 - 353f
- 0xCC, 0x83, 0xE6, 0x03, 0x76, 0xCC, 0xA3, 0xDC,
- 0x03, 0x77, 0xCC, 0x80, 0xE6, 0x03, 0x77, 0xCC,
- 0x81, 0xE6, 0x03, 0x77, 0xCC, 0x82, 0xE6, 0x03,
- 0x77, 0xCC, 0x87, 0xE6, 0x03, 0x77, 0xCC, 0x88,
- 0xE6, 0x03, 0x77, 0xCC, 0x8A, 0xE6, 0x03, 0x77,
- 0xCC, 0xA3, 0xDC, 0x03, 0x78, 0xCC, 0x87, 0xE6,
- 0x03, 0x78, 0xCC, 0x88, 0xE6, 0x03, 0x79, 0xCC,
- 0x80, 0xE6, 0x03, 0x79, 0xCC, 0x81, 0xE6, 0x03,
- // Bytes 3540 - 357f
- 0x79, 0xCC, 0x82, 0xE6, 0x03, 0x79, 0xCC, 0x83,
- 0xE6, 0x03, 0x79, 0xCC, 0x84, 0xE6, 0x03, 0x79,
- 0xCC, 0x87, 0xE6, 0x03, 0x79, 0xCC, 0x88, 0xE6,
- 0x03, 0x79, 0xCC, 0x89, 0xE6, 0x03, 0x79, 0xCC,
- 0x8A, 0xE6, 0x03, 0x79, 0xCC, 0xA3, 0xDC, 0x03,
- 0x7A, 0xCC, 0x81, 0xE6, 0x03, 0x7A, 0xCC, 0x82,
- 0xE6, 0x03, 0x7A, 0xCC, 0x87, 0xE6, 0x03, 0x7A,
- 0xCC, 0x8C, 0xE6, 0x03, 0x7A, 0xCC, 0xA3, 0xDC,
- // Bytes 3580 - 35bf
- 0x03, 0x7A, 0xCC, 0xB1, 0xDC, 0x04, 0xC2, 0xA8,
- 0xCC, 0x80, 0xE6, 0x04, 0xC2, 0xA8, 0xCC, 0x81,
- 0xE6, 0x04, 0xC2, 0xA8, 0xCD, 0x82, 0xE6, 0x04,
- 0xC3, 0x86, 0xCC, 0x81, 0xE6, 0x04, 0xC3, 0x86,
- 0xCC, 0x84, 0xE6, 0x04, 0xC3, 0x98, 0xCC, 0x81,
- 0xE6, 0x04, 0xC3, 0xA6, 0xCC, 0x81, 0xE6, 0x04,
- 0xC3, 0xA6, 0xCC, 0x84, 0xE6, 0x04, 0xC3, 0xB8,
- 0xCC, 0x81, 0xE6, 0x04, 0xC5, 0xBF, 0xCC, 0x87,
- // Bytes 35c0 - 35ff
- 0xE6, 0x04, 0xC6, 0xB7, 0xCC, 0x8C, 0xE6, 0x04,
- 0xCA, 0x92, 0xCC, 0x8C, 0xE6, 0x04, 0xCE, 0x91,
- 0xCC, 0x80, 0xE6, 0x04, 0xCE, 0x91, 0xCC, 0x81,
- 0xE6, 0x04, 0xCE, 0x91, 0xCC, 0x84, 0xE6, 0x04,
- 0xCE, 0x91, 0xCC, 0x86, 0xE6, 0x04, 0xCE, 0x91,
- 0xCD, 0x85, 0xF0, 0x04, 0xCE, 0x95, 0xCC, 0x80,
- 0xE6, 0x04, 0xCE, 0x95, 0xCC, 0x81, 0xE6, 0x04,
- 0xCE, 0x97, 0xCC, 0x80, 0xE6, 0x04, 0xCE, 0x97,
- // Bytes 3600 - 363f
- 0xCC, 0x81, 0xE6, 0x04, 0xCE, 0x97, 0xCD, 0x85,
- 0xF0, 0x04, 0xCE, 0x99, 0xCC, 0x80, 0xE6, 0x04,
- 0xCE, 0x99, 0xCC, 0x81, 0xE6, 0x04, 0xCE, 0x99,
- 0xCC, 0x84, 0xE6, 0x04, 0xCE, 0x99, 0xCC, 0x86,
- 0xE6, 0x04, 0xCE, 0x99, 0xCC, 0x88, 0xE6, 0x04,
- 0xCE, 0x9F, 0xCC, 0x80, 0xE6, 0x04, 0xCE, 0x9F,
- 0xCC, 0x81, 0xE6, 0x04, 0xCE, 0xA1, 0xCC, 0x94,
- 0xE6, 0x04, 0xCE, 0xA5, 0xCC, 0x80, 0xE6, 0x04,
- // Bytes 3640 - 367f
- 0xCE, 0xA5, 0xCC, 0x81, 0xE6, 0x04, 0xCE, 0xA5,
- 0xCC, 0x84, 0xE6, 0x04, 0xCE, 0xA5, 0xCC, 0x86,
- 0xE6, 0x04, 0xCE, 0xA5, 0xCC, 0x88, 0xE6, 0x04,
- 0xCE, 0xA9, 0xCC, 0x80, 0xE6, 0x04, 0xCE, 0xA9,
- 0xCC, 0x81, 0xE6, 0x04, 0xCE, 0xA9, 0xCD, 0x85,
- 0xF0, 0x04, 0xCE, 0xB1, 0xCC, 0x84, 0xE6, 0x04,
- 0xCE, 0xB1, 0xCC, 0x86, 0xE6, 0x04, 0xCE, 0xB1,
- 0xCD, 0x85, 0xF0, 0x04, 0xCE, 0xB5, 0xCC, 0x80,
- // Bytes 3680 - 36bf
- 0xE6, 0x04, 0xCE, 0xB5, 0xCC, 0x81, 0xE6, 0x04,
- 0xCE, 0xB7, 0xCD, 0x85, 0xF0, 0x04, 0xCE, 0xB9,
- 0xCC, 0x80, 0xE6, 0x04, 0xCE, 0xB9, 0xCC, 0x81,
- 0xE6, 0x04, 0xCE, 0xB9, 0xCC, 0x84, 0xE6, 0x04,
- 0xCE, 0xB9, 0xCC, 0x86, 0xE6, 0x04, 0xCE, 0xB9,
- 0xCD, 0x82, 0xE6, 0x04, 0xCE, 0xBF, 0xCC, 0x80,
- 0xE6, 0x04, 0xCE, 0xBF, 0xCC, 0x81, 0xE6, 0x04,
- 0xCF, 0x81, 0xCC, 0x93, 0xE6, 0x04, 0xCF, 0x81,
- // Bytes 36c0 - 36ff
- 0xCC, 0x94, 0xE6, 0x04, 0xCF, 0x85, 0xCC, 0x80,
- 0xE6, 0x04, 0xCF, 0x85, 0xCC, 0x81, 0xE6, 0x04,
- 0xCF, 0x85, 0xCC, 0x84, 0xE6, 0x04, 0xCF, 0x85,
- 0xCC, 0x86, 0xE6, 0x04, 0xCF, 0x85, 0xCD, 0x82,
- 0xE6, 0x04, 0xCF, 0x89, 0xCD, 0x85, 0xF0, 0x04,
- 0xCF, 0x92, 0xCC, 0x81, 0xE6, 0x04, 0xCF, 0x92,
- 0xCC, 0x88, 0xE6, 0x04, 0xD0, 0x86, 0xCC, 0x88,
- 0xE6, 0x04, 0xD0, 0x90, 0xCC, 0x86, 0xE6, 0x04,
- // Bytes 3700 - 373f
- 0xD0, 0x90, 0xCC, 0x88, 0xE6, 0x04, 0xD0, 0x93,
- 0xCC, 0x81, 0xE6, 0x04, 0xD0, 0x95, 0xCC, 0x80,
- 0xE6, 0x04, 0xD0, 0x95, 0xCC, 0x86, 0xE6, 0x04,
- 0xD0, 0x95, 0xCC, 0x88, 0xE6, 0x04, 0xD0, 0x96,
- 0xCC, 0x86, 0xE6, 0x04, 0xD0, 0x96, 0xCC, 0x88,
- 0xE6, 0x04, 0xD0, 0x97, 0xCC, 0x88, 0xE6, 0x04,
- 0xD0, 0x98, 0xCC, 0x80, 0xE6, 0x04, 0xD0, 0x98,
- 0xCC, 0x84, 0xE6, 0x04, 0xD0, 0x98, 0xCC, 0x86,
- // Bytes 3740 - 377f
- 0xE6, 0x04, 0xD0, 0x98, 0xCC, 0x88, 0xE6, 0x04,
- 0xD0, 0x9A, 0xCC, 0x81, 0xE6, 0x04, 0xD0, 0x9E,
- 0xCC, 0x88, 0xE6, 0x04, 0xD0, 0xA3, 0xCC, 0x84,
- 0xE6, 0x04, 0xD0, 0xA3, 0xCC, 0x86, 0xE6, 0x04,
- 0xD0, 0xA3, 0xCC, 0x88, 0xE6, 0x04, 0xD0, 0xA3,
- 0xCC, 0x8B, 0xE6, 0x04, 0xD0, 0xA7, 0xCC, 0x88,
- 0xE6, 0x04, 0xD0, 0xAB, 0xCC, 0x88, 0xE6, 0x04,
- 0xD0, 0xAD, 0xCC, 0x88, 0xE6, 0x04, 0xD0, 0xB0,
- // Bytes 3780 - 37bf
- 0xCC, 0x86, 0xE6, 0x04, 0xD0, 0xB0, 0xCC, 0x88,
- 0xE6, 0x04, 0xD0, 0xB3, 0xCC, 0x81, 0xE6, 0x04,
- 0xD0, 0xB5, 0xCC, 0x80, 0xE6, 0x04, 0xD0, 0xB5,
- 0xCC, 0x86, 0xE6, 0x04, 0xD0, 0xB5, 0xCC, 0x88,
- 0xE6, 0x04, 0xD0, 0xB6, 0xCC, 0x86, 0xE6, 0x04,
- 0xD0, 0xB6, 0xCC, 0x88, 0xE6, 0x04, 0xD0, 0xB7,
- 0xCC, 0x88, 0xE6, 0x04, 0xD0, 0xB8, 0xCC, 0x80,
- 0xE6, 0x04, 0xD0, 0xB8, 0xCC, 0x84, 0xE6, 0x04,
- // Bytes 37c0 - 37ff
- 0xD0, 0xB8, 0xCC, 0x86, 0xE6, 0x04, 0xD0, 0xB8,
- 0xCC, 0x88, 0xE6, 0x04, 0xD0, 0xBA, 0xCC, 0x81,
- 0xE6, 0x04, 0xD0, 0xBE, 0xCC, 0x88, 0xE6, 0x04,
- 0xD1, 0x83, 0xCC, 0x84, 0xE6, 0x04, 0xD1, 0x83,
- 0xCC, 0x86, 0xE6, 0x04, 0xD1, 0x83, 0xCC, 0x88,
- 0xE6, 0x04, 0xD1, 0x83, 0xCC, 0x8B, 0xE6, 0x04,
- 0xD1, 0x87, 0xCC, 0x88, 0xE6, 0x04, 0xD1, 0x8B,
- 0xCC, 0x88, 0xE6, 0x04, 0xD1, 0x8D, 0xCC, 0x88,
- // Bytes 3800 - 383f
- 0xE6, 0x04, 0xD1, 0x96, 0xCC, 0x88, 0xE6, 0x04,
- 0xD1, 0xB4, 0xCC, 0x8F, 0xE6, 0x04, 0xD1, 0xB5,
- 0xCC, 0x8F, 0xE6, 0x04, 0xD3, 0x98, 0xCC, 0x88,
- 0xE6, 0x04, 0xD3, 0x99, 0xCC, 0x88, 0xE6, 0x04,
- 0xD3, 0xA8, 0xCC, 0x88, 0xE6, 0x04, 0xD3, 0xA9,
- 0xCC, 0x88, 0xE6, 0x04, 0xD8, 0xA7, 0xD9, 0x93,
- 0xE6, 0x04, 0xD8, 0xA7, 0xD9, 0x94, 0xE6, 0x04,
- 0xD8, 0xA7, 0xD9, 0x95, 0xDC, 0x04, 0xD9, 0x88,
- // Bytes 3840 - 387f
- 0xD9, 0x94, 0xE6, 0x04, 0xD9, 0x8A, 0xD9, 0x94,
- 0xE6, 0x04, 0xDB, 0x81, 0xD9, 0x94, 0xE6, 0x04,
- 0xDB, 0x92, 0xD9, 0x94, 0xE6, 0x04, 0xDB, 0x95,
- 0xD9, 0x94, 0xE6, 0x05, 0x41, 0xCC, 0x82, 0xCC,
- 0x80, 0xE6, 0x05, 0x41, 0xCC, 0x82, 0xCC, 0x81,
- 0xE6, 0x05, 0x41, 0xCC, 0x82, 0xCC, 0x83, 0xE6,
- 0x05, 0x41, 0xCC, 0x82, 0xCC, 0x89, 0xE6, 0x05,
- 0x41, 0xCC, 0x86, 0xCC, 0x80, 0xE6, 0x05, 0x41,
- // Bytes 3880 - 38bf
- 0xCC, 0x86, 0xCC, 0x81, 0xE6, 0x05, 0x41, 0xCC,
- 0x86, 0xCC, 0x83, 0xE6, 0x05, 0x41, 0xCC, 0x86,
- 0xCC, 0x89, 0xE6, 0x05, 0x41, 0xCC, 0x87, 0xCC,
- 0x84, 0xE6, 0x05, 0x41, 0xCC, 0x88, 0xCC, 0x84,
- 0xE6, 0x05, 0x41, 0xCC, 0x8A, 0xCC, 0x81, 0xE6,
- 0x05, 0x41, 0xCC, 0xA3, 0xCC, 0x82, 0xE6, 0x05,
- 0x41, 0xCC, 0xA3, 0xCC, 0x86, 0xE6, 0x05, 0x43,
- 0xCC, 0xA7, 0xCC, 0x81, 0xE6, 0x05, 0x45, 0xCC,
- // Bytes 38c0 - 38ff
- 0x82, 0xCC, 0x80, 0xE6, 0x05, 0x45, 0xCC, 0x82,
- 0xCC, 0x81, 0xE6, 0x05, 0x45, 0xCC, 0x82, 0xCC,
- 0x83, 0xE6, 0x05, 0x45, 0xCC, 0x82, 0xCC, 0x89,
- 0xE6, 0x05, 0x45, 0xCC, 0x84, 0xCC, 0x80, 0xE6,
- 0x05, 0x45, 0xCC, 0x84, 0xCC, 0x81, 0xE6, 0x05,
- 0x45, 0xCC, 0xA3, 0xCC, 0x82, 0xE6, 0x05, 0x45,
- 0xCC, 0xA7, 0xCC, 0x86, 0xE6, 0x05, 0x49, 0xCC,
- 0x88, 0xCC, 0x81, 0xE6, 0x05, 0x4C, 0xCC, 0xA3,
- // Bytes 3900 - 393f
- 0xCC, 0x84, 0xE6, 0x05, 0x4F, 0xCC, 0x82, 0xCC,
- 0x80, 0xE6, 0x05, 0x4F, 0xCC, 0x82, 0xCC, 0x81,
- 0xE6, 0x05, 0x4F, 0xCC, 0x82, 0xCC, 0x83, 0xE6,
- 0x05, 0x4F, 0xCC, 0x82, 0xCC, 0x89, 0xE6, 0x05,
- 0x4F, 0xCC, 0x83, 0xCC, 0x81, 0xE6, 0x05, 0x4F,
- 0xCC, 0x83, 0xCC, 0x84, 0xE6, 0x05, 0x4F, 0xCC,
- 0x83, 0xCC, 0x88, 0xE6, 0x05, 0x4F, 0xCC, 0x84,
- 0xCC, 0x80, 0xE6, 0x05, 0x4F, 0xCC, 0x84, 0xCC,
- // Bytes 3940 - 397f
- 0x81, 0xE6, 0x05, 0x4F, 0xCC, 0x87, 0xCC, 0x84,
- 0xE6, 0x05, 0x4F, 0xCC, 0x88, 0xCC, 0x84, 0xE6,
- 0x05, 0x4F, 0xCC, 0x9B, 0xCC, 0x80, 0xE6, 0x05,
- 0x4F, 0xCC, 0x9B, 0xCC, 0x81, 0xE6, 0x05, 0x4F,
- 0xCC, 0x9B, 0xCC, 0x83, 0xE6, 0x05, 0x4F, 0xCC,
- 0x9B, 0xCC, 0x89, 0xE6, 0x05, 0x4F, 0xCC, 0x9B,
- 0xCC, 0xA3, 0xDC, 0x05, 0x4F, 0xCC, 0xA3, 0xCC,
- 0x82, 0xE6, 0x05, 0x4F, 0xCC, 0xA8, 0xCC, 0x84,
- // Bytes 3980 - 39bf
- 0xE6, 0x05, 0x52, 0xCC, 0xA3, 0xCC, 0x84, 0xE6,
- 0x05, 0x53, 0xCC, 0x81, 0xCC, 0x87, 0xE6, 0x05,
- 0x53, 0xCC, 0x8C, 0xCC, 0x87, 0xE6, 0x05, 0x53,
- 0xCC, 0xA3, 0xCC, 0x87, 0xE6, 0x05, 0x55, 0xCC,
- 0x83, 0xCC, 0x81, 0xE6, 0x05, 0x55, 0xCC, 0x84,
- 0xCC, 0x88, 0xE6, 0x05, 0x55, 0xCC, 0x88, 0xCC,
- 0x80, 0xE6, 0x05, 0x55, 0xCC, 0x88, 0xCC, 0x81,
- 0xE6, 0x05, 0x55, 0xCC, 0x88, 0xCC, 0x84, 0xE6,
- // Bytes 39c0 - 39ff
- 0x05, 0x55, 0xCC, 0x88, 0xCC, 0x8C, 0xE6, 0x05,
- 0x55, 0xCC, 0x9B, 0xCC, 0x80, 0xE6, 0x05, 0x55,
- 0xCC, 0x9B, 0xCC, 0x81, 0xE6, 0x05, 0x55, 0xCC,
- 0x9B, 0xCC, 0x83, 0xE6, 0x05, 0x55, 0xCC, 0x9B,
- 0xCC, 0x89, 0xE6, 0x05, 0x55, 0xCC, 0x9B, 0xCC,
- 0xA3, 0xDC, 0x05, 0x61, 0xCC, 0x82, 0xCC, 0x80,
- 0xE6, 0x05, 0x61, 0xCC, 0x82, 0xCC, 0x81, 0xE6,
- 0x05, 0x61, 0xCC, 0x82, 0xCC, 0x83, 0xE6, 0x05,
- // Bytes 3a00 - 3a3f
- 0x61, 0xCC, 0x82, 0xCC, 0x89, 0xE6, 0x05, 0x61,
- 0xCC, 0x86, 0xCC, 0x80, 0xE6, 0x05, 0x61, 0xCC,
- 0x86, 0xCC, 0x81, 0xE6, 0x05, 0x61, 0xCC, 0x86,
- 0xCC, 0x83, 0xE6, 0x05, 0x61, 0xCC, 0x86, 0xCC,
- 0x89, 0xE6, 0x05, 0x61, 0xCC, 0x87, 0xCC, 0x84,
- 0xE6, 0x05, 0x61, 0xCC, 0x88, 0xCC, 0x84, 0xE6,
- 0x05, 0x61, 0xCC, 0x8A, 0xCC, 0x81, 0xE6, 0x05,
- 0x61, 0xCC, 0xA3, 0xCC, 0x82, 0xE6, 0x05, 0x61,
- // Bytes 3a40 - 3a7f
- 0xCC, 0xA3, 0xCC, 0x86, 0xE6, 0x05, 0x63, 0xCC,
- 0xA7, 0xCC, 0x81, 0xE6, 0x05, 0x65, 0xCC, 0x82,
- 0xCC, 0x80, 0xE6, 0x05, 0x65, 0xCC, 0x82, 0xCC,
- 0x81, 0xE6, 0x05, 0x65, 0xCC, 0x82, 0xCC, 0x83,
- 0xE6, 0x05, 0x65, 0xCC, 0x82, 0xCC, 0x89, 0xE6,
- 0x05, 0x65, 0xCC, 0x84, 0xCC, 0x80, 0xE6, 0x05,
- 0x65, 0xCC, 0x84, 0xCC, 0x81, 0xE6, 0x05, 0x65,
- 0xCC, 0xA3, 0xCC, 0x82, 0xE6, 0x05, 0x65, 0xCC,
- // Bytes 3a80 - 3abf
- 0xA7, 0xCC, 0x86, 0xE6, 0x05, 0x69, 0xCC, 0x88,
- 0xCC, 0x81, 0xE6, 0x05, 0x6C, 0xCC, 0xA3, 0xCC,
- 0x84, 0xE6, 0x05, 0x6F, 0xCC, 0x82, 0xCC, 0x80,
- 0xE6, 0x05, 0x6F, 0xCC, 0x82, 0xCC, 0x81, 0xE6,
- 0x05, 0x6F, 0xCC, 0x82, 0xCC, 0x83, 0xE6, 0x05,
- 0x6F, 0xCC, 0x82, 0xCC, 0x89, 0xE6, 0x05, 0x6F,
- 0xCC, 0x83, 0xCC, 0x81, 0xE6, 0x05, 0x6F, 0xCC,
- 0x83, 0xCC, 0x84, 0xE6, 0x05, 0x6F, 0xCC, 0x83,
- // Bytes 3ac0 - 3aff
- 0xCC, 0x88, 0xE6, 0x05, 0x6F, 0xCC, 0x84, 0xCC,
- 0x80, 0xE6, 0x05, 0x6F, 0xCC, 0x84, 0xCC, 0x81,
- 0xE6, 0x05, 0x6F, 0xCC, 0x87, 0xCC, 0x84, 0xE6,
- 0x05, 0x6F, 0xCC, 0x88, 0xCC, 0x84, 0xE6, 0x05,
- 0x6F, 0xCC, 0x9B, 0xCC, 0x80, 0xE6, 0x05, 0x6F,
- 0xCC, 0x9B, 0xCC, 0x81, 0xE6, 0x05, 0x6F, 0xCC,
- 0x9B, 0xCC, 0x83, 0xE6, 0x05, 0x6F, 0xCC, 0x9B,
- 0xCC, 0x89, 0xE6, 0x05, 0x6F, 0xCC, 0x9B, 0xCC,
- // Bytes 3b00 - 3b3f
- 0xA3, 0xDC, 0x05, 0x6F, 0xCC, 0xA3, 0xCC, 0x82,
- 0xE6, 0x05, 0x6F, 0xCC, 0xA8, 0xCC, 0x84, 0xE6,
- 0x05, 0x72, 0xCC, 0xA3, 0xCC, 0x84, 0xE6, 0x05,
- 0x73, 0xCC, 0x81, 0xCC, 0x87, 0xE6, 0x05, 0x73,
- 0xCC, 0x8C, 0xCC, 0x87, 0xE6, 0x05, 0x73, 0xCC,
- 0xA3, 0xCC, 0x87, 0xE6, 0x05, 0x75, 0xCC, 0x83,
- 0xCC, 0x81, 0xE6, 0x05, 0x75, 0xCC, 0x84, 0xCC,
- 0x88, 0xE6, 0x05, 0x75, 0xCC, 0x88, 0xCC, 0x80,
- // Bytes 3b40 - 3b7f
- 0xE6, 0x05, 0x75, 0xCC, 0x88, 0xCC, 0x81, 0xE6,
- 0x05, 0x75, 0xCC, 0x88, 0xCC, 0x84, 0xE6, 0x05,
- 0x75, 0xCC, 0x88, 0xCC, 0x8C, 0xE6, 0x05, 0x75,
- 0xCC, 0x9B, 0xCC, 0x80, 0xE6, 0x05, 0x75, 0xCC,
- 0x9B, 0xCC, 0x81, 0xE6, 0x05, 0x75, 0xCC, 0x9B,
- 0xCC, 0x83, 0xE6, 0x05, 0x75, 0xCC, 0x9B, 0xCC,
- 0x89, 0xE6, 0x05, 0x75, 0xCC, 0x9B, 0xCC, 0xA3,
- 0xDC, 0x05, 0xE1, 0xBE, 0xBF, 0xCC, 0x80, 0xE6,
- // Bytes 3b80 - 3bbf
- 0x05, 0xE1, 0xBE, 0xBF, 0xCC, 0x81, 0xE6, 0x05,
- 0xE1, 0xBE, 0xBF, 0xCD, 0x82, 0xE6, 0x05, 0xE1,
- 0xBF, 0xBE, 0xCC, 0x80, 0xE6, 0x05, 0xE1, 0xBF,
- 0xBE, 0xCC, 0x81, 0xE6, 0x05, 0xE1, 0xBF, 0xBE,
- 0xCD, 0x82, 0xE6, 0x05, 0xE2, 0x86, 0x90, 0xCC,
- 0xB8, 0x01, 0x05, 0xE2, 0x86, 0x92, 0xCC, 0xB8,
- 0x01, 0x05, 0xE2, 0x86, 0x94, 0xCC, 0xB8, 0x01,
- 0x05, 0xE2, 0x87, 0x90, 0xCC, 0xB8, 0x01, 0x05,
- // Bytes 3bc0 - 3bff
- 0xE2, 0x87, 0x92, 0xCC, 0xB8, 0x01, 0x05, 0xE2,
- 0x87, 0x94, 0xCC, 0xB8, 0x01, 0x05, 0xE2, 0x88,
- 0x83, 0xCC, 0xB8, 0x01, 0x05, 0xE2, 0x88, 0x88,
- 0xCC, 0xB8, 0x01, 0x05, 0xE2, 0x88, 0x8B, 0xCC,
- 0xB8, 0x01, 0x05, 0xE2, 0x88, 0xA3, 0xCC, 0xB8,
- 0x01, 0x05, 0xE2, 0x88, 0xA5, 0xCC, 0xB8, 0x01,
- 0x05, 0xE2, 0x88, 0xBC, 0xCC, 0xB8, 0x01, 0x05,
- 0xE2, 0x89, 0x83, 0xCC, 0xB8, 0x01, 0x05, 0xE2,
- // Bytes 3c00 - 3c3f
- 0x89, 0x85, 0xCC, 0xB8, 0x01, 0x05, 0xE2, 0x89,
- 0x88, 0xCC, 0xB8, 0x01, 0x05, 0xE2, 0x89, 0x8D,
- 0xCC, 0xB8, 0x01, 0x05, 0xE2, 0x89, 0xA1, 0xCC,
- 0xB8, 0x01, 0x05, 0xE2, 0x89, 0xA4, 0xCC, 0xB8,
- 0x01, 0x05, 0xE2, 0x89, 0xA5, 0xCC, 0xB8, 0x01,
- 0x05, 0xE2, 0x89, 0xB2, 0xCC, 0xB8, 0x01, 0x05,
- 0xE2, 0x89, 0xB3, 0xCC, 0xB8, 0x01, 0x05, 0xE2,
- 0x89, 0xB6, 0xCC, 0xB8, 0x01, 0x05, 0xE2, 0x89,
- // Bytes 3c40 - 3c7f
- 0xB7, 0xCC, 0xB8, 0x01, 0x05, 0xE2, 0x89, 0xBA,
- 0xCC, 0xB8, 0x01, 0x05, 0xE2, 0x89, 0xBB, 0xCC,
- 0xB8, 0x01, 0x05, 0xE2, 0x89, 0xBC, 0xCC, 0xB8,
- 0x01, 0x05, 0xE2, 0x89, 0xBD, 0xCC, 0xB8, 0x01,
- 0x05, 0xE2, 0x8A, 0x82, 0xCC, 0xB8, 0x01, 0x05,
- 0xE2, 0x8A, 0x83, 0xCC, 0xB8, 0x01, 0x05, 0xE2,
- 0x8A, 0x86, 0xCC, 0xB8, 0x01, 0x05, 0xE2, 0x8A,
- 0x87, 0xCC, 0xB8, 0x01, 0x05, 0xE2, 0x8A, 0x91,
- // Bytes 3c80 - 3cbf
- 0xCC, 0xB8, 0x01, 0x05, 0xE2, 0x8A, 0x92, 0xCC,
- 0xB8, 0x01, 0x05, 0xE2, 0x8A, 0xA2, 0xCC, 0xB8,
- 0x01, 0x05, 0xE2, 0x8A, 0xA8, 0xCC, 0xB8, 0x01,
- 0x05, 0xE2, 0x8A, 0xA9, 0xCC, 0xB8, 0x01, 0x05,
- 0xE2, 0x8A, 0xAB, 0xCC, 0xB8, 0x01, 0x05, 0xE2,
- 0x8A, 0xB2, 0xCC, 0xB8, 0x01, 0x05, 0xE2, 0x8A,
- 0xB3, 0xCC, 0xB8, 0x01, 0x05, 0xE2, 0x8A, 0xB4,
- 0xCC, 0xB8, 0x01, 0x05, 0xE2, 0x8A, 0xB5, 0xCC,
- // Bytes 3cc0 - 3cff
- 0xB8, 0x01, 0x06, 0xCE, 0x91, 0xCC, 0x93, 0xCD,
- 0x85, 0xF0, 0x06, 0xCE, 0x91, 0xCC, 0x94, 0xCD,
- 0x85, 0xF0, 0x06, 0xCE, 0x95, 0xCC, 0x93, 0xCC,
- 0x80, 0xE6, 0x06, 0xCE, 0x95, 0xCC, 0x93, 0xCC,
- 0x81, 0xE6, 0x06, 0xCE, 0x95, 0xCC, 0x94, 0xCC,
- 0x80, 0xE6, 0x06, 0xCE, 0x95, 0xCC, 0x94, 0xCC,
- 0x81, 0xE6, 0x06, 0xCE, 0x97, 0xCC, 0x93, 0xCD,
- 0x85, 0xF0, 0x06, 0xCE, 0x97, 0xCC, 0x94, 0xCD,
- // Bytes 3d00 - 3d3f
- 0x85, 0xF0, 0x06, 0xCE, 0x99, 0xCC, 0x93, 0xCC,
- 0x80, 0xE6, 0x06, 0xCE, 0x99, 0xCC, 0x93, 0xCC,
- 0x81, 0xE6, 0x06, 0xCE, 0x99, 0xCC, 0x93, 0xCD,
- 0x82, 0xE6, 0x06, 0xCE, 0x99, 0xCC, 0x94, 0xCC,
- 0x80, 0xE6, 0x06, 0xCE, 0x99, 0xCC, 0x94, 0xCC,
- 0x81, 0xE6, 0x06, 0xCE, 0x99, 0xCC, 0x94, 0xCD,
- 0x82, 0xE6, 0x06, 0xCE, 0x9F, 0xCC, 0x93, 0xCC,
- 0x80, 0xE6, 0x06, 0xCE, 0x9F, 0xCC, 0x93, 0xCC,
- // Bytes 3d40 - 3d7f
- 0x81, 0xE6, 0x06, 0xCE, 0x9F, 0xCC, 0x94, 0xCC,
- 0x80, 0xE6, 0x06, 0xCE, 0x9F, 0xCC, 0x94, 0xCC,
- 0x81, 0xE6, 0x06, 0xCE, 0xA5, 0xCC, 0x94, 0xCC,
- 0x80, 0xE6, 0x06, 0xCE, 0xA5, 0xCC, 0x94, 0xCC,
- 0x81, 0xE6, 0x06, 0xCE, 0xA5, 0xCC, 0x94, 0xCD,
- 0x82, 0xE6, 0x06, 0xCE, 0xA9, 0xCC, 0x93, 0xCD,
- 0x85, 0xF0, 0x06, 0xCE, 0xA9, 0xCC, 0x94, 0xCD,
- 0x85, 0xF0, 0x06, 0xCE, 0xB1, 0xCC, 0x80, 0xCD,
- // Bytes 3d80 - 3dbf
- 0x85, 0xF0, 0x06, 0xCE, 0xB1, 0xCC, 0x81, 0xCD,
- 0x85, 0xF0, 0x06, 0xCE, 0xB1, 0xCC, 0x93, 0xCD,
- 0x85, 0xF0, 0x06, 0xCE, 0xB1, 0xCC, 0x94, 0xCD,
- 0x85, 0xF0, 0x06, 0xCE, 0xB1, 0xCD, 0x82, 0xCD,
- 0x85, 0xF0, 0x06, 0xCE, 0xB5, 0xCC, 0x93, 0xCC,
- 0x80, 0xE6, 0x06, 0xCE, 0xB5, 0xCC, 0x93, 0xCC,
- 0x81, 0xE6, 0x06, 0xCE, 0xB5, 0xCC, 0x94, 0xCC,
- 0x80, 0xE6, 0x06, 0xCE, 0xB5, 0xCC, 0x94, 0xCC,
- // Bytes 3dc0 - 3dff
- 0x81, 0xE6, 0x06, 0xCE, 0xB7, 0xCC, 0x80, 0xCD,
- 0x85, 0xF0, 0x06, 0xCE, 0xB7, 0xCC, 0x81, 0xCD,
- 0x85, 0xF0, 0x06, 0xCE, 0xB7, 0xCC, 0x93, 0xCD,
- 0x85, 0xF0, 0x06, 0xCE, 0xB7, 0xCC, 0x94, 0xCD,
- 0x85, 0xF0, 0x06, 0xCE, 0xB7, 0xCD, 0x82, 0xCD,
- 0x85, 0xF0, 0x06, 0xCE, 0xB9, 0xCC, 0x88, 0xCC,
- 0x80, 0xE6, 0x06, 0xCE, 0xB9, 0xCC, 0x88, 0xCC,
- 0x81, 0xE6, 0x06, 0xCE, 0xB9, 0xCC, 0x88, 0xCD,
- // Bytes 3e00 - 3e3f
- 0x82, 0xE6, 0x06, 0xCE, 0xB9, 0xCC, 0x93, 0xCC,
- 0x80, 0xE6, 0x06, 0xCE, 0xB9, 0xCC, 0x93, 0xCC,
- 0x81, 0xE6, 0x06, 0xCE, 0xB9, 0xCC, 0x93, 0xCD,
- 0x82, 0xE6, 0x06, 0xCE, 0xB9, 0xCC, 0x94, 0xCC,
- 0x80, 0xE6, 0x06, 0xCE, 0xB9, 0xCC, 0x94, 0xCC,
- 0x81, 0xE6, 0x06, 0xCE, 0xB9, 0xCC, 0x94, 0xCD,
- 0x82, 0xE6, 0x06, 0xCE, 0xBF, 0xCC, 0x93, 0xCC,
- 0x80, 0xE6, 0x06, 0xCE, 0xBF, 0xCC, 0x93, 0xCC,
- // Bytes 3e40 - 3e7f
- 0x81, 0xE6, 0x06, 0xCE, 0xBF, 0xCC, 0x94, 0xCC,
- 0x80, 0xE6, 0x06, 0xCE, 0xBF, 0xCC, 0x94, 0xCC,
- 0x81, 0xE6, 0x06, 0xCF, 0x85, 0xCC, 0x88, 0xCC,
- 0x80, 0xE6, 0x06, 0xCF, 0x85, 0xCC, 0x88, 0xCC,
- 0x81, 0xE6, 0x06, 0xCF, 0x85, 0xCC, 0x88, 0xCD,
- 0x82, 0xE6, 0x06, 0xCF, 0x85, 0xCC, 0x93, 0xCC,
- 0x80, 0xE6, 0x06, 0xCF, 0x85, 0xCC, 0x93, 0xCC,
- 0x81, 0xE6, 0x06, 0xCF, 0x85, 0xCC, 0x93, 0xCD,
- // Bytes 3e80 - 3ebf
- 0x82, 0xE6, 0x06, 0xCF, 0x85, 0xCC, 0x94, 0xCC,
- 0x80, 0xE6, 0x06, 0xCF, 0x85, 0xCC, 0x94, 0xCC,
- 0x81, 0xE6, 0x06, 0xCF, 0x85, 0xCC, 0x94, 0xCD,
- 0x82, 0xE6, 0x06, 0xCF, 0x89, 0xCC, 0x80, 0xCD,
- 0x85, 0xF0, 0x06, 0xCF, 0x89, 0xCC, 0x81, 0xCD,
- 0x85, 0xF0, 0x06, 0xCF, 0x89, 0xCC, 0x93, 0xCD,
- 0x85, 0xF0, 0x06, 0xCF, 0x89, 0xCC, 0x94, 0xCD,
- 0x85, 0xF0, 0x06, 0xCF, 0x89, 0xCD, 0x82, 0xCD,
- // Bytes 3ec0 - 3eff
- 0x85, 0xF0, 0x06, 0xE0, 0xA4, 0xA8, 0xE0, 0xA4,
- 0xBC, 0x07, 0x06, 0xE0, 0xA4, 0xB0, 0xE0, 0xA4,
- 0xBC, 0x07, 0x06, 0xE0, 0xA4, 0xB3, 0xE0, 0xA4,
- 0xBC, 0x07, 0x06, 0xE0, 0xB1, 0x86, 0xE0, 0xB1,
- 0x96, 0x5B, 0x06, 0xE0, 0xB7, 0x99, 0xE0, 0xB7,
- 0x8A, 0x09, 0x06, 0xE3, 0x81, 0x86, 0xE3, 0x82,
- 0x99, 0x08, 0x06, 0xE3, 0x81, 0x8B, 0xE3, 0x82,
- 0x99, 0x08, 0x06, 0xE3, 0x81, 0x8D, 0xE3, 0x82,
- // Bytes 3f00 - 3f3f
- 0x99, 0x08, 0x06, 0xE3, 0x81, 0x8F, 0xE3, 0x82,
- 0x99, 0x08, 0x06, 0xE3, 0x81, 0x91, 0xE3, 0x82,
- 0x99, 0x08, 0x06, 0xE3, 0x81, 0x93, 0xE3, 0x82,
- 0x99, 0x08, 0x06, 0xE3, 0x81, 0x95, 0xE3, 0x82,
- 0x99, 0x08, 0x06, 0xE3, 0x81, 0x97, 0xE3, 0x82,
- 0x99, 0x08, 0x06, 0xE3, 0x81, 0x99, 0xE3, 0x82,
- 0x99, 0x08, 0x06, 0xE3, 0x81, 0x9B, 0xE3, 0x82,
- 0x99, 0x08, 0x06, 0xE3, 0x81, 0x9D, 0xE3, 0x82,
- // Bytes 3f40 - 3f7f
- 0x99, 0x08, 0x06, 0xE3, 0x81, 0x9F, 0xE3, 0x82,
- 0x99, 0x08, 0x06, 0xE3, 0x81, 0xA1, 0xE3, 0x82,
- 0x99, 0x08, 0x06, 0xE3, 0x81, 0xA4, 0xE3, 0x82,
- 0x99, 0x08, 0x06, 0xE3, 0x81, 0xA6, 0xE3, 0x82,
- 0x99, 0x08, 0x06, 0xE3, 0x81, 0xA8, 0xE3, 0x82,
- 0x99, 0x08, 0x06, 0xE3, 0x81, 0xAF, 0xE3, 0x82,
- 0x99, 0x08, 0x06, 0xE3, 0x81, 0xAF, 0xE3, 0x82,
- 0x9A, 0x08, 0x06, 0xE3, 0x81, 0xB2, 0xE3, 0x82,
- // Bytes 3f80 - 3fbf
- 0x99, 0x08, 0x06, 0xE3, 0x81, 0xB2, 0xE3, 0x82,
- 0x9A, 0x08, 0x06, 0xE3, 0x81, 0xB5, 0xE3, 0x82,
- 0x99, 0x08, 0x06, 0xE3, 0x81, 0xB5, 0xE3, 0x82,
- 0x9A, 0x08, 0x06, 0xE3, 0x81, 0xB8, 0xE3, 0x82,
- 0x99, 0x08, 0x06, 0xE3, 0x81, 0xB8, 0xE3, 0x82,
- 0x9A, 0x08, 0x06, 0xE3, 0x81, 0xBB, 0xE3, 0x82,
- 0x99, 0x08, 0x06, 0xE3, 0x81, 0xBB, 0xE3, 0x82,
- 0x9A, 0x08, 0x06, 0xE3, 0x82, 0x9D, 0xE3, 0x82,
- // Bytes 3fc0 - 3fff
- 0x99, 0x08, 0x06, 0xE3, 0x82, 0xA6, 0xE3, 0x82,
- 0x99, 0x08, 0x06, 0xE3, 0x82, 0xAB, 0xE3, 0x82,
- 0x99, 0x08, 0x06, 0xE3, 0x82, 0xAD, 0xE3, 0x82,
- 0x99, 0x08, 0x06, 0xE3, 0x82, 0xAF, 0xE3, 0x82,
- 0x99, 0x08, 0x06, 0xE3, 0x82, 0xB1, 0xE3, 0x82,
- 0x99, 0x08, 0x06, 0xE3, 0x82, 0xB3, 0xE3, 0x82,
- 0x99, 0x08, 0x06, 0xE3, 0x82, 0xB5, 0xE3, 0x82,
- 0x99, 0x08, 0x06, 0xE3, 0x82, 0xB7, 0xE3, 0x82,
- // Bytes 4000 - 403f
- 0x99, 0x08, 0x06, 0xE3, 0x82, 0xB9, 0xE3, 0x82,
- 0x99, 0x08, 0x06, 0xE3, 0x82, 0xBB, 0xE3, 0x82,
- 0x99, 0x08, 0x06, 0xE3, 0x82, 0xBD, 0xE3, 0x82,
- 0x99, 0x08, 0x06, 0xE3, 0x82, 0xBF, 0xE3, 0x82,
- 0x99, 0x08, 0x06, 0xE3, 0x83, 0x81, 0xE3, 0x82,
- 0x99, 0x08, 0x06, 0xE3, 0x83, 0x84, 0xE3, 0x82,
- 0x99, 0x08, 0x06, 0xE3, 0x83, 0x86, 0xE3, 0x82,
- 0x99, 0x08, 0x06, 0xE3, 0x83, 0x88, 0xE3, 0x82,
- // Bytes 4040 - 407f
- 0x99, 0x08, 0x06, 0xE3, 0x83, 0x8F, 0xE3, 0x82,
- 0x99, 0x08, 0x06, 0xE3, 0x83, 0x8F, 0xE3, 0x82,
- 0x9A, 0x08, 0x06, 0xE3, 0x83, 0x92, 0xE3, 0x82,
- 0x99, 0x08, 0x06, 0xE3, 0x83, 0x92, 0xE3, 0x82,
- 0x9A, 0x08, 0x06, 0xE3, 0x83, 0x95, 0xE3, 0x82,
- 0x99, 0x08, 0x06, 0xE3, 0x83, 0x95, 0xE3, 0x82,
- 0x9A, 0x08, 0x06, 0xE3, 0x83, 0x98, 0xE3, 0x82,
- 0x99, 0x08, 0x06, 0xE3, 0x83, 0x98, 0xE3, 0x82,
- // Bytes 4080 - 40bf
- 0x9A, 0x08, 0x06, 0xE3, 0x83, 0x9B, 0xE3, 0x82,
- 0x99, 0x08, 0x06, 0xE3, 0x83, 0x9B, 0xE3, 0x82,
- 0x9A, 0x08, 0x06, 0xE3, 0x83, 0xAF, 0xE3, 0x82,
- 0x99, 0x08, 0x06, 0xE3, 0x83, 0xB0, 0xE3, 0x82,
- 0x99, 0x08, 0x06, 0xE3, 0x83, 0xB1, 0xE3, 0x82,
- 0x99, 0x08, 0x06, 0xE3, 0x83, 0xB2, 0xE3, 0x82,
- 0x99, 0x08, 0x06, 0xE3, 0x83, 0xBD, 0xE3, 0x82,
- 0x99, 0x08, 0x08, 0xCE, 0x91, 0xCC, 0x93, 0xCC,
- // Bytes 40c0 - 40ff
- 0x80, 0xCD, 0x85, 0xF0, 0x08, 0xCE, 0x91, 0xCC,
- 0x93, 0xCC, 0x81, 0xCD, 0x85, 0xF0, 0x08, 0xCE,
- 0x91, 0xCC, 0x93, 0xCD, 0x82, 0xCD, 0x85, 0xF0,
- 0x08, 0xCE, 0x91, 0xCC, 0x94, 0xCC, 0x80, 0xCD,
- 0x85, 0xF0, 0x08, 0xCE, 0x91, 0xCC, 0x94, 0xCC,
- 0x81, 0xCD, 0x85, 0xF0, 0x08, 0xCE, 0x91, 0xCC,
- 0x94, 0xCD, 0x82, 0xCD, 0x85, 0xF0, 0x08, 0xCE,
- 0x97, 0xCC, 0x93, 0xCC, 0x80, 0xCD, 0x85, 0xF0,
- // Bytes 4100 - 413f
- 0x08, 0xCE, 0x97, 0xCC, 0x93, 0xCC, 0x81, 0xCD,
- 0x85, 0xF0, 0x08, 0xCE, 0x97, 0xCC, 0x93, 0xCD,
- 0x82, 0xCD, 0x85, 0xF0, 0x08, 0xCE, 0x97, 0xCC,
- 0x94, 0xCC, 0x80, 0xCD, 0x85, 0xF0, 0x08, 0xCE,
- 0x97, 0xCC, 0x94, 0xCC, 0x81, 0xCD, 0x85, 0xF0,
- 0x08, 0xCE, 0x97, 0xCC, 0x94, 0xCD, 0x82, 0xCD,
- 0x85, 0xF0, 0x08, 0xCE, 0xA9, 0xCC, 0x93, 0xCC,
- 0x80, 0xCD, 0x85, 0xF0, 0x08, 0xCE, 0xA9, 0xCC,
- // Bytes 4140 - 417f
- 0x93, 0xCC, 0x81, 0xCD, 0x85, 0xF0, 0x08, 0xCE,
- 0xA9, 0xCC, 0x93, 0xCD, 0x82, 0xCD, 0x85, 0xF0,
- 0x08, 0xCE, 0xA9, 0xCC, 0x94, 0xCC, 0x80, 0xCD,
- 0x85, 0xF0, 0x08, 0xCE, 0xA9, 0xCC, 0x94, 0xCC,
- 0x81, 0xCD, 0x85, 0xF0, 0x08, 0xCE, 0xA9, 0xCC,
- 0x94, 0xCD, 0x82, 0xCD, 0x85, 0xF0, 0x08, 0xCE,
- 0xB1, 0xCC, 0x93, 0xCC, 0x80, 0xCD, 0x85, 0xF0,
- 0x08, 0xCE, 0xB1, 0xCC, 0x93, 0xCC, 0x81, 0xCD,
- // Bytes 4180 - 41bf
- 0x85, 0xF0, 0x08, 0xCE, 0xB1, 0xCC, 0x93, 0xCD,
- 0x82, 0xCD, 0x85, 0xF0, 0x08, 0xCE, 0xB1, 0xCC,
- 0x94, 0xCC, 0x80, 0xCD, 0x85, 0xF0, 0x08, 0xCE,
- 0xB1, 0xCC, 0x94, 0xCC, 0x81, 0xCD, 0x85, 0xF0,
- 0x08, 0xCE, 0xB1, 0xCC, 0x94, 0xCD, 0x82, 0xCD,
- 0x85, 0xF0, 0x08, 0xCE, 0xB7, 0xCC, 0x93, 0xCC,
- 0x80, 0xCD, 0x85, 0xF0, 0x08, 0xCE, 0xB7, 0xCC,
- 0x93, 0xCC, 0x81, 0xCD, 0x85, 0xF0, 0x08, 0xCE,
- // Bytes 41c0 - 41ff
- 0xB7, 0xCC, 0x93, 0xCD, 0x82, 0xCD, 0x85, 0xF0,
- 0x08, 0xCE, 0xB7, 0xCC, 0x94, 0xCC, 0x80, 0xCD,
- 0x85, 0xF0, 0x08, 0xCE, 0xB7, 0xCC, 0x94, 0xCC,
- 0x81, 0xCD, 0x85, 0xF0, 0x08, 0xCE, 0xB7, 0xCC,
- 0x94, 0xCD, 0x82, 0xCD, 0x85, 0xF0, 0x08, 0xCF,
- 0x89, 0xCC, 0x93, 0xCC, 0x80, 0xCD, 0x85, 0xF0,
- 0x08, 0xCF, 0x89, 0xCC, 0x93, 0xCC, 0x81, 0xCD,
- 0x85, 0xF0, 0x08, 0xCF, 0x89, 0xCC, 0x93, 0xCD,
- // Bytes 4200 - 423f
- 0x82, 0xCD, 0x85, 0xF0, 0x08, 0xCF, 0x89, 0xCC,
- 0x94, 0xCC, 0x80, 0xCD, 0x85, 0xF0, 0x08, 0xCF,
- 0x89, 0xCC, 0x94, 0xCC, 0x81, 0xCD, 0x85, 0xF0,
- 0x08, 0xCF, 0x89, 0xCC, 0x94, 0xCD, 0x82, 0xCD,
- 0x85, 0xF0, 0x08, 0xF0, 0x91, 0x82, 0x99, 0xF0,
- 0x91, 0x82, 0xBA, 0x07, 0x08, 0xF0, 0x91, 0x82,
- 0x9B, 0xF0, 0x91, 0x82, 0xBA, 0x07, 0x08, 0xF0,
- 0x91, 0x82, 0xA5, 0xF0, 0x91, 0x82, 0xBA, 0x07,
- // Bytes 4240 - 427f
- 0x43, 0x20, 0xCC, 0x81, 0xE6, 0x43, 0x20, 0xCC,
- 0x83, 0xE6, 0x43, 0x20, 0xCC, 0x84, 0xE6, 0x43,
- 0x20, 0xCC, 0x85, 0xE6, 0x43, 0x20, 0xCC, 0x86,
- 0xE6, 0x43, 0x20, 0xCC, 0x87, 0xE6, 0x43, 0x20,
- 0xCC, 0x88, 0xE6, 0x43, 0x20, 0xCC, 0x8A, 0xE6,
- 0x43, 0x20, 0xCC, 0x8B, 0xE6, 0x43, 0x20, 0xCC,
- 0x93, 0xE6, 0x43, 0x20, 0xCC, 0x94, 0xE6, 0x43,
- 0x20, 0xCC, 0xA7, 0xCA, 0x43, 0x20, 0xCC, 0xA8,
- // Bytes 4280 - 42bf
- 0xCA, 0x43, 0x20, 0xCC, 0xB3, 0xDC, 0x43, 0x20,
- 0xCD, 0x82, 0xE6, 0x43, 0x20, 0xCD, 0x85, 0xF0,
- 0x43, 0x20, 0xD9, 0x8B, 0x1B, 0x43, 0x20, 0xD9,
- 0x8C, 0x1C, 0x43, 0x20, 0xD9, 0x8D, 0x1D, 0x43,
- 0x20, 0xD9, 0x8E, 0x1E, 0x43, 0x20, 0xD9, 0x8F,
- 0x1F, 0x43, 0x20, 0xD9, 0x90, 0x20, 0x43, 0x20,
- 0xD9, 0x91, 0x21, 0x43, 0x20, 0xD9, 0x92, 0x22,
- 0x43, 0x41, 0xCC, 0x8A, 0xE6, 0x43, 0x73, 0xCC,
- // Bytes 42c0 - 42ff
- 0x87, 0xE6, 0x44, 0x20, 0xE3, 0x82, 0x99, 0x08,
- 0x44, 0x20, 0xE3, 0x82, 0x9A, 0x08, 0x44, 0xC2,
- 0xA8, 0xCC, 0x81, 0xE6, 0x44, 0xCE, 0x91, 0xCC,
- 0x81, 0xE6, 0x44, 0xCE, 0x95, 0xCC, 0x81, 0xE6,
- 0x44, 0xCE, 0x97, 0xCC, 0x81, 0xE6, 0x44, 0xCE,
- 0x99, 0xCC, 0x81, 0xE6, 0x44, 0xCE, 0x9F, 0xCC,
- 0x81, 0xE6, 0x44, 0xCE, 0xA5, 0xCC, 0x81, 0xE6,
- 0x44, 0xCE, 0xA5, 0xCC, 0x88, 0xE6, 0x44, 0xCE,
- // Bytes 4300 - 433f
- 0xA9, 0xCC, 0x81, 0xE6, 0x44, 0xCE, 0xB1, 0xCC,
- 0x81, 0xE6, 0x44, 0xCE, 0xB5, 0xCC, 0x81, 0xE6,
- 0x44, 0xCE, 0xB7, 0xCC, 0x81, 0xE6, 0x44, 0xCE,
- 0xB9, 0xCC, 0x81, 0xE6, 0x44, 0xCE, 0xBF, 0xCC,
- 0x81, 0xE6, 0x44, 0xCF, 0x85, 0xCC, 0x81, 0xE6,
- 0x44, 0xCF, 0x89, 0xCC, 0x81, 0xE6, 0x44, 0xD7,
- 0x90, 0xD6, 0xB7, 0x11, 0x44, 0xD7, 0x90, 0xD6,
- 0xB8, 0x12, 0x44, 0xD7, 0x90, 0xD6, 0xBC, 0x15,
- // Bytes 4340 - 437f
- 0x44, 0xD7, 0x91, 0xD6, 0xBC, 0x15, 0x44, 0xD7,
- 0x91, 0xD6, 0xBF, 0x17, 0x44, 0xD7, 0x92, 0xD6,
- 0xBC, 0x15, 0x44, 0xD7, 0x93, 0xD6, 0xBC, 0x15,
- 0x44, 0xD7, 0x94, 0xD6, 0xBC, 0x15, 0x44, 0xD7,
- 0x95, 0xD6, 0xB9, 0x13, 0x44, 0xD7, 0x95, 0xD6,
- 0xBC, 0x15, 0x44, 0xD7, 0x96, 0xD6, 0xBC, 0x15,
- 0x44, 0xD7, 0x98, 0xD6, 0xBC, 0x15, 0x44, 0xD7,
- 0x99, 0xD6, 0xB4, 0x0E, 0x44, 0xD7, 0x99, 0xD6,
- // Bytes 4380 - 43bf
- 0xBC, 0x15, 0x44, 0xD7, 0x9A, 0xD6, 0xBC, 0x15,
- 0x44, 0xD7, 0x9B, 0xD6, 0xBC, 0x15, 0x44, 0xD7,
- 0x9B, 0xD6, 0xBF, 0x17, 0x44, 0xD7, 0x9C, 0xD6,
- 0xBC, 0x15, 0x44, 0xD7, 0x9E, 0xD6, 0xBC, 0x15,
- 0x44, 0xD7, 0xA0, 0xD6, 0xBC, 0x15, 0x44, 0xD7,
- 0xA1, 0xD6, 0xBC, 0x15, 0x44, 0xD7, 0xA3, 0xD6,
- 0xBC, 0x15, 0x44, 0xD7, 0xA4, 0xD6, 0xBC, 0x15,
- 0x44, 0xD7, 0xA4, 0xD6, 0xBF, 0x17, 0x44, 0xD7,
- // Bytes 43c0 - 43ff
- 0xA6, 0xD6, 0xBC, 0x15, 0x44, 0xD7, 0xA7, 0xD6,
- 0xBC, 0x15, 0x44, 0xD7, 0xA8, 0xD6, 0xBC, 0x15,
- 0x44, 0xD7, 0xA9, 0xD6, 0xBC, 0x15, 0x44, 0xD7,
- 0xA9, 0xD7, 0x81, 0x18, 0x44, 0xD7, 0xA9, 0xD7,
- 0x82, 0x19, 0x44, 0xD7, 0xAA, 0xD6, 0xBC, 0x15,
- 0x44, 0xD7, 0xB2, 0xD6, 0xB7, 0x11, 0x44, 0xD8,
- 0xA7, 0xD9, 0x8B, 0x1B, 0x44, 0xD8, 0xA7, 0xD9,
- 0x93, 0xE6, 0x44, 0xD8, 0xA7, 0xD9, 0x94, 0xE6,
- // Bytes 4400 - 443f
- 0x44, 0xD8, 0xA7, 0xD9, 0x95, 0xDC, 0x44, 0xD8,
- 0xB0, 0xD9, 0xB0, 0x23, 0x44, 0xD8, 0xB1, 0xD9,
- 0xB0, 0x23, 0x44, 0xD9, 0x80, 0xD9, 0x8B, 0x1B,
- 0x44, 0xD9, 0x80, 0xD9, 0x8E, 0x1E, 0x44, 0xD9,
- 0x80, 0xD9, 0x8F, 0x1F, 0x44, 0xD9, 0x80, 0xD9,
- 0x90, 0x20, 0x44, 0xD9, 0x80, 0xD9, 0x91, 0x21,
- 0x44, 0xD9, 0x80, 0xD9, 0x92, 0x22, 0x44, 0xD9,
- 0x87, 0xD9, 0xB0, 0x23, 0x44, 0xD9, 0x88, 0xD9,
- // Bytes 4440 - 447f
- 0x94, 0xE6, 0x44, 0xD9, 0x89, 0xD9, 0xB0, 0x23,
- 0x44, 0xD9, 0x8A, 0xD9, 0x94, 0xE6, 0x44, 0xDB,
- 0x92, 0xD9, 0x94, 0xE6, 0x44, 0xDB, 0x95, 0xD9,
- 0x94, 0xE6, 0x45, 0x20, 0xCC, 0x88, 0xCC, 0x80,
- 0xE6, 0x45, 0x20, 0xCC, 0x88, 0xCC, 0x81, 0xE6,
- 0x45, 0x20, 0xCC, 0x88, 0xCD, 0x82, 0xE6, 0x45,
- 0x20, 0xCC, 0x93, 0xCC, 0x80, 0xE6, 0x45, 0x20,
- 0xCC, 0x93, 0xCC, 0x81, 0xE6, 0x45, 0x20, 0xCC,
- // Bytes 4480 - 44bf
- 0x93, 0xCD, 0x82, 0xE6, 0x45, 0x20, 0xCC, 0x94,
- 0xCC, 0x80, 0xE6, 0x45, 0x20, 0xCC, 0x94, 0xCC,
- 0x81, 0xE6, 0x45, 0x20, 0xCC, 0x94, 0xCD, 0x82,
- 0xE6, 0x45, 0x20, 0xD9, 0x8C, 0xD9, 0x91, 0x21,
- 0x45, 0x20, 0xD9, 0x8D, 0xD9, 0x91, 0x21, 0x45,
- 0x20, 0xD9, 0x8E, 0xD9, 0x91, 0x21, 0x45, 0x20,
- 0xD9, 0x8F, 0xD9, 0x91, 0x21, 0x45, 0x20, 0xD9,
- 0x90, 0xD9, 0x91, 0x21, 0x45, 0x20, 0xD9, 0x91,
- // Bytes 44c0 - 44ff
- 0xD9, 0xB0, 0x23, 0x45, 0xE2, 0xAB, 0x9D, 0xCC,
- 0xB8, 0x01, 0x46, 0xCE, 0xB9, 0xCC, 0x88, 0xCC,
- 0x81, 0xE6, 0x46, 0xCF, 0x85, 0xCC, 0x88, 0xCC,
- 0x81, 0xE6, 0x46, 0xD7, 0xA9, 0xD6, 0xBC, 0xD7,
- 0x81, 0x18, 0x46, 0xD7, 0xA9, 0xD6, 0xBC, 0xD7,
- 0x82, 0x19, 0x46, 0xD9, 0x80, 0xD9, 0x8E, 0xD9,
- 0x91, 0x21, 0x46, 0xD9, 0x80, 0xD9, 0x8F, 0xD9,
- 0x91, 0x21, 0x46, 0xD9, 0x80, 0xD9, 0x90, 0xD9,
- // Bytes 4500 - 453f
- 0x91, 0x21, 0x46, 0xE0, 0xA4, 0x95, 0xE0, 0xA4,
- 0xBC, 0x07, 0x46, 0xE0, 0xA4, 0x96, 0xE0, 0xA4,
- 0xBC, 0x07, 0x46, 0xE0, 0xA4, 0x97, 0xE0, 0xA4,
- 0xBC, 0x07, 0x46, 0xE0, 0xA4, 0x9C, 0xE0, 0xA4,
- 0xBC, 0x07, 0x46, 0xE0, 0xA4, 0xA1, 0xE0, 0xA4,
- 0xBC, 0x07, 0x46, 0xE0, 0xA4, 0xA2, 0xE0, 0xA4,
- 0xBC, 0x07, 0x46, 0xE0, 0xA4, 0xAB, 0xE0, 0xA4,
- 0xBC, 0x07, 0x46, 0xE0, 0xA4, 0xAF, 0xE0, 0xA4,
- // Bytes 4540 - 457f
- 0xBC, 0x07, 0x46, 0xE0, 0xA6, 0xA1, 0xE0, 0xA6,
- 0xBC, 0x07, 0x46, 0xE0, 0xA6, 0xA2, 0xE0, 0xA6,
- 0xBC, 0x07, 0x46, 0xE0, 0xA6, 0xAF, 0xE0, 0xA6,
- 0xBC, 0x07, 0x46, 0xE0, 0xA8, 0x96, 0xE0, 0xA8,
- 0xBC, 0x07, 0x46, 0xE0, 0xA8, 0x97, 0xE0, 0xA8,
- 0xBC, 0x07, 0x46, 0xE0, 0xA8, 0x9C, 0xE0, 0xA8,
- 0xBC, 0x07, 0x46, 0xE0, 0xA8, 0xAB, 0xE0, 0xA8,
- 0xBC, 0x07, 0x46, 0xE0, 0xA8, 0xB2, 0xE0, 0xA8,
- // Bytes 4580 - 45bf
- 0xBC, 0x07, 0x46, 0xE0, 0xA8, 0xB8, 0xE0, 0xA8,
- 0xBC, 0x07, 0x46, 0xE0, 0xAC, 0xA1, 0xE0, 0xAC,
- 0xBC, 0x07, 0x46, 0xE0, 0xAC, 0xA2, 0xE0, 0xAC,
- 0xBC, 0x07, 0x46, 0xE0, 0xBE, 0xB2, 0xE0, 0xBE,
- 0x80, 0x82, 0x46, 0xE0, 0xBE, 0xB3, 0xE0, 0xBE,
- 0x80, 0x82, 0x46, 0xE3, 0x83, 0x86, 0xE3, 0x82,
- 0x99, 0x08, 0x48, 0xF0, 0x9D, 0x85, 0x97, 0xF0,
- 0x9D, 0x85, 0xA5, 0xD8, 0x48, 0xF0, 0x9D, 0x85,
- // Bytes 45c0 - 45ff
- 0x98, 0xF0, 0x9D, 0x85, 0xA5, 0xD8, 0x48, 0xF0,
- 0x9D, 0x86, 0xB9, 0xF0, 0x9D, 0x85, 0xA5, 0xD8,
- 0x48, 0xF0, 0x9D, 0x86, 0xBA, 0xF0, 0x9D, 0x85,
- 0xA5, 0xD8, 0x49, 0xE0, 0xBE, 0xB2, 0xE0, 0xBD,
- 0xB1, 0xE0, 0xBE, 0x80, 0x82, 0x49, 0xE0, 0xBE,
- 0xB3, 0xE0, 0xBD, 0xB1, 0xE0, 0xBE, 0x80, 0x82,
- 0x4C, 0xF0, 0x9D, 0x85, 0x98, 0xF0, 0x9D, 0x85,
- 0xA5, 0xF0, 0x9D, 0x85, 0xAE, 0xD8, 0x4C, 0xF0,
- // Bytes 4600 - 463f
- 0x9D, 0x85, 0x98, 0xF0, 0x9D, 0x85, 0xA5, 0xF0,
- 0x9D, 0x85, 0xAF, 0xD8, 0x4C, 0xF0, 0x9D, 0x85,
- 0x98, 0xF0, 0x9D, 0x85, 0xA5, 0xF0, 0x9D, 0x85,
- 0xB0, 0xD8, 0x4C, 0xF0, 0x9D, 0x85, 0x98, 0xF0,
- 0x9D, 0x85, 0xA5, 0xF0, 0x9D, 0x85, 0xB1, 0xD8,
- 0x4C, 0xF0, 0x9D, 0x85, 0x98, 0xF0, 0x9D, 0x85,
- 0xA5, 0xF0, 0x9D, 0x85, 0xB2, 0xD8, 0x4C, 0xF0,
- 0x9D, 0x86, 0xB9, 0xF0, 0x9D, 0x85, 0xA5, 0xF0,
- // Bytes 4640 - 467f
- 0x9D, 0x85, 0xAE, 0xD8, 0x4C, 0xF0, 0x9D, 0x86,
- 0xB9, 0xF0, 0x9D, 0x85, 0xA5, 0xF0, 0x9D, 0x85,
- 0xAF, 0xD8, 0x4C, 0xF0, 0x9D, 0x86, 0xBA, 0xF0,
- 0x9D, 0x85, 0xA5, 0xF0, 0x9D, 0x85, 0xAE, 0xD8,
- 0x4C, 0xF0, 0x9D, 0x86, 0xBA, 0xF0, 0x9D, 0x85,
- 0xA5, 0xF0, 0x9D, 0x85, 0xAF, 0xD8, 0x83, 0x41,
- 0xCC, 0x82, 0xE6, 0x83, 0x41, 0xCC, 0x86, 0xE6,
- 0x83, 0x41, 0xCC, 0x87, 0xE6, 0x83, 0x41, 0xCC,
- // Bytes 4680 - 46bf
- 0x88, 0xE6, 0x83, 0x41, 0xCC, 0x8A, 0xE6, 0x83,
- 0x41, 0xCC, 0xA3, 0xDC, 0x83, 0x43, 0xCC, 0xA7,
- 0xCA, 0x83, 0x45, 0xCC, 0x82, 0xE6, 0x83, 0x45,
- 0xCC, 0x84, 0xE6, 0x83, 0x45, 0xCC, 0xA3, 0xDC,
- 0x83, 0x45, 0xCC, 0xA7, 0xCA, 0x83, 0x49, 0xCC,
- 0x88, 0xE6, 0x83, 0x4C, 0xCC, 0xA3, 0xDC, 0x83,
- 0x4F, 0xCC, 0x82, 0xE6, 0x83, 0x4F, 0xCC, 0x83,
- 0xE6, 0x83, 0x4F, 0xCC, 0x84, 0xE6, 0x83, 0x4F,
- // Bytes 46c0 - 46ff
- 0xCC, 0x87, 0xE6, 0x83, 0x4F, 0xCC, 0x88, 0xE6,
- 0x83, 0x4F, 0xCC, 0x9B, 0xD8, 0x83, 0x4F, 0xCC,
- 0xA3, 0xDC, 0x83, 0x4F, 0xCC, 0xA8, 0xCA, 0x83,
- 0x52, 0xCC, 0xA3, 0xDC, 0x83, 0x53, 0xCC, 0x81,
- 0xE6, 0x83, 0x53, 0xCC, 0x8C, 0xE6, 0x83, 0x53,
- 0xCC, 0xA3, 0xDC, 0x83, 0x55, 0xCC, 0x83, 0xE6,
- 0x83, 0x55, 0xCC, 0x84, 0xE6, 0x83, 0x55, 0xCC,
- 0x88, 0xE6, 0x83, 0x55, 0xCC, 0x9B, 0xD8, 0x83,
- // Bytes 4700 - 473f
- 0x61, 0xCC, 0x82, 0xE6, 0x83, 0x61, 0xCC, 0x86,
- 0xE6, 0x83, 0x61, 0xCC, 0x87, 0xE6, 0x83, 0x61,
- 0xCC, 0x88, 0xE6, 0x83, 0x61, 0xCC, 0x8A, 0xE6,
- 0x83, 0x61, 0xCC, 0xA3, 0xDC, 0x83, 0x63, 0xCC,
- 0xA7, 0xCA, 0x83, 0x65, 0xCC, 0x82, 0xE6, 0x83,
- 0x65, 0xCC, 0x84, 0xE6, 0x83, 0x65, 0xCC, 0xA3,
- 0xDC, 0x83, 0x65, 0xCC, 0xA7, 0xCA, 0x83, 0x69,
- 0xCC, 0x88, 0xE6, 0x83, 0x6C, 0xCC, 0xA3, 0xDC,
- // Bytes 4740 - 477f
- 0x83, 0x6F, 0xCC, 0x82, 0xE6, 0x83, 0x6F, 0xCC,
- 0x83, 0xE6, 0x83, 0x6F, 0xCC, 0x84, 0xE6, 0x83,
- 0x6F, 0xCC, 0x87, 0xE6, 0x83, 0x6F, 0xCC, 0x88,
- 0xE6, 0x83, 0x6F, 0xCC, 0x9B, 0xD8, 0x83, 0x6F,
- 0xCC, 0xA3, 0xDC, 0x83, 0x6F, 0xCC, 0xA8, 0xCA,
- 0x83, 0x72, 0xCC, 0xA3, 0xDC, 0x83, 0x73, 0xCC,
- 0x81, 0xE6, 0x83, 0x73, 0xCC, 0x8C, 0xE6, 0x83,
- 0x73, 0xCC, 0xA3, 0xDC, 0x83, 0x75, 0xCC, 0x83,
- // Bytes 4780 - 47bf
- 0xE6, 0x83, 0x75, 0xCC, 0x84, 0xE6, 0x83, 0x75,
- 0xCC, 0x88, 0xE6, 0x83, 0x75, 0xCC, 0x9B, 0xD8,
- 0x84, 0xCE, 0x91, 0xCC, 0x93, 0xE6, 0x84, 0xCE,
- 0x91, 0xCC, 0x94, 0xE6, 0x84, 0xCE, 0x95, 0xCC,
- 0x93, 0xE6, 0x84, 0xCE, 0x95, 0xCC, 0x94, 0xE6,
- 0x84, 0xCE, 0x97, 0xCC, 0x93, 0xE6, 0x84, 0xCE,
- 0x97, 0xCC, 0x94, 0xE6, 0x84, 0xCE, 0x99, 0xCC,
- 0x93, 0xE6, 0x84, 0xCE, 0x99, 0xCC, 0x94, 0xE6,
- // Bytes 47c0 - 47ff
- 0x84, 0xCE, 0x9F, 0xCC, 0x93, 0xE6, 0x84, 0xCE,
- 0x9F, 0xCC, 0x94, 0xE6, 0x84, 0xCE, 0xA5, 0xCC,
- 0x94, 0xE6, 0x84, 0xCE, 0xA9, 0xCC, 0x93, 0xE6,
- 0x84, 0xCE, 0xA9, 0xCC, 0x94, 0xE6, 0x84, 0xCE,
- 0xB1, 0xCC, 0x80, 0xE6, 0x84, 0xCE, 0xB1, 0xCC,
- 0x81, 0xE6, 0x84, 0xCE, 0xB1, 0xCC, 0x93, 0xE6,
- 0x84, 0xCE, 0xB1, 0xCC, 0x94, 0xE6, 0x84, 0xCE,
- 0xB1, 0xCD, 0x82, 0xE6, 0x84, 0xCE, 0xB5, 0xCC,
- // Bytes 4800 - 483f
- 0x93, 0xE6, 0x84, 0xCE, 0xB5, 0xCC, 0x94, 0xE6,
- 0x84, 0xCE, 0xB7, 0xCC, 0x80, 0xE6, 0x84, 0xCE,
- 0xB7, 0xCC, 0x81, 0xE6, 0x84, 0xCE, 0xB7, 0xCC,
- 0x93, 0xE6, 0x84, 0xCE, 0xB7, 0xCC, 0x94, 0xE6,
- 0x84, 0xCE, 0xB7, 0xCD, 0x82, 0xE6, 0x84, 0xCE,
- 0xB9, 0xCC, 0x88, 0xE6, 0x84, 0xCE, 0xB9, 0xCC,
- 0x93, 0xE6, 0x84, 0xCE, 0xB9, 0xCC, 0x94, 0xE6,
- 0x84, 0xCE, 0xBF, 0xCC, 0x93, 0xE6, 0x84, 0xCE,
- // Bytes 4840 - 487f
- 0xBF, 0xCC, 0x94, 0xE6, 0x84, 0xCF, 0x85, 0xCC,
- 0x88, 0xE6, 0x84, 0xCF, 0x85, 0xCC, 0x93, 0xE6,
- 0x84, 0xCF, 0x85, 0xCC, 0x94, 0xE6, 0x84, 0xCF,
- 0x89, 0xCC, 0x80, 0xE6, 0x84, 0xCF, 0x89, 0xCC,
- 0x81, 0xE6, 0x84, 0xCF, 0x89, 0xCC, 0x93, 0xE6,
- 0x84, 0xCF, 0x89, 0xCC, 0x94, 0xE6, 0x84, 0xCF,
- 0x89, 0xCD, 0x82, 0xE6, 0x86, 0xCE, 0x91, 0xCC,
- 0x93, 0xCC, 0x80, 0xE6, 0x86, 0xCE, 0x91, 0xCC,
- // Bytes 4880 - 48bf
- 0x93, 0xCC, 0x81, 0xE6, 0x86, 0xCE, 0x91, 0xCC,
- 0x93, 0xCD, 0x82, 0xE6, 0x86, 0xCE, 0x91, 0xCC,
- 0x94, 0xCC, 0x80, 0xE6, 0x86, 0xCE, 0x91, 0xCC,
- 0x94, 0xCC, 0x81, 0xE6, 0x86, 0xCE, 0x91, 0xCC,
- 0x94, 0xCD, 0x82, 0xE6, 0x86, 0xCE, 0x97, 0xCC,
- 0x93, 0xCC, 0x80, 0xE6, 0x86, 0xCE, 0x97, 0xCC,
- 0x93, 0xCC, 0x81, 0xE6, 0x86, 0xCE, 0x97, 0xCC,
- 0x93, 0xCD, 0x82, 0xE6, 0x86, 0xCE, 0x97, 0xCC,
- // Bytes 48c0 - 48ff
- 0x94, 0xCC, 0x80, 0xE6, 0x86, 0xCE, 0x97, 0xCC,
- 0x94, 0xCC, 0x81, 0xE6, 0x86, 0xCE, 0x97, 0xCC,
- 0x94, 0xCD, 0x82, 0xE6, 0x86, 0xCE, 0xA9, 0xCC,
- 0x93, 0xCC, 0x80, 0xE6, 0x86, 0xCE, 0xA9, 0xCC,
- 0x93, 0xCC, 0x81, 0xE6, 0x86, 0xCE, 0xA9, 0xCC,
- 0x93, 0xCD, 0x82, 0xE6, 0x86, 0xCE, 0xA9, 0xCC,
- 0x94, 0xCC, 0x80, 0xE6, 0x86, 0xCE, 0xA9, 0xCC,
- 0x94, 0xCC, 0x81, 0xE6, 0x86, 0xCE, 0xA9, 0xCC,
- // Bytes 4900 - 493f
- 0x94, 0xCD, 0x82, 0xE6, 0x86, 0xCE, 0xB1, 0xCC,
- 0x93, 0xCC, 0x80, 0xE6, 0x86, 0xCE, 0xB1, 0xCC,
- 0x93, 0xCC, 0x81, 0xE6, 0x86, 0xCE, 0xB1, 0xCC,
- 0x93, 0xCD, 0x82, 0xE6, 0x86, 0xCE, 0xB1, 0xCC,
- 0x94, 0xCC, 0x80, 0xE6, 0x86, 0xCE, 0xB1, 0xCC,
- 0x94, 0xCC, 0x81, 0xE6, 0x86, 0xCE, 0xB1, 0xCC,
- 0x94, 0xCD, 0x82, 0xE6, 0x86, 0xCE, 0xB7, 0xCC,
- 0x93, 0xCC, 0x80, 0xE6, 0x86, 0xCE, 0xB7, 0xCC,
- // Bytes 4940 - 497f
- 0x93, 0xCC, 0x81, 0xE6, 0x86, 0xCE, 0xB7, 0xCC,
- 0x93, 0xCD, 0x82, 0xE6, 0x86, 0xCE, 0xB7, 0xCC,
- 0x94, 0xCC, 0x80, 0xE6, 0x86, 0xCE, 0xB7, 0xCC,
- 0x94, 0xCC, 0x81, 0xE6, 0x86, 0xCE, 0xB7, 0xCC,
- 0x94, 0xCD, 0x82, 0xE6, 0x86, 0xCF, 0x89, 0xCC,
- 0x93, 0xCC, 0x80, 0xE6, 0x86, 0xCF, 0x89, 0xCC,
- 0x93, 0xCC, 0x81, 0xE6, 0x86, 0xCF, 0x89, 0xCC,
- 0x93, 0xCD, 0x82, 0xE6, 0x86, 0xCF, 0x89, 0xCC,
- // Bytes 4980 - 49bf
- 0x94, 0xCC, 0x80, 0xE6, 0x86, 0xCF, 0x89, 0xCC,
- 0x94, 0xCC, 0x81, 0xE6, 0x86, 0xCF, 0x89, 0xCC,
- 0x94, 0xCD, 0x82, 0xE6, 0x42, 0xCC, 0x80, 0xE6,
- 0xE6, 0x42, 0xCC, 0x81, 0xE6, 0xE6, 0x42, 0xCC,
- 0x93, 0xE6, 0xE6, 0x44, 0xCC, 0x88, 0xCC, 0x81,
- 0xE6, 0xE6, 0x43, 0xE3, 0x82, 0x99, 0x08, 0x08,
- 0x43, 0xE3, 0x82, 0x9A, 0x08, 0x08, 0x46, 0xE0,
- 0xBD, 0xB1, 0xE0, 0xBD, 0xB2, 0x82, 0x81, 0x46,
- // Bytes 49c0 - 49ff
- 0xE0, 0xBD, 0xB1, 0xE0, 0xBD, 0xB4, 0x84, 0x81,
- 0x46, 0xE0, 0xBD, 0xB1, 0xE0, 0xBE, 0x80, 0x82,
- 0x81,
-}
-
-// nfcValues: 2944 entries, 5888 bytes
-// Block 2 is the null block.
-var nfcValues = [2944]uint16{
- // Block 0x0, offset 0x0
- 0x003c: 0x8800, 0x003d: 0x8800, 0x003e: 0x8800,
- // Block 0x1, offset 0x40
- 0x0041: 0x8800, 0x0042: 0x8800, 0x0043: 0x8800, 0x0044: 0x8800, 0x0045: 0x8800,
- 0x0046: 0x8800, 0x0047: 0x8800, 0x0048: 0x8800, 0x0049: 0x8800, 0x004a: 0x8800, 0x004b: 0x8800,
- 0x004c: 0x8800, 0x004d: 0x8800, 0x004e: 0x8800, 0x004f: 0x8800, 0x0050: 0x8800,
- 0x0052: 0x8800, 0x0053: 0x8800, 0x0054: 0x8800, 0x0055: 0x8800, 0x0056: 0x8800, 0x0057: 0x8800,
- 0x0058: 0x8800, 0x0059: 0x8800, 0x005a: 0x8800,
- 0x0061: 0x8800, 0x0062: 0x8800, 0x0063: 0x8800,
- 0x0064: 0x8800, 0x0065: 0x8800, 0x0066: 0x8800, 0x0067: 0x8800, 0x0068: 0x8800, 0x0069: 0x8800,
- 0x006a: 0x8800, 0x006b: 0x8800, 0x006c: 0x8800, 0x006d: 0x8800, 0x006e: 0x8800, 0x006f: 0x8800,
- 0x0070: 0x8800, 0x0072: 0x8800, 0x0073: 0x8800, 0x0074: 0x8800, 0x0075: 0x8800,
- 0x0076: 0x8800, 0x0077: 0x8800, 0x0078: 0x8800, 0x0079: 0x8800, 0x007a: 0x8800,
- // Block 0x2, offset 0x80
- // Block 0x3, offset 0xc0
- 0x00c0: 0x2f59, 0x00c1: 0x2f5e, 0x00c2: 0x466e, 0x00c3: 0x2f63, 0x00c4: 0x467d, 0x00c5: 0x4682,
- 0x00c6: 0x8800, 0x00c7: 0x468c, 0x00c8: 0x2fcc, 0x00c9: 0x2fd1, 0x00ca: 0x4691, 0x00cb: 0x2fe5,
- 0x00cc: 0x3058, 0x00cd: 0x305d, 0x00ce: 0x3062, 0x00cf: 0x46a5, 0x00d1: 0x30ee,
- 0x00d2: 0x3111, 0x00d3: 0x3116, 0x00d4: 0x46af, 0x00d5: 0x46b4, 0x00d6: 0x46c3,
- 0x00d8: 0x8800, 0x00d9: 0x319d, 0x00da: 0x31a2, 0x00db: 0x31a7, 0x00dc: 0x46f5, 0x00dd: 0x321f,
- 0x00e0: 0x3265, 0x00e1: 0x326a, 0x00e2: 0x46ff, 0x00e3: 0x326f,
- 0x00e4: 0x470e, 0x00e5: 0x4713, 0x00e6: 0x8800, 0x00e7: 0x471d, 0x00e8: 0x32d8, 0x00e9: 0x32dd,
- 0x00ea: 0x4722, 0x00eb: 0x32f1, 0x00ec: 0x3369, 0x00ed: 0x336e, 0x00ee: 0x3373, 0x00ef: 0x4736,
- 0x00f1: 0x33ff, 0x00f2: 0x3422, 0x00f3: 0x3427, 0x00f4: 0x4740, 0x00f5: 0x4745,
- 0x00f6: 0x4754, 0x00f8: 0x8800, 0x00f9: 0x34b3, 0x00fa: 0x34b8, 0x00fb: 0x34bd,
- 0x00fc: 0x4786, 0x00fd: 0x353a, 0x00ff: 0x3553,
- // Block 0x4, offset 0x100
- 0x0100: 0x2f68, 0x0101: 0x3274, 0x0102: 0x4673, 0x0103: 0x4704, 0x0104: 0x2f86, 0x0105: 0x3292,
- 0x0106: 0x2f9a, 0x0107: 0x32a6, 0x0108: 0x2f9f, 0x0109: 0x32ab, 0x010a: 0x2fa4, 0x010b: 0x32b0,
- 0x010c: 0x2fa9, 0x010d: 0x32b5, 0x010e: 0x2fb3, 0x010f: 0x32bf,
- 0x0112: 0x4696, 0x0113: 0x4727, 0x0114: 0x2fdb, 0x0115: 0x32e7, 0x0116: 0x2fe0, 0x0117: 0x32ec,
- 0x0118: 0x2ffe, 0x0119: 0x330a, 0x011a: 0x2fef, 0x011b: 0x32fb, 0x011c: 0x3017, 0x011d: 0x3323,
- 0x011e: 0x3021, 0x011f: 0x332d, 0x0120: 0x3026, 0x0121: 0x3332, 0x0122: 0x3030, 0x0123: 0x333c,
- 0x0124: 0x3035, 0x0125: 0x3341, 0x0128: 0x3067, 0x0129: 0x3378,
- 0x012a: 0x306c, 0x012b: 0x337d, 0x012c: 0x3071, 0x012d: 0x3382, 0x012e: 0x3094, 0x012f: 0x33a0,
- 0x0130: 0x3076, 0x0134: 0x309e, 0x0135: 0x33aa,
- 0x0136: 0x30b2, 0x0137: 0x33c3, 0x0139: 0x30bc, 0x013a: 0x33cd, 0x013b: 0x30c6,
- 0x013c: 0x33d7, 0x013d: 0x30c1, 0x013e: 0x33d2,
- // Block 0x5, offset 0x140
- 0x0143: 0x30e9, 0x0144: 0x33fa, 0x0145: 0x3102,
- 0x0146: 0x3413, 0x0147: 0x30f8, 0x0148: 0x3409,
- 0x014c: 0x46b9, 0x014d: 0x474a, 0x014e: 0x311b, 0x014f: 0x342c, 0x0150: 0x3125, 0x0151: 0x3436,
- 0x0154: 0x3143, 0x0155: 0x3454, 0x0156: 0x315c, 0x0157: 0x346d,
- 0x0158: 0x314d, 0x0159: 0x345e, 0x015a: 0x46dc, 0x015b: 0x476d, 0x015c: 0x3166, 0x015d: 0x3477,
- 0x015e: 0x3175, 0x015f: 0x3486, 0x0160: 0x46e1, 0x0161: 0x4772, 0x0162: 0x318e, 0x0163: 0x34a4,
- 0x0164: 0x317f, 0x0165: 0x3495, 0x0168: 0x46eb, 0x0169: 0x477c,
- 0x016a: 0x46f0, 0x016b: 0x4781, 0x016c: 0x31ac, 0x016d: 0x34c2, 0x016e: 0x31b6, 0x016f: 0x34cc,
- 0x0170: 0x31bb, 0x0171: 0x34d1, 0x0172: 0x31d9, 0x0173: 0x34ef, 0x0174: 0x31fc, 0x0175: 0x3512,
- 0x0176: 0x3224, 0x0177: 0x353f, 0x0178: 0x3238, 0x0179: 0x3247, 0x017a: 0x3567, 0x017b: 0x3251,
- 0x017c: 0x3571, 0x017d: 0x3256, 0x017e: 0x3576, 0x017f: 0x8800,
- // Block 0x6, offset 0x180
- 0x018d: 0x2f72, 0x018e: 0x327e, 0x018f: 0x3080, 0x0190: 0x338c, 0x0191: 0x312a,
- 0x0192: 0x343b, 0x0193: 0x31c0, 0x0194: 0x34d6, 0x0195: 0x39b9, 0x0196: 0x3b48, 0x0197: 0x39b2,
- 0x0198: 0x3b41, 0x0199: 0x39c0, 0x019a: 0x3b4f, 0x019b: 0x39ab, 0x019c: 0x3b3a,
- 0x019e: 0x389a, 0x019f: 0x3a29, 0x01a0: 0x3893, 0x01a1: 0x3a22, 0x01a2: 0x359d, 0x01a3: 0x35af,
- 0x01a6: 0x302b, 0x01a7: 0x3337, 0x01a8: 0x30a8, 0x01a9: 0x33b9,
- 0x01aa: 0x46d2, 0x01ab: 0x4763, 0x01ac: 0x397a, 0x01ad: 0x3b09, 0x01ae: 0x35c1, 0x01af: 0x35c7,
- 0x01b0: 0x33af, 0x01b4: 0x3012, 0x01b5: 0x331e,
- 0x01b8: 0x30e4, 0x01b9: 0x33f5, 0x01ba: 0x38a1, 0x01bb: 0x3a30,
- 0x01bc: 0x3597, 0x01bd: 0x35a9, 0x01be: 0x35a3, 0x01bf: 0x35b5,
- // Block 0x7, offset 0x1c0
- 0x01c0: 0x2f77, 0x01c1: 0x3283, 0x01c2: 0x2f7c, 0x01c3: 0x3288, 0x01c4: 0x2ff4, 0x01c5: 0x3300,
- 0x01c6: 0x2ff9, 0x01c7: 0x3305, 0x01c8: 0x3085, 0x01c9: 0x3391, 0x01ca: 0x308a, 0x01cb: 0x3396,
- 0x01cc: 0x312f, 0x01cd: 0x3440, 0x01ce: 0x3134, 0x01cf: 0x3445, 0x01d0: 0x3152, 0x01d1: 0x3463,
- 0x01d2: 0x3157, 0x01d3: 0x3468, 0x01d4: 0x31c5, 0x01d5: 0x34db, 0x01d6: 0x31ca, 0x01d7: 0x34e0,
- 0x01d8: 0x3170, 0x01d9: 0x3481, 0x01da: 0x3189, 0x01db: 0x349f,
- 0x01de: 0x3044, 0x01df: 0x3350,
- 0x01e6: 0x4678, 0x01e7: 0x4709, 0x01e8: 0x46a0, 0x01e9: 0x4731,
- 0x01ea: 0x3949, 0x01eb: 0x3ad8, 0x01ec: 0x3926, 0x01ed: 0x3ab5, 0x01ee: 0x46be, 0x01ef: 0x474f,
- 0x01f0: 0x3942, 0x01f1: 0x3ad1, 0x01f2: 0x322e, 0x01f3: 0x3549,
- // Block 0x8, offset 0x200
- 0x0200: 0x86e6, 0x0201: 0x86e6, 0x0202: 0x86e6, 0x0203: 0x86e6, 0x0204: 0x86e6, 0x0205: 0x80e6,
- 0x0206: 0x86e6, 0x0207: 0x86e6, 0x0208: 0x86e6, 0x0209: 0x86e6, 0x020a: 0x86e6, 0x020b: 0x86e6,
- 0x020c: 0x86e6, 0x020d: 0x80e6, 0x020e: 0x80e6, 0x020f: 0x86e6, 0x0210: 0x80e6, 0x0211: 0x86e6,
- 0x0212: 0x80e6, 0x0213: 0x86e6, 0x0214: 0x86e6, 0x0215: 0x80e8, 0x0216: 0x80dc, 0x0217: 0x80dc,
- 0x0218: 0x80dc, 0x0219: 0x80dc, 0x021a: 0x80e8, 0x021b: 0x86d8, 0x021c: 0x80dc, 0x021d: 0x80dc,
- 0x021e: 0x80dc, 0x021f: 0x80dc, 0x0220: 0x80dc, 0x0221: 0x80ca, 0x0222: 0x80ca, 0x0223: 0x86dc,
- 0x0224: 0x86dc, 0x0225: 0x86dc, 0x0226: 0x86dc, 0x0227: 0x86ca, 0x0228: 0x86ca, 0x0229: 0x80dc,
- 0x022a: 0x80dc, 0x022b: 0x80dc, 0x022c: 0x80dc, 0x022d: 0x86dc, 0x022e: 0x86dc, 0x022f: 0x80dc,
- 0x0230: 0x86dc, 0x0231: 0x86dc, 0x0232: 0x80dc, 0x0233: 0x80dc, 0x0234: 0x8001, 0x0235: 0x8001,
- 0x0236: 0x8001, 0x0237: 0x8001, 0x0238: 0x8601, 0x0239: 0x80dc, 0x023a: 0x80dc, 0x023b: 0x80dc,
- 0x023c: 0x80dc, 0x023d: 0x80e6, 0x023e: 0x80e6, 0x023f: 0x80e6,
- // Block 0x9, offset 0x240
- 0x0240: 0x4994, 0x0241: 0x4999, 0x0242: 0x86e6, 0x0243: 0x499e, 0x0244: 0x49a3, 0x0245: 0x86f0,
- 0x0246: 0x80e6, 0x0247: 0x80dc, 0x0248: 0x80dc, 0x0249: 0x80dc, 0x024a: 0x80e6, 0x024b: 0x80e6,
- 0x024c: 0x80e6, 0x024d: 0x80dc, 0x024e: 0x80dc, 0x0250: 0x80e6, 0x0251: 0x80e6,
- 0x0252: 0x80e6, 0x0253: 0x80dc, 0x0254: 0x80dc, 0x0255: 0x80dc, 0x0256: 0x80dc, 0x0257: 0x80e6,
- 0x0258: 0x80e8, 0x0259: 0x80dc, 0x025a: 0x80dc, 0x025b: 0x80e6, 0x025c: 0x80e9, 0x025d: 0x80ea,
- 0x025e: 0x80ea, 0x025f: 0x80e9, 0x0260: 0x80ea, 0x0261: 0x80ea, 0x0262: 0x80e9, 0x0263: 0x80e6,
- 0x0264: 0x80e6, 0x0265: 0x80e6, 0x0266: 0x80e6, 0x0267: 0x80e6, 0x0268: 0x80e6, 0x0269: 0x80e6,
- 0x026a: 0x80e6, 0x026b: 0x80e6, 0x026c: 0x80e6, 0x026d: 0x80e6, 0x026e: 0x80e6, 0x026f: 0x80e6,
- 0x0274: 0x0170,
- 0x027e: 0x0037,
- // Block 0xa, offset 0x280
- 0x0285: 0x358b,
- 0x0286: 0x35d3, 0x0287: 0x00d1, 0x0288: 0x35f1, 0x0289: 0x35fd, 0x028a: 0x360f,
- 0x028c: 0x362d, 0x028e: 0x363f, 0x028f: 0x365d, 0x0290: 0x3df2, 0x0291: 0x8800,
- 0x0295: 0x8800, 0x0297: 0x8800,
- 0x0299: 0x8800,
- 0x029f: 0x8800, 0x02a1: 0x8800,
- 0x02a5: 0x8800, 0x02a9: 0x8800,
- 0x02aa: 0x3621, 0x02ab: 0x3651, 0x02ac: 0x47e4, 0x02ad: 0x3681, 0x02ae: 0x480e, 0x02af: 0x3693,
- 0x02b0: 0x3e5a, 0x02b1: 0x8800, 0x02b5: 0x8800,
- 0x02b7: 0x8800, 0x02b9: 0x8800,
- 0x02bf: 0x8800,
- // Block 0xb, offset 0x2c0
- 0x02c0: 0x370b, 0x02c1: 0x3717, 0x02c3: 0x3705,
- 0x02c6: 0x8800, 0x02c7: 0x36f3,
- 0x02cc: 0x3747, 0x02cd: 0x372f, 0x02ce: 0x3759, 0x02d0: 0x8800,
- 0x02d3: 0x8800, 0x02d5: 0x8800, 0x02d6: 0x8800, 0x02d7: 0x8800,
- 0x02d8: 0x8800, 0x02d9: 0x373b, 0x02da: 0x8800,
- 0x02de: 0x8800, 0x02e3: 0x8800,
- 0x02e7: 0x8800,
- 0x02eb: 0x8800, 0x02ed: 0x8800,
- 0x02f0: 0x8800, 0x02f3: 0x8800, 0x02f5: 0x8800,
- 0x02f6: 0x8800, 0x02f7: 0x8800, 0x02f8: 0x8800, 0x02f9: 0x37bf, 0x02fa: 0x8800,
- 0x02fe: 0x8800,
- // Block 0xc, offset 0x300
- 0x0301: 0x371d, 0x0302: 0x37a1,
- 0x0310: 0x36f9, 0x0311: 0x377d,
- 0x0312: 0x36ff, 0x0313: 0x3783, 0x0316: 0x3711, 0x0317: 0x3795,
- 0x0318: 0x8800, 0x0319: 0x8800, 0x031a: 0x3813, 0x031b: 0x3819, 0x031c: 0x3723, 0x031d: 0x37a7,
- 0x031e: 0x3729, 0x031f: 0x37ad, 0x0322: 0x3735, 0x0323: 0x37b9,
- 0x0324: 0x3741, 0x0325: 0x37c5, 0x0326: 0x374d, 0x0327: 0x37d1, 0x0328: 0x8800, 0x0329: 0x8800,
- 0x032a: 0x381f, 0x032b: 0x3825, 0x032c: 0x3777, 0x032d: 0x37fb, 0x032e: 0x3753, 0x032f: 0x37d7,
- 0x0330: 0x375f, 0x0331: 0x37e3, 0x0332: 0x3765, 0x0333: 0x37e9, 0x0334: 0x376b, 0x0335: 0x37ef,
- 0x0338: 0x3771, 0x0339: 0x37f5,
- // Block 0xd, offset 0x340
- 0x0351: 0x80dc,
- 0x0352: 0x80e6, 0x0353: 0x80e6, 0x0354: 0x80e6, 0x0355: 0x80e6, 0x0356: 0x80dc, 0x0357: 0x80e6,
- 0x0358: 0x80e6, 0x0359: 0x80e6, 0x035a: 0x80de, 0x035b: 0x80dc, 0x035c: 0x80e6, 0x035d: 0x80e6,
- 0x035e: 0x80e6, 0x035f: 0x80e6, 0x0360: 0x80e6, 0x0361: 0x80e6, 0x0362: 0x80dc, 0x0363: 0x80dc,
- 0x0364: 0x80dc, 0x0365: 0x80dc, 0x0366: 0x80dc, 0x0367: 0x80dc, 0x0368: 0x80e6, 0x0369: 0x80e6,
- 0x036a: 0x80dc, 0x036b: 0x80e6, 0x036c: 0x80e6, 0x036d: 0x80de, 0x036e: 0x80e4, 0x036f: 0x80e6,
- 0x0370: 0x800a, 0x0371: 0x800b, 0x0372: 0x800c, 0x0373: 0x800d, 0x0374: 0x800e, 0x0375: 0x800f,
- 0x0376: 0x8010, 0x0377: 0x8011, 0x0378: 0x8012, 0x0379: 0x8013, 0x037a: 0x8013, 0x037b: 0x8014,
- 0x037c: 0x8015, 0x037d: 0x8016, 0x037f: 0x8017,
- // Block 0xe, offset 0x380
- 0x0388: 0x8800, 0x038a: 0x8800, 0x038b: 0x801b,
- 0x038c: 0x801c, 0x038d: 0x801d, 0x038e: 0x801e, 0x038f: 0x801f, 0x0390: 0x8020, 0x0391: 0x8021,
- 0x0392: 0x8022, 0x0393: 0x86e6, 0x0394: 0x86e6, 0x0395: 0x86dc, 0x0396: 0x80dc, 0x0397: 0x80e6,
- 0x0398: 0x80e6, 0x0399: 0x80e6, 0x039a: 0x80e6, 0x039b: 0x80e6, 0x039c: 0x80dc, 0x039d: 0x80e6,
- 0x039e: 0x80e6, 0x039f: 0x80dc,
- 0x03b0: 0x8023,
- // Block 0xf, offset 0x3c0
- 0x03c5: 0x8800,
- 0x03c6: 0x1946, 0x03c7: 0x8800, 0x03c8: 0x194d, 0x03c9: 0x8800, 0x03ca: 0x1954, 0x03cb: 0x8800,
- 0x03cc: 0x195b, 0x03cd: 0x8800, 0x03ce: 0x1962, 0x03d1: 0x8800,
- 0x03d2: 0x1969,
- 0x03f4: 0x8007, 0x03f5: 0x8600,
- 0x03fa: 0x8800, 0x03fb: 0x1970,
- 0x03fc: 0x8800, 0x03fd: 0x1977, 0x03fe: 0x8800, 0x03ff: 0x8800,
- // Block 0x10, offset 0x400
- 0x0400: 0x2f81, 0x0401: 0x328d, 0x0402: 0x2f8b, 0x0403: 0x3297, 0x0404: 0x2f90, 0x0405: 0x329c,
- 0x0406: 0x2f95, 0x0407: 0x32a1, 0x0408: 0x38b6, 0x0409: 0x3a45, 0x040a: 0x2fae, 0x040b: 0x32ba,
- 0x040c: 0x2fb8, 0x040d: 0x32c4, 0x040e: 0x2fc7, 0x040f: 0x32d3, 0x0410: 0x2fbd, 0x0411: 0x32c9,
- 0x0412: 0x2fc2, 0x0413: 0x32ce, 0x0414: 0x38d9, 0x0415: 0x3a68, 0x0416: 0x38e0, 0x0417: 0x3a6f,
- 0x0418: 0x3003, 0x0419: 0x330f, 0x041a: 0x3008, 0x041b: 0x3314, 0x041c: 0x38ee, 0x041d: 0x3a7d,
- 0x041e: 0x300d, 0x041f: 0x3319, 0x0420: 0x301c, 0x0421: 0x3328, 0x0422: 0x303a, 0x0423: 0x3346,
- 0x0424: 0x3049, 0x0425: 0x3355, 0x0426: 0x303f, 0x0427: 0x334b, 0x0428: 0x304e, 0x0429: 0x335a,
- 0x042a: 0x3053, 0x042b: 0x335f, 0x042c: 0x3099, 0x042d: 0x33a5, 0x042e: 0x38f5, 0x042f: 0x3a84,
- 0x0430: 0x30a3, 0x0431: 0x33b4, 0x0432: 0x30ad, 0x0433: 0x33be, 0x0434: 0x30b7, 0x0435: 0x33c8,
- 0x0436: 0x46aa, 0x0437: 0x473b, 0x0438: 0x38fc, 0x0439: 0x3a8b, 0x043a: 0x30d0, 0x043b: 0x33e1,
- 0x043c: 0x30cb, 0x043d: 0x33dc, 0x043e: 0x30d5, 0x043f: 0x33e6,
- // Block 0x11, offset 0x440
- 0x0440: 0x30da, 0x0441: 0x33eb, 0x0442: 0x30df, 0x0443: 0x33f0, 0x0444: 0x30f3, 0x0445: 0x3404,
- 0x0446: 0x30fd, 0x0447: 0x340e, 0x0448: 0x310c, 0x0449: 0x341d, 0x044a: 0x3107, 0x044b: 0x3418,
- 0x044c: 0x391f, 0x044d: 0x3aae, 0x044e: 0x392d, 0x044f: 0x3abc, 0x0450: 0x3934, 0x0451: 0x3ac3,
- 0x0452: 0x393b, 0x0453: 0x3aca, 0x0454: 0x3139, 0x0455: 0x344a, 0x0456: 0x313e, 0x0457: 0x344f,
- 0x0458: 0x3148, 0x0459: 0x3459, 0x045a: 0x46d7, 0x045b: 0x4768, 0x045c: 0x3981, 0x045d: 0x3b10,
- 0x045e: 0x3161, 0x045f: 0x3472, 0x0460: 0x316b, 0x0461: 0x347c, 0x0462: 0x46e6, 0x0463: 0x4777,
- 0x0464: 0x3988, 0x0465: 0x3b17, 0x0466: 0x398f, 0x0467: 0x3b1e, 0x0468: 0x3996, 0x0469: 0x3b25,
- 0x046a: 0x317a, 0x046b: 0x348b, 0x046c: 0x3184, 0x046d: 0x349a, 0x046e: 0x3198, 0x046f: 0x34ae,
- 0x0470: 0x3193, 0x0471: 0x34a9, 0x0472: 0x31d4, 0x0473: 0x34ea, 0x0474: 0x31e3, 0x0475: 0x34f9,
- 0x0476: 0x31de, 0x0477: 0x34f4, 0x0478: 0x399d, 0x0479: 0x3b2c, 0x047a: 0x39a4, 0x047b: 0x3b33,
- 0x047c: 0x31e8, 0x047d: 0x34fe, 0x047e: 0x31ed, 0x047f: 0x3503,
- // Block 0x12, offset 0x480
- 0x0480: 0x31f2, 0x0481: 0x3508, 0x0482: 0x31f7, 0x0483: 0x350d, 0x0484: 0x3206, 0x0485: 0x351c,
- 0x0486: 0x3201, 0x0487: 0x3517, 0x0488: 0x320b, 0x0489: 0x3526, 0x048a: 0x3210, 0x048b: 0x352b,
- 0x048c: 0x3215, 0x048d: 0x3530, 0x048e: 0x3233, 0x048f: 0x354e, 0x0490: 0x324c, 0x0491: 0x356c,
- 0x0492: 0x325b, 0x0493: 0x357b, 0x0494: 0x3260, 0x0495: 0x3580, 0x0496: 0x3364, 0x0497: 0x3490,
- 0x0498: 0x3521, 0x0499: 0x355d, 0x049b: 0x35bb,
- 0x04a0: 0x4687, 0x04a1: 0x4718, 0x04a2: 0x2f6d, 0x04a3: 0x3279,
- 0x04a4: 0x3862, 0x04a5: 0x39f1, 0x04a6: 0x385b, 0x04a7: 0x39ea, 0x04a8: 0x3870, 0x04a9: 0x39ff,
- 0x04aa: 0x3869, 0x04ab: 0x39f8, 0x04ac: 0x38a8, 0x04ad: 0x3a37, 0x04ae: 0x387e, 0x04af: 0x3a0d,
- 0x04b0: 0x3877, 0x04b1: 0x3a06, 0x04b2: 0x388c, 0x04b3: 0x3a1b, 0x04b4: 0x3885, 0x04b5: 0x3a14,
- 0x04b6: 0x38af, 0x04b7: 0x3a3e, 0x04b8: 0x469b, 0x04b9: 0x472c, 0x04ba: 0x2fea, 0x04bb: 0x32f6,
- 0x04bc: 0x2fd6, 0x04bd: 0x32e2, 0x04be: 0x38c4, 0x04bf: 0x3a53,
- // Block 0x13, offset 0x4c0
- 0x04c0: 0x38bd, 0x04c1: 0x3a4c, 0x04c2: 0x38d2, 0x04c3: 0x3a61, 0x04c4: 0x38cb, 0x04c5: 0x3a5a,
- 0x04c6: 0x38e7, 0x04c7: 0x3a76, 0x04c8: 0x307b, 0x04c9: 0x3387, 0x04ca: 0x308f, 0x04cb: 0x339b,
- 0x04cc: 0x46cd, 0x04cd: 0x475e, 0x04ce: 0x3120, 0x04cf: 0x3431, 0x04d0: 0x390a, 0x04d1: 0x3a99,
- 0x04d2: 0x3903, 0x04d3: 0x3a92, 0x04d4: 0x3918, 0x04d5: 0x3aa7, 0x04d6: 0x3911, 0x04d7: 0x3aa0,
- 0x04d8: 0x3973, 0x04d9: 0x3b02, 0x04da: 0x3957, 0x04db: 0x3ae6, 0x04dc: 0x3950, 0x04dd: 0x3adf,
- 0x04de: 0x3965, 0x04df: 0x3af4, 0x04e0: 0x395e, 0x04e1: 0x3aed, 0x04e2: 0x396c, 0x04e3: 0x3afb,
- 0x04e4: 0x31cf, 0x04e5: 0x34e5, 0x04e6: 0x31b1, 0x04e7: 0x34c7, 0x04e8: 0x39ce, 0x04e9: 0x3b5d,
- 0x04ea: 0x39c7, 0x04eb: 0x3b56, 0x04ec: 0x39dc, 0x04ed: 0x3b6b, 0x04ee: 0x39d5, 0x04ef: 0x3b64,
- 0x04f0: 0x39e3, 0x04f1: 0x3b72, 0x04f2: 0x321a, 0x04f3: 0x3535, 0x04f4: 0x3242, 0x04f5: 0x3562,
- 0x04f6: 0x323d, 0x04f7: 0x3558, 0x04f8: 0x3229, 0x04f9: 0x3544,
- // Block 0x14, offset 0x500
- 0x0500: 0x47ea, 0x0501: 0x47f0, 0x0502: 0x4904, 0x0503: 0x491c, 0x0504: 0x490c, 0x0505: 0x4924,
- 0x0506: 0x4914, 0x0507: 0x492c, 0x0508: 0x4790, 0x0509: 0x4796, 0x050a: 0x4874, 0x050b: 0x488c,
- 0x050c: 0x487c, 0x050d: 0x4894, 0x050e: 0x4884, 0x050f: 0x489c, 0x0510: 0x47fc, 0x0511: 0x4802,
- 0x0512: 0x3da2, 0x0513: 0x3db2, 0x0514: 0x3daa, 0x0515: 0x3dba,
- 0x0518: 0x479c, 0x0519: 0x47a2, 0x051a: 0x3cd2, 0x051b: 0x3ce2, 0x051c: 0x3cda, 0x051d: 0x3cea,
- 0x0520: 0x4814, 0x0521: 0x481a, 0x0522: 0x4934, 0x0523: 0x494c,
- 0x0524: 0x493c, 0x0525: 0x4954, 0x0526: 0x4944, 0x0527: 0x495c, 0x0528: 0x47a8, 0x0529: 0x47ae,
- 0x052a: 0x48a4, 0x052b: 0x48bc, 0x052c: 0x48ac, 0x052d: 0x48c4, 0x052e: 0x48b4, 0x052f: 0x48cc,
- 0x0530: 0x482c, 0x0531: 0x4832, 0x0532: 0x3e02, 0x0533: 0x3e1a, 0x0534: 0x3e0a, 0x0535: 0x3e22,
- 0x0536: 0x3e12, 0x0537: 0x3e2a, 0x0538: 0x47b4, 0x0539: 0x47ba, 0x053a: 0x3d02, 0x053b: 0x3d1a,
- 0x053c: 0x3d0a, 0x053d: 0x3d22, 0x053e: 0x3d12, 0x053f: 0x3d2a,
- // Block 0x15, offset 0x540
- 0x0540: 0x4838, 0x0541: 0x483e, 0x0542: 0x3e32, 0x0543: 0x3e42, 0x0544: 0x3e3a, 0x0545: 0x3e4a,
- 0x0548: 0x47c0, 0x0549: 0x47c6, 0x054a: 0x3d32, 0x054b: 0x3d42,
- 0x054c: 0x3d3a, 0x054d: 0x3d4a, 0x0550: 0x484a, 0x0551: 0x4850,
- 0x0552: 0x3e6a, 0x0553: 0x3e82, 0x0554: 0x3e72, 0x0555: 0x3e8a, 0x0556: 0x3e7a, 0x0557: 0x3e92,
- 0x0559: 0x47cc, 0x055b: 0x3d52, 0x055d: 0x3d5a,
- 0x055f: 0x3d62, 0x0560: 0x4862, 0x0561: 0x4868, 0x0562: 0x4964, 0x0563: 0x497c,
- 0x0564: 0x496c, 0x0565: 0x4984, 0x0566: 0x4974, 0x0567: 0x498c, 0x0568: 0x47d2, 0x0569: 0x47d8,
- 0x056a: 0x48d4, 0x056b: 0x48ec, 0x056c: 0x48dc, 0x056d: 0x48f4, 0x056e: 0x48e4, 0x056f: 0x48fc,
- 0x0570: 0x47de, 0x0571: 0x4304, 0x0572: 0x367b, 0x0573: 0x430a, 0x0574: 0x4808, 0x0575: 0x4310,
- 0x0576: 0x368d, 0x0577: 0x4316, 0x0578: 0x36ab, 0x0579: 0x431c, 0x057a: 0x36c3, 0x057b: 0x4322,
- 0x057c: 0x4856, 0x057d: 0x4328,
- // Block 0x16, offset 0x580
- 0x0580: 0x3d8a, 0x0581: 0x3d92, 0x0582: 0x416e, 0x0583: 0x418c, 0x0584: 0x4178, 0x0585: 0x4196,
- 0x0586: 0x4182, 0x0587: 0x41a0, 0x0588: 0x3cc2, 0x0589: 0x3cca, 0x058a: 0x40ba, 0x058b: 0x40d8,
- 0x058c: 0x40c4, 0x058d: 0x40e2, 0x058e: 0x40ce, 0x058f: 0x40ec, 0x0590: 0x3dd2, 0x0591: 0x3dda,
- 0x0592: 0x41aa, 0x0593: 0x41c8, 0x0594: 0x41b4, 0x0595: 0x41d2, 0x0596: 0x41be, 0x0597: 0x41dc,
- 0x0598: 0x3cf2, 0x0599: 0x3cfa, 0x059a: 0x40f6, 0x059b: 0x4114, 0x059c: 0x4100, 0x059d: 0x411e,
- 0x059e: 0x410a, 0x059f: 0x4128, 0x05a0: 0x3eaa, 0x05a1: 0x3eb2, 0x05a2: 0x41e6, 0x05a3: 0x4204,
- 0x05a4: 0x41f0, 0x05a5: 0x420e, 0x05a6: 0x41fa, 0x05a7: 0x4218, 0x05a8: 0x3d6a, 0x05a9: 0x3d72,
- 0x05aa: 0x4132, 0x05ab: 0x4150, 0x05ac: 0x413c, 0x05ad: 0x415a, 0x05ae: 0x4146, 0x05af: 0x4164,
- 0x05b0: 0x366f, 0x05b1: 0x3669, 0x05b2: 0x3d7a, 0x05b3: 0x3675, 0x05b4: 0x3d82,
- 0x05b6: 0x47f6, 0x05b7: 0x3d9a, 0x05b8: 0x35df, 0x05b9: 0x35d9, 0x05ba: 0x35cd, 0x05bb: 0x42d4,
- 0x05bc: 0x35e5, 0x05be: 0x01d3, 0x05bf: 0x8800,
- // Block 0x17, offset 0x5c0
- 0x05c1: 0x3591, 0x05c2: 0x3dc2, 0x05c3: 0x3687, 0x05c4: 0x3dca,
- 0x05c6: 0x4820, 0x05c7: 0x3de2, 0x05c8: 0x35eb, 0x05c9: 0x42da, 0x05ca: 0x35f7, 0x05cb: 0x42e0,
- 0x05cc: 0x3603, 0x05cd: 0x3b79, 0x05ce: 0x3b80, 0x05cf: 0x3b87, 0x05d0: 0x369f, 0x05d1: 0x3699,
- 0x05d2: 0x3dea, 0x05d3: 0x44ca, 0x05d6: 0x36a5, 0x05d7: 0x3dfa,
- 0x05d8: 0x361b, 0x05d9: 0x3615, 0x05da: 0x3609, 0x05db: 0x42e6, 0x05dd: 0x3b8e,
- 0x05de: 0x3b95, 0x05df: 0x3b9c, 0x05e0: 0x36d5, 0x05e1: 0x36cf, 0x05e2: 0x3e52, 0x05e3: 0x44d2,
- 0x05e4: 0x36b7, 0x05e5: 0x36bd, 0x05e6: 0x36db, 0x05e7: 0x3e62, 0x05e8: 0x364b, 0x05e9: 0x3645,
- 0x05ea: 0x3639, 0x05eb: 0x42f2, 0x05ec: 0x3633, 0x05ed: 0x3585, 0x05ee: 0x42ce, 0x05ef: 0x0081,
- 0x05f2: 0x3e9a, 0x05f3: 0x36e1, 0x05f4: 0x3ea2,
- 0x05f6: 0x486e, 0x05f7: 0x3eba, 0x05f8: 0x3627, 0x05f9: 0x42ec, 0x05fa: 0x3657, 0x05fb: 0x42fe,
- 0x05fc: 0x3663, 0x05fd: 0x00ce, 0x05fe: 0x8800,
- // Block 0x18, offset 0x600
- 0x0601: 0x3bf0, 0x0603: 0x8800, 0x0604: 0x3bf7, 0x0605: 0x8800,
- 0x0607: 0x3bfe, 0x0608: 0x8800, 0x0609: 0x3c05,
- 0x060d: 0x8800,
- 0x0620: 0x2f4f, 0x0621: 0x8800, 0x0622: 0x3c13,
- 0x0624: 0x8800, 0x0625: 0x8800,
- 0x062d: 0x3c0c, 0x062e: 0x2f4a, 0x062f: 0x2f54,
- 0x0630: 0x3c1a, 0x0631: 0x3c21, 0x0632: 0x8800, 0x0633: 0x8800, 0x0634: 0x3c28, 0x0635: 0x3c2f,
- 0x0636: 0x8800, 0x0637: 0x8800, 0x0638: 0x3c36, 0x0639: 0x3c3d, 0x063a: 0x8800, 0x063b: 0x8800,
- 0x063c: 0x8800, 0x063d: 0x8800,
- // Block 0x19, offset 0x640
- 0x0640: 0x3c44, 0x0641: 0x3c4b, 0x0642: 0x8800, 0x0643: 0x8800, 0x0644: 0x3c60, 0x0645: 0x3c67,
- 0x0646: 0x8800, 0x0647: 0x8800, 0x0648: 0x3c6e, 0x0649: 0x3c75,
- 0x0651: 0x8800,
- 0x0652: 0x8800,
- 0x0662: 0x8800,
- 0x0668: 0x8800, 0x0669: 0x8800,
- 0x066b: 0x8800, 0x066c: 0x3c8a, 0x066d: 0x3c91, 0x066e: 0x3c98, 0x066f: 0x3c9f,
- 0x0672: 0x8800, 0x0673: 0x8800, 0x0674: 0x8800, 0x0675: 0x8800,
- // Block 0x1a, offset 0x680
- 0x0686: 0x8800, 0x068b: 0x8800,
- 0x068c: 0x3ef2, 0x068d: 0x8800, 0x068e: 0x3efa, 0x068f: 0x8800, 0x0690: 0x3f02, 0x0691: 0x8800,
- 0x0692: 0x3f0a, 0x0693: 0x8800, 0x0694: 0x3f12, 0x0695: 0x8800, 0x0696: 0x3f1a, 0x0697: 0x8800,
- 0x0698: 0x3f22, 0x0699: 0x8800, 0x069a: 0x3f2a, 0x069b: 0x8800, 0x069c: 0x3f32, 0x069d: 0x8800,
- 0x069e: 0x3f3a, 0x069f: 0x8800, 0x06a0: 0x3f42, 0x06a1: 0x8800, 0x06a2: 0x3f4a,
- 0x06a4: 0x8800, 0x06a5: 0x3f52, 0x06a6: 0x8800, 0x06a7: 0x3f5a, 0x06a8: 0x8800, 0x06a9: 0x3f62,
- 0x06af: 0x8800,
- 0x06b0: 0x3f6a, 0x06b1: 0x3f72, 0x06b2: 0x8800, 0x06b3: 0x3f7a, 0x06b4: 0x3f82, 0x06b5: 0x8800,
- 0x06b6: 0x3f8a, 0x06b7: 0x3f92, 0x06b8: 0x8800, 0x06b9: 0x3f9a, 0x06ba: 0x3fa2, 0x06bb: 0x8800,
- 0x06bc: 0x3faa, 0x06bd: 0x3fb2,
- // Block 0x1b, offset 0x6c0
- 0x06d4: 0x3eea,
- 0x06d9: 0x8608, 0x06da: 0x8608, 0x06dd: 0x8800,
- 0x06de: 0x3fba,
- 0x06e6: 0x8800,
- 0x06eb: 0x8800, 0x06ec: 0x3fca, 0x06ed: 0x8800, 0x06ee: 0x3fd2, 0x06ef: 0x8800,
- 0x06f0: 0x3fda, 0x06f1: 0x8800, 0x06f2: 0x3fe2, 0x06f3: 0x8800, 0x06f4: 0x3fea, 0x06f5: 0x8800,
- 0x06f6: 0x3ff2, 0x06f7: 0x8800, 0x06f8: 0x3ffa, 0x06f9: 0x8800, 0x06fa: 0x4002, 0x06fb: 0x8800,
- 0x06fc: 0x400a, 0x06fd: 0x8800, 0x06fe: 0x4012, 0x06ff: 0x8800,
- // Block 0x1c, offset 0x700
- 0x0700: 0x401a, 0x0701: 0x8800, 0x0702: 0x4022, 0x0704: 0x8800, 0x0705: 0x402a,
- 0x0706: 0x8800, 0x0707: 0x4032, 0x0708: 0x8800, 0x0709: 0x403a,
- 0x070f: 0x8800, 0x0710: 0x4042, 0x0711: 0x404a,
- 0x0712: 0x8800, 0x0713: 0x4052, 0x0714: 0x405a, 0x0715: 0x8800, 0x0716: 0x4062, 0x0717: 0x406a,
- 0x0718: 0x8800, 0x0719: 0x4072, 0x071a: 0x407a, 0x071b: 0x8800, 0x071c: 0x4082, 0x071d: 0x408a,
- 0x072f: 0x8800,
- 0x0730: 0x8800, 0x0731: 0x8800, 0x0732: 0x8800, 0x0734: 0x3fc2,
- 0x0737: 0x4092, 0x0738: 0x409a, 0x0739: 0x40a2, 0x073a: 0x40aa,
- 0x073d: 0x8800, 0x073e: 0x40b2,
- // Block 0x1d, offset 0x740
- 0x0740: 0x13e9, 0x0741: 0x0d6d, 0x0742: 0x1445, 0x0743: 0x1411, 0x0744: 0x0ec9, 0x0745: 0x075d,
- 0x0746: 0x0951, 0x0747: 0x1699, 0x0748: 0x1699, 0x0749: 0x0a7d, 0x074a: 0x14cd, 0x074b: 0x09b5,
- 0x074c: 0x0a79, 0x074d: 0x0c61, 0x074e: 0x1041, 0x074f: 0x11d1, 0x0750: 0x1309, 0x0751: 0x1345,
- 0x0752: 0x1379, 0x0753: 0x148d, 0x0754: 0x0de5, 0x0755: 0x0e71, 0x0756: 0x0f1d, 0x0757: 0x0fb5,
- 0x0758: 0x12d1, 0x0759: 0x14b5, 0x075a: 0x15e1, 0x075b: 0x0781, 0x075c: 0x0925, 0x075d: 0x0df9,
- 0x075e: 0x0f41, 0x075f: 0x1305, 0x0760: 0x1631, 0x0761: 0x0b25, 0x0762: 0x0ee9, 0x0763: 0x12f5,
- 0x0764: 0x1389, 0x0765: 0x0c95, 0x0766: 0x122d, 0x0767: 0x1351, 0x0768: 0x0b91, 0x0769: 0x0d81,
- 0x076a: 0x0e89, 0x076b: 0x0f8d, 0x076c: 0x1499, 0x076d: 0x07c1, 0x076e: 0x0859, 0x076f: 0x08c5,
- 0x0770: 0x0cfd, 0x0771: 0x0df1, 0x0772: 0x0f3d, 0x0773: 0x1061, 0x0774: 0x11e9, 0x0775: 0x12fd,
- 0x0776: 0x1315, 0x0777: 0x1439, 0x0778: 0x155d, 0x0779: 0x1611, 0x077a: 0x162d, 0x077b: 0x109d,
- 0x077c: 0x10dd, 0x077d: 0x1195, 0x077e: 0x12b5, 0x077f: 0x14e9,
- // Block 0x1e, offset 0x780
- 0x0780: 0x1639, 0x0781: 0x13bd, 0x0782: 0x0a39, 0x0783: 0x0bad, 0x0784: 0x114d, 0x0785: 0x120d,
- 0x0786: 0x0f71, 0x0787: 0x10a5, 0x0788: 0x1409, 0x0789: 0x1555, 0x078a: 0x0a35, 0x078b: 0x0b01,
- 0x078c: 0x0de9, 0x078d: 0x0e9d, 0x078e: 0x0ed1, 0x078f: 0x1185, 0x0790: 0x11ad, 0x0791: 0x1515,
- 0x0792: 0x08c1, 0x0793: 0x1219, 0x0794: 0x0865, 0x0795: 0x0861, 0x0796: 0x1109, 0x0797: 0x1199,
- 0x0798: 0x12cd, 0x0799: 0x151d, 0x079a: 0x13d9, 0x079b: 0x0c99, 0x079c: 0x0de5, 0x079d: 0x13c9,
- 0x079e: 0x0769, 0x079f: 0x0ad5, 0x07a0: 0x0c05, 0x07a1: 0x0fa1, 0x07a2: 0x1021, 0x07a3: 0x08e5,
- 0x07a4: 0x10ad, 0x07a5: 0x07d1, 0x07a6: 0x0be9, 0x07a7: 0x0749, 0x07a8: 0x0e5d, 0x07a9: 0x0d15,
- 0x07aa: 0x1181, 0x07ab: 0x0939, 0x07ac: 0x0a25, 0x07ad: 0x106d, 0x07ae: 0x12d5, 0x07af: 0x13ad,
- 0x07b0: 0x0e29, 0x07b1: 0x1469, 0x07b2: 0x0e55, 0x07b3: 0x0ca9, 0x07b4: 0x128d, 0x07b5: 0x0cc9,
- 0x07b6: 0x101d, 0x07b7: 0x079d, 0x07b8: 0x0819, 0x07b9: 0x085d, 0x07ba: 0x0dc5, 0x07bb: 0x116d,
- 0x07bc: 0x1265, 0x07bd: 0x13b9, 0x07be: 0x14c9, 0x07bf: 0x08cd,
- // Block 0x1f, offset 0x7c0
- 0x07c0: 0x0981, 0x07c1: 0x0a89, 0x07c2: 0x0ba1, 0x07c3: 0x0d31, 0x07c4: 0x0eed, 0x07c5: 0x10b1,
- 0x07c6: 0x1505, 0x07c7: 0x15e9, 0x07c8: 0x163d, 0x07c9: 0x1655, 0x07ca: 0x08a9, 0x07cb: 0x0d65,
- 0x07cc: 0x0e15, 0x07cd: 0x145d, 0x07ce: 0x0b6d, 0x07cf: 0x0c49, 0x07d0: 0x0c65, 0x07d1: 0x0cf5,
- 0x07d2: 0x0edd, 0x07d3: 0x0f29, 0x07d4: 0x0fd9, 0x07d5: 0x10fd, 0x07d6: 0x11a1, 0x07d7: 0x1205,
- 0x07d8: 0x144d, 0x07d9: 0x12dd, 0x07da: 0x1475, 0x07db: 0x14ed, 0x07dc: 0x0881, 0x07dd: 0x08ad,
- 0x07de: 0x0995, 0x07df: 0x0f19, 0x07e0: 0x1365, 0x07e1: 0x13ad, 0x07e2: 0x0b8d, 0x07e3: 0x0bfd,
- 0x07e4: 0x0cc1, 0x07e5: 0x0e21, 0x07e6: 0x1149, 0x07e7: 0x0f95, 0x07e8: 0x07ad, 0x07e9: 0x09f1,
- 0x07ea: 0x0ad5, 0x07eb: 0x0b39, 0x07ec: 0x0c09, 0x07ed: 0x0fb1, 0x07ee: 0x0fcd, 0x07ef: 0x11dd,
- 0x07f0: 0x11fd, 0x07f1: 0x14d1, 0x07f2: 0x1551, 0x07f3: 0x1561, 0x07f4: 0x159d, 0x07f5: 0x07c5,
- 0x07f6: 0x10f1, 0x07f7: 0x14bd, 0x07f8: 0x1539, 0x07f9: 0x0c21, 0x07fa: 0x0789, 0x07fb: 0x07e9,
- 0x07fc: 0x0ad9, 0x07fd: 0x0af9, 0x07fe: 0x0d21, 0x07ff: 0x0de5,
- // Block 0x20, offset 0x800
- 0x0800: 0x0f35, 0x0801: 0x103d, 0x0802: 0x12e9, 0x0803: 0x1489, 0x0804: 0x1691, 0x0805: 0x0d55,
- 0x0806: 0x1511, 0x0807: 0x08a5, 0x0808: 0x0da1, 0x0809: 0x0dad, 0x080a: 0x0e81, 0x080b: 0x0eb9,
- 0x080c: 0x0fbd, 0x080d: 0x1019, 0x080e: 0x1099, 0x080f: 0x117d, 0x0810: 0x15a9, 0x0811: 0x0821,
- 0x0812: 0x0c75, 0x0813: 0x1521, 0x0814: 0x07d9, 0x0815: 0x0b1d, 0x0816: 0x0ea1, 0x0817: 0x1451,
- 0x0818: 0x0bd9, 0x0819: 0x0c29, 0x081a: 0x0db5, 0x081b: 0x0fa1, 0x081c: 0x1529, 0x081d: 0x0889,
- 0x081e: 0x0971, 0x081f: 0x0b09, 0x0820: 0x0d45, 0x0821: 0x0d91, 0x0822: 0x0dd1, 0x0823: 0x0e65,
- 0x0824: 0x0fb9, 0x0825: 0x102d, 0x0826: 0x11c9, 0x0827: 0x1369, 0x0828: 0x1375, 0x0829: 0x14c5,
- 0x082a: 0x1545, 0x082b: 0x08f5, 0x082c: 0x0ebd, 0x082d: 0x0975, 0x082e: 0x0f39, 0x082f: 0x0fdd,
- 0x0830: 0x12f9, 0x0831: 0x152d, 0x0832: 0x1619, 0x0833: 0x1641, 0x0834: 0x0da9, 0x0835: 0x0e99,
- 0x0836: 0x1235, 0x0837: 0x1129, 0x0838: 0x1135, 0x0839: 0x1159, 0x083a: 0x0f89, 0x083b: 0x0f11,
- 0x083c: 0x13d5, 0x083d: 0x07a5, 0x083e: 0x129d, 0x083f: 0x088d,
- // Block 0x21, offset 0x840
- 0x0840: 0x087d, 0x0841: 0x0b7d, 0x0842: 0x0c9d, 0x0843: 0x1165, 0x0844: 0x0ac5, 0x0845: 0x0e75,
- 0x0846: 0x0d61, 0x0847: 0x1459, 0x0848: 0x1359, 0x0849: 0x1519, 0x084a: 0x1395, 0x084b: 0x0b99,
- 0x084c: 0x07f9, 0x084d: 0x09cd, 0x0850: 0x0a21,
- 0x0852: 0x0d51, 0x0855: 0x0869, 0x0856: 0x0f91, 0x0857: 0x1055,
- 0x0858: 0x10b9, 0x0859: 0x10d5, 0x085a: 0x10d9, 0x085b: 0x10ed, 0x085c: 0x1569, 0x085d: 0x115d,
- 0x085e: 0x11e1, 0x0860: 0x1301, 0x0862: 0x13c5,
- 0x0865: 0x1479, 0x0866: 0x14a5,
- 0x086a: 0x15bd, 0x086b: 0x15c1, 0x086c: 0x15c5, 0x086d: 0x1629, 0x086e: 0x149d, 0x086f: 0x1535,
- 0x0870: 0x07c9, 0x0871: 0x07ed, 0x0872: 0x0801, 0x0873: 0x08bd, 0x0874: 0x08c9, 0x0875: 0x0909,
- 0x0876: 0x09bd, 0x0877: 0x09d9, 0x0878: 0x09e1, 0x0879: 0x0a1d, 0x087a: 0x0a29, 0x087b: 0x0b05,
- 0x087c: 0x0b0d, 0x087d: 0x0c15, 0x087e: 0x0c3d, 0x087f: 0x0c45,
- // Block 0x22, offset 0x880
- 0x0880: 0x0c5d, 0x0881: 0x0d09, 0x0882: 0x0d39, 0x0883: 0x0d59, 0x0884: 0x0dc9, 0x0885: 0x0e8d,
- 0x0886: 0x0ea9, 0x0887: 0x0ed9, 0x0888: 0x0f2d, 0x0889: 0x0f4d, 0x088a: 0x0fc1, 0x088b: 0x10a1,
- 0x088c: 0x10bd, 0x088d: 0x10c5, 0x088e: 0x10c1, 0x088f: 0x10c9, 0x0890: 0x10cd, 0x0891: 0x10d1,
- 0x0892: 0x10e5, 0x0893: 0x10e9, 0x0894: 0x110d, 0x0895: 0x1121, 0x0896: 0x113d, 0x0897: 0x11a1,
- 0x0898: 0x11a9, 0x0899: 0x11b1, 0x089a: 0x11c5, 0x089b: 0x11ed, 0x089c: 0x123d, 0x089d: 0x1271,
- 0x089e: 0x1271, 0x089f: 0x12d9, 0x08a0: 0x1381, 0x08a1: 0x1399, 0x08a2: 0x13cd, 0x08a3: 0x13d1,
- 0x08a4: 0x1415, 0x08a5: 0x1419, 0x08a6: 0x1471, 0x08a7: 0x1479, 0x08a8: 0x1549, 0x08a9: 0x158d,
- 0x08aa: 0x15a5, 0x08ab: 0x0c0d, 0x08ac: 0x1780, 0x08ad: 0x1255,
- 0x08b0: 0x0751, 0x08b1: 0x0855, 0x08b2: 0x0815, 0x08b3: 0x07bd, 0x08b4: 0x07fd, 0x08b5: 0x0829,
- 0x08b6: 0x08b9, 0x08b7: 0x08d5, 0x08b8: 0x09bd, 0x08b9: 0x09a9, 0x08ba: 0x09b9, 0x08bb: 0x09d5,
- 0x08bc: 0x0a21, 0x08bd: 0x0a31, 0x08be: 0x0a75, 0x08bf: 0x0a81,
- // Block 0x23, offset 0x8c0
- 0x08c0: 0x0a9d, 0x08c1: 0x0aad, 0x08c2: 0x0b95, 0x08c3: 0x0b9d, 0x08c4: 0x0bcd, 0x08c5: 0x0bed,
- 0x08c6: 0x0c1d, 0x08c7: 0x0c35, 0x08c8: 0x0c25, 0x08c9: 0x0c45, 0x08ca: 0x0c39, 0x08cb: 0x0c5d,
- 0x08cc: 0x0c79, 0x08cd: 0x0cd1, 0x08ce: 0x0cdd, 0x08cf: 0x0ce5, 0x08d0: 0x0d0d, 0x08d1: 0x0d51,
- 0x08d2: 0x0d81, 0x08d3: 0x0d85, 0x08d4: 0x0d99, 0x08d5: 0x0e19, 0x08d6: 0x0e29, 0x08d7: 0x0e81,
- 0x08d8: 0x0ecd, 0x08d9: 0x0ec5, 0x08da: 0x0ed9, 0x08db: 0x0ef5, 0x08dc: 0x0f2d, 0x08dd: 0x1085,
- 0x08de: 0x0f51, 0x08df: 0x0f85, 0x08e0: 0x0f91, 0x08e1: 0x0fd1, 0x08e2: 0x0fed, 0x08e3: 0x1011,
- 0x08e4: 0x1035, 0x08e5: 0x1039, 0x08e6: 0x1055, 0x08e7: 0x1059, 0x08e8: 0x1069, 0x08e9: 0x107d,
- 0x08ea: 0x1079, 0x08eb: 0x10a9, 0x08ec: 0x1125, 0x08ed: 0x113d, 0x08ee: 0x1155, 0x08ef: 0x118d,
- 0x08f0: 0x11a1, 0x08f1: 0x11bd, 0x08f2: 0x11ed, 0x08f3: 0x12a1, 0x08f4: 0x12c9, 0x08f5: 0x133d,
- 0x08f6: 0x1385, 0x08f7: 0x1391, 0x08f8: 0x1399, 0x08f9: 0x13b1, 0x08fa: 0x13c5, 0x08fb: 0x13b5,
- 0x08fc: 0x13cd, 0x08fd: 0x13c9, 0x08fe: 0x13c1, 0x08ff: 0x13d1,
- // Block 0x24, offset 0x900
- 0x0900: 0x13dd, 0x0901: 0x1419, 0x0902: 0x1455, 0x0903: 0x1485, 0x0904: 0x14b9, 0x0905: 0x14d9,
- 0x0906: 0x1525, 0x0907: 0x1549, 0x0908: 0x1569, 0x0909: 0x157d, 0x090a: 0x158d, 0x090b: 0x1599,
- 0x090c: 0x15a5, 0x090d: 0x15f9, 0x090e: 0x1699, 0x090f: 0x1717, 0x0910: 0x1712, 0x0911: 0x1744,
- 0x0912: 0x0679, 0x0913: 0x06a1, 0x0914: 0x06a5, 0x0915: 0x17c6, 0x0916: 0x17f3, 0x0917: 0x186b,
- 0x0918: 0x1685, 0x0919: 0x1695,
- // Block 0x25, offset 0x940
- 0x0940: 0x076d, 0x0941: 0x0765, 0x0942: 0x0775, 0x0943: 0x16a9, 0x0944: 0x07b9, 0x0945: 0x07c9,
- 0x0946: 0x07cd, 0x0947: 0x07d5, 0x0948: 0x07dd, 0x0949: 0x07e1, 0x094a: 0x07ed, 0x094b: 0x07e5,
- 0x094c: 0x0625, 0x094d: 0x16bd, 0x094e: 0x0801, 0x094f: 0x0805, 0x0950: 0x0809, 0x0951: 0x0825,
- 0x0952: 0x16ae, 0x0953: 0x0629, 0x0954: 0x0811, 0x0955: 0x0831, 0x0956: 0x16b8, 0x0957: 0x0841,
- 0x0958: 0x0849, 0x0959: 0x07a9, 0x095a: 0x0851, 0x095b: 0x0855, 0x095c: 0x1893, 0x095d: 0x0871,
- 0x095e: 0x0879, 0x095f: 0x0631, 0x0960: 0x0891, 0x0961: 0x0895, 0x0962: 0x089d, 0x0963: 0x08a1,
- 0x0964: 0x0635, 0x0965: 0x08b9, 0x0966: 0x08bd, 0x0967: 0x08c9, 0x0968: 0x08d5, 0x0969: 0x08d9,
- 0x096a: 0x08dd, 0x096b: 0x08e5, 0x096c: 0x0905, 0x096d: 0x0909, 0x096e: 0x0911, 0x096f: 0x0921,
- 0x0970: 0x0929, 0x0971: 0x092d, 0x0972: 0x092d, 0x0973: 0x092d, 0x0974: 0x16cc, 0x0975: 0x0f05,
- 0x0976: 0x0941, 0x0977: 0x0949, 0x0978: 0x16d1, 0x0979: 0x0955, 0x097a: 0x095d, 0x097b: 0x0965,
- 0x097c: 0x098d, 0x097d: 0x0979, 0x097e: 0x0985, 0x097f: 0x0989,
- // Block 0x26, offset 0x980
- 0x0980: 0x0991, 0x0981: 0x0999, 0x0982: 0x099d, 0x0983: 0x09a5, 0x0984: 0x09ad, 0x0985: 0x09b1,
- 0x0986: 0x09b1, 0x0987: 0x09b9, 0x0988: 0x09c1, 0x0989: 0x09c5, 0x098a: 0x09d1, 0x098b: 0x09f5,
- 0x098c: 0x09d9, 0x098d: 0x09f9, 0x098e: 0x09dd, 0x098f: 0x09e5, 0x0990: 0x087d, 0x0991: 0x0a41,
- 0x0992: 0x0a09, 0x0993: 0x0a0d, 0x0994: 0x0a11, 0x0995: 0x0a05, 0x0996: 0x0a19, 0x0997: 0x0a15,
- 0x0998: 0x0a2d, 0x0999: 0x16d6, 0x099a: 0x0a49, 0x099b: 0x0a4d, 0x099c: 0x0a55, 0x099d: 0x0a61,
- 0x099e: 0x0a69, 0x099f: 0x0a85, 0x09a0: 0x16db, 0x09a1: 0x16e0, 0x09a2: 0x0a91, 0x09a3: 0x0a95,
- 0x09a4: 0x0a99, 0x09a5: 0x0a8d, 0x09a6: 0x0aa1, 0x09a7: 0x0639, 0x09a8: 0x063d, 0x09a9: 0x0aa9,
- 0x09aa: 0x0ab1, 0x09ab: 0x0ab1, 0x09ac: 0x16e5, 0x09ad: 0x0acd, 0x09ae: 0x0ad1, 0x09af: 0x0ad5,
- 0x09b0: 0x0add, 0x09b1: 0x16ea, 0x09b2: 0x0ae5, 0x09b3: 0x0ae9, 0x09b4: 0x0bc1, 0x09b5: 0x0af1,
- 0x09b6: 0x0641, 0x09b7: 0x0afd, 0x09b8: 0x0b0d, 0x09b9: 0x0b19, 0x09ba: 0x0b15, 0x09bb: 0x16f4,
- 0x09bc: 0x0b21, 0x09bd: 0x16f9, 0x09be: 0x0b2d, 0x09bf: 0x0b29,
- // Block 0x27, offset 0x9c0
- 0x09c0: 0x0b31, 0x09c1: 0x0b41, 0x09c2: 0x0b45, 0x09c3: 0x0645, 0x09c4: 0x0b55, 0x09c5: 0x0b5d,
- 0x09c6: 0x0b61, 0x09c7: 0x0b65, 0x09c8: 0x0649, 0x09c9: 0x16fe, 0x09ca: 0x064d, 0x09cb: 0x0b81,
- 0x09cc: 0x0b85, 0x09cd: 0x0b89, 0x09ce: 0x0b91, 0x09cf: 0x18c5, 0x09d0: 0x0ba9, 0x09d1: 0x1708,
- 0x09d2: 0x1708, 0x09d3: 0x1249, 0x09d4: 0x0bb9, 0x09d5: 0x0bb9, 0x09d6: 0x0651, 0x09d7: 0x172b,
- 0x09d8: 0x17fd, 0x09d9: 0x0bc9, 0x09da: 0x0bd1, 0x09db: 0x0655, 0x09dc: 0x0be5, 0x09dd: 0x0bf5,
- 0x09de: 0x0bf9, 0x09df: 0x0c01, 0x09e0: 0x0c11, 0x09e1: 0x065d, 0x09e2: 0x0659, 0x09e3: 0x0c15,
- 0x09e4: 0x170d, 0x09e5: 0x0c19, 0x09e6: 0x0c2d, 0x09e7: 0x0c31, 0x09e8: 0x0c35, 0x09e9: 0x0c31,
- 0x09ea: 0x0c41, 0x09eb: 0x0c45, 0x09ec: 0x0c55, 0x09ed: 0x0c4d, 0x09ee: 0x0c51, 0x09ef: 0x0c59,
- 0x09f0: 0x0c5d, 0x09f1: 0x0c61, 0x09f2: 0x0c6d, 0x09f3: 0x0c71, 0x09f4: 0x0c89, 0x09f5: 0x0c91,
- 0x09f6: 0x0ca1, 0x09f7: 0x0cb5, 0x09f8: 0x171c, 0x09f9: 0x0cb1, 0x09fa: 0x0ca5, 0x09fb: 0x0cbd,
- 0x09fc: 0x0cc5, 0x09fd: 0x0cd9, 0x09fe: 0x1721, 0x09ff: 0x0ce1,
- // Block 0x28, offset 0xa00
- 0x0a00: 0x0cd5, 0x0a01: 0x0ccd, 0x0a02: 0x0661, 0x0a03: 0x0ce9, 0x0a04: 0x0cf1, 0x0a05: 0x0cf9,
- 0x0a06: 0x0ced, 0x0a07: 0x0665, 0x0a08: 0x0d09, 0x0a09: 0x0d11, 0x0a0a: 0x1726, 0x0a0b: 0x0d3d,
- 0x0a0c: 0x0d71, 0x0a0d: 0x0d4d, 0x0a0e: 0x0671, 0x0a0f: 0x0d59, 0x0a10: 0x066d, 0x0a11: 0x0669,
- 0x0a12: 0x0835, 0x0a13: 0x0839, 0x0a14: 0x0d75, 0x0a15: 0x0d5d, 0x0a16: 0x121d, 0x0a17: 0x06d5,
- 0x0a18: 0x0d81, 0x0a19: 0x0d85, 0x0a1a: 0x0d89, 0x0a1b: 0x0d9d, 0x0a1c: 0x0d95, 0x0a1d: 0x173f,
- 0x0a1e: 0x0675, 0x0a1f: 0x0db1, 0x0a20: 0x0da5, 0x0a21: 0x0dc1, 0x0a22: 0x0dc9, 0x0a23: 0x1749,
- 0x0a24: 0x0dcd, 0x0a25: 0x0db9, 0x0a26: 0x0dd5, 0x0a27: 0x0679, 0x0a28: 0x0dd9, 0x0a29: 0x0ddd,
- 0x0a2a: 0x0de1, 0x0a2b: 0x0ded, 0x0a2c: 0x174e, 0x0a2d: 0x0df5, 0x0a2e: 0x067d, 0x0a2f: 0x0e01,
- 0x0a30: 0x1753, 0x0a31: 0x0e05, 0x0a32: 0x0681, 0x0a33: 0x0e11, 0x0a34: 0x0e1d, 0x0a35: 0x0e29,
- 0x0a36: 0x0e2d, 0x0a37: 0x1758, 0x0a38: 0x16ef, 0x0a39: 0x175d, 0x0a3a: 0x0e4d, 0x0a3b: 0x1762,
- 0x0a3c: 0x0e59, 0x0a3d: 0x0e61, 0x0a3e: 0x0e51, 0x0a3f: 0x0e6d,
- // Block 0x29, offset 0xa40
- 0x0a40: 0x0e7d, 0x0a41: 0x0e8d, 0x0a42: 0x0e81, 0x0a43: 0x0e85, 0x0a44: 0x0e91, 0x0a45: 0x0e95,
- 0x0a46: 0x1767, 0x0a47: 0x0e79, 0x0a48: 0x0ead, 0x0a49: 0x0eb1, 0x0a4a: 0x0685, 0x0a4b: 0x0ec5,
- 0x0a4c: 0x0ec1, 0x0a4d: 0x176c, 0x0a4e: 0x0ea5, 0x0a4f: 0x0ee1, 0x0a50: 0x1771, 0x0a51: 0x1776,
- 0x0a52: 0x0ee5, 0x0a53: 0x0ef9, 0x0a54: 0x0ef5, 0x0a55: 0x0ef1, 0x0a56: 0x0689, 0x0a57: 0x0efd,
- 0x0a58: 0x0f0d, 0x0a59: 0x0f09, 0x0a5a: 0x0f15, 0x0a5b: 0x16b3, 0x0a5c: 0x0f25, 0x0a5d: 0x177b,
- 0x0a5e: 0x0f31, 0x0a5f: 0x1785, 0x0a60: 0x0f45, 0x0a61: 0x0f51, 0x0a62: 0x0f65, 0x0a63: 0x178a,
- 0x0a64: 0x0f79, 0x0a65: 0x0f7d, 0x0a66: 0x178f, 0x0a67: 0x1794, 0x0a68: 0x0f99, 0x0a69: 0x0fa9,
- 0x0a6a: 0x068d, 0x0a6b: 0x0fad, 0x0a6c: 0x0691, 0x0a6d: 0x0691, 0x0a6e: 0x0fc5, 0x0a6f: 0x0fc9,
- 0x0a70: 0x0fd1, 0x0a71: 0x0fd5, 0x0a72: 0x0fe1, 0x0a73: 0x0695, 0x0a74: 0x0ff9, 0x0a75: 0x1799,
- 0x0a76: 0x1015, 0x0a77: 0x179e, 0x0a78: 0x1021, 0x0a79: 0x1703, 0x0a7a: 0x1031, 0x0a7b: 0x17a3,
- 0x0a7c: 0x17a8, 0x0a7d: 0x17ad, 0x0a7e: 0x0699, 0x0a7f: 0x069d,
- // Block 0x2a, offset 0xa80
- 0x0a80: 0x1069, 0x0a81: 0x17b7, 0x0a82: 0x17b2, 0x0a83: 0x17bc, 0x0a84: 0x17c1, 0x0a85: 0x1071,
- 0x0a86: 0x1075, 0x0a87: 0x1075, 0x0a88: 0x107d, 0x0a89: 0x06a5, 0x0a8a: 0x1081, 0x0a8b: 0x06a9,
- 0x0a8c: 0x06ad, 0x0a8d: 0x17cb, 0x0a8e: 0x1095, 0x0a8f: 0x109d, 0x0a90: 0x10a9, 0x0a91: 0x06b1,
- 0x0a92: 0x17d0, 0x0a93: 0x10cd, 0x0a94: 0x17d5, 0x0a95: 0x17da, 0x0a96: 0x10ed, 0x0a97: 0x1105,
- 0x0a98: 0x06b5, 0x0a99: 0x110d, 0x0a9a: 0x1111, 0x0a9b: 0x1115, 0x0a9c: 0x17df, 0x0a9d: 0x17e4,
- 0x0a9e: 0x17e4, 0x0a9f: 0x112d, 0x0aa0: 0x06b9, 0x0aa1: 0x17e9, 0x0aa2: 0x1141, 0x0aa3: 0x1145,
- 0x0aa4: 0x06bd, 0x0aa5: 0x17ee, 0x0aa6: 0x1161, 0x0aa7: 0x06c1, 0x0aa8: 0x1171, 0x0aa9: 0x1169,
- 0x0aaa: 0x1179, 0x0aab: 0x17f8, 0x0aac: 0x1191, 0x0aad: 0x06c5, 0x0aae: 0x119d, 0x0aaf: 0x11a5,
- 0x0ab0: 0x11b5, 0x0ab1: 0x06c9, 0x0ab2: 0x1802, 0x0ab3: 0x1807, 0x0ab4: 0x06cd, 0x0ab5: 0x180c,
- 0x0ab6: 0x11cd, 0x0ab7: 0x1811, 0x0ab8: 0x11d9, 0x0ab9: 0x11e5, 0x0aba: 0x11ed, 0x0abb: 0x1816,
- 0x0abc: 0x181b, 0x0abd: 0x1201, 0x0abe: 0x1820, 0x0abf: 0x1209,
- // Block 0x2b, offset 0xac0
- 0x0ac0: 0x1730, 0x0ac1: 0x06d1, 0x0ac2: 0x1221, 0x0ac3: 0x1225, 0x0ac4: 0x06d9, 0x0ac5: 0x1229,
- 0x0ac6: 0x0aa5, 0x0ac7: 0x1825, 0x0ac8: 0x182a, 0x0ac9: 0x1735, 0x0aca: 0x173a, 0x0acb: 0x1249,
- 0x0acc: 0x124d, 0x0acd: 0x1465, 0x0ace: 0x06dd, 0x0acf: 0x1279, 0x0ad0: 0x1275, 0x0ad1: 0x127d,
- 0x0ad2: 0x08b1, 0x0ad3: 0x1281, 0x0ad4: 0x1285, 0x0ad5: 0x1289, 0x0ad6: 0x1291, 0x0ad7: 0x182f,
- 0x0ad8: 0x128d, 0x0ad9: 0x1295, 0x0ada: 0x12a9, 0x0adb: 0x12ad, 0x0adc: 0x1299, 0x0add: 0x12b1,
- 0x0ade: 0x12c5, 0x0adf: 0x12d9, 0x0ae0: 0x12a5, 0x0ae1: 0x12b9, 0x0ae2: 0x12bd, 0x0ae3: 0x12c1,
- 0x0ae4: 0x1834, 0x0ae5: 0x183e, 0x0ae6: 0x1839, 0x0ae7: 0x06e1, 0x0ae8: 0x12e1, 0x0ae9: 0x12e5,
- 0x0aea: 0x12ed, 0x0aeb: 0x1852, 0x0aec: 0x12f1, 0x0aed: 0x1843, 0x0aee: 0x06e5, 0x0aef: 0x06e9,
- 0x0af0: 0x1848, 0x0af1: 0x184d, 0x0af2: 0x06ed, 0x0af3: 0x1311, 0x0af4: 0x1315, 0x0af5: 0x1319,
- 0x0af6: 0x131d, 0x0af7: 0x1329, 0x0af8: 0x1325, 0x0af9: 0x1331, 0x0afa: 0x132d, 0x0afb: 0x133d,
- 0x0afc: 0x1335, 0x0afd: 0x1339, 0x0afe: 0x1341, 0x0aff: 0x06f1,
- // Block 0x2c, offset 0xb00
- 0x0b00: 0x1349, 0x0b01: 0x134d, 0x0b02: 0x06f5, 0x0b03: 0x135d, 0x0b04: 0x1361, 0x0b05: 0x1857,
- 0x0b06: 0x136d, 0x0b07: 0x1371, 0x0b08: 0x06f9, 0x0b09: 0x137d, 0x0b0a: 0x062d, 0x0b0b: 0x185c,
- 0x0b0c: 0x1861, 0x0b0d: 0x06fd, 0x0b0e: 0x0701, 0x0b0f: 0x13a9, 0x0b10: 0x13c1, 0x0b11: 0x13dd,
- 0x0b12: 0x13ed, 0x0b13: 0x1866, 0x0b14: 0x1401, 0x0b15: 0x1405, 0x0b16: 0x141d, 0x0b17: 0x1429,
- 0x0b18: 0x1870, 0x0b19: 0x16c2, 0x0b1a: 0x1435, 0x0b1b: 0x1431, 0x0b1c: 0x143d, 0x0b1d: 0x16c7,
- 0x0b1e: 0x1449, 0x0b1f: 0x1455, 0x0b20: 0x1875, 0x0b21: 0x187a, 0x0b22: 0x1495, 0x0b23: 0x14a1,
- 0x0b24: 0x14a9, 0x0b25: 0x187f, 0x0b26: 0x14ad, 0x0b27: 0x14d5, 0x0b28: 0x14e1, 0x0b29: 0x14e5,
- 0x0b2a: 0x14dd, 0x0b2b: 0x14f1, 0x0b2c: 0x14f5, 0x0b2d: 0x1884, 0x0b2e: 0x1501, 0x0b2f: 0x0705,
- 0x0b30: 0x1509, 0x0b31: 0x1889, 0x0b32: 0x0709, 0x0b33: 0x1541, 0x0b34: 0x0b35, 0x0b35: 0x1559,
- 0x0b36: 0x188e, 0x0b37: 0x1898, 0x0b38: 0x070d, 0x0b39: 0x0711, 0x0b3a: 0x1581, 0x0b3b: 0x189d,
- 0x0b3c: 0x0715, 0x0b3d: 0x18a2, 0x0b3e: 0x1599, 0x0b3f: 0x1599,
- // Block 0x2d, offset 0xb40
- 0x0b40: 0x15a1, 0x0b41: 0x18a7, 0x0b42: 0x15b9, 0x0b43: 0x0719, 0x0b44: 0x15c9, 0x0b45: 0x15d5,
- 0x0b46: 0x15dd, 0x0b47: 0x15e5, 0x0b48: 0x071d, 0x0b49: 0x18ac, 0x0b4a: 0x15f9, 0x0b4b: 0x1615,
- 0x0b4c: 0x1621, 0x0b4d: 0x0721, 0x0b4e: 0x0725, 0x0b4f: 0x1625, 0x0b50: 0x18b1, 0x0b51: 0x0729,
- 0x0b52: 0x18b6, 0x0b53: 0x18bb, 0x0b54: 0x18c0, 0x0b55: 0x1649, 0x0b56: 0x072d, 0x0b57: 0x165d,
- 0x0b58: 0x1665, 0x0b59: 0x1669, 0x0b5a: 0x1671, 0x0b5b: 0x1679, 0x0b5c: 0x1681, 0x0b5d: 0x18ca,
-}
-
-// nfcSparseOffset: 98 entries, 196 bytes
-var nfcSparseOffset = []uint16{0x0, 0x2, 0x6, 0x8, 0x13, 0x23, 0x25, 0x2a, 0x35, 0x44, 0x51, 0x59, 0x5d, 0x62, 0x64, 0x73, 0x7b, 0x82, 0x85, 0x8d, 0x91, 0x95, 0x97, 0x99, 0xa2, 0xa6, 0xad, 0xb2, 0xb5, 0xbf, 0xc1, 0xc8, 0xd0, 0xd3, 0xd5, 0xd7, 0xd9, 0xde, 0xed, 0xf9, 0xfb, 0x101, 0x103, 0x105, 0x107, 0x109, 0x10b, 0x10d, 0x110, 0x113, 0x115, 0x118, 0x11b, 0x11f, 0x128, 0x12a, 0x12d, 0x12f, 0x139, 0x148, 0x14a, 0x158, 0x15b, 0x161, 0x167, 0x172, 0x176, 0x178, 0x17a, 0x17c, 0x17e, 0x180, 0x186, 0x189, 0x18b, 0x18d, 0x18f, 0x192, 0x194, 0x196, 0x198, 0x19a, 0x1a0, 0x1a3, 0x1a5, 0x1a7, 0x1a9, 0x1b7, 0x1c0, 0x1c2, 0x1c4, 0x1ca, 0x1d2, 0x1d9, 0x1dc, 0x1e9, 0x1f3, 0x1f5}
-
-// nfcSparseValues: 503 entries, 2012 bytes
-var nfcSparseValues = [503]valueRange{
- // Block 0x0, offset 0x1
- {value: 0x0000, lo: 0x01},
- {value: 0x8800, lo: 0xa8, hi: 0xa8},
- // Block 0x1, offset 0x2
- {value: 0x0091, lo: 0x03},
- {value: 0x46c8, lo: 0xa0, hi: 0xa1},
- {value: 0x46fa, lo: 0xaf, hi: 0xb0},
- {value: 0x8800, lo: 0xb7, hi: 0xb7},
- // Block 0x2, offset 0x3
- {value: 0x0000, lo: 0x01},
- {value: 0x8800, lo: 0x92, hi: 0x92},
- // Block 0x3, offset 0x4
- {value: 0x0006, lo: 0x0a},
- {value: 0x8800, lo: 0x81, hi: 0x81},
- {value: 0x8800, lo: 0x85, hi: 0x85},
- {value: 0x8800, lo: 0x89, hi: 0x89},
- {value: 0x4826, lo: 0x8a, hi: 0x8a},
- {value: 0x4844, lo: 0x8b, hi: 0x8b},
- {value: 0x36b1, lo: 0x8c, hi: 0x8c},
- {value: 0x36c9, lo: 0x8d, hi: 0x8d},
- {value: 0x485c, lo: 0x8e, hi: 0x8e},
- {value: 0x8800, lo: 0x92, hi: 0x92},
- {value: 0x36e7, lo: 0x93, hi: 0x94},
- // Block 0x4, offset 0x5
- {value: 0x0000, lo: 0x0f},
- {value: 0x8800, lo: 0x83, hi: 0x83},
- {value: 0x8800, lo: 0x87, hi: 0x87},
- {value: 0x8800, lo: 0x8b, hi: 0x8b},
- {value: 0x8800, lo: 0x8d, hi: 0x8d},
- {value: 0x378f, lo: 0x90, hi: 0x90},
- {value: 0x379b, lo: 0x91, hi: 0x91},
- {value: 0x3789, lo: 0x93, hi: 0x93},
- {value: 0x8800, lo: 0x96, hi: 0x96},
- {value: 0x3801, lo: 0x97, hi: 0x97},
- {value: 0x37cb, lo: 0x9c, hi: 0x9c},
- {value: 0x37b3, lo: 0x9d, hi: 0x9d},
- {value: 0x37dd, lo: 0x9e, hi: 0x9e},
- {value: 0x8800, lo: 0xb4, hi: 0xb5},
- {value: 0x3807, lo: 0xb6, hi: 0xb6},
- {value: 0x380d, lo: 0xb7, hi: 0xb7},
- // Block 0x5, offset 0x6
- {value: 0x0000, lo: 0x01},
- {value: 0x80e6, lo: 0x83, hi: 0x87},
- // Block 0x6, offset 0x7
- {value: 0x0001, lo: 0x04},
- {value: 0x8018, lo: 0x81, hi: 0x82},
- {value: 0x80e6, lo: 0x84, hi: 0x84},
- {value: 0x80dc, lo: 0x85, hi: 0x85},
- {value: 0x8012, lo: 0x87, hi: 0x87},
- // Block 0x7, offset 0x8
- {value: 0x0000, lo: 0x0a},
- {value: 0x80e6, lo: 0x90, hi: 0x97},
- {value: 0x801e, lo: 0x98, hi: 0x98},
- {value: 0x801f, lo: 0x99, hi: 0x99},
- {value: 0x8020, lo: 0x9a, hi: 0x9a},
- {value: 0x382b, lo: 0xa2, hi: 0xa2},
- {value: 0x3831, lo: 0xa3, hi: 0xa3},
- {value: 0x383d, lo: 0xa4, hi: 0xa4},
- {value: 0x3837, lo: 0xa5, hi: 0xa5},
- {value: 0x3843, lo: 0xa6, hi: 0xa6},
- {value: 0x8800, lo: 0xa7, hi: 0xa7},
- // Block 0x8, offset 0x9
- {value: 0x0000, lo: 0x0e},
- {value: 0x3855, lo: 0x80, hi: 0x80},
- {value: 0x8800, lo: 0x81, hi: 0x81},
- {value: 0x3849, lo: 0x82, hi: 0x82},
- {value: 0x8800, lo: 0x92, hi: 0x92},
- {value: 0x384f, lo: 0x93, hi: 0x93},
- {value: 0x8800, lo: 0x95, hi: 0x95},
- {value: 0x80e6, lo: 0x96, hi: 0x9c},
- {value: 0x80e6, lo: 0x9f, hi: 0xa2},
- {value: 0x80dc, lo: 0xa3, hi: 0xa3},
- {value: 0x80e6, lo: 0xa4, hi: 0xa4},
- {value: 0x80e6, lo: 0xa7, hi: 0xa8},
- {value: 0x80dc, lo: 0xaa, hi: 0xaa},
- {value: 0x80e6, lo: 0xab, hi: 0xac},
- {value: 0x80dc, lo: 0xad, hi: 0xad},
- // Block 0x9, offset 0xa
- {value: 0x0000, lo: 0x0c},
- {value: 0x8024, lo: 0x91, hi: 0x91},
- {value: 0x80e6, lo: 0xb0, hi: 0xb0},
- {value: 0x80dc, lo: 0xb1, hi: 0xb1},
- {value: 0x80e6, lo: 0xb2, hi: 0xb3},
- {value: 0x80dc, lo: 0xb4, hi: 0xb4},
- {value: 0x80e6, lo: 0xb5, hi: 0xb6},
- {value: 0x80dc, lo: 0xb7, hi: 0xb9},
- {value: 0x80e6, lo: 0xba, hi: 0xba},
- {value: 0x80dc, lo: 0xbb, hi: 0xbc},
- {value: 0x80e6, lo: 0xbd, hi: 0xbd},
- {value: 0x80dc, lo: 0xbe, hi: 0xbe},
- {value: 0x80e6, lo: 0xbf, hi: 0xbf},
- // Block 0xa, offset 0xb
- {value: 0x000a, lo: 0x07},
- {value: 0x80e6, lo: 0x80, hi: 0x80},
- {value: 0x80e6, lo: 0x81, hi: 0x81},
- {value: 0x80dc, lo: 0x82, hi: 0x83},
- {value: 0x80dc, lo: 0x84, hi: 0x85},
- {value: 0x80dc, lo: 0x86, hi: 0x87},
- {value: 0x80dc, lo: 0x88, hi: 0x89},
- {value: 0x80e6, lo: 0x8a, hi: 0x8a},
- // Block 0xb, offset 0xc
- {value: 0x0000, lo: 0x03},
- {value: 0x80e6, lo: 0xab, hi: 0xb1},
- {value: 0x80dc, lo: 0xb2, hi: 0xb2},
- {value: 0x80e6, lo: 0xb3, hi: 0xb3},
- // Block 0xc, offset 0xd
- {value: 0x0000, lo: 0x04},
- {value: 0x80e6, lo: 0x96, hi: 0x99},
- {value: 0x80e6, lo: 0x9b, hi: 0xa3},
- {value: 0x80e6, lo: 0xa5, hi: 0xa7},
- {value: 0x80e6, lo: 0xa9, hi: 0xad},
- // Block 0xd, offset 0xe
- {value: 0x0000, lo: 0x01},
- {value: 0x80dc, lo: 0x99, hi: 0x9b},
- // Block 0xe, offset 0xf
- {value: 0x0000, lo: 0x0e},
- {value: 0x80e6, lo: 0xa4, hi: 0xa5},
- {value: 0x80dc, lo: 0xa6, hi: 0xa6},
- {value: 0x80e6, lo: 0xa7, hi: 0xa8},
- {value: 0x80dc, lo: 0xa9, hi: 0xa9},
- {value: 0x80e6, lo: 0xaa, hi: 0xac},
- {value: 0x80dc, lo: 0xad, hi: 0xaf},
- {value: 0x801b, lo: 0xb0, hi: 0xb0},
- {value: 0x801c, lo: 0xb1, hi: 0xb1},
- {value: 0x801d, lo: 0xb2, hi: 0xb2},
- {value: 0x80e6, lo: 0xb3, hi: 0xb5},
- {value: 0x80dc, lo: 0xb6, hi: 0xb6},
- {value: 0x80e6, lo: 0xb7, hi: 0xb8},
- {value: 0x80dc, lo: 0xb9, hi: 0xba},
- {value: 0x80e6, lo: 0xbb, hi: 0xbe},
- // Block 0xf, offset 0x10
- {value: 0x0000, lo: 0x07},
- {value: 0x8800, lo: 0xa8, hi: 0xa8},
- {value: 0x3ec2, lo: 0xa9, hi: 0xa9},
- {value: 0x8800, lo: 0xb0, hi: 0xb0},
- {value: 0x3eca, lo: 0xb1, hi: 0xb1},
- {value: 0x8800, lo: 0xb3, hi: 0xb3},
- {value: 0x3ed2, lo: 0xb4, hi: 0xb4},
- {value: 0x8607, lo: 0xbc, hi: 0xbc},
- // Block 0x10, offset 0x11
- {value: 0x0008, lo: 0x06},
- {value: 0x8009, lo: 0x8d, hi: 0x8d},
- {value: 0x80e6, lo: 0x91, hi: 0x91},
- {value: 0x80dc, lo: 0x92, hi: 0x92},
- {value: 0x80e6, lo: 0x93, hi: 0x93},
- {value: 0x80e6, lo: 0x94, hi: 0x94},
- {value: 0x4502, lo: 0x98, hi: 0x9f},
- // Block 0x11, offset 0x12
- {value: 0x0000, lo: 0x02},
- {value: 0x8007, lo: 0xbc, hi: 0xbc},
- {value: 0x8600, lo: 0xbe, hi: 0xbe},
- // Block 0x12, offset 0x13
- {value: 0x0007, lo: 0x07},
- {value: 0x8800, lo: 0x87, hi: 0x87},
- {value: 0x18cf, lo: 0x8b, hi: 0x8c},
- {value: 0x8009, lo: 0x8d, hi: 0x8d},
- {value: 0x8600, lo: 0x97, hi: 0x97},
- {value: 0x4542, lo: 0x9c, hi: 0x9c},
- {value: 0x454a, lo: 0x9d, hi: 0x9d},
- {value: 0x4552, lo: 0x9f, hi: 0x9f},
- // Block 0x13, offset 0x14
- {value: 0x0000, lo: 0x03},
- {value: 0x457a, lo: 0xb3, hi: 0xb3},
- {value: 0x4582, lo: 0xb6, hi: 0xb6},
- {value: 0x8007, lo: 0xbc, hi: 0xbc},
- // Block 0x14, offset 0x15
- {value: 0x0008, lo: 0x03},
- {value: 0x8009, lo: 0x8d, hi: 0x8d},
- {value: 0x455a, lo: 0x99, hi: 0x9b},
- {value: 0x4572, lo: 0x9e, hi: 0x9e},
- // Block 0x15, offset 0x16
- {value: 0x0000, lo: 0x01},
- {value: 0x8007, lo: 0xbc, hi: 0xbc},
- // Block 0x16, offset 0x17
- {value: 0x0000, lo: 0x01},
- {value: 0x8009, lo: 0x8d, hi: 0x8d},
- // Block 0x17, offset 0x18
- {value: 0x0000, lo: 0x08},
- {value: 0x8800, lo: 0x87, hi: 0x87},
- {value: 0x18e4, lo: 0x88, hi: 0x88},
- {value: 0x18dd, lo: 0x8b, hi: 0x8b},
- {value: 0x18eb, lo: 0x8c, hi: 0x8c},
- {value: 0x8009, lo: 0x8d, hi: 0x8d},
- {value: 0x8600, lo: 0x96, hi: 0x97},
- {value: 0x458a, lo: 0x9c, hi: 0x9c},
- {value: 0x4592, lo: 0x9d, hi: 0x9d},
- // Block 0x18, offset 0x19
- {value: 0x0000, lo: 0x03},
- {value: 0x8800, lo: 0x92, hi: 0x92},
- {value: 0x18f2, lo: 0x94, hi: 0x94},
- {value: 0x8600, lo: 0xbe, hi: 0xbe},
- // Block 0x19, offset 0x1a
- {value: 0x0000, lo: 0x06},
- {value: 0x8800, lo: 0x86, hi: 0x87},
- {value: 0x18f9, lo: 0x8a, hi: 0x8a},
- {value: 0x1907, lo: 0x8b, hi: 0x8b},
- {value: 0x1900, lo: 0x8c, hi: 0x8c},
- {value: 0x8009, lo: 0x8d, hi: 0x8d},
- {value: 0x8600, lo: 0x97, hi: 0x97},
- // Block 0x1a, offset 0x1b
- {value: 0x0607, lo: 0x04},
- {value: 0x8800, lo: 0x86, hi: 0x86},
- {value: 0x3eda, lo: 0x88, hi: 0x88},
- {value: 0x8009, lo: 0x8d, hi: 0x8d},
- {value: 0x8054, lo: 0x95, hi: 0x96},
- // Block 0x1b, offset 0x1c
- {value: 0x0000, lo: 0x02},
- {value: 0x8007, lo: 0xbc, hi: 0xbc},
- {value: 0x8800, lo: 0xbf, hi: 0xbf},
- // Block 0x1c, offset 0x1d
- {value: 0x0000, lo: 0x09},
- {value: 0x190e, lo: 0x80, hi: 0x80},
- {value: 0x8600, lo: 0x82, hi: 0x82},
- {value: 0x8800, lo: 0x86, hi: 0x86},
- {value: 0x1915, lo: 0x87, hi: 0x87},
- {value: 0x191c, lo: 0x88, hi: 0x88},
- {value: 0x2e66, lo: 0x8a, hi: 0x8a},
- {value: 0x19a5, lo: 0x8b, hi: 0x8b},
- {value: 0x8009, lo: 0x8d, hi: 0x8d},
- {value: 0x8600, lo: 0x95, hi: 0x96},
- // Block 0x1d, offset 0x1e
- {value: 0x0000, lo: 0x01},
- {value: 0x8600, lo: 0xbe, hi: 0xbe},
- // Block 0x1e, offset 0x1f
- {value: 0x0000, lo: 0x06},
- {value: 0x8800, lo: 0x86, hi: 0x87},
- {value: 0x1923, lo: 0x8a, hi: 0x8a},
- {value: 0x1931, lo: 0x8b, hi: 0x8b},
- {value: 0x192a, lo: 0x8c, hi: 0x8c},
- {value: 0x8009, lo: 0x8d, hi: 0x8d},
- {value: 0x8600, lo: 0x97, hi: 0x97},
- // Block 0x1f, offset 0x20
- {value: 0x0007, lo: 0x07},
- {value: 0x8609, lo: 0x8a, hi: 0x8a},
- {value: 0x8600, lo: 0x8f, hi: 0x8f},
- {value: 0x8800, lo: 0x99, hi: 0x99},
- {value: 0x3ee2, lo: 0x9a, hi: 0x9a},
- {value: 0x2e6d, lo: 0x9c, hi: 0x9d},
- {value: 0x1938, lo: 0x9e, hi: 0x9e},
- {value: 0x8600, lo: 0x9f, hi: 0x9f},
- // Block 0x20, offset 0x21
- {value: 0x0000, lo: 0x02},
- {value: 0x8067, lo: 0xb8, hi: 0xb9},
- {value: 0x8009, lo: 0xba, hi: 0xba},
- // Block 0x21, offset 0x22
- {value: 0x0000, lo: 0x01},
- {value: 0x806b, lo: 0x88, hi: 0x8b},
- // Block 0x22, offset 0x23
- {value: 0x0000, lo: 0x01},
- {value: 0x8076, lo: 0xb8, hi: 0xb9},
- // Block 0x23, offset 0x24
- {value: 0x0000, lo: 0x01},
- {value: 0x807a, lo: 0x88, hi: 0x8b},
- // Block 0x24, offset 0x25
- {value: 0x0000, lo: 0x04},
- {value: 0x80dc, lo: 0x98, hi: 0x99},
- {value: 0x80dc, lo: 0xb5, hi: 0xb5},
- {value: 0x80dc, lo: 0xb7, hi: 0xb7},
- {value: 0x80d8, lo: 0xb9, hi: 0xb9},
- // Block 0x25, offset 0x26
- {value: 0x0000, lo: 0x0e},
- {value: 0x2786, lo: 0x83, hi: 0x83},
- {value: 0x278d, lo: 0x8d, hi: 0x8d},
- {value: 0x2794, lo: 0x92, hi: 0x92},
- {value: 0x279b, lo: 0x97, hi: 0x97},
- {value: 0x27a2, lo: 0x9c, hi: 0x9c},
- {value: 0x277f, lo: 0xa9, hi: 0xa9},
- {value: 0x8081, lo: 0xb1, hi: 0xb1},
- {value: 0x8082, lo: 0xb2, hi: 0xb2},
- {value: 0x49b6, lo: 0xb3, hi: 0xb3},
- {value: 0x8084, lo: 0xb4, hi: 0xb4},
- {value: 0x49bf, lo: 0xb5, hi: 0xb5},
- {value: 0x459a, lo: 0xb6, hi: 0xb6},
- {value: 0x45a2, lo: 0xb8, hi: 0xb8},
- {value: 0x8082, lo: 0xba, hi: 0xbd},
- // Block 0x26, offset 0x27
- {value: 0x0000, lo: 0x0b},
- {value: 0x8082, lo: 0x80, hi: 0x80},
- {value: 0x49c8, lo: 0x81, hi: 0x81},
- {value: 0x80e6, lo: 0x82, hi: 0x83},
- {value: 0x8009, lo: 0x84, hi: 0x84},
- {value: 0x80e6, lo: 0x86, hi: 0x87},
- {value: 0x27b0, lo: 0x93, hi: 0x93},
- {value: 0x27b7, lo: 0x9d, hi: 0x9d},
- {value: 0x27be, lo: 0xa2, hi: 0xa2},
- {value: 0x27c5, lo: 0xa7, hi: 0xa7},
- {value: 0x27cc, lo: 0xac, hi: 0xac},
- {value: 0x27a9, lo: 0xb9, hi: 0xb9},
- // Block 0x27, offset 0x28
- {value: 0x0000, lo: 0x01},
- {value: 0x80dc, lo: 0x86, hi: 0x86},
- // Block 0x28, offset 0x29
- {value: 0x0000, lo: 0x05},
- {value: 0x8800, lo: 0xa5, hi: 0xa5},
- {value: 0x193f, lo: 0xa6, hi: 0xa6},
- {value: 0x8600, lo: 0xae, hi: 0xae},
- {value: 0x8007, lo: 0xb7, hi: 0xb7},
- {value: 0x8009, lo: 0xb9, hi: 0xba},
- // Block 0x29, offset 0x2a
- {value: 0x0000, lo: 0x01},
- {value: 0x80dc, lo: 0x8d, hi: 0x8d},
- // Block 0x2a, offset 0x2b
- {value: 0x0000, lo: 0x01},
- {value: 0x8800, lo: 0x80, hi: 0x92},
- // Block 0x2b, offset 0x2c
- {value: 0x0000, lo: 0x01},
- {value: 0x8e00, lo: 0xa1, hi: 0xb5},
- // Block 0x2c, offset 0x2d
- {value: 0x0000, lo: 0x01},
- {value: 0x8600, lo: 0xa8, hi: 0xbf},
- // Block 0x2d, offset 0x2e
- {value: 0x0000, lo: 0x01},
- {value: 0x8600, lo: 0x80, hi: 0x82},
- // Block 0x2e, offset 0x2f
- {value: 0x0000, lo: 0x01},
- {value: 0x80e6, lo: 0x9d, hi: 0x9f},
- // Block 0x2f, offset 0x30
- {value: 0x0000, lo: 0x02},
- {value: 0x8009, lo: 0x94, hi: 0x94},
- {value: 0x8009, lo: 0xb4, hi: 0xb4},
- // Block 0x30, offset 0x31
- {value: 0x0000, lo: 0x02},
- {value: 0x8009, lo: 0x92, hi: 0x92},
- {value: 0x80e6, lo: 0x9d, hi: 0x9d},
- // Block 0x31, offset 0x32
- {value: 0x0000, lo: 0x01},
- {value: 0x80e4, lo: 0xa9, hi: 0xa9},
- // Block 0x32, offset 0x33
- {value: 0x0008, lo: 0x02},
- {value: 0x80de, lo: 0xb9, hi: 0xba},
- {value: 0x80dc, lo: 0xbb, hi: 0xbb},
- // Block 0x33, offset 0x34
- {value: 0x0000, lo: 0x02},
- {value: 0x80e6, lo: 0x97, hi: 0x97},
- {value: 0x80dc, lo: 0x98, hi: 0x98},
- // Block 0x34, offset 0x35
- {value: 0x0000, lo: 0x03},
- {value: 0x8009, lo: 0xa0, hi: 0xa0},
- {value: 0x80e6, lo: 0xb5, hi: 0xbc},
- {value: 0x80dc, lo: 0xbf, hi: 0xbf},
- // Block 0x35, offset 0x36
- {value: 0x0000, lo: 0x08},
- {value: 0x197e, lo: 0x80, hi: 0x80},
- {value: 0x1985, lo: 0x81, hi: 0x81},
- {value: 0x8800, lo: 0x82, hi: 0x82},
- {value: 0x198c, lo: 0x83, hi: 0x83},
- {value: 0x8009, lo: 0x84, hi: 0x84},
- {value: 0x80e6, lo: 0xab, hi: 0xab},
- {value: 0x80dc, lo: 0xac, hi: 0xac},
- {value: 0x80e6, lo: 0xad, hi: 0xb3},
- // Block 0x36, offset 0x37
- {value: 0x0000, lo: 0x01},
- {value: 0x8009, lo: 0xaa, hi: 0xab},
- // Block 0x37, offset 0x38
- {value: 0x0000, lo: 0x02},
- {value: 0x8007, lo: 0xa6, hi: 0xa6},
- {value: 0x8009, lo: 0xb2, hi: 0xb3},
- // Block 0x38, offset 0x39
- {value: 0x0000, lo: 0x01},
- {value: 0x8007, lo: 0xb7, hi: 0xb7},
- // Block 0x39, offset 0x3a
- {value: 0x0000, lo: 0x09},
- {value: 0x80e6, lo: 0x90, hi: 0x92},
- {value: 0x8001, lo: 0x94, hi: 0x94},
- {value: 0x80dc, lo: 0x95, hi: 0x99},
- {value: 0x80e6, lo: 0x9a, hi: 0x9b},
- {value: 0x80dc, lo: 0x9c, hi: 0x9f},
- {value: 0x80e6, lo: 0xa0, hi: 0xa0},
- {value: 0x8001, lo: 0xa2, hi: 0xa8},
- {value: 0x80dc, lo: 0xad, hi: 0xad},
- {value: 0x80e6, lo: 0xb4, hi: 0xb4},
- // Block 0x3a, offset 0x3b
- {value: 0x0000, lo: 0x0e},
- {value: 0x80e6, lo: 0x80, hi: 0x81},
- {value: 0x80dc, lo: 0x82, hi: 0x82},
- {value: 0x80e6, lo: 0x83, hi: 0x89},
- {value: 0x80dc, lo: 0x8a, hi: 0x8a},
- {value: 0x80e6, lo: 0x8b, hi: 0x8c},
- {value: 0x80ea, lo: 0x8d, hi: 0x8d},
- {value: 0x80d6, lo: 0x8e, hi: 0x8e},
- {value: 0x80dc, lo: 0x8f, hi: 0x8f},
- {value: 0x80ca, lo: 0x90, hi: 0x90},
- {value: 0x80e6, lo: 0x91, hi: 0xa6},
- {value: 0x80e9, lo: 0xbc, hi: 0xbc},
- {value: 0x80dc, lo: 0xbd, hi: 0xbd},
- {value: 0x80e6, lo: 0xbe, hi: 0xbe},
- {value: 0x80dc, lo: 0xbf, hi: 0xbf},
- // Block 0x3b, offset 0x3c
- {value: 0x0004, lo: 0x01},
- {value: 0x04a5, lo: 0x80, hi: 0x81},
- // Block 0x3c, offset 0x3d
- {value: 0x0000, lo: 0x0d},
- {value: 0x80e6, lo: 0x90, hi: 0x91},
- {value: 0x8001, lo: 0x92, hi: 0x93},
- {value: 0x80e6, lo: 0x94, hi: 0x97},
- {value: 0x8001, lo: 0x98, hi: 0x9a},
- {value: 0x80e6, lo: 0x9b, hi: 0x9c},
- {value: 0x80e6, lo: 0xa1, hi: 0xa1},
- {value: 0x8001, lo: 0xa5, hi: 0xa6},
- {value: 0x80e6, lo: 0xa7, hi: 0xa7},
- {value: 0x80dc, lo: 0xa8, hi: 0xa8},
- {value: 0x80e6, lo: 0xa9, hi: 0xa9},
- {value: 0x8001, lo: 0xaa, hi: 0xab},
- {value: 0x80dc, lo: 0xac, hi: 0xaf},
- {value: 0x80e6, lo: 0xb0, hi: 0xb0},
- // Block 0x3d, offset 0x3e
- {value: 0x4261, lo: 0x02},
- {value: 0x01b8, lo: 0xa6, hi: 0xa6},
- {value: 0x0057, lo: 0xaa, hi: 0xab},
- // Block 0x3e, offset 0x3f
- {value: 0x0007, lo: 0x05},
- {value: 0x8800, lo: 0x90, hi: 0x90},
- {value: 0x8800, lo: 0x92, hi: 0x92},
- {value: 0x8800, lo: 0x94, hi: 0x94},
- {value: 0x3ba3, lo: 0x9a, hi: 0x9b},
- {value: 0x3bb1, lo: 0xae, hi: 0xae},
- // Block 0x3f, offset 0x40
- {value: 0x000e, lo: 0x05},
- {value: 0x3bb8, lo: 0x8d, hi: 0x8e},
- {value: 0x3bbf, lo: 0x8f, hi: 0x8f},
- {value: 0x8800, lo: 0x90, hi: 0x90},
- {value: 0x8800, lo: 0x92, hi: 0x92},
- {value: 0x8800, lo: 0x94, hi: 0x94},
- // Block 0x40, offset 0x41
- {value: 0x4c1e, lo: 0x0a},
- {value: 0x8800, lo: 0x83, hi: 0x83},
- {value: 0x3bcd, lo: 0x84, hi: 0x84},
- {value: 0x8800, lo: 0x88, hi: 0x88},
- {value: 0x3bd4, lo: 0x89, hi: 0x89},
- {value: 0x8800, lo: 0x8b, hi: 0x8b},
- {value: 0x3bdb, lo: 0x8c, hi: 0x8c},
- {value: 0x8800, lo: 0xa3, hi: 0xa3},
- {value: 0x3be2, lo: 0xa4, hi: 0xa5},
- {value: 0x3be9, lo: 0xa6, hi: 0xa6},
- {value: 0x8800, lo: 0xbc, hi: 0xbc},
- // Block 0x41, offset 0x42
- {value: 0x0007, lo: 0x03},
- {value: 0x3c52, lo: 0xa0, hi: 0xa1},
- {value: 0x3c7c, lo: 0xa2, hi: 0xa3},
- {value: 0x3ca6, lo: 0xaa, hi: 0xad},
- // Block 0x42, offset 0x43
- {value: 0x0004, lo: 0x01},
- {value: 0x04fd, lo: 0xa9, hi: 0xaa},
- // Block 0x43, offset 0x44
- {value: 0x0000, lo: 0x01},
- {value: 0x44c3, lo: 0x9c, hi: 0x9c},
- // Block 0x44, offset 0x45
- {value: 0x0000, lo: 0x01},
- {value: 0x80e6, lo: 0xaf, hi: 0xb1},
- // Block 0x45, offset 0x46
- {value: 0x0000, lo: 0x01},
- {value: 0x8009, lo: 0xbf, hi: 0xbf},
- // Block 0x46, offset 0x47
- {value: 0x0000, lo: 0x01},
- {value: 0x80e6, lo: 0xa0, hi: 0xbf},
- // Block 0x47, offset 0x48
- {value: 0x0000, lo: 0x05},
- {value: 0x80da, lo: 0xaa, hi: 0xaa},
- {value: 0x80e4, lo: 0xab, hi: 0xab},
- {value: 0x80e8, lo: 0xac, hi: 0xac},
- {value: 0x80de, lo: 0xad, hi: 0xad},
- {value: 0x80e0, lo: 0xae, hi: 0xaf},
- // Block 0x48, offset 0x49
- {value: 0x0000, lo: 0x02},
- {value: 0x80e6, lo: 0xaf, hi: 0xaf},
- {value: 0x80e6, lo: 0xb4, hi: 0xbd},
- // Block 0x49, offset 0x4a
- {value: 0x0000, lo: 0x01},
- {value: 0x80e6, lo: 0x9f, hi: 0x9f},
- // Block 0x4a, offset 0x4b
- {value: 0x0000, lo: 0x01},
- {value: 0x80e6, lo: 0xb0, hi: 0xb1},
- // Block 0x4b, offset 0x4c
- {value: 0x0000, lo: 0x01},
- {value: 0x8009, lo: 0x86, hi: 0x86},
- // Block 0x4c, offset 0x4d
- {value: 0x0000, lo: 0x02},
- {value: 0x8009, lo: 0x84, hi: 0x84},
- {value: 0x80e6, lo: 0xa0, hi: 0xb1},
- // Block 0x4d, offset 0x4e
- {value: 0x0000, lo: 0x01},
- {value: 0x80dc, lo: 0xab, hi: 0xad},
- // Block 0x4e, offset 0x4f
- {value: 0x0000, lo: 0x01},
- {value: 0x8009, lo: 0x93, hi: 0x93},
- // Block 0x4f, offset 0x50
- {value: 0x0000, lo: 0x01},
- {value: 0x8007, lo: 0xb3, hi: 0xb3},
- // Block 0x50, offset 0x51
- {value: 0x0000, lo: 0x01},
- {value: 0x8009, lo: 0x80, hi: 0x80},
- // Block 0x51, offset 0x52
- {value: 0x0000, lo: 0x05},
- {value: 0x80e6, lo: 0xb0, hi: 0xb0},
- {value: 0x80e6, lo: 0xb2, hi: 0xb3},
- {value: 0x80dc, lo: 0xb4, hi: 0xb4},
- {value: 0x80e6, lo: 0xb7, hi: 0xb8},
- {value: 0x80e6, lo: 0xbe, hi: 0xbf},
- // Block 0x52, offset 0x53
- {value: 0x0000, lo: 0x02},
- {value: 0x80e6, lo: 0x81, hi: 0x81},
- {value: 0x8009, lo: 0xb6, hi: 0xb6},
- // Block 0x53, offset 0x54
- {value: 0x0000, lo: 0x01},
- {value: 0x8009, lo: 0xad, hi: 0xad},
- // Block 0x54, offset 0x55
- {value: 0x0000, lo: 0x01},
- {value: 0x8100, lo: 0x80, hi: 0xbf},
- // Block 0x55, offset 0x56
- {value: 0x0000, lo: 0x01},
- {value: 0x8100, lo: 0x80, hi: 0xa3},
- // Block 0x56, offset 0x57
- {value: 0x0006, lo: 0x0d},
- {value: 0x4376, lo: 0x9d, hi: 0x9d},
- {value: 0x801a, lo: 0x9e, hi: 0x9e},
- {value: 0x43e8, lo: 0x9f, hi: 0x9f},
- {value: 0x43d6, lo: 0xaa, hi: 0xab},
- {value: 0x44da, lo: 0xac, hi: 0xac},
- {value: 0x44e2, lo: 0xad, hi: 0xad},
- {value: 0x432e, lo: 0xae, hi: 0xb1},
- {value: 0x434c, lo: 0xb2, hi: 0xb4},
- {value: 0x4364, lo: 0xb5, hi: 0xb6},
- {value: 0x4370, lo: 0xb8, hi: 0xb8},
- {value: 0x437c, lo: 0xb9, hi: 0xbb},
- {value: 0x4394, lo: 0xbc, hi: 0xbc},
- {value: 0x439a, lo: 0xbe, hi: 0xbe},
- // Block 0x57, offset 0x58
- {value: 0x0006, lo: 0x08},
- {value: 0x43a0, lo: 0x80, hi: 0x81},
- {value: 0x43ac, lo: 0x83, hi: 0x84},
- {value: 0x43be, lo: 0x86, hi: 0x89},
- {value: 0x43e2, lo: 0x8a, hi: 0x8a},
- {value: 0x435e, lo: 0x8b, hi: 0x8b},
- {value: 0x4346, lo: 0x8c, hi: 0x8c},
- {value: 0x438e, lo: 0x8d, hi: 0x8d},
- {value: 0x43b8, lo: 0x8e, hi: 0x8e},
- // Block 0x58, offset 0x59
- {value: 0x0000, lo: 0x01},
- {value: 0x80e6, lo: 0xa0, hi: 0xa6},
- // Block 0x59, offset 0x5a
- {value: 0x0000, lo: 0x01},
- {value: 0x80dc, lo: 0xbd, hi: 0xbd},
- // Block 0x5a, offset 0x5b
- {value: 0x00db, lo: 0x05},
- {value: 0x80dc, lo: 0x8d, hi: 0x8d},
- {value: 0x80e6, lo: 0x8f, hi: 0x8f},
- {value: 0x80e6, lo: 0xb8, hi: 0xb8},
- {value: 0x8001, lo: 0xb9, hi: 0xba},
- {value: 0x8009, lo: 0xbf, hi: 0xbf},
- // Block 0x5b, offset 0x5c
- {value: 0x05fe, lo: 0x07},
- {value: 0x8800, lo: 0x99, hi: 0x99},
- {value: 0x4222, lo: 0x9a, hi: 0x9a},
- {value: 0x8800, lo: 0x9b, hi: 0x9b},
- {value: 0x422c, lo: 0x9c, hi: 0x9c},
- {value: 0x8800, lo: 0xa5, hi: 0xa5},
- {value: 0x4236, lo: 0xab, hi: 0xab},
- {value: 0x8009, lo: 0xb9, hi: 0xba},
- // Block 0x5c, offset 0x5d
- {value: 0x0000, lo: 0x06},
- {value: 0x80e6, lo: 0x80, hi: 0x82},
- {value: 0x8600, lo: 0xa7, hi: 0xa7},
- {value: 0x1993, lo: 0xae, hi: 0xae},
- {value: 0x199c, lo: 0xaf, hi: 0xaf},
- {value: 0x8800, lo: 0xb1, hi: 0xb2},
- {value: 0x8009, lo: 0xb3, hi: 0xb4},
- // Block 0x5d, offset 0x5e
- {value: 0x0000, lo: 0x02},
- {value: 0x8009, lo: 0xb6, hi: 0xb6},
- {value: 0x8007, lo: 0xb7, hi: 0xb7},
- // Block 0x5e, offset 0x5f
- {value: 0x0000, lo: 0x0c},
- {value: 0x45b2, lo: 0x9e, hi: 0x9e},
- {value: 0x45bc, lo: 0x9f, hi: 0x9f},
- {value: 0x45f0, lo: 0xa0, hi: 0xa0},
- {value: 0x45fe, lo: 0xa1, hi: 0xa1},
- {value: 0x460c, lo: 0xa2, hi: 0xa2},
- {value: 0x461a, lo: 0xa3, hi: 0xa3},
- {value: 0x4628, lo: 0xa4, hi: 0xa4},
- {value: 0x80d8, lo: 0xa5, hi: 0xa6},
- {value: 0x8001, lo: 0xa7, hi: 0xa9},
- {value: 0x80e2, lo: 0xad, hi: 0xad},
- {value: 0x80d8, lo: 0xae, hi: 0xb2},
- {value: 0x80dc, lo: 0xbb, hi: 0xbf},
- // Block 0x5f, offset 0x60
- {value: 0x0000, lo: 0x09},
- {value: 0x80dc, lo: 0x80, hi: 0x82},
- {value: 0x80e6, lo: 0x85, hi: 0x89},
- {value: 0x80dc, lo: 0x8a, hi: 0x8b},
- {value: 0x80e6, lo: 0xaa, hi: 0xad},
- {value: 0x45c6, lo: 0xbb, hi: 0xbb},
- {value: 0x45d0, lo: 0xbc, hi: 0xbc},
- {value: 0x4636, lo: 0xbd, hi: 0xbd},
- {value: 0x4652, lo: 0xbe, hi: 0xbe},
- {value: 0x4644, lo: 0xbf, hi: 0xbf},
- // Block 0x60, offset 0x61
- {value: 0x0000, lo: 0x01},
- {value: 0x4660, lo: 0x80, hi: 0x80},
- // Block 0x61, offset 0x62
- {value: 0x0000, lo: 0x01},
- {value: 0x80e6, lo: 0x82, hi: 0x84},
-}
-
-// nfcLookup: 1088 bytes
-// Block 0 is the null block.
-var nfcLookup = [1088]uint8{
- // Block 0x0, offset 0x0
- // Block 0x1, offset 0x40
- // Block 0x2, offset 0x80
- // Block 0x3, offset 0xc0
- 0x0c2: 0x2c, 0x0c3: 0x01, 0x0c4: 0x02, 0x0c5: 0x03, 0x0c6: 0x2d, 0x0c7: 0x04,
- 0x0c8: 0x05, 0x0ca: 0x2e, 0x0cc: 0x06, 0x0cd: 0x07, 0x0ce: 0x08, 0x0cf: 0x2f,
- 0x0d0: 0x09, 0x0d1: 0x30, 0x0d2: 0x31, 0x0d3: 0x0a, 0x0d6: 0x0b, 0x0d7: 0x32,
- 0x0d8: 0x33, 0x0d9: 0x0c, 0x0db: 0x34, 0x0dc: 0x35, 0x0dd: 0x36, 0x0df: 0x37,
- 0x0e0: 0x02, 0x0e1: 0x03, 0x0e2: 0x04, 0x0e3: 0x05,
- 0x0ea: 0x06, 0x0eb: 0x07, 0x0ec: 0x07, 0x0ed: 0x08, 0x0ef: 0x09,
- 0x0f0: 0x0e,
- // Block 0x4, offset 0x100
- 0x120: 0x38, 0x121: 0x39, 0x123: 0x3a, 0x124: 0x3b, 0x125: 0x3c, 0x126: 0x3d, 0x127: 0x3e,
- 0x128: 0x3f, 0x129: 0x40, 0x12a: 0x41, 0x12b: 0x42, 0x12c: 0x3d, 0x12d: 0x43, 0x12e: 0x44, 0x12f: 0x45,
- 0x131: 0x46, 0x132: 0x47, 0x133: 0x48, 0x134: 0x49, 0x135: 0x4a, 0x137: 0x4b,
- 0x138: 0x4c, 0x139: 0x4d, 0x13a: 0x4e, 0x13b: 0x4f, 0x13c: 0x50, 0x13d: 0x51, 0x13e: 0x52, 0x13f: 0x53,
- // Block 0x5, offset 0x140
- 0x140: 0x54, 0x142: 0x55, 0x144: 0x56, 0x145: 0x57, 0x146: 0x58, 0x147: 0x59,
- 0x14d: 0x5a,
- 0x15c: 0x5b, 0x15f: 0x5c,
- 0x162: 0x5d, 0x164: 0x5e,
- 0x168: 0x5f, 0x169: 0x60, 0x16c: 0x0d, 0x16d: 0x61, 0x16e: 0x62, 0x16f: 0x63,
- 0x170: 0x64, 0x173: 0x65, 0x177: 0x66,
- 0x178: 0x0e, 0x179: 0x0f, 0x17a: 0x10, 0x17b: 0x11, 0x17c: 0x12, 0x17d: 0x13, 0x17e: 0x14, 0x17f: 0x15,
- // Block 0x6, offset 0x180
- 0x180: 0x67, 0x183: 0x68, 0x184: 0x69, 0x186: 0x6a, 0x187: 0x6b,
- 0x188: 0x6c, 0x189: 0x16, 0x18a: 0x17, 0x18b: 0x6d, 0x18c: 0x6e,
- 0x1ab: 0x6f,
- 0x1b3: 0x70, 0x1b5: 0x71, 0x1b7: 0x72,
- // Block 0x7, offset 0x1c0
- 0x1c0: 0x73, 0x1c1: 0x18, 0x1c2: 0x19, 0x1c3: 0x1a,
- // Block 0x8, offset 0x200
- 0x219: 0x74, 0x21a: 0x75, 0x21b: 0x76,
- 0x220: 0x77, 0x223: 0x78, 0x224: 0x79, 0x225: 0x7a, 0x226: 0x7b, 0x227: 0x7c,
- 0x22a: 0x7d, 0x22b: 0x7e, 0x22f: 0x7f,
- 0x230: 0x80, 0x231: 0x80, 0x232: 0x80, 0x233: 0x80, 0x234: 0x80, 0x235: 0x80, 0x236: 0x80, 0x237: 0x80,
- 0x238: 0x80, 0x239: 0x80, 0x23a: 0x80, 0x23b: 0x80, 0x23c: 0x80, 0x23d: 0x80, 0x23e: 0x80, 0x23f: 0x80,
- // Block 0x9, offset 0x240
- 0x240: 0x80, 0x241: 0x80, 0x242: 0x80, 0x243: 0x80, 0x244: 0x80, 0x245: 0x80, 0x246: 0x80, 0x247: 0x80,
- 0x248: 0x80, 0x249: 0x80, 0x24a: 0x80, 0x24b: 0x80, 0x24c: 0x80, 0x24d: 0x80, 0x24e: 0x80, 0x24f: 0x80,
- 0x250: 0x80, 0x251: 0x80, 0x252: 0x80, 0x253: 0x80, 0x254: 0x80, 0x255: 0x80, 0x256: 0x80, 0x257: 0x80,
- 0x258: 0x80, 0x259: 0x80, 0x25a: 0x80, 0x25b: 0x80, 0x25c: 0x80, 0x25d: 0x80, 0x25e: 0x80, 0x25f: 0x80,
- 0x260: 0x80, 0x261: 0x80, 0x262: 0x80, 0x263: 0x80, 0x264: 0x80, 0x265: 0x80, 0x266: 0x80, 0x267: 0x80,
- 0x268: 0x80, 0x269: 0x80, 0x26a: 0x80, 0x26b: 0x80, 0x26c: 0x80, 0x26d: 0x80, 0x26e: 0x80, 0x26f: 0x80,
- 0x270: 0x80, 0x271: 0x80, 0x272: 0x80, 0x273: 0x80, 0x274: 0x80, 0x275: 0x80, 0x276: 0x80, 0x277: 0x80,
- 0x278: 0x80, 0x279: 0x80, 0x27a: 0x80, 0x27b: 0x80, 0x27c: 0x80, 0x27d: 0x80, 0x27e: 0x80, 0x27f: 0x80,
- // Block 0xa, offset 0x280
- 0x280: 0x80, 0x281: 0x80, 0x282: 0x80, 0x283: 0x80, 0x284: 0x80, 0x285: 0x80, 0x286: 0x80, 0x287: 0x80,
- 0x288: 0x80, 0x289: 0x80, 0x28a: 0x80, 0x28b: 0x80, 0x28c: 0x80, 0x28d: 0x80, 0x28e: 0x80, 0x28f: 0x80,
- 0x290: 0x80, 0x291: 0x80, 0x292: 0x80, 0x293: 0x80, 0x294: 0x80, 0x295: 0x80, 0x296: 0x80, 0x297: 0x80,
- 0x298: 0x80, 0x299: 0x80, 0x29a: 0x80, 0x29b: 0x80, 0x29c: 0x80, 0x29d: 0x80, 0x29e: 0x81,
- // Block 0xb, offset 0x2c0
- 0x2e4: 0x1b, 0x2e5: 0x1c, 0x2e6: 0x1d, 0x2e7: 0x1e,
- 0x2e8: 0x1f, 0x2e9: 0x20, 0x2ea: 0x21, 0x2eb: 0x22, 0x2ec: 0x82, 0x2ed: 0x83,
- 0x2f8: 0x84,
- // Block 0xc, offset 0x300
- 0x307: 0x85,
- 0x328: 0x86,
- // Block 0xd, offset 0x340
- 0x341: 0x77, 0x342: 0x87, 0x344: 0x88, 0x347: 0x7c,
- 0x35a: 0x89,
- // Block 0xe, offset 0x380
- 0x385: 0x8a, 0x386: 0x8b, 0x387: 0x8c,
- 0x389: 0x8d,
- // Block 0xf, offset 0x3c0
- 0x3e0: 0x23, 0x3e1: 0x24, 0x3e2: 0x25, 0x3e3: 0x26, 0x3e4: 0x27, 0x3e5: 0x28, 0x3e6: 0x29, 0x3e7: 0x2a,
- 0x3e8: 0x2b,
- // Block 0x10, offset 0x400
- 0x410: 0x0a, 0x411: 0x0b,
- 0x41d: 0x0c,
- 0x42f: 0x0d,
-}
-
-var nfcTrie = trie{nfcLookup[:], nfcValues[:], nfcSparseValues[:], nfcSparseOffset[:], 44}
-
-// nfkcValues: 5760 entries, 11520 bytes
-// Block 2 is the null block.
-var nfkcValues = [5760]uint16{
- // Block 0x0, offset 0x0
- 0x003c: 0x8800, 0x003d: 0x8800, 0x003e: 0x8800,
- // Block 0x1, offset 0x40
- 0x0041: 0x8800, 0x0042: 0x8800, 0x0043: 0x8800, 0x0044: 0x8800, 0x0045: 0x8800,
- 0x0046: 0x8800, 0x0047: 0x8800, 0x0048: 0x8800, 0x0049: 0x8800, 0x004a: 0x8800, 0x004b: 0x8800,
- 0x004c: 0x8800, 0x004d: 0x8800, 0x004e: 0x8800, 0x004f: 0x8800, 0x0050: 0x8800,
- 0x0052: 0x8800, 0x0053: 0x8800, 0x0054: 0x8800, 0x0055: 0x8800, 0x0056: 0x8800, 0x0057: 0x8800,
- 0x0058: 0x8800, 0x0059: 0x8800, 0x005a: 0x8800,
- 0x0061: 0x8800, 0x0062: 0x8800, 0x0063: 0x8800,
- 0x0064: 0x8800, 0x0065: 0x8800, 0x0066: 0x8800, 0x0067: 0x8800, 0x0068: 0x8800, 0x0069: 0x8800,
- 0x006a: 0x8800, 0x006b: 0x8800, 0x006c: 0x8800, 0x006d: 0x8800, 0x006e: 0x8800, 0x006f: 0x8800,
- 0x0070: 0x8800, 0x0072: 0x8800, 0x0073: 0x8800, 0x0074: 0x8800, 0x0075: 0x8800,
- 0x0076: 0x8800, 0x0077: 0x8800, 0x0078: 0x8800, 0x0079: 0x8800, 0x007a: 0x8800,
- // Block 0x2, offset 0x80
- // Block 0x3, offset 0xc0
- 0x00c0: 0x2f59, 0x00c1: 0x2f5e, 0x00c2: 0x466e, 0x00c3: 0x2f63, 0x00c4: 0x467d, 0x00c5: 0x4682,
- 0x00c6: 0x8800, 0x00c7: 0x468c, 0x00c8: 0x2fcc, 0x00c9: 0x2fd1, 0x00ca: 0x4691, 0x00cb: 0x2fe5,
- 0x00cc: 0x3058, 0x00cd: 0x305d, 0x00ce: 0x3062, 0x00cf: 0x46a5, 0x00d1: 0x30ee,
- 0x00d2: 0x3111, 0x00d3: 0x3116, 0x00d4: 0x46af, 0x00d5: 0x46b4, 0x00d6: 0x46c3,
- 0x00d8: 0x8800, 0x00d9: 0x319d, 0x00da: 0x31a2, 0x00db: 0x31a7, 0x00dc: 0x46f5, 0x00dd: 0x321f,
- 0x00e0: 0x3265, 0x00e1: 0x326a, 0x00e2: 0x46ff, 0x00e3: 0x326f,
- 0x00e4: 0x470e, 0x00e5: 0x4713, 0x00e6: 0x8800, 0x00e7: 0x471d, 0x00e8: 0x32d8, 0x00e9: 0x32dd,
- 0x00ea: 0x4722, 0x00eb: 0x32f1, 0x00ec: 0x3369, 0x00ed: 0x336e, 0x00ee: 0x3373, 0x00ef: 0x4736,
- 0x00f1: 0x33ff, 0x00f2: 0x3422, 0x00f3: 0x3427, 0x00f4: 0x4740, 0x00f5: 0x4745,
- 0x00f6: 0x4754, 0x00f8: 0x8800, 0x00f9: 0x34b3, 0x00fa: 0x34b8, 0x00fb: 0x34bd,
- 0x00fc: 0x4786, 0x00fd: 0x353a, 0x00ff: 0x3553,
- // Block 0x4, offset 0x100
- 0x0100: 0x2f68, 0x0101: 0x3274, 0x0102: 0x4673, 0x0103: 0x4704, 0x0104: 0x2f86, 0x0105: 0x3292,
- 0x0106: 0x2f9a, 0x0107: 0x32a6, 0x0108: 0x2f9f, 0x0109: 0x32ab, 0x010a: 0x2fa4, 0x010b: 0x32b0,
- 0x010c: 0x2fa9, 0x010d: 0x32b5, 0x010e: 0x2fb3, 0x010f: 0x32bf,
- 0x0112: 0x4696, 0x0113: 0x4727, 0x0114: 0x2fdb, 0x0115: 0x32e7, 0x0116: 0x2fe0, 0x0117: 0x32ec,
- 0x0118: 0x2ffe, 0x0119: 0x330a, 0x011a: 0x2fef, 0x011b: 0x32fb, 0x011c: 0x3017, 0x011d: 0x3323,
- 0x011e: 0x3021, 0x011f: 0x332d, 0x0120: 0x3026, 0x0121: 0x3332, 0x0122: 0x3030, 0x0123: 0x333c,
- 0x0124: 0x3035, 0x0125: 0x3341, 0x0128: 0x3067, 0x0129: 0x3378,
- 0x012a: 0x306c, 0x012b: 0x337d, 0x012c: 0x3071, 0x012d: 0x3382, 0x012e: 0x3094, 0x012f: 0x33a0,
- 0x0130: 0x3076, 0x0132: 0x1a9f, 0x0133: 0x1b29, 0x0134: 0x309e, 0x0135: 0x33aa,
- 0x0136: 0x30b2, 0x0137: 0x33c3, 0x0139: 0x30bc, 0x013a: 0x33cd, 0x013b: 0x30c6,
- 0x013c: 0x33d7, 0x013d: 0x30c1, 0x013e: 0x33d2, 0x013f: 0x1cee,
- // Block 0x5, offset 0x140
- 0x0140: 0x1d76, 0x0143: 0x30e9, 0x0144: 0x33fa, 0x0145: 0x3102,
- 0x0146: 0x3413, 0x0147: 0x30f8, 0x0148: 0x3409, 0x0149: 0x1d9e,
- 0x014c: 0x46b9, 0x014d: 0x474a, 0x014e: 0x311b, 0x014f: 0x342c, 0x0150: 0x3125, 0x0151: 0x3436,
- 0x0154: 0x3143, 0x0155: 0x3454, 0x0156: 0x315c, 0x0157: 0x346d,
- 0x0158: 0x314d, 0x0159: 0x345e, 0x015a: 0x46dc, 0x015b: 0x476d, 0x015c: 0x3166, 0x015d: 0x3477,
- 0x015e: 0x3175, 0x015f: 0x3486, 0x0160: 0x46e1, 0x0161: 0x4772, 0x0162: 0x318e, 0x0163: 0x34a4,
- 0x0164: 0x317f, 0x0165: 0x3495, 0x0168: 0x46eb, 0x0169: 0x477c,
- 0x016a: 0x46f0, 0x016b: 0x4781, 0x016c: 0x31ac, 0x016d: 0x34c2, 0x016e: 0x31b6, 0x016f: 0x34cc,
- 0x0170: 0x31bb, 0x0171: 0x34d1, 0x0172: 0x31d9, 0x0173: 0x34ef, 0x0174: 0x31fc, 0x0175: 0x3512,
- 0x0176: 0x3224, 0x0177: 0x353f, 0x0178: 0x3238, 0x0179: 0x3247, 0x017a: 0x3567, 0x017b: 0x3251,
- 0x017c: 0x3571, 0x017d: 0x3256, 0x017e: 0x3576, 0x017f: 0x00a7,
- // Block 0x6, offset 0x180
- 0x0184: 0x2e7f, 0x0185: 0x2e85,
- 0x0186: 0x2e8b, 0x0187: 0x1ab4, 0x0188: 0x1ab7, 0x0189: 0x1b4a, 0x018a: 0x1ac9, 0x018b: 0x1acc,
- 0x018c: 0x1b80, 0x018d: 0x2f72, 0x018e: 0x327e, 0x018f: 0x3080, 0x0190: 0x338c, 0x0191: 0x312a,
- 0x0192: 0x343b, 0x0193: 0x31c0, 0x0194: 0x34d6, 0x0195: 0x39b9, 0x0196: 0x3b48, 0x0197: 0x39b2,
- 0x0198: 0x3b41, 0x0199: 0x39c0, 0x019a: 0x3b4f, 0x019b: 0x39ab, 0x019c: 0x3b3a,
- 0x019e: 0x389a, 0x019f: 0x3a29, 0x01a0: 0x3893, 0x01a1: 0x3a22, 0x01a2: 0x359d, 0x01a3: 0x35af,
- 0x01a6: 0x302b, 0x01a7: 0x3337, 0x01a8: 0x30a8, 0x01a9: 0x33b9,
- 0x01aa: 0x46d2, 0x01ab: 0x4763, 0x01ac: 0x397a, 0x01ad: 0x3b09, 0x01ae: 0x35c1, 0x01af: 0x35c7,
- 0x01b0: 0x33af, 0x01b1: 0x1a84, 0x01b2: 0x1a87, 0x01b3: 0x1b11, 0x01b4: 0x3012, 0x01b5: 0x331e,
- 0x01b8: 0x30e4, 0x01b9: 0x33f5, 0x01ba: 0x38a1, 0x01bb: 0x3a30,
- 0x01bc: 0x3597, 0x01bd: 0x35a9, 0x01be: 0x35a3, 0x01bf: 0x35b5,
- // Block 0x7, offset 0x1c0
- 0x01c0: 0x2f77, 0x01c1: 0x3283, 0x01c2: 0x2f7c, 0x01c3: 0x3288, 0x01c4: 0x2ff4, 0x01c5: 0x3300,
- 0x01c6: 0x2ff9, 0x01c7: 0x3305, 0x01c8: 0x3085, 0x01c9: 0x3391, 0x01ca: 0x308a, 0x01cb: 0x3396,
- 0x01cc: 0x312f, 0x01cd: 0x3440, 0x01ce: 0x3134, 0x01cf: 0x3445, 0x01d0: 0x3152, 0x01d1: 0x3463,
- 0x01d2: 0x3157, 0x01d3: 0x3468, 0x01d4: 0x31c5, 0x01d5: 0x34db, 0x01d6: 0x31ca, 0x01d7: 0x34e0,
- 0x01d8: 0x3170, 0x01d9: 0x3481, 0x01da: 0x3189, 0x01db: 0x349f,
- 0x01de: 0x3044, 0x01df: 0x3350,
- 0x01e6: 0x4678, 0x01e7: 0x4709, 0x01e8: 0x46a0, 0x01e9: 0x4731,
- 0x01ea: 0x3949, 0x01eb: 0x3ad8, 0x01ec: 0x3926, 0x01ed: 0x3ab5, 0x01ee: 0x46be, 0x01ef: 0x474f,
- 0x01f0: 0x3942, 0x01f1: 0x3ad1, 0x01f2: 0x322e, 0x01f3: 0x3549,
- // Block 0x8, offset 0x200
- 0x0200: 0x86e6, 0x0201: 0x86e6, 0x0202: 0x86e6, 0x0203: 0x86e6, 0x0204: 0x86e6, 0x0205: 0x80e6,
- 0x0206: 0x86e6, 0x0207: 0x86e6, 0x0208: 0x86e6, 0x0209: 0x86e6, 0x020a: 0x86e6, 0x020b: 0x86e6,
- 0x020c: 0x86e6, 0x020d: 0x80e6, 0x020e: 0x80e6, 0x020f: 0x86e6, 0x0210: 0x80e6, 0x0211: 0x86e6,
- 0x0212: 0x80e6, 0x0213: 0x86e6, 0x0214: 0x86e6, 0x0215: 0x80e8, 0x0216: 0x80dc, 0x0217: 0x80dc,
- 0x0218: 0x80dc, 0x0219: 0x80dc, 0x021a: 0x80e8, 0x021b: 0x86d8, 0x021c: 0x80dc, 0x021d: 0x80dc,
- 0x021e: 0x80dc, 0x021f: 0x80dc, 0x0220: 0x80dc, 0x0221: 0x80ca, 0x0222: 0x80ca, 0x0223: 0x86dc,
- 0x0224: 0x86dc, 0x0225: 0x86dc, 0x0226: 0x86dc, 0x0227: 0x86ca, 0x0228: 0x86ca, 0x0229: 0x80dc,
- 0x022a: 0x80dc, 0x022b: 0x80dc, 0x022c: 0x80dc, 0x022d: 0x86dc, 0x022e: 0x86dc, 0x022f: 0x80dc,
- 0x0230: 0x86dc, 0x0231: 0x86dc, 0x0232: 0x80dc, 0x0233: 0x80dc, 0x0234: 0x8001, 0x0235: 0x8001,
- 0x0236: 0x8001, 0x0237: 0x8001, 0x0238: 0x8601, 0x0239: 0x80dc, 0x023a: 0x80dc, 0x023b: 0x80dc,
- 0x023c: 0x80dc, 0x023d: 0x80e6, 0x023e: 0x80e6, 0x023f: 0x80e6,
- // Block 0x9, offset 0x240
- 0x0240: 0x4994, 0x0241: 0x4999, 0x0242: 0x86e6, 0x0243: 0x499e, 0x0244: 0x49a3, 0x0245: 0x86f0,
- 0x0246: 0x80e6, 0x0247: 0x80dc, 0x0248: 0x80dc, 0x0249: 0x80dc, 0x024a: 0x80e6, 0x024b: 0x80e6,
- 0x024c: 0x80e6, 0x024d: 0x80dc, 0x024e: 0x80dc, 0x0250: 0x80e6, 0x0251: 0x80e6,
- 0x0252: 0x80e6, 0x0253: 0x80dc, 0x0254: 0x80dc, 0x0255: 0x80dc, 0x0256: 0x80dc, 0x0257: 0x80e6,
- 0x0258: 0x80e8, 0x0259: 0x80dc, 0x025a: 0x80dc, 0x025b: 0x80e6, 0x025c: 0x80e9, 0x025d: 0x80ea,
- 0x025e: 0x80ea, 0x025f: 0x80e9, 0x0260: 0x80ea, 0x0261: 0x80ea, 0x0262: 0x80e9, 0x0263: 0x80e6,
- 0x0264: 0x80e6, 0x0265: 0x80e6, 0x0266: 0x80e6, 0x0267: 0x80e6, 0x0268: 0x80e6, 0x0269: 0x80e6,
- 0x026a: 0x80e6, 0x026b: 0x80e6, 0x026c: 0x80e6, 0x026d: 0x80e6, 0x026e: 0x80e6, 0x026f: 0x80e6,
- 0x0274: 0x0170,
- 0x027a: 0x428b,
- 0x027e: 0x0037,
- // Block 0xa, offset 0x280
- 0x0284: 0x4240, 0x0285: 0x4461,
- 0x0286: 0x35d3, 0x0287: 0x00d1, 0x0288: 0x35f1, 0x0289: 0x35fd, 0x028a: 0x360f,
- 0x028c: 0x362d, 0x028e: 0x363f, 0x028f: 0x365d, 0x0290: 0x3df2, 0x0291: 0x8800,
- 0x0295: 0x8800, 0x0297: 0x8800,
- 0x0299: 0x8800,
- 0x029f: 0x8800, 0x02a1: 0x8800,
- 0x02a5: 0x8800, 0x02a9: 0x8800,
- 0x02aa: 0x3621, 0x02ab: 0x3651, 0x02ac: 0x47e4, 0x02ad: 0x3681, 0x02ae: 0x480e, 0x02af: 0x3693,
- 0x02b0: 0x3e5a, 0x02b1: 0x8800, 0x02b5: 0x8800,
- 0x02b7: 0x8800, 0x02b9: 0x8800,
- 0x02bf: 0x8800,
- // Block 0xb, offset 0x2c0
- 0x02c1: 0x8800, 0x02c5: 0x8800,
- 0x02c9: 0x8800, 0x02ca: 0x4826, 0x02cb: 0x4844,
- 0x02cc: 0x36b1, 0x02cd: 0x36c9, 0x02ce: 0x485c, 0x02d0: 0x01be, 0x02d1: 0x01d0,
- 0x02d2: 0x01ac, 0x02d3: 0x42f2, 0x02d4: 0x42f8, 0x02d5: 0x01fa, 0x02d6: 0x01e8,
- 0x02f0: 0x01d6, 0x02f1: 0x01eb, 0x02f2: 0x01ee, 0x02f4: 0x0188, 0x02f5: 0x01c7,
- 0x02f9: 0x01a6,
- // Block 0xc, offset 0x300
- 0x0300: 0x370b, 0x0301: 0x3717, 0x0303: 0x3705,
- 0x0306: 0x8800, 0x0307: 0x36f3,
- 0x030c: 0x3747, 0x030d: 0x372f, 0x030e: 0x3759, 0x0310: 0x8800,
- 0x0313: 0x8800, 0x0315: 0x8800, 0x0316: 0x8800, 0x0317: 0x8800,
- 0x0318: 0x8800, 0x0319: 0x373b, 0x031a: 0x8800,
- 0x031e: 0x8800, 0x0323: 0x8800,
- 0x0327: 0x8800,
- 0x032b: 0x8800, 0x032d: 0x8800,
- 0x0330: 0x8800, 0x0333: 0x8800, 0x0335: 0x8800,
- 0x0336: 0x8800, 0x0337: 0x8800, 0x0338: 0x8800, 0x0339: 0x37bf, 0x033a: 0x8800,
- 0x033e: 0x8800,
- // Block 0xd, offset 0x340
- 0x0341: 0x371d, 0x0342: 0x37a1,
- 0x0350: 0x36f9, 0x0351: 0x377d,
- 0x0352: 0x36ff, 0x0353: 0x3783, 0x0356: 0x3711, 0x0357: 0x3795,
- 0x0358: 0x8800, 0x0359: 0x8800, 0x035a: 0x3813, 0x035b: 0x3819, 0x035c: 0x3723, 0x035d: 0x37a7,
- 0x035e: 0x3729, 0x035f: 0x37ad, 0x0362: 0x3735, 0x0363: 0x37b9,
- 0x0364: 0x3741, 0x0365: 0x37c5, 0x0366: 0x374d, 0x0367: 0x37d1, 0x0368: 0x8800, 0x0369: 0x8800,
- 0x036a: 0x381f, 0x036b: 0x3825, 0x036c: 0x3777, 0x036d: 0x37fb, 0x036e: 0x3753, 0x036f: 0x37d7,
- 0x0370: 0x375f, 0x0371: 0x37e3, 0x0372: 0x3765, 0x0373: 0x37e9, 0x0374: 0x376b, 0x0375: 0x37ef,
- 0x0378: 0x3771, 0x0379: 0x37f5,
- // Block 0xe, offset 0x380
- 0x0387: 0x1ea3,
- 0x0391: 0x80dc,
- 0x0392: 0x80e6, 0x0393: 0x80e6, 0x0394: 0x80e6, 0x0395: 0x80e6, 0x0396: 0x80dc, 0x0397: 0x80e6,
- 0x0398: 0x80e6, 0x0399: 0x80e6, 0x039a: 0x80de, 0x039b: 0x80dc, 0x039c: 0x80e6, 0x039d: 0x80e6,
- 0x039e: 0x80e6, 0x039f: 0x80e6, 0x03a0: 0x80e6, 0x03a1: 0x80e6, 0x03a2: 0x80dc, 0x03a3: 0x80dc,
- 0x03a4: 0x80dc, 0x03a5: 0x80dc, 0x03a6: 0x80dc, 0x03a7: 0x80dc, 0x03a8: 0x80e6, 0x03a9: 0x80e6,
- 0x03aa: 0x80dc, 0x03ab: 0x80e6, 0x03ac: 0x80e6, 0x03ad: 0x80de, 0x03ae: 0x80e4, 0x03af: 0x80e6,
- 0x03b0: 0x800a, 0x03b1: 0x800b, 0x03b2: 0x800c, 0x03b3: 0x800d, 0x03b4: 0x800e, 0x03b5: 0x800f,
- 0x03b6: 0x8010, 0x03b7: 0x8011, 0x03b8: 0x8012, 0x03b9: 0x8013, 0x03ba: 0x8013, 0x03bb: 0x8014,
- 0x03bc: 0x8015, 0x03bd: 0x8016, 0x03bf: 0x8017,
- // Block 0xf, offset 0x3c0
- 0x03c8: 0x8800, 0x03ca: 0x8800, 0x03cb: 0x801b,
- 0x03cc: 0x801c, 0x03cd: 0x801d, 0x03ce: 0x801e, 0x03cf: 0x801f, 0x03d0: 0x8020, 0x03d1: 0x8021,
- 0x03d2: 0x8022, 0x03d3: 0x86e6, 0x03d4: 0x86e6, 0x03d5: 0x86dc, 0x03d6: 0x80dc, 0x03d7: 0x80e6,
- 0x03d8: 0x80e6, 0x03d9: 0x80e6, 0x03da: 0x80e6, 0x03db: 0x80e6, 0x03dc: 0x80dc, 0x03dd: 0x80e6,
- 0x03de: 0x80e6, 0x03df: 0x80dc,
- 0x03f0: 0x8023, 0x03f5: 0x1ec6,
- 0x03f6: 0x2155, 0x03f7: 0x2191, 0x03f8: 0x218c,
- // Block 0x10, offset 0x400
- 0x0405: 0x8800,
- 0x0406: 0x1946, 0x0407: 0x8800, 0x0408: 0x194d, 0x0409: 0x8800, 0x040a: 0x1954, 0x040b: 0x8800,
- 0x040c: 0x195b, 0x040d: 0x8800, 0x040e: 0x1962, 0x0411: 0x8800,
- 0x0412: 0x1969,
- 0x0434: 0x8007, 0x0435: 0x8600,
- 0x043a: 0x8800, 0x043b: 0x1970,
- 0x043c: 0x8800, 0x043d: 0x1977, 0x043e: 0x8800, 0x043f: 0x8800,
- // Block 0x11, offset 0x440
- 0x0440: 0x0069, 0x0441: 0x006b, 0x0442: 0x006f, 0x0443: 0x0083, 0x0444: 0x00f8, 0x0445: 0x00fb,
- 0x0446: 0x0485, 0x0447: 0x0085, 0x0448: 0x0089, 0x0449: 0x008b, 0x044a: 0x0107, 0x044b: 0x010a,
- 0x044c: 0x010d, 0x044d: 0x008f, 0x044f: 0x0097, 0x0450: 0x009b, 0x0451: 0x00e3,
- 0x0452: 0x009f, 0x0453: 0x0101, 0x0454: 0x0489, 0x0455: 0x048d, 0x0456: 0x00a1, 0x0457: 0x00a9,
- 0x0458: 0x00ab, 0x0459: 0x0495, 0x045a: 0x012b, 0x045b: 0x00ad, 0x045c: 0x0499, 0x045d: 0x01be,
- 0x045e: 0x01c1, 0x045f: 0x01c4, 0x0460: 0x01fa, 0x0461: 0x01fd, 0x0462: 0x0093, 0x0463: 0x00a5,
- 0x0464: 0x00ab, 0x0465: 0x00ad, 0x0466: 0x01be, 0x0467: 0x01c1, 0x0468: 0x01eb, 0x0469: 0x01fa,
- 0x046a: 0x01fd,
- 0x0478: 0x020c,
- // Block 0x12, offset 0x480
- 0x049b: 0x00fe, 0x049c: 0x0087, 0x049d: 0x0104,
- 0x049e: 0x00d7, 0x049f: 0x010d, 0x04a0: 0x008d, 0x04a1: 0x0110, 0x04a2: 0x0113, 0x04a3: 0x0119,
- 0x04a4: 0x011f, 0x04a5: 0x0122, 0x04a6: 0x0125, 0x04a7: 0x049d, 0x04a8: 0x016a, 0x04a9: 0x0128,
- 0x04aa: 0x04a1, 0x04ab: 0x016d, 0x04ac: 0x0131, 0x04ad: 0x012e, 0x04ae: 0x0134, 0x04af: 0x0137,
- 0x04b0: 0x013a, 0x04b1: 0x013d, 0x04b2: 0x0140, 0x04b3: 0x014c, 0x04b4: 0x014f, 0x04b5: 0x00ef,
- 0x04b6: 0x0152, 0x04b7: 0x0155, 0x04b8: 0x0491, 0x04b9: 0x0158, 0x04ba: 0x015b, 0x04bb: 0x00b5,
- 0x04bc: 0x015e, 0x04bd: 0x0161, 0x04be: 0x0164, 0x04bf: 0x01d0,
- // Block 0x13, offset 0x4c0
- 0x04c0: 0x2f81, 0x04c1: 0x328d, 0x04c2: 0x2f8b, 0x04c3: 0x3297, 0x04c4: 0x2f90, 0x04c5: 0x329c,
- 0x04c6: 0x2f95, 0x04c7: 0x32a1, 0x04c8: 0x38b6, 0x04c9: 0x3a45, 0x04ca: 0x2fae, 0x04cb: 0x32ba,
- 0x04cc: 0x2fb8, 0x04cd: 0x32c4, 0x04ce: 0x2fc7, 0x04cf: 0x32d3, 0x04d0: 0x2fbd, 0x04d1: 0x32c9,
- 0x04d2: 0x2fc2, 0x04d3: 0x32ce, 0x04d4: 0x38d9, 0x04d5: 0x3a68, 0x04d6: 0x38e0, 0x04d7: 0x3a6f,
- 0x04d8: 0x3003, 0x04d9: 0x330f, 0x04da: 0x3008, 0x04db: 0x3314, 0x04dc: 0x38ee, 0x04dd: 0x3a7d,
- 0x04de: 0x300d, 0x04df: 0x3319, 0x04e0: 0x301c, 0x04e1: 0x3328, 0x04e2: 0x303a, 0x04e3: 0x3346,
- 0x04e4: 0x3049, 0x04e5: 0x3355, 0x04e6: 0x303f, 0x04e7: 0x334b, 0x04e8: 0x304e, 0x04e9: 0x335a,
- 0x04ea: 0x3053, 0x04eb: 0x335f, 0x04ec: 0x3099, 0x04ed: 0x33a5, 0x04ee: 0x38f5, 0x04ef: 0x3a84,
- 0x04f0: 0x30a3, 0x04f1: 0x33b4, 0x04f2: 0x30ad, 0x04f3: 0x33be, 0x04f4: 0x30b7, 0x04f5: 0x33c8,
- 0x04f6: 0x46aa, 0x04f7: 0x473b, 0x04f8: 0x38fc, 0x04f9: 0x3a8b, 0x04fa: 0x30d0, 0x04fb: 0x33e1,
- 0x04fc: 0x30cb, 0x04fd: 0x33dc, 0x04fe: 0x30d5, 0x04ff: 0x33e6,
- // Block 0x14, offset 0x500
- 0x0500: 0x30da, 0x0501: 0x33eb, 0x0502: 0x30df, 0x0503: 0x33f0, 0x0504: 0x30f3, 0x0505: 0x3404,
- 0x0506: 0x30fd, 0x0507: 0x340e, 0x0508: 0x310c, 0x0509: 0x341d, 0x050a: 0x3107, 0x050b: 0x3418,
- 0x050c: 0x391f, 0x050d: 0x3aae, 0x050e: 0x392d, 0x050f: 0x3abc, 0x0510: 0x3934, 0x0511: 0x3ac3,
- 0x0512: 0x393b, 0x0513: 0x3aca, 0x0514: 0x3139, 0x0515: 0x344a, 0x0516: 0x313e, 0x0517: 0x344f,
- 0x0518: 0x3148, 0x0519: 0x3459, 0x051a: 0x46d7, 0x051b: 0x4768, 0x051c: 0x3981, 0x051d: 0x3b10,
- 0x051e: 0x3161, 0x051f: 0x3472, 0x0520: 0x316b, 0x0521: 0x347c, 0x0522: 0x46e6, 0x0523: 0x4777,
- 0x0524: 0x3988, 0x0525: 0x3b17, 0x0526: 0x398f, 0x0527: 0x3b1e, 0x0528: 0x3996, 0x0529: 0x3b25,
- 0x052a: 0x317a, 0x052b: 0x348b, 0x052c: 0x3184, 0x052d: 0x349a, 0x052e: 0x3198, 0x052f: 0x34ae,
- 0x0530: 0x3193, 0x0531: 0x34a9, 0x0532: 0x31d4, 0x0533: 0x34ea, 0x0534: 0x31e3, 0x0535: 0x34f9,
- 0x0536: 0x31de, 0x0537: 0x34f4, 0x0538: 0x399d, 0x0539: 0x3b2c, 0x053a: 0x39a4, 0x053b: 0x3b33,
- 0x053c: 0x31e8, 0x053d: 0x34fe, 0x053e: 0x31ed, 0x053f: 0x3503,
- // Block 0x15, offset 0x540
- 0x0540: 0x31f2, 0x0541: 0x3508, 0x0542: 0x31f7, 0x0543: 0x350d, 0x0544: 0x3206, 0x0545: 0x351c,
- 0x0546: 0x3201, 0x0547: 0x3517, 0x0548: 0x320b, 0x0549: 0x3526, 0x054a: 0x3210, 0x054b: 0x352b,
- 0x054c: 0x3215, 0x054d: 0x3530, 0x054e: 0x3233, 0x054f: 0x354e, 0x0550: 0x324c, 0x0551: 0x356c,
- 0x0552: 0x325b, 0x0553: 0x357b, 0x0554: 0x3260, 0x0555: 0x3580, 0x0556: 0x3364, 0x0557: 0x3490,
- 0x0558: 0x3521, 0x0559: 0x355d, 0x055a: 0x1d22, 0x055b: 0x42bd,
- 0x0560: 0x4687, 0x0561: 0x4718, 0x0562: 0x2f6d, 0x0563: 0x3279,
- 0x0564: 0x3862, 0x0565: 0x39f1, 0x0566: 0x385b, 0x0567: 0x39ea, 0x0568: 0x3870, 0x0569: 0x39ff,
- 0x056a: 0x3869, 0x056b: 0x39f8, 0x056c: 0x38a8, 0x056d: 0x3a37, 0x056e: 0x387e, 0x056f: 0x3a0d,
- 0x0570: 0x3877, 0x0571: 0x3a06, 0x0572: 0x388c, 0x0573: 0x3a1b, 0x0574: 0x3885, 0x0575: 0x3a14,
- 0x0576: 0x38af, 0x0577: 0x3a3e, 0x0578: 0x469b, 0x0579: 0x472c, 0x057a: 0x2fea, 0x057b: 0x32f6,
- 0x057c: 0x2fd6, 0x057d: 0x32e2, 0x057e: 0x38c4, 0x057f: 0x3a53,
- // Block 0x16, offset 0x580
- 0x0580: 0x38bd, 0x0581: 0x3a4c, 0x0582: 0x38d2, 0x0583: 0x3a61, 0x0584: 0x38cb, 0x0585: 0x3a5a,
- 0x0586: 0x38e7, 0x0587: 0x3a76, 0x0588: 0x307b, 0x0589: 0x3387, 0x058a: 0x308f, 0x058b: 0x339b,
- 0x058c: 0x46cd, 0x058d: 0x475e, 0x058e: 0x3120, 0x058f: 0x3431, 0x0590: 0x390a, 0x0591: 0x3a99,
- 0x0592: 0x3903, 0x0593: 0x3a92, 0x0594: 0x3918, 0x0595: 0x3aa7, 0x0596: 0x3911, 0x0597: 0x3aa0,
- 0x0598: 0x3973, 0x0599: 0x3b02, 0x059a: 0x3957, 0x059b: 0x3ae6, 0x059c: 0x3950, 0x059d: 0x3adf,
- 0x059e: 0x3965, 0x059f: 0x3af4, 0x05a0: 0x395e, 0x05a1: 0x3aed, 0x05a2: 0x396c, 0x05a3: 0x3afb,
- 0x05a4: 0x31cf, 0x05a5: 0x34e5, 0x05a6: 0x31b1, 0x05a7: 0x34c7, 0x05a8: 0x39ce, 0x05a9: 0x3b5d,
- 0x05aa: 0x39c7, 0x05ab: 0x3b56, 0x05ac: 0x39dc, 0x05ad: 0x3b6b, 0x05ae: 0x39d5, 0x05af: 0x3b64,
- 0x05b0: 0x39e3, 0x05b1: 0x3b72, 0x05b2: 0x321a, 0x05b3: 0x3535, 0x05b4: 0x3242, 0x05b5: 0x3562,
- 0x05b6: 0x323d, 0x05b7: 0x3558, 0x05b8: 0x3229, 0x05b9: 0x3544,
- // Block 0x17, offset 0x5c0
- 0x05c0: 0x47ea, 0x05c1: 0x47f0, 0x05c2: 0x4904, 0x05c3: 0x491c, 0x05c4: 0x490c, 0x05c5: 0x4924,
- 0x05c6: 0x4914, 0x05c7: 0x492c, 0x05c8: 0x4790, 0x05c9: 0x4796, 0x05ca: 0x4874, 0x05cb: 0x488c,
- 0x05cc: 0x487c, 0x05cd: 0x4894, 0x05ce: 0x4884, 0x05cf: 0x489c, 0x05d0: 0x47fc, 0x05d1: 0x4802,
- 0x05d2: 0x3da2, 0x05d3: 0x3db2, 0x05d4: 0x3daa, 0x05d5: 0x3dba,
- 0x05d8: 0x479c, 0x05d9: 0x47a2, 0x05da: 0x3cd2, 0x05db: 0x3ce2, 0x05dc: 0x3cda, 0x05dd: 0x3cea,
- 0x05e0: 0x4814, 0x05e1: 0x481a, 0x05e2: 0x4934, 0x05e3: 0x494c,
- 0x05e4: 0x493c, 0x05e5: 0x4954, 0x05e6: 0x4944, 0x05e7: 0x495c, 0x05e8: 0x47a8, 0x05e9: 0x47ae,
- 0x05ea: 0x48a4, 0x05eb: 0x48bc, 0x05ec: 0x48ac, 0x05ed: 0x48c4, 0x05ee: 0x48b4, 0x05ef: 0x48cc,
- 0x05f0: 0x482c, 0x05f1: 0x4832, 0x05f2: 0x3e02, 0x05f3: 0x3e1a, 0x05f4: 0x3e0a, 0x05f5: 0x3e22,
- 0x05f6: 0x3e12, 0x05f7: 0x3e2a, 0x05f8: 0x47b4, 0x05f9: 0x47ba, 0x05fa: 0x3d02, 0x05fb: 0x3d1a,
- 0x05fc: 0x3d0a, 0x05fd: 0x3d22, 0x05fe: 0x3d12, 0x05ff: 0x3d2a,
- // Block 0x18, offset 0x600
- 0x0600: 0x4838, 0x0601: 0x483e, 0x0602: 0x3e32, 0x0603: 0x3e42, 0x0604: 0x3e3a, 0x0605: 0x3e4a,
- 0x0608: 0x47c0, 0x0609: 0x47c6, 0x060a: 0x3d32, 0x060b: 0x3d42,
- 0x060c: 0x3d3a, 0x060d: 0x3d4a, 0x0610: 0x484a, 0x0611: 0x4850,
- 0x0612: 0x3e6a, 0x0613: 0x3e82, 0x0614: 0x3e72, 0x0615: 0x3e8a, 0x0616: 0x3e7a, 0x0617: 0x3e92,
- 0x0619: 0x47cc, 0x061b: 0x3d52, 0x061d: 0x3d5a,
- 0x061f: 0x3d62, 0x0620: 0x4862, 0x0621: 0x4868, 0x0622: 0x4964, 0x0623: 0x497c,
- 0x0624: 0x496c, 0x0625: 0x4984, 0x0626: 0x4974, 0x0627: 0x498c, 0x0628: 0x47d2, 0x0629: 0x47d8,
- 0x062a: 0x48d4, 0x062b: 0x48ec, 0x062c: 0x48dc, 0x062d: 0x48f4, 0x062e: 0x48e4, 0x062f: 0x48fc,
- 0x0630: 0x47de, 0x0631: 0x4304, 0x0632: 0x367b, 0x0633: 0x430a, 0x0634: 0x4808, 0x0635: 0x4310,
- 0x0636: 0x368d, 0x0637: 0x4316, 0x0638: 0x36ab, 0x0639: 0x431c, 0x063a: 0x36c3, 0x063b: 0x4322,
- 0x063c: 0x4856, 0x063d: 0x4328,
- // Block 0x19, offset 0x640
- 0x0640: 0x3d8a, 0x0641: 0x3d92, 0x0642: 0x416e, 0x0643: 0x418c, 0x0644: 0x4178, 0x0645: 0x4196,
- 0x0646: 0x4182, 0x0647: 0x41a0, 0x0648: 0x3cc2, 0x0649: 0x3cca, 0x064a: 0x40ba, 0x064b: 0x40d8,
- 0x064c: 0x40c4, 0x064d: 0x40e2, 0x064e: 0x40ce, 0x064f: 0x40ec, 0x0650: 0x3dd2, 0x0651: 0x3dda,
- 0x0652: 0x41aa, 0x0653: 0x41c8, 0x0654: 0x41b4, 0x0655: 0x41d2, 0x0656: 0x41be, 0x0657: 0x41dc,
- 0x0658: 0x3cf2, 0x0659: 0x3cfa, 0x065a: 0x40f6, 0x065b: 0x4114, 0x065c: 0x4100, 0x065d: 0x411e,
- 0x065e: 0x410a, 0x065f: 0x4128, 0x0660: 0x3eaa, 0x0661: 0x3eb2, 0x0662: 0x41e6, 0x0663: 0x4204,
- 0x0664: 0x41f0, 0x0665: 0x420e, 0x0666: 0x41fa, 0x0667: 0x4218, 0x0668: 0x3d6a, 0x0669: 0x3d72,
- 0x066a: 0x4132, 0x066b: 0x4150, 0x066c: 0x413c, 0x066d: 0x415a, 0x066e: 0x4146, 0x066f: 0x4164,
- 0x0670: 0x366f, 0x0671: 0x3669, 0x0672: 0x3d7a, 0x0673: 0x3675, 0x0674: 0x3d82,
- 0x0676: 0x47f6, 0x0677: 0x3d9a, 0x0678: 0x35df, 0x0679: 0x35d9, 0x067a: 0x35cd, 0x067b: 0x42d4,
- 0x067c: 0x35e5, 0x067d: 0x426d, 0x067e: 0x01d3, 0x067f: 0x426d,
- // Block 0x1a, offset 0x680
- 0x0680: 0x4286, 0x0681: 0x4468, 0x0682: 0x3dc2, 0x0683: 0x3687, 0x0684: 0x3dca,
- 0x0686: 0x4820, 0x0687: 0x3de2, 0x0688: 0x35eb, 0x0689: 0x42da, 0x068a: 0x35f7, 0x068b: 0x42e0,
- 0x068c: 0x3603, 0x068d: 0x446f, 0x068e: 0x4476, 0x068f: 0x447d, 0x0690: 0x369f, 0x0691: 0x3699,
- 0x0692: 0x3dea, 0x0693: 0x44ca, 0x0696: 0x36a5, 0x0697: 0x3dfa,
- 0x0698: 0x361b, 0x0699: 0x3615, 0x069a: 0x3609, 0x069b: 0x42e6, 0x069d: 0x4484,
- 0x069e: 0x448b, 0x069f: 0x4492, 0x06a0: 0x36d5, 0x06a1: 0x36cf, 0x06a2: 0x3e52, 0x06a3: 0x44d2,
- 0x06a4: 0x36b7, 0x06a5: 0x36bd, 0x06a6: 0x36db, 0x06a7: 0x3e62, 0x06a8: 0x364b, 0x06a9: 0x3645,
- 0x06aa: 0x3639, 0x06ab: 0x42f2, 0x06ac: 0x3633, 0x06ad: 0x445a, 0x06ae: 0x4461, 0x06af: 0x0081,
- 0x06b2: 0x3e9a, 0x06b3: 0x36e1, 0x06b4: 0x3ea2,
- 0x06b6: 0x486e, 0x06b7: 0x3eba, 0x06b8: 0x3627, 0x06b9: 0x42ec, 0x06ba: 0x3657, 0x06bb: 0x42fe,
- 0x06bc: 0x3663, 0x06bd: 0x4240, 0x06be: 0x4272,
- // Block 0x1b, offset 0x6c0
- 0x06c0: 0x1d1a, 0x06c1: 0x1d1e, 0x06c2: 0x0047, 0x06c3: 0x1d96, 0x06c5: 0x1d2a,
- 0x06c6: 0x1d2e, 0x06c7: 0x00ec, 0x06c9: 0x1d9a, 0x06ca: 0x008f, 0x06cb: 0x0051,
- 0x06cc: 0x0051, 0x06cd: 0x0051, 0x06ce: 0x0091, 0x06cf: 0x00dd, 0x06d0: 0x0053, 0x06d1: 0x0053,
- 0x06d2: 0x0059, 0x06d3: 0x0099, 0x06d5: 0x005d, 0x06d6: 0x1acf,
- 0x06d9: 0x0061, 0x06da: 0x0063, 0x06db: 0x0065, 0x06dc: 0x0065, 0x06dd: 0x0065,
- 0x06e0: 0x1ae1, 0x06e1: 0x1d0a, 0x06e2: 0x1aea,
- 0x06e4: 0x0075, 0x06e6: 0x01b8, 0x06e8: 0x0075,
- 0x06ea: 0x0057, 0x06eb: 0x42b8, 0x06ec: 0x0045, 0x06ed: 0x0047, 0x06ef: 0x008b,
- 0x06f0: 0x004b, 0x06f1: 0x004d, 0x06f3: 0x005b, 0x06f4: 0x009f, 0x06f5: 0x020f,
- 0x06f6: 0x0212, 0x06f7: 0x0215, 0x06f8: 0x0218, 0x06f9: 0x0093, 0x06fb: 0x1cda,
- 0x06fc: 0x01e8, 0x06fd: 0x01c1, 0x06fe: 0x0179, 0x06ff: 0x01a0,
- // Block 0x1c, offset 0x700
- 0x0700: 0x04d5, 0x0705: 0x0049,
- 0x0706: 0x0089, 0x0707: 0x008b, 0x0708: 0x0093, 0x0709: 0x0095,
- 0x0710: 0x2370, 0x0711: 0x237c,
- 0x0712: 0x2430, 0x0713: 0x2358, 0x0714: 0x23dc, 0x0715: 0x2364, 0x0716: 0x23e2, 0x0717: 0x23fa,
- 0x0718: 0x2406, 0x0719: 0x236a, 0x071a: 0x240c, 0x071b: 0x2376, 0x071c: 0x2400, 0x071d: 0x2412,
- 0x071e: 0x2418, 0x071f: 0x1dfe, 0x0720: 0x0053, 0x0721: 0x1a9c, 0x0722: 0x1ce6, 0x0723: 0x1aa5,
- 0x0724: 0x006d, 0x0725: 0x1aed, 0x0726: 0x1d12, 0x0727: 0x1e8a, 0x0728: 0x1aa8, 0x0729: 0x0071,
- 0x072a: 0x1af9, 0x072b: 0x1d16, 0x072c: 0x0059, 0x072d: 0x0047, 0x072e: 0x0049, 0x072f: 0x005b,
- 0x0730: 0x0093, 0x0731: 0x1b26, 0x0732: 0x1d5a, 0x0733: 0x1b2f, 0x0734: 0x00ad, 0x0735: 0x1ba4,
- 0x0736: 0x1d8e, 0x0737: 0x1e9e, 0x0738: 0x1b32, 0x0739: 0x00b1, 0x073a: 0x1ba7, 0x073b: 0x1d92,
- 0x073c: 0x0099, 0x073d: 0x0087, 0x073e: 0x0089, 0x073f: 0x009b,
- // Block 0x1d, offset 0x740
- 0x0741: 0x3bf0, 0x0743: 0x8800, 0x0744: 0x3bf7, 0x0745: 0x8800,
- 0x0747: 0x3bfe, 0x0748: 0x8800, 0x0749: 0x3c05,
- 0x074d: 0x8800,
- 0x0760: 0x2f4f, 0x0761: 0x8800, 0x0762: 0x3c13,
- 0x0764: 0x8800, 0x0765: 0x8800,
- 0x076d: 0x3c0c, 0x076e: 0x2f4a, 0x076f: 0x2f54,
- 0x0770: 0x3c1a, 0x0771: 0x3c21, 0x0772: 0x8800, 0x0773: 0x8800, 0x0774: 0x3c28, 0x0775: 0x3c2f,
- 0x0776: 0x8800, 0x0777: 0x8800, 0x0778: 0x3c36, 0x0779: 0x3c3d, 0x077a: 0x8800, 0x077b: 0x8800,
- 0x077c: 0x8800, 0x077d: 0x8800,
- // Block 0x1e, offset 0x780
- 0x0780: 0x3c44, 0x0781: 0x3c4b, 0x0782: 0x8800, 0x0783: 0x8800, 0x0784: 0x3c60, 0x0785: 0x3c67,
- 0x0786: 0x8800, 0x0787: 0x8800, 0x0788: 0x3c6e, 0x0789: 0x3c75,
- 0x0791: 0x8800,
- 0x0792: 0x8800,
- 0x07a2: 0x8800,
- 0x07a8: 0x8800, 0x07a9: 0x8800,
- 0x07ab: 0x8800, 0x07ac: 0x3c8a, 0x07ad: 0x3c91, 0x07ae: 0x3c98, 0x07af: 0x3c9f,
- 0x07b2: 0x8800, 0x07b3: 0x8800, 0x07b4: 0x8800, 0x07b5: 0x8800,
- // Block 0x1f, offset 0x7c0
- 0x07e0: 0x0023, 0x07e1: 0x0025, 0x07e2: 0x0027, 0x07e3: 0x0029,
- 0x07e4: 0x002b, 0x07e5: 0x002d, 0x07e6: 0x002f, 0x07e7: 0x0031, 0x07e8: 0x0033, 0x07e9: 0x19c4,
- 0x07ea: 0x19c7, 0x07eb: 0x19ca, 0x07ec: 0x19cd, 0x07ed: 0x19d0, 0x07ee: 0x19d3, 0x07ef: 0x19d6,
- 0x07f0: 0x19d9, 0x07f1: 0x19dc, 0x07f2: 0x19df, 0x07f3: 0x19e8, 0x07f4: 0x1baa, 0x07f5: 0x1bae,
- 0x07f6: 0x1bb2, 0x07f7: 0x1bb6, 0x07f8: 0x1bba, 0x07f9: 0x1bbe, 0x07fa: 0x1bc2, 0x07fb: 0x1bc6,
- 0x07fc: 0x1bca, 0x07fd: 0x1dc2, 0x07fe: 0x1dc7, 0x07ff: 0x1dcc,
- // Block 0x20, offset 0x800
- 0x0800: 0x1dd1, 0x0801: 0x1dd6, 0x0802: 0x1ddb, 0x0803: 0x1de0, 0x0804: 0x1de5, 0x0805: 0x1dea,
- 0x0806: 0x1def, 0x0807: 0x1df4, 0x0808: 0x19c1, 0x0809: 0x19e5, 0x080a: 0x1a09, 0x080b: 0x1a2d,
- 0x080c: 0x1a51, 0x080d: 0x1a5a, 0x080e: 0x1a60, 0x080f: 0x1a66, 0x0810: 0x1a6c, 0x0811: 0x1ca2,
- 0x0812: 0x1ca6, 0x0813: 0x1caa, 0x0814: 0x1cae, 0x0815: 0x1cb2, 0x0816: 0x1cb6, 0x0817: 0x1cba,
- 0x0818: 0x1cbe, 0x0819: 0x1cc2, 0x081a: 0x1cc6, 0x081b: 0x1cca, 0x081c: 0x1c36, 0x081d: 0x1c3a,
- 0x081e: 0x1c3e, 0x081f: 0x1c42, 0x0820: 0x1c46, 0x0821: 0x1c4a, 0x0822: 0x1c4e, 0x0823: 0x1c52,
- 0x0824: 0x1c56, 0x0825: 0x1c5a, 0x0826: 0x1c5e, 0x0827: 0x1c62, 0x0828: 0x1c66, 0x0829: 0x1c6a,
- 0x082a: 0x1c6e, 0x082b: 0x1c72, 0x082c: 0x1c76, 0x082d: 0x1c7a, 0x082e: 0x1c7e, 0x082f: 0x1c82,
- 0x0830: 0x1c86, 0x0831: 0x1c8a, 0x0832: 0x1c8e, 0x0833: 0x1c92, 0x0834: 0x1c96, 0x0835: 0x1c9a,
- 0x0836: 0x0043, 0x0837: 0x0045, 0x0838: 0x0047, 0x0839: 0x0049, 0x083a: 0x004b, 0x083b: 0x004d,
- 0x083c: 0x004f, 0x083d: 0x0051, 0x083e: 0x0053, 0x083f: 0x0055,
- // Block 0x21, offset 0x840
- 0x0840: 0x0731, 0x0841: 0x0755, 0x0842: 0x0761, 0x0843: 0x0771, 0x0844: 0x0779, 0x0845: 0x0785,
- 0x0846: 0x078d, 0x0847: 0x0795, 0x0848: 0x07a1, 0x0849: 0x07f5, 0x084a: 0x080d, 0x084b: 0x081d,
- 0x084c: 0x082d, 0x084d: 0x083d, 0x084e: 0x084d, 0x084f: 0x086d, 0x0850: 0x0871, 0x0851: 0x0875,
- 0x0852: 0x08a9, 0x0853: 0x08d1, 0x0854: 0x08e1, 0x0855: 0x08e9, 0x0856: 0x08ed, 0x0857: 0x08f9,
- 0x0858: 0x0915, 0x0859: 0x0919, 0x085a: 0x0931, 0x085b: 0x0935, 0x085c: 0x093d, 0x085d: 0x094d,
- 0x085e: 0x09e9, 0x085f: 0x09fd, 0x0860: 0x0a3d, 0x0861: 0x0a51, 0x0862: 0x0a59, 0x0863: 0x0a5d,
- 0x0864: 0x0a6d, 0x0865: 0x0a89, 0x0866: 0x0ab5, 0x0867: 0x0ac1, 0x0868: 0x0ae1, 0x0869: 0x0aed,
- 0x086a: 0x0af1, 0x086b: 0x0af5, 0x086c: 0x0b0d, 0x086d: 0x0b11, 0x086e: 0x0b3d, 0x086f: 0x0b49,
- 0x0870: 0x0b51, 0x0871: 0x0b59, 0x0872: 0x0b69, 0x0873: 0x0b71, 0x0874: 0x0b79, 0x0875: 0x0ba5,
- 0x0876: 0x0ba9, 0x0877: 0x0bb1, 0x0878: 0x0bb5, 0x0879: 0x0bbd, 0x087a: 0x0bc5, 0x087b: 0x0bd5,
- 0x087c: 0x0bf1, 0x087d: 0x0c69, 0x087e: 0x0c7d, 0x087f: 0x0c81,
- // Block 0x22, offset 0x880
- 0x0880: 0x0d01, 0x0881: 0x0d05, 0x0882: 0x0d19, 0x0883: 0x0d1d, 0x0884: 0x0d25, 0x0885: 0x0d2d,
- 0x0886: 0x0d35, 0x0887: 0x0d41, 0x0888: 0x0d69, 0x0889: 0x0d79, 0x088a: 0x0d8d, 0x088b: 0x0dfd,
- 0x088c: 0x0e09, 0x088d: 0x0e19, 0x088e: 0x0e25, 0x088f: 0x0e31, 0x0890: 0x0e39, 0x0891: 0x0e3d,
- 0x0892: 0x0e41, 0x0893: 0x0e45, 0x0894: 0x0e49, 0x0895: 0x0f01, 0x0896: 0x0f49, 0x0897: 0x0f55,
- 0x0898: 0x0f59, 0x0899: 0x0f5d, 0x089a: 0x0f61, 0x089b: 0x0f69, 0x089c: 0x0f6d, 0x089d: 0x0f81,
- 0x089e: 0x0f9d, 0x089f: 0x0fa5, 0x08a0: 0x0fe5, 0x08a1: 0x0fe9, 0x08a2: 0x0ff1, 0x08a3: 0x0ff5,
- 0x08a4: 0x0ffd, 0x08a5: 0x1001, 0x08a6: 0x1025, 0x08a7: 0x1029, 0x08a8: 0x1045, 0x08a9: 0x1049,
- 0x08aa: 0x104d, 0x08ab: 0x1051, 0x08ac: 0x1065, 0x08ad: 0x1089, 0x08ae: 0x108d, 0x08af: 0x1091,
- 0x08b0: 0x10b5, 0x08b1: 0x10f5, 0x08b2: 0x10f9, 0x08b3: 0x1119, 0x08b4: 0x1129, 0x08b5: 0x1131,
- 0x08b6: 0x1151, 0x08b7: 0x1175, 0x08b8: 0x11b9, 0x08b9: 0x11c1, 0x08ba: 0x11d5, 0x08bb: 0x11e1,
- 0x08bc: 0x11e9, 0x08bd: 0x11f1, 0x08be: 0x11f5, 0x08bf: 0x11f9,
- // Block 0x23, offset 0x8c0
- 0x08c0: 0x1211, 0x08c1: 0x1215, 0x08c2: 0x1231, 0x08c3: 0x1239, 0x08c4: 0x1241, 0x08c5: 0x1245,
- 0x08c6: 0x1251, 0x08c7: 0x1259, 0x08c8: 0x125d, 0x08c9: 0x1261, 0x08ca: 0x1269, 0x08cb: 0x126d,
- 0x08cc: 0x130d, 0x08cd: 0x1321, 0x08ce: 0x1355, 0x08cf: 0x1359, 0x08d0: 0x1361, 0x08d1: 0x138d,
- 0x08d2: 0x1395, 0x08d3: 0x139d, 0x08d4: 0x13a5, 0x08d5: 0x13e1, 0x08d6: 0x13e5, 0x08d7: 0x13ed,
- 0x08d8: 0x13f1, 0x08d9: 0x13f5, 0x08da: 0x1421, 0x08db: 0x1425, 0x08dc: 0x142d, 0x08dd: 0x1441,
- 0x08de: 0x1445, 0x08df: 0x1461, 0x08e0: 0x1469, 0x08e1: 0x146d, 0x08e2: 0x1491, 0x08e3: 0x14b1,
- 0x08e4: 0x14c1, 0x08e5: 0x14c5, 0x08e6: 0x14cd, 0x08e7: 0x14f9, 0x08e8: 0x14fd, 0x08e9: 0x150d,
- 0x08ea: 0x1531, 0x08eb: 0x153d, 0x08ec: 0x154d, 0x08ed: 0x1565, 0x08ee: 0x156d, 0x08ef: 0x1571,
- 0x08f0: 0x1575, 0x08f1: 0x1579, 0x08f2: 0x1585, 0x08f3: 0x1589, 0x08f4: 0x1591, 0x08f5: 0x15ad,
- 0x08f6: 0x15b1, 0x08f7: 0x15b5, 0x08f8: 0x15cd, 0x08f9: 0x15d1, 0x08fa: 0x15d9, 0x08fb: 0x15ed,
- 0x08fc: 0x15f1, 0x08fd: 0x15f5, 0x08fe: 0x15fd, 0x08ff: 0x1601,
- // Block 0x24, offset 0x900
- 0x0906: 0x8800, 0x090b: 0x8800,
- 0x090c: 0x3ef2, 0x090d: 0x8800, 0x090e: 0x3efa, 0x090f: 0x8800, 0x0910: 0x3f02, 0x0911: 0x8800,
- 0x0912: 0x3f0a, 0x0913: 0x8800, 0x0914: 0x3f12, 0x0915: 0x8800, 0x0916: 0x3f1a, 0x0917: 0x8800,
- 0x0918: 0x3f22, 0x0919: 0x8800, 0x091a: 0x3f2a, 0x091b: 0x8800, 0x091c: 0x3f32, 0x091d: 0x8800,
- 0x091e: 0x3f3a, 0x091f: 0x8800, 0x0920: 0x3f42, 0x0921: 0x8800, 0x0922: 0x3f4a,
- 0x0924: 0x8800, 0x0925: 0x3f52, 0x0926: 0x8800, 0x0927: 0x3f5a, 0x0928: 0x8800, 0x0929: 0x3f62,
- 0x092f: 0x8800,
- 0x0930: 0x3f6a, 0x0931: 0x3f72, 0x0932: 0x8800, 0x0933: 0x3f7a, 0x0934: 0x3f82, 0x0935: 0x8800,
- 0x0936: 0x3f8a, 0x0937: 0x3f92, 0x0938: 0x8800, 0x0939: 0x3f9a, 0x093a: 0x3fa2, 0x093b: 0x8800,
- 0x093c: 0x3faa, 0x093d: 0x3fb2,
- // Block 0x25, offset 0x940
- 0x0954: 0x3eea,
- 0x0959: 0x8608, 0x095a: 0x8608, 0x095b: 0x42c2, 0x095c: 0x42c8, 0x095d: 0x8800,
- 0x095e: 0x3fba, 0x095f: 0x285f,
- 0x0966: 0x8800,
- 0x096b: 0x8800, 0x096c: 0x3fca, 0x096d: 0x8800, 0x096e: 0x3fd2, 0x096f: 0x8800,
- 0x0970: 0x3fda, 0x0971: 0x8800, 0x0972: 0x3fe2, 0x0973: 0x8800, 0x0974: 0x3fea, 0x0975: 0x8800,
- 0x0976: 0x3ff2, 0x0977: 0x8800, 0x0978: 0x3ffa, 0x0979: 0x8800, 0x097a: 0x4002, 0x097b: 0x8800,
- 0x097c: 0x400a, 0x097d: 0x8800, 0x097e: 0x4012, 0x097f: 0x8800,
- // Block 0x26, offset 0x980
- 0x0980: 0x401a, 0x0981: 0x8800, 0x0982: 0x4022, 0x0984: 0x8800, 0x0985: 0x402a,
- 0x0986: 0x8800, 0x0987: 0x4032, 0x0988: 0x8800, 0x0989: 0x403a,
- 0x098f: 0x8800, 0x0990: 0x4042, 0x0991: 0x404a,
- 0x0992: 0x8800, 0x0993: 0x4052, 0x0994: 0x405a, 0x0995: 0x8800, 0x0996: 0x4062, 0x0997: 0x406a,
- 0x0998: 0x8800, 0x0999: 0x4072, 0x099a: 0x407a, 0x099b: 0x8800, 0x099c: 0x4082, 0x099d: 0x408a,
- 0x09af: 0x8800,
- 0x09b0: 0x8800, 0x09b1: 0x8800, 0x09b2: 0x8800, 0x09b4: 0x3fc2,
- 0x09b7: 0x4092, 0x09b8: 0x409a, 0x09b9: 0x40a2, 0x09ba: 0x40aa,
- 0x09bd: 0x8800, 0x09be: 0x40b2, 0x09bf: 0x2874,
- // Block 0x27, offset 0x9c0
- 0x09c0: 0x03a9, 0x09c1: 0x03ad, 0x09c2: 0x047d, 0x09c3: 0x0481, 0x09c4: 0x03b1, 0x09c5: 0x03b5,
- 0x09c6: 0x03b9, 0x09c7: 0x0415, 0x09c8: 0x0419, 0x09c9: 0x041d, 0x09ca: 0x0421, 0x09cb: 0x0425,
- 0x09cc: 0x0429, 0x09cd: 0x042d, 0x09ce: 0x0431,
- 0x09d2: 0x0731, 0x09d3: 0x078d, 0x09d4: 0x073d, 0x09d5: 0x09ed, 0x09d6: 0x0741, 0x09d7: 0x0759,
- 0x09d8: 0x0745, 0x09d9: 0x1005, 0x09da: 0x0779, 0x09db: 0x074d, 0x09dc: 0x0735, 0x09dd: 0x0a71,
- 0x09de: 0x0a01, 0x09df: 0x07a1,
- // Block 0x28, offset 0xa00
- 0x0a00: 0x2196, 0x0a01: 0x219c, 0x0a02: 0x21a2, 0x0a03: 0x21a8, 0x0a04: 0x21ae, 0x0a05: 0x21b4,
- 0x0a06: 0x21ba, 0x0a07: 0x21c0, 0x0a08: 0x21c6, 0x0a09: 0x21cc, 0x0a0a: 0x21d2, 0x0a0b: 0x21d8,
- 0x0a0c: 0x21de, 0x0a0d: 0x21e4, 0x0a0e: 0x28d1, 0x0a0f: 0x28da, 0x0a10: 0x28e3, 0x0a11: 0x28ec,
- 0x0a12: 0x28f5, 0x0a13: 0x28fe, 0x0a14: 0x2907, 0x0a15: 0x2910, 0x0a16: 0x2919, 0x0a17: 0x292b,
- 0x0a18: 0x2934, 0x0a19: 0x293d, 0x0a1a: 0x2946, 0x0a1b: 0x294f, 0x0a1c: 0x2922, 0x0a1d: 0x2d74,
- 0x0a1e: 0x2ca5, 0x0a20: 0x21ea, 0x0a21: 0x2202, 0x0a22: 0x21f6, 0x0a23: 0x224a,
- 0x0a24: 0x2208, 0x0a25: 0x2226, 0x0a26: 0x21f0, 0x0a27: 0x2220, 0x0a28: 0x21fc, 0x0a29: 0x2232,
- 0x0a2a: 0x2262, 0x0a2b: 0x2280, 0x0a2c: 0x227a, 0x0a2d: 0x226e, 0x0a2e: 0x22bc, 0x0a2f: 0x2250,
- 0x0a30: 0x225c, 0x0a31: 0x2274, 0x0a32: 0x2268, 0x0a33: 0x2292, 0x0a34: 0x223e, 0x0a35: 0x2286,
- 0x0a36: 0x22b0, 0x0a37: 0x2298, 0x0a38: 0x222c, 0x0a39: 0x220e, 0x0a3a: 0x2244, 0x0a3b: 0x2256,
- 0x0a3c: 0x228c, 0x0a3d: 0x2214, 0x0a3e: 0x22b6, 0x0a3f: 0x2238,
- // Block 0x29, offset 0xa40
- 0x0a40: 0x229e, 0x0a41: 0x221a, 0x0a42: 0x22a4, 0x0a43: 0x22aa, 0x0a44: 0x09a1, 0x0a45: 0x0b75,
- 0x0a46: 0x0d19, 0x0a47: 0x1139,
- 0x0a50: 0x1d06, 0x0a51: 0x19eb,
- 0x0a52: 0x19ee, 0x0a53: 0x19f1, 0x0a54: 0x19f4, 0x0a55: 0x19f7, 0x0a56: 0x19fa, 0x0a57: 0x19fd,
- 0x0a58: 0x1a00, 0x0a59: 0x1a03, 0x0a5a: 0x1a0c, 0x0a5b: 0x1a0f, 0x0a5c: 0x1a12, 0x0a5d: 0x1a15,
- 0x0a5e: 0x1a18, 0x0a5f: 0x1a1b, 0x0a60: 0x030d, 0x0a61: 0x0315, 0x0a62: 0x0319, 0x0a63: 0x0321,
- 0x0a64: 0x0325, 0x0a65: 0x0329, 0x0a66: 0x0331, 0x0a67: 0x0339, 0x0a68: 0x033d, 0x0a69: 0x0345,
- 0x0a6a: 0x0349, 0x0a6b: 0x034d, 0x0a6c: 0x0351, 0x0a6d: 0x0355, 0x0a6e: 0x27d3, 0x0a6f: 0x27da,
- 0x0a70: 0x27e1, 0x0a71: 0x27e8, 0x0a72: 0x27ef, 0x0a73: 0x27f6, 0x0a74: 0x27fd, 0x0a75: 0x2804,
- 0x0a76: 0x2812, 0x0a77: 0x2819, 0x0a78: 0x2820, 0x0a79: 0x2827, 0x0a7a: 0x282e, 0x0a7b: 0x2835,
- 0x0a7c: 0x2cc4, 0x0a7d: 0x2b39, 0x0a7e: 0x280b,
- // Block 0x2a, offset 0xa80
- 0x0a80: 0x0731, 0x0a81: 0x078d, 0x0a82: 0x073d, 0x0a83: 0x09ed, 0x0a84: 0x0791, 0x0a85: 0x0821,
- 0x0a86: 0x0739, 0x0a87: 0x081d, 0x0a88: 0x077d, 0x0a89: 0x08f9, 0x0a8a: 0x0d79, 0x0a8b: 0x0f01,
- 0x0a8c: 0x0e49, 0x0a8d: 0x0d8d, 0x0a8e: 0x14cd, 0x0a8f: 0x09fd, 0x0a90: 0x0d41, 0x0a91: 0x0dbd,
- 0x0a92: 0x0d7d, 0x0a93: 0x10bd, 0x0a94: 0x096d, 0x0a95: 0x0f75, 0x0a96: 0x13f9, 0x0a97: 0x10d1,
- 0x0a98: 0x08b5, 0x0a99: 0x1101, 0x0a9a: 0x100d, 0x0a9b: 0x0a89, 0x0a9c: 0x1481, 0x0a9d: 0x07f1,
- 0x0a9e: 0x091d, 0x0a9f: 0x0e69, 0x0aa0: 0x1595, 0x0aa1: 0x07b5, 0x0aa2: 0x0845, 0x0aa3: 0x0e0d,
- 0x0aa4: 0x0741, 0x0aa5: 0x0759, 0x0aa6: 0x0745, 0x0aa7: 0x0b4d, 0x0aa8: 0x0961, 0x0aa9: 0x08f1,
- 0x0aaa: 0x0ac9, 0x0aab: 0x0abd, 0x0aac: 0x105d, 0x0aad: 0x07b1, 0x0aae: 0x140d, 0x0aaf: 0x090d,
- 0x0ab0: 0x0a65, 0x0ab1: 0x1a1e, 0x0ab2: 0x1a21, 0x0ab3: 0x1a24, 0x0ab4: 0x1a27, 0x0ab5: 0x1a30,
- 0x0ab6: 0x1a33, 0x0ab7: 0x1a36, 0x0ab8: 0x1a39, 0x0ab9: 0x1a3c, 0x0aba: 0x1a3f, 0x0abb: 0x1a42,
- 0x0abc: 0x1a45, 0x0abd: 0x1a48, 0x0abe: 0x1a4b, 0x0abf: 0x1a54,
- // Block 0x2b, offset 0xac0
- 0x0ac0: 0x1e08, 0x0ac1: 0x1e17, 0x0ac2: 0x1e26, 0x0ac3: 0x1e35, 0x0ac4: 0x1e44, 0x0ac5: 0x1e53,
- 0x0ac6: 0x1e62, 0x0ac7: 0x1e71, 0x0ac8: 0x1e80, 0x0ac9: 0x22ce, 0x0aca: 0x22e0, 0x0acb: 0x22f2,
- 0x0acc: 0x1a96, 0x0acd: 0x1d46, 0x0ace: 0x1b14, 0x0acf: 0x1cea, 0x0ad0: 0x053d, 0x0ad1: 0x0545,
- 0x0ad2: 0x054d, 0x0ad3: 0x0555, 0x0ad4: 0x055d, 0x0ad5: 0x0561, 0x0ad6: 0x0565, 0x0ad7: 0x0569,
- 0x0ad8: 0x056d, 0x0ad9: 0x0571, 0x0ada: 0x0575, 0x0adb: 0x0579, 0x0adc: 0x057d, 0x0add: 0x0581,
- 0x0ade: 0x0585, 0x0adf: 0x0589, 0x0ae0: 0x058d, 0x0ae1: 0x0595, 0x0ae2: 0x0599, 0x0ae3: 0x059d,
- 0x0ae4: 0x05a1, 0x0ae5: 0x05a5, 0x0ae6: 0x05a9, 0x0ae7: 0x05ad, 0x0ae8: 0x05b1, 0x0ae9: 0x05b5,
- 0x0aea: 0x05b9, 0x0aeb: 0x05bd, 0x0aec: 0x05c1, 0x0aed: 0x05c5, 0x0aee: 0x05c9, 0x0aef: 0x05cd,
- 0x0af0: 0x05d1, 0x0af1: 0x05d5, 0x0af2: 0x05d9, 0x0af3: 0x05e1, 0x0af4: 0x05e9, 0x0af5: 0x05f1,
- 0x0af6: 0x05f5, 0x0af7: 0x05f9, 0x0af8: 0x05fd, 0x0af9: 0x0601, 0x0afa: 0x0605, 0x0afb: 0x0609,
- 0x0afc: 0x060d, 0x0afd: 0x0611, 0x0afe: 0x0615,
- // Block 0x2c, offset 0xb00
- 0x0b00: 0x2cd4, 0x0b01: 0x2b60, 0x0b02: 0x2ce4, 0x0b03: 0x2a2b, 0x0b04: 0x2ede, 0x0b05: 0x2a35,
- 0x0b06: 0x2a3f, 0x0b07: 0x2f22, 0x0b08: 0x2b6d, 0x0b09: 0x2a49, 0x0b0a: 0x2a53, 0x0b0b: 0x2a5d,
- 0x0b0c: 0x2b94, 0x0b0d: 0x2ba1, 0x0b0e: 0x2b7a, 0x0b0f: 0x2b87, 0x0b10: 0x2eb4, 0x0b11: 0x2bae,
- 0x0b12: 0x2bbb, 0x0b13: 0x2d86, 0x0b14: 0x2866, 0x0b15: 0x2d99, 0x0b16: 0x2dac, 0x0b17: 0x2cf4,
- 0x0b18: 0x2bc8, 0x0b19: 0x2dbf, 0x0b1a: 0x2dd2, 0x0b1b: 0x2bd5, 0x0b1c: 0x2a67, 0x0b1d: 0x2a71,
- 0x0b1e: 0x2ec2, 0x0b1f: 0x2be2, 0x0b20: 0x2d04, 0x0b21: 0x2eef, 0x0b22: 0x2a7b, 0x0b23: 0x2a85,
- 0x0b24: 0x2bef, 0x0b25: 0x2a8f, 0x0b26: 0x2a99, 0x0b27: 0x287b, 0x0b28: 0x2882, 0x0b29: 0x2aa3,
- 0x0b2a: 0x2aad, 0x0b2b: 0x2de5, 0x0b2c: 0x2bfc, 0x0b2d: 0x2d14, 0x0b2e: 0x2df8, 0x0b2f: 0x2c09,
- 0x0b30: 0x2ac1, 0x0b31: 0x2ab7, 0x0b32: 0x2f36, 0x0b33: 0x2c16, 0x0b34: 0x2e0b, 0x0b35: 0x2acb,
- 0x0b36: 0x2d24, 0x0b37: 0x2ad5, 0x0b38: 0x2c30, 0x0b39: 0x2adf, 0x0b3a: 0x2c3d, 0x0b3b: 0x2f00,
- 0x0b3c: 0x2c23, 0x0b3d: 0x2d34, 0x0b3e: 0x2c4a, 0x0b3f: 0x2889,
- // Block 0x2d, offset 0xb40
- 0x0b40: 0x2f11, 0x0b41: 0x2ae9, 0x0b42: 0x2af3, 0x0b43: 0x2c57, 0x0b44: 0x2afd, 0x0b45: 0x2b07,
- 0x0b46: 0x2b11, 0x0b47: 0x2d44, 0x0b48: 0x2c64, 0x0b49: 0x2890, 0x0b4a: 0x2e1e, 0x0b4b: 0x2ea9,
- 0x0b4c: 0x2d54, 0x0b4d: 0x2c71, 0x0b4e: 0x2ed0, 0x0b4f: 0x2b1b, 0x0b50: 0x2b25, 0x0b51: 0x2c7e,
- 0x0b52: 0x2897, 0x0b53: 0x2c8b, 0x0b54: 0x2d64, 0x0b55: 0x289e, 0x0b56: 0x2e31, 0x0b57: 0x2b2f,
- 0x0b58: 0x1df9, 0x0b59: 0x1e0d, 0x0b5a: 0x1e1c, 0x0b5b: 0x1e2b, 0x0b5c: 0x1e3a, 0x0b5d: 0x1e49,
- 0x0b5e: 0x1e58, 0x0b5f: 0x1e67, 0x0b60: 0x1e76, 0x0b61: 0x1e85, 0x0b62: 0x22d4, 0x0b63: 0x22e6,
- 0x0b64: 0x22f8, 0x0b65: 0x2304, 0x0b66: 0x2310, 0x0b67: 0x231c, 0x0b68: 0x2328, 0x0b69: 0x2334,
- 0x0b6a: 0x2340, 0x0b6b: 0x234c, 0x0b6c: 0x2388, 0x0b6d: 0x2394, 0x0b6e: 0x23a0, 0x0b6f: 0x23ac,
- 0x0b70: 0x23b8, 0x0b71: 0x1d56, 0x0b72: 0x1b08, 0x0b73: 0x1a78, 0x0b74: 0x1d26, 0x0b75: 0x1b89,
- 0x0b76: 0x1b98, 0x0b77: 0x1b0e, 0x0b78: 0x1d3e, 0x0b79: 0x1d42, 0x0b7a: 0x1aa2, 0x0b7b: 0x28ac,
- 0x0b7c: 0x28ba, 0x0b7d: 0x28a5, 0x0b7e: 0x28b3, 0x0b7f: 0x2c98,
- // Block 0x2e, offset 0xb80
- 0x0b80: 0x1b8c, 0x0b81: 0x1b74, 0x0b82: 0x1da2, 0x0b83: 0x1b5c, 0x0b84: 0x1b35, 0x0b85: 0x1aab,
- 0x0b86: 0x1aba, 0x0b87: 0x1a8a, 0x0b88: 0x1d32, 0x0b89: 0x1e94, 0x0b8a: 0x1b8f, 0x0b8b: 0x1b77,
- 0x0b8c: 0x1da6, 0x0b8d: 0x1db2, 0x0b8e: 0x1b68, 0x0b8f: 0x1b3e, 0x0b90: 0x1a99, 0x0b91: 0x1d5e,
- 0x0b92: 0x1cf2, 0x0b93: 0x1cde, 0x0b94: 0x1d0e, 0x0b95: 0x1db6, 0x0b96: 0x1b6b, 0x0b97: 0x1b0b,
- 0x0b98: 0x1b41, 0x0b99: 0x1b20, 0x0b9a: 0x1b83, 0x0b9b: 0x1dba, 0x0b9c: 0x1b6e, 0x0b9d: 0x1b02,
- 0x0b9e: 0x1b44, 0x0b9f: 0x1d7e, 0x0ba0: 0x1d36, 0x0ba1: 0x1b56, 0x0ba2: 0x1d66, 0x0ba3: 0x1d82,
- 0x0ba4: 0x1d3a, 0x0ba5: 0x1b59, 0x0ba6: 0x1d6a, 0x0ba7: 0x242a, 0x0ba8: 0x243e, 0x0ba9: 0x1ad8,
- 0x0baa: 0x1d62, 0x0bab: 0x1cf6, 0x0bac: 0x1ce2, 0x0bad: 0x1d8a, 0x0bae: 0x28c1, 0x0baf: 0x2958,
- 0x0bb0: 0x1b9b, 0x0bb1: 0x1b86, 0x0bb2: 0x1dbe, 0x0bb3: 0x1b71, 0x0bb4: 0x1b92, 0x0bb5: 0x1b7a,
- 0x0bb6: 0x1daa, 0x0bb7: 0x1b5f, 0x0bb8: 0x1b38, 0x0bb9: 0x1ac3, 0x0bba: 0x1b95, 0x0bbb: 0x1b7d,
- 0x0bbc: 0x1dae, 0x0bbd: 0x1b62, 0x0bbe: 0x1b3b, 0x0bbf: 0x1ac6,
- // Block 0x2f, offset 0xbc0
- 0x0bc0: 0x1d6e, 0x0bc1: 0x1cfa, 0x0bc2: 0x1e8f, 0x0bc3: 0x1a7b, 0x0bc4: 0x1afc, 0x0bc5: 0x1aff,
- 0x0bc6: 0x2437, 0x0bc7: 0x1cd6, 0x0bc8: 0x1b05, 0x0bc9: 0x1a8d, 0x0bca: 0x1b23, 0x0bcb: 0x1a90,
- 0x0bcc: 0x1b2c, 0x0bcd: 0x1aae, 0x0bce: 0x1ab1, 0x0bcf: 0x1b47, 0x0bd0: 0x1b4d, 0x0bd1: 0x1b50,
- 0x0bd2: 0x1d72, 0x0bd3: 0x1b53, 0x0bd4: 0x1b65, 0x0bd5: 0x1d7a, 0x0bd6: 0x1d86, 0x0bd7: 0x1ad2,
- 0x0bd8: 0x1e99, 0x0bd9: 0x1cfe, 0x0bda: 0x1ad5, 0x0bdb: 0x1b9e, 0x0bdc: 0x1ae7, 0x0bdd: 0x1af6,
- 0x0bde: 0x2424, 0x0bdf: 0x241e, 0x0be0: 0x1e03, 0x0be1: 0x1e12, 0x0be2: 0x1e21, 0x0be3: 0x1e30,
- 0x0be4: 0x1e3f, 0x0be5: 0x1e4e, 0x0be6: 0x1e5d, 0x0be7: 0x1e6c, 0x0be8: 0x1e7b, 0x0be9: 0x22c8,
- 0x0bea: 0x22da, 0x0beb: 0x22ec, 0x0bec: 0x22fe, 0x0bed: 0x230a, 0x0bee: 0x2316, 0x0bef: 0x2322,
- 0x0bf0: 0x232e, 0x0bf1: 0x233a, 0x0bf2: 0x2346, 0x0bf3: 0x2382, 0x0bf4: 0x238e, 0x0bf5: 0x239a,
- 0x0bf6: 0x23a6, 0x0bf7: 0x23b2, 0x0bf8: 0x23be, 0x0bf9: 0x23c4, 0x0bfa: 0x23ca, 0x0bfb: 0x23d0,
- 0x0bfc: 0x23d6, 0x0bfd: 0x23e8, 0x0bfe: 0x23ee, 0x0bff: 0x1d52,
- // Block 0x30, offset 0xc00
- 0x0c00: 0x13e9, 0x0c01: 0x0d6d, 0x0c02: 0x1445, 0x0c03: 0x1411, 0x0c04: 0x0ec9, 0x0c05: 0x075d,
- 0x0c06: 0x0951, 0x0c07: 0x1699, 0x0c08: 0x1699, 0x0c09: 0x0a7d, 0x0c0a: 0x14cd, 0x0c0b: 0x09b5,
- 0x0c0c: 0x0a79, 0x0c0d: 0x0c61, 0x0c0e: 0x1041, 0x0c0f: 0x11d1, 0x0c10: 0x1309, 0x0c11: 0x1345,
- 0x0c12: 0x1379, 0x0c13: 0x148d, 0x0c14: 0x0de5, 0x0c15: 0x0e71, 0x0c16: 0x0f1d, 0x0c17: 0x0fb5,
- 0x0c18: 0x12d1, 0x0c19: 0x14b5, 0x0c1a: 0x15e1, 0x0c1b: 0x0781, 0x0c1c: 0x0925, 0x0c1d: 0x0df9,
- 0x0c1e: 0x0f41, 0x0c1f: 0x1305, 0x0c20: 0x1631, 0x0c21: 0x0b25, 0x0c22: 0x0ee9, 0x0c23: 0x12f5,
- 0x0c24: 0x1389, 0x0c25: 0x0c95, 0x0c26: 0x122d, 0x0c27: 0x1351, 0x0c28: 0x0b91, 0x0c29: 0x0d81,
- 0x0c2a: 0x0e89, 0x0c2b: 0x0f8d, 0x0c2c: 0x1499, 0x0c2d: 0x07c1, 0x0c2e: 0x0859, 0x0c2f: 0x08c5,
- 0x0c30: 0x0cfd, 0x0c31: 0x0df1, 0x0c32: 0x0f3d, 0x0c33: 0x1061, 0x0c34: 0x11e9, 0x0c35: 0x12fd,
- 0x0c36: 0x1315, 0x0c37: 0x1439, 0x0c38: 0x155d, 0x0c39: 0x1611, 0x0c3a: 0x162d, 0x0c3b: 0x109d,
- 0x0c3c: 0x10dd, 0x0c3d: 0x1195, 0x0c3e: 0x12b5, 0x0c3f: 0x14e9,
- // Block 0x31, offset 0xc40
- 0x0c40: 0x1639, 0x0c41: 0x13bd, 0x0c42: 0x0a39, 0x0c43: 0x0bad, 0x0c44: 0x114d, 0x0c45: 0x120d,
- 0x0c46: 0x0f71, 0x0c47: 0x10a5, 0x0c48: 0x1409, 0x0c49: 0x1555, 0x0c4a: 0x0a35, 0x0c4b: 0x0b01,
- 0x0c4c: 0x0de9, 0x0c4d: 0x0e9d, 0x0c4e: 0x0ed1, 0x0c4f: 0x1185, 0x0c50: 0x11ad, 0x0c51: 0x1515,
- 0x0c52: 0x08c1, 0x0c53: 0x1219, 0x0c54: 0x0865, 0x0c55: 0x0861, 0x0c56: 0x1109, 0x0c57: 0x1199,
- 0x0c58: 0x12cd, 0x0c59: 0x151d, 0x0c5a: 0x13d9, 0x0c5b: 0x0c99, 0x0c5c: 0x0de5, 0x0c5d: 0x13c9,
- 0x0c5e: 0x0769, 0x0c5f: 0x0ad5, 0x0c60: 0x0c05, 0x0c61: 0x0fa1, 0x0c62: 0x1021, 0x0c63: 0x08e5,
- 0x0c64: 0x10ad, 0x0c65: 0x07d1, 0x0c66: 0x0be9, 0x0c67: 0x0749, 0x0c68: 0x0e5d, 0x0c69: 0x0d15,
- 0x0c6a: 0x1181, 0x0c6b: 0x0939, 0x0c6c: 0x0a25, 0x0c6d: 0x106d, 0x0c6e: 0x12d5, 0x0c6f: 0x13ad,
- 0x0c70: 0x0e29, 0x0c71: 0x1469, 0x0c72: 0x0e55, 0x0c73: 0x0ca9, 0x0c74: 0x128d, 0x0c75: 0x0cc9,
- 0x0c76: 0x101d, 0x0c77: 0x079d, 0x0c78: 0x0819, 0x0c79: 0x085d, 0x0c7a: 0x0dc5, 0x0c7b: 0x116d,
- 0x0c7c: 0x1265, 0x0c7d: 0x13b9, 0x0c7e: 0x14c9, 0x0c7f: 0x08cd,
- // Block 0x32, offset 0xc80
- 0x0c80: 0x0981, 0x0c81: 0x0a89, 0x0c82: 0x0ba1, 0x0c83: 0x0d31, 0x0c84: 0x0eed, 0x0c85: 0x10b1,
- 0x0c86: 0x1505, 0x0c87: 0x15e9, 0x0c88: 0x163d, 0x0c89: 0x1655, 0x0c8a: 0x08a9, 0x0c8b: 0x0d65,
- 0x0c8c: 0x0e15, 0x0c8d: 0x145d, 0x0c8e: 0x0b6d, 0x0c8f: 0x0c49, 0x0c90: 0x0c65, 0x0c91: 0x0cf5,
- 0x0c92: 0x0edd, 0x0c93: 0x0f29, 0x0c94: 0x0fd9, 0x0c95: 0x10fd, 0x0c96: 0x11a1, 0x0c97: 0x1205,
- 0x0c98: 0x144d, 0x0c99: 0x12dd, 0x0c9a: 0x1475, 0x0c9b: 0x14ed, 0x0c9c: 0x0881, 0x0c9d: 0x08ad,
- 0x0c9e: 0x0995, 0x0c9f: 0x0f19, 0x0ca0: 0x1365, 0x0ca1: 0x13ad, 0x0ca2: 0x0b8d, 0x0ca3: 0x0bfd,
- 0x0ca4: 0x0cc1, 0x0ca5: 0x0e21, 0x0ca6: 0x1149, 0x0ca7: 0x0f95, 0x0ca8: 0x07ad, 0x0ca9: 0x09f1,
- 0x0caa: 0x0ad5, 0x0cab: 0x0b39, 0x0cac: 0x0c09, 0x0cad: 0x0fb1, 0x0cae: 0x0fcd, 0x0caf: 0x11dd,
- 0x0cb0: 0x11fd, 0x0cb1: 0x14d1, 0x0cb2: 0x1551, 0x0cb3: 0x1561, 0x0cb4: 0x159d, 0x0cb5: 0x07c5,
- 0x0cb6: 0x10f1, 0x0cb7: 0x14bd, 0x0cb8: 0x1539, 0x0cb9: 0x0c21, 0x0cba: 0x0789, 0x0cbb: 0x07e9,
- 0x0cbc: 0x0ad9, 0x0cbd: 0x0af9, 0x0cbe: 0x0d21, 0x0cbf: 0x0de5,
- // Block 0x33, offset 0xcc0
- 0x0cc0: 0x0f35, 0x0cc1: 0x103d, 0x0cc2: 0x12e9, 0x0cc3: 0x1489, 0x0cc4: 0x1691, 0x0cc5: 0x0d55,
- 0x0cc6: 0x1511, 0x0cc7: 0x08a5, 0x0cc8: 0x0da1, 0x0cc9: 0x0dad, 0x0cca: 0x0e81, 0x0ccb: 0x0eb9,
- 0x0ccc: 0x0fbd, 0x0ccd: 0x1019, 0x0cce: 0x1099, 0x0ccf: 0x117d, 0x0cd0: 0x15a9, 0x0cd1: 0x0821,
- 0x0cd2: 0x0c75, 0x0cd3: 0x1521, 0x0cd4: 0x07d9, 0x0cd5: 0x0b1d, 0x0cd6: 0x0ea1, 0x0cd7: 0x1451,
- 0x0cd8: 0x0bd9, 0x0cd9: 0x0c29, 0x0cda: 0x0db5, 0x0cdb: 0x0fa1, 0x0cdc: 0x1529, 0x0cdd: 0x0889,
- 0x0cde: 0x0971, 0x0cdf: 0x0b09, 0x0ce0: 0x0d45, 0x0ce1: 0x0d91, 0x0ce2: 0x0dd1, 0x0ce3: 0x0e65,
- 0x0ce4: 0x0fb9, 0x0ce5: 0x102d, 0x0ce6: 0x11c9, 0x0ce7: 0x1369, 0x0ce8: 0x1375, 0x0ce9: 0x14c5,
- 0x0cea: 0x1545, 0x0ceb: 0x08f5, 0x0cec: 0x0ebd, 0x0ced: 0x0975, 0x0cee: 0x0f39, 0x0cef: 0x0fdd,
- 0x0cf0: 0x12f9, 0x0cf1: 0x152d, 0x0cf2: 0x1619, 0x0cf3: 0x1641, 0x0cf4: 0x0da9, 0x0cf5: 0x0e99,
- 0x0cf6: 0x1235, 0x0cf7: 0x1129, 0x0cf8: 0x1135, 0x0cf9: 0x1159, 0x0cfa: 0x0f89, 0x0cfb: 0x0f11,
- 0x0cfc: 0x13d5, 0x0cfd: 0x07a5, 0x0cfe: 0x129d, 0x0cff: 0x088d,
- // Block 0x34, offset 0xd00
- 0x0d00: 0x087d, 0x0d01: 0x0b7d, 0x0d02: 0x0c9d, 0x0d03: 0x1165, 0x0d04: 0x0ac5, 0x0d05: 0x0e75,
- 0x0d06: 0x0d61, 0x0d07: 0x1459, 0x0d08: 0x1359, 0x0d09: 0x1519, 0x0d0a: 0x1395, 0x0d0b: 0x0b99,
- 0x0d0c: 0x07f9, 0x0d0d: 0x09cd, 0x0d10: 0x0a21,
- 0x0d12: 0x0d51, 0x0d15: 0x0869, 0x0d16: 0x0f91, 0x0d17: 0x1055,
- 0x0d18: 0x10b9, 0x0d19: 0x10d5, 0x0d1a: 0x10d9, 0x0d1b: 0x10ed, 0x0d1c: 0x1569, 0x0d1d: 0x115d,
- 0x0d1e: 0x11e1, 0x0d20: 0x1301, 0x0d22: 0x13c5,
- 0x0d25: 0x1479, 0x0d26: 0x14a5,
- 0x0d2a: 0x15bd, 0x0d2b: 0x15c1, 0x0d2c: 0x15c5, 0x0d2d: 0x1629, 0x0d2e: 0x149d, 0x0d2f: 0x1535,
- 0x0d30: 0x07c9, 0x0d31: 0x07ed, 0x0d32: 0x0801, 0x0d33: 0x08bd, 0x0d34: 0x08c9, 0x0d35: 0x0909,
- 0x0d36: 0x09bd, 0x0d37: 0x09d9, 0x0d38: 0x09e1, 0x0d39: 0x0a1d, 0x0d3a: 0x0a29, 0x0d3b: 0x0b05,
- 0x0d3c: 0x0b0d, 0x0d3d: 0x0c15, 0x0d3e: 0x0c3d, 0x0d3f: 0x0c45,
- // Block 0x35, offset 0xd40
- 0x0d40: 0x0c5d, 0x0d41: 0x0d09, 0x0d42: 0x0d39, 0x0d43: 0x0d59, 0x0d44: 0x0dc9, 0x0d45: 0x0e8d,
- 0x0d46: 0x0ea9, 0x0d47: 0x0ed9, 0x0d48: 0x0f2d, 0x0d49: 0x0f4d, 0x0d4a: 0x0fc1, 0x0d4b: 0x10a1,
- 0x0d4c: 0x10bd, 0x0d4d: 0x10c5, 0x0d4e: 0x10c1, 0x0d4f: 0x10c9, 0x0d50: 0x10cd, 0x0d51: 0x10d1,
- 0x0d52: 0x10e5, 0x0d53: 0x10e9, 0x0d54: 0x110d, 0x0d55: 0x1121, 0x0d56: 0x113d, 0x0d57: 0x11a1,
- 0x0d58: 0x11a9, 0x0d59: 0x11b1, 0x0d5a: 0x11c5, 0x0d5b: 0x11ed, 0x0d5c: 0x123d, 0x0d5d: 0x1271,
- 0x0d5e: 0x1271, 0x0d5f: 0x12d9, 0x0d60: 0x1381, 0x0d61: 0x1399, 0x0d62: 0x13cd, 0x0d63: 0x13d1,
- 0x0d64: 0x1415, 0x0d65: 0x1419, 0x0d66: 0x1471, 0x0d67: 0x1479, 0x0d68: 0x1549, 0x0d69: 0x158d,
- 0x0d6a: 0x15a5, 0x0d6b: 0x0c0d, 0x0d6c: 0x1780, 0x0d6d: 0x1255,
- 0x0d70: 0x0751, 0x0d71: 0x0855, 0x0d72: 0x0815, 0x0d73: 0x07bd, 0x0d74: 0x07fd, 0x0d75: 0x0829,
- 0x0d76: 0x08b9, 0x0d77: 0x08d5, 0x0d78: 0x09bd, 0x0d79: 0x09a9, 0x0d7a: 0x09b9, 0x0d7b: 0x09d5,
- 0x0d7c: 0x0a21, 0x0d7d: 0x0a31, 0x0d7e: 0x0a75, 0x0d7f: 0x0a81,
- // Block 0x36, offset 0xd80
- 0x0d80: 0x0a9d, 0x0d81: 0x0aad, 0x0d82: 0x0b95, 0x0d83: 0x0b9d, 0x0d84: 0x0bcd, 0x0d85: 0x0bed,
- 0x0d86: 0x0c1d, 0x0d87: 0x0c35, 0x0d88: 0x0c25, 0x0d89: 0x0c45, 0x0d8a: 0x0c39, 0x0d8b: 0x0c5d,
- 0x0d8c: 0x0c79, 0x0d8d: 0x0cd1, 0x0d8e: 0x0cdd, 0x0d8f: 0x0ce5, 0x0d90: 0x0d0d, 0x0d91: 0x0d51,
- 0x0d92: 0x0d81, 0x0d93: 0x0d85, 0x0d94: 0x0d99, 0x0d95: 0x0e19, 0x0d96: 0x0e29, 0x0d97: 0x0e81,
- 0x0d98: 0x0ecd, 0x0d99: 0x0ec5, 0x0d9a: 0x0ed9, 0x0d9b: 0x0ef5, 0x0d9c: 0x0f2d, 0x0d9d: 0x1085,
- 0x0d9e: 0x0f51, 0x0d9f: 0x0f85, 0x0da0: 0x0f91, 0x0da1: 0x0fd1, 0x0da2: 0x0fed, 0x0da3: 0x1011,
- 0x0da4: 0x1035, 0x0da5: 0x1039, 0x0da6: 0x1055, 0x0da7: 0x1059, 0x0da8: 0x1069, 0x0da9: 0x107d,
- 0x0daa: 0x1079, 0x0dab: 0x10a9, 0x0dac: 0x1125, 0x0dad: 0x113d, 0x0dae: 0x1155, 0x0daf: 0x118d,
- 0x0db0: 0x11a1, 0x0db1: 0x11bd, 0x0db2: 0x11ed, 0x0db3: 0x12a1, 0x0db4: 0x12c9, 0x0db5: 0x133d,
- 0x0db6: 0x1385, 0x0db7: 0x1391, 0x0db8: 0x1399, 0x0db9: 0x13b1, 0x0dba: 0x13c5, 0x0dbb: 0x13b5,
- 0x0dbc: 0x13cd, 0x0dbd: 0x13c9, 0x0dbe: 0x13c1, 0x0dbf: 0x13d1,
- // Block 0x37, offset 0xdc0
- 0x0dc0: 0x13dd, 0x0dc1: 0x1419, 0x0dc2: 0x1455, 0x0dc3: 0x1485, 0x0dc4: 0x14b9, 0x0dc5: 0x14d9,
- 0x0dc6: 0x1525, 0x0dc7: 0x1549, 0x0dc8: 0x1569, 0x0dc9: 0x157d, 0x0dca: 0x158d, 0x0dcb: 0x1599,
- 0x0dcc: 0x15a5, 0x0dcd: 0x15f9, 0x0dce: 0x1699, 0x0dcf: 0x1717, 0x0dd0: 0x1712, 0x0dd1: 0x1744,
- 0x0dd2: 0x0679, 0x0dd3: 0x06a1, 0x0dd4: 0x06a5, 0x0dd5: 0x17c6, 0x0dd6: 0x17f3, 0x0dd7: 0x186b,
- 0x0dd8: 0x1685, 0x0dd9: 0x1695,
- // Block 0x38, offset 0xe00
- 0x0e00: 0x1b17, 0x0e01: 0x1b1a, 0x0e02: 0x1b1d, 0x0e03: 0x1d4a, 0x0e04: 0x1d4e, 0x0e05: 0x1ba1,
- 0x0e06: 0x1ba1,
- 0x0e13: 0x1eb7, 0x0e14: 0x1ea8, 0x0e15: 0x1ead, 0x0e16: 0x1ebc, 0x0e17: 0x1eb2,
- 0x0e1d: 0x4376,
- 0x0e1e: 0x801a, 0x0e1f: 0x43e8, 0x0e20: 0x0227, 0x0e21: 0x020f, 0x0e22: 0x0218, 0x0e23: 0x021b,
- 0x0e24: 0x021e, 0x0e25: 0x0221, 0x0e26: 0x0224, 0x0e27: 0x022a, 0x0e28: 0x022d, 0x0e29: 0x0017,
- 0x0e2a: 0x43d6, 0x0e2b: 0x43dc, 0x0e2c: 0x44da, 0x0e2d: 0x44e2, 0x0e2e: 0x432e, 0x0e2f: 0x4334,
- 0x0e30: 0x433a, 0x0e31: 0x4340, 0x0e32: 0x434c, 0x0e33: 0x4352, 0x0e34: 0x4358, 0x0e35: 0x4364,
- 0x0e36: 0x436a, 0x0e38: 0x4370, 0x0e39: 0x437c, 0x0e3a: 0x4382, 0x0e3b: 0x4388,
- 0x0e3c: 0x4394, 0x0e3e: 0x439a,
- // Block 0x39, offset 0xe40
- 0x0e40: 0x43a0, 0x0e41: 0x43a6, 0x0e43: 0x43ac, 0x0e44: 0x43b2,
- 0x0e46: 0x43be, 0x0e47: 0x43c4, 0x0e48: 0x43ca, 0x0e49: 0x43d0, 0x0e4a: 0x43e2, 0x0e4b: 0x435e,
- 0x0e4c: 0x4346, 0x0e4d: 0x438e, 0x0e4e: 0x43b8, 0x0e4f: 0x1ec1, 0x0e50: 0x0293, 0x0e51: 0x0293,
- 0x0e52: 0x029c, 0x0e53: 0x029c, 0x0e54: 0x029c, 0x0e55: 0x029c, 0x0e56: 0x029f, 0x0e57: 0x029f,
- 0x0e58: 0x029f, 0x0e59: 0x029f, 0x0e5a: 0x02a5, 0x0e5b: 0x02a5, 0x0e5c: 0x02a5, 0x0e5d: 0x02a5,
- 0x0e5e: 0x0299, 0x0e5f: 0x0299, 0x0e60: 0x0299, 0x0e61: 0x0299, 0x0e62: 0x02a2, 0x0e63: 0x02a2,
- 0x0e64: 0x02a2, 0x0e65: 0x02a2, 0x0e66: 0x0296, 0x0e67: 0x0296, 0x0e68: 0x0296, 0x0e69: 0x0296,
- 0x0e6a: 0x02c9, 0x0e6b: 0x02c9, 0x0e6c: 0x02c9, 0x0e6d: 0x02c9, 0x0e6e: 0x02cc, 0x0e6f: 0x02cc,
- 0x0e70: 0x02cc, 0x0e71: 0x02cc, 0x0e72: 0x02ab, 0x0e73: 0x02ab, 0x0e74: 0x02ab, 0x0e75: 0x02ab,
- 0x0e76: 0x02a8, 0x0e77: 0x02a8, 0x0e78: 0x02a8, 0x0e79: 0x02a8, 0x0e7a: 0x02ae, 0x0e7b: 0x02ae,
- 0x0e7c: 0x02ae, 0x0e7d: 0x02ae, 0x0e7e: 0x02b1, 0x0e7f: 0x02b1,
- // Block 0x3a, offset 0xe80
- 0x0e80: 0x02b1, 0x0e81: 0x02b1, 0x0e82: 0x02ba, 0x0e83: 0x02ba, 0x0e84: 0x02b7, 0x0e85: 0x02b7,
- 0x0e86: 0x02bd, 0x0e87: 0x02bd, 0x0e88: 0x02b4, 0x0e89: 0x02b4, 0x0e8a: 0x02c3, 0x0e8b: 0x02c3,
- 0x0e8c: 0x02c0, 0x0e8d: 0x02c0, 0x0e8e: 0x02cf, 0x0e8f: 0x02cf, 0x0e90: 0x02cf, 0x0e91: 0x02cf,
- 0x0e92: 0x02d5, 0x0e93: 0x02d5, 0x0e94: 0x02d5, 0x0e95: 0x02d5, 0x0e96: 0x02db, 0x0e97: 0x02db,
- 0x0e98: 0x02db, 0x0e99: 0x02db, 0x0e9a: 0x02d8, 0x0e9b: 0x02d8, 0x0e9c: 0x02d8, 0x0e9d: 0x02d8,
- 0x0e9e: 0x02de, 0x0e9f: 0x02de, 0x0ea0: 0x02e1, 0x0ea1: 0x02e1, 0x0ea2: 0x02e1, 0x0ea3: 0x02e1,
- 0x0ea4: 0x4454, 0x0ea5: 0x4454, 0x0ea6: 0x02e7, 0x0ea7: 0x02e7, 0x0ea8: 0x02e7, 0x0ea9: 0x02e7,
- 0x0eaa: 0x02e4, 0x0eab: 0x02e4, 0x0eac: 0x02e4, 0x0ead: 0x02e4, 0x0eae: 0x0302, 0x0eaf: 0x0302,
- 0x0eb0: 0x444e, 0x0eb1: 0x444e,
- // Block 0x3b, offset 0xec0
- 0x0ed3: 0x02d2, 0x0ed4: 0x02d2, 0x0ed5: 0x02d2, 0x0ed6: 0x02d2, 0x0ed7: 0x02f0,
- 0x0ed8: 0x02f0, 0x0ed9: 0x02ed, 0x0eda: 0x02ed, 0x0edb: 0x02f3, 0x0edc: 0x02f3, 0x0edd: 0x2191,
- 0x0ede: 0x02f9, 0x0edf: 0x02f9, 0x0ee0: 0x02ea, 0x0ee1: 0x02ea, 0x0ee2: 0x02f6, 0x0ee3: 0x02f6,
- 0x0ee4: 0x02ff, 0x0ee5: 0x02ff, 0x0ee6: 0x02ff, 0x0ee7: 0x02ff, 0x0ee8: 0x0287, 0x0ee9: 0x0287,
- 0x0eea: 0x26ec, 0x0eeb: 0x26ec, 0x0eec: 0x275c, 0x0eed: 0x275c, 0x0eee: 0x272b, 0x0eef: 0x272b,
- 0x0ef0: 0x2747, 0x0ef1: 0x2747, 0x0ef2: 0x2740, 0x0ef3: 0x2740, 0x0ef4: 0x274e, 0x0ef5: 0x274e,
- 0x0ef6: 0x2755, 0x0ef7: 0x2755, 0x0ef8: 0x2755, 0x0ef9: 0x2732, 0x0efa: 0x2732, 0x0efb: 0x2732,
- 0x0efc: 0x02fc, 0x0efd: 0x02fc, 0x0efe: 0x02fc, 0x0eff: 0x02fc,
- // Block 0x3c, offset 0xf00
- 0x0f00: 0x26f3, 0x0f01: 0x26fa, 0x0f02: 0x2716, 0x0f03: 0x2732, 0x0f04: 0x2739, 0x0f05: 0x1ecb,
- 0x0f06: 0x1ed0, 0x0f07: 0x1ed5, 0x0f08: 0x1ee4, 0x0f09: 0x1ef3, 0x0f0a: 0x1ef8, 0x0f0b: 0x1efd,
- 0x0f0c: 0x1f02, 0x0f0d: 0x1f07, 0x0f0e: 0x1f16, 0x0f0f: 0x1f25, 0x0f10: 0x1f2a, 0x0f11: 0x1f2f,
- 0x0f12: 0x1f3e, 0x0f13: 0x1f4d, 0x0f14: 0x1f52, 0x0f15: 0x1f57, 0x0f16: 0x1f5c, 0x0f17: 0x1f6b,
- 0x0f18: 0x1f70, 0x0f19: 0x1f7f, 0x0f1a: 0x1f84, 0x0f1b: 0x1f89, 0x0f1c: 0x1f98, 0x0f1d: 0x1f9d,
- 0x0f1e: 0x1fa2, 0x0f1f: 0x1fac, 0x0f20: 0x1fe8, 0x0f21: 0x1ff7, 0x0f22: 0x2006, 0x0f23: 0x200b,
- 0x0f24: 0x2010, 0x0f25: 0x201a, 0x0f26: 0x2029, 0x0f27: 0x202e, 0x0f28: 0x203d, 0x0f29: 0x2042,
- 0x0f2a: 0x2047, 0x0f2b: 0x2056, 0x0f2c: 0x205b, 0x0f2d: 0x206a, 0x0f2e: 0x206f, 0x0f2f: 0x2074,
- 0x0f30: 0x2079, 0x0f31: 0x207e, 0x0f32: 0x2083, 0x0f33: 0x2088, 0x0f34: 0x208d, 0x0f35: 0x2092,
- 0x0f36: 0x2097, 0x0f37: 0x209c, 0x0f38: 0x20a1, 0x0f39: 0x20a6, 0x0f3a: 0x20ab, 0x0f3b: 0x20b0,
- 0x0f3c: 0x20b5, 0x0f3d: 0x20ba, 0x0f3e: 0x20bf, 0x0f3f: 0x20c9,
- // Block 0x3d, offset 0xf40
- 0x0f40: 0x20ce, 0x0f41: 0x20d3, 0x0f42: 0x20d8, 0x0f43: 0x20e2, 0x0f44: 0x20e7, 0x0f45: 0x20f1,
- 0x0f46: 0x20f6, 0x0f47: 0x20fb, 0x0f48: 0x2100, 0x0f49: 0x2105, 0x0f4a: 0x210a, 0x0f4b: 0x210f,
- 0x0f4c: 0x2114, 0x0f4d: 0x2119, 0x0f4e: 0x2128, 0x0f4f: 0x2137, 0x0f50: 0x213c, 0x0f51: 0x2141,
- 0x0f52: 0x2146, 0x0f53: 0x214b, 0x0f54: 0x2150, 0x0f55: 0x215a, 0x0f56: 0x215f, 0x0f57: 0x2164,
- 0x0f58: 0x2173, 0x0f59: 0x2182, 0x0f5a: 0x2187, 0x0f5b: 0x4406, 0x0f5c: 0x440c, 0x0f5d: 0x4442,
- 0x0f5e: 0x4499, 0x0f5f: 0x44a0, 0x0f60: 0x44a7, 0x0f61: 0x44ae, 0x0f62: 0x44b5, 0x0f63: 0x44bc,
- 0x0f64: 0x2708, 0x0f65: 0x270f, 0x0f66: 0x2716, 0x0f67: 0x271d, 0x0f68: 0x2732, 0x0f69: 0x2739,
- 0x0f6a: 0x1eda, 0x0f6b: 0x1edf, 0x0f6c: 0x1ee4, 0x0f6d: 0x1ee9, 0x0f6e: 0x1ef3, 0x0f6f: 0x1ef8,
- 0x0f70: 0x1f0c, 0x0f71: 0x1f11, 0x0f72: 0x1f16, 0x0f73: 0x1f1b, 0x0f74: 0x1f25, 0x0f75: 0x1f2a,
- 0x0f76: 0x1f34, 0x0f77: 0x1f39, 0x0f78: 0x1f3e, 0x0f79: 0x1f43, 0x0f7a: 0x1f4d, 0x0f7b: 0x1f52,
- 0x0f7c: 0x207e, 0x0f7d: 0x2083, 0x0f7e: 0x2092, 0x0f7f: 0x2097,
- // Block 0x3e, offset 0xf80
- 0x0f80: 0x209c, 0x0f81: 0x20b0, 0x0f82: 0x20b5, 0x0f83: 0x20ba, 0x0f84: 0x20bf, 0x0f85: 0x20d8,
- 0x0f86: 0x20e2, 0x0f87: 0x20e7, 0x0f88: 0x20ec, 0x0f89: 0x2100, 0x0f8a: 0x211e, 0x0f8b: 0x2123,
- 0x0f8c: 0x2128, 0x0f8d: 0x212d, 0x0f8e: 0x2137, 0x0f8f: 0x213c, 0x0f90: 0x4442, 0x0f91: 0x2169,
- 0x0f92: 0x216e, 0x0f93: 0x2173, 0x0f94: 0x2178, 0x0f95: 0x2182, 0x0f96: 0x2187, 0x0f97: 0x26f3,
- 0x0f98: 0x26fa, 0x0f99: 0x2701, 0x0f9a: 0x2716, 0x0f9b: 0x2724, 0x0f9c: 0x1ecb, 0x0f9d: 0x1ed0,
- 0x0f9e: 0x1ed5, 0x0f9f: 0x1ee4, 0x0fa0: 0x1eee, 0x0fa1: 0x1efd, 0x0fa2: 0x1f02, 0x0fa3: 0x1f07,
- 0x0fa4: 0x1f16, 0x0fa5: 0x1f20, 0x0fa6: 0x1f3e, 0x0fa7: 0x1f57, 0x0fa8: 0x1f5c, 0x0fa9: 0x1f6b,
- 0x0faa: 0x1f70, 0x0fab: 0x1f7f, 0x0fac: 0x1f89, 0x0fad: 0x1f98, 0x0fae: 0x1f9d, 0x0faf: 0x1fa2,
- 0x0fb0: 0x1fac, 0x0fb1: 0x1fe8, 0x0fb2: 0x1fed, 0x0fb3: 0x1ff7, 0x0fb4: 0x2006, 0x0fb5: 0x200b,
- 0x0fb6: 0x2010, 0x0fb7: 0x201a, 0x0fb8: 0x2029, 0x0fb9: 0x203d, 0x0fba: 0x2042, 0x0fbb: 0x2047,
- 0x0fbc: 0x2056, 0x0fbd: 0x205b, 0x0fbe: 0x206a, 0x0fbf: 0x206f,
- // Block 0x3f, offset 0xfc0
- 0x0fc0: 0x2074, 0x0fc1: 0x2079, 0x0fc2: 0x2088, 0x0fc3: 0x208d, 0x0fc4: 0x20a1, 0x0fc5: 0x20a6,
- 0x0fc6: 0x20ab, 0x0fc7: 0x20b0, 0x0fc8: 0x20b5, 0x0fc9: 0x20c9, 0x0fca: 0x20ce, 0x0fcb: 0x20d3,
- 0x0fcc: 0x20d8, 0x0fcd: 0x20dd, 0x0fce: 0x20f1, 0x0fcf: 0x20f6, 0x0fd0: 0x20fb, 0x0fd1: 0x2100,
- 0x0fd2: 0x210f, 0x0fd3: 0x2114, 0x0fd4: 0x2119, 0x0fd5: 0x2128, 0x0fd6: 0x2132, 0x0fd7: 0x2141,
- 0x0fd8: 0x2146, 0x0fd9: 0x4436, 0x0fda: 0x215a, 0x0fdb: 0x215f, 0x0fdc: 0x2164, 0x0fdd: 0x2173,
- 0x0fde: 0x217d, 0x0fdf: 0x2716, 0x0fe0: 0x2724, 0x0fe1: 0x1ee4, 0x0fe2: 0x1eee, 0x0fe3: 0x1f16,
- 0x0fe4: 0x1f20, 0x0fe5: 0x1f3e, 0x0fe6: 0x1f48, 0x0fe7: 0x1fac, 0x0fe8: 0x1fb1, 0x0fe9: 0x1fd4,
- 0x0fea: 0x1fd9, 0x0feb: 0x20b0, 0x0fec: 0x20b5, 0x0fed: 0x20d8, 0x0fee: 0x2128, 0x0fef: 0x2132,
- 0x0ff0: 0x2173, 0x0ff1: 0x217d, 0x0ff2: 0x44ea, 0x0ff3: 0x44f2, 0x0ff4: 0x44fa, 0x0ff5: 0x2033,
- 0x0ff6: 0x2038, 0x0ff7: 0x204c, 0x0ff8: 0x2051, 0x0ff9: 0x2060, 0x0ffa: 0x2065, 0x0ffb: 0x1fb6,
- 0x0ffc: 0x1fbb, 0x0ffd: 0x1fde, 0x0ffe: 0x1fe3, 0x0fff: 0x1f75,
- // Block 0x40, offset 0x1000
- 0x1000: 0x1f7a, 0x1001: 0x1f61, 0x1002: 0x1f66, 0x1003: 0x1f8e, 0x1004: 0x1f93, 0x1005: 0x1ffc,
- 0x1006: 0x2001, 0x1007: 0x201f, 0x1008: 0x2024, 0x1009: 0x1fc0, 0x100a: 0x1fc5, 0x100b: 0x1fca,
- 0x100c: 0x1fd4, 0x100d: 0x1fcf, 0x100e: 0x1fa7, 0x100f: 0x1ff2, 0x1010: 0x2015, 0x1011: 0x2033,
- 0x1012: 0x2038, 0x1013: 0x204c, 0x1014: 0x2051, 0x1015: 0x2060, 0x1016: 0x2065, 0x1017: 0x1fb6,
- 0x1018: 0x1fbb, 0x1019: 0x1fde, 0x101a: 0x1fe3, 0x101b: 0x1f75, 0x101c: 0x1f7a, 0x101d: 0x1f61,
- 0x101e: 0x1f66, 0x101f: 0x1f8e, 0x1020: 0x1f93, 0x1021: 0x1ffc, 0x1022: 0x2001, 0x1023: 0x201f,
- 0x1024: 0x2024, 0x1025: 0x1fc0, 0x1026: 0x1fc5, 0x1027: 0x1fca, 0x1028: 0x1fd4, 0x1029: 0x1fcf,
- 0x102a: 0x1fa7, 0x102b: 0x1ff2, 0x102c: 0x2015, 0x102d: 0x1fc0, 0x102e: 0x1fc5, 0x102f: 0x1fca,
- 0x1030: 0x1fd4, 0x1031: 0x1fb1, 0x1032: 0x1fd9, 0x1033: 0x202e, 0x1034: 0x1f98, 0x1035: 0x1f9d,
- 0x1036: 0x1fa2, 0x1037: 0x1fc0, 0x1038: 0x1fc5, 0x1039: 0x1fca, 0x103a: 0x202e, 0x103b: 0x203d,
- 0x103c: 0x43ee, 0x103d: 0x43ee,
- // Block 0x41, offset 0x1040
- 0x1050: 0x2453, 0x1051: 0x2468,
- 0x1052: 0x2468, 0x1053: 0x246f, 0x1054: 0x2476, 0x1055: 0x248b, 0x1056: 0x2492, 0x1057: 0x2499,
- 0x1058: 0x24bc, 0x1059: 0x24bc, 0x105a: 0x24df, 0x105b: 0x24d8, 0x105c: 0x24f4, 0x105d: 0x24e6,
- 0x105e: 0x24ed, 0x105f: 0x2510, 0x1060: 0x2510, 0x1061: 0x2509, 0x1062: 0x2517, 0x1063: 0x2517,
- 0x1064: 0x2541, 0x1065: 0x2541, 0x1066: 0x255d, 0x1067: 0x2525, 0x1068: 0x2525, 0x1069: 0x251e,
- 0x106a: 0x2533, 0x106b: 0x2533, 0x106c: 0x253a, 0x106d: 0x253a, 0x106e: 0x2564, 0x106f: 0x2572,
- 0x1070: 0x2572, 0x1071: 0x2579, 0x1072: 0x2579, 0x1073: 0x2580, 0x1074: 0x2587, 0x1075: 0x258e,
- 0x1076: 0x2595, 0x1077: 0x2595, 0x1078: 0x259c, 0x1079: 0x25aa, 0x107a: 0x25b8, 0x107b: 0x25b1,
- 0x107c: 0x25bf, 0x107d: 0x25bf, 0x107e: 0x25d4, 0x107f: 0x25db,
- // Block 0x42, offset 0x1080
- 0x1080: 0x260c, 0x1081: 0x261a, 0x1082: 0x2613, 0x1083: 0x25f7, 0x1084: 0x25f7, 0x1085: 0x2621,
- 0x1086: 0x2621, 0x1087: 0x2628, 0x1088: 0x2628, 0x1089: 0x2652, 0x108a: 0x2659, 0x108b: 0x2660,
- 0x108c: 0x2636, 0x108d: 0x2644, 0x108e: 0x2667, 0x108f: 0x266e,
- 0x1092: 0x263d, 0x1093: 0x26c2, 0x1094: 0x26c9, 0x1095: 0x269f, 0x1096: 0x26a6, 0x1097: 0x268a,
- 0x1098: 0x268a, 0x1099: 0x2691, 0x109a: 0x26bb, 0x109b: 0x26b4, 0x109c: 0x26de, 0x109d: 0x26de,
- 0x109e: 0x244c, 0x109f: 0x2461, 0x10a0: 0x245a, 0x10a1: 0x2484, 0x10a2: 0x247d, 0x10a3: 0x24a7,
- 0x10a4: 0x24a0, 0x10a5: 0x24ca, 0x10a6: 0x24ae, 0x10a7: 0x24c3, 0x10a8: 0x24fb, 0x10a9: 0x2548,
- 0x10aa: 0x252c, 0x10ab: 0x256b, 0x10ac: 0x2605, 0x10ad: 0x262f, 0x10ae: 0x26d7, 0x10af: 0x26d0,
- 0x10b0: 0x26e5, 0x10b1: 0x267c, 0x10b2: 0x25e2, 0x10b3: 0x26ad, 0x10b4: 0x25d4, 0x10b5: 0x260c,
- 0x10b6: 0x25a3, 0x10b7: 0x25f0, 0x10b8: 0x2683, 0x10b9: 0x2675, 0x10ba: 0x25fe, 0x10bb: 0x25e9,
- 0x10bc: 0x25fe, 0x10bd: 0x2683, 0x10be: 0x24b5, 0x10bf: 0x24d1,
- // Block 0x43, offset 0x10c0
- 0x10c0: 0x264b, 0x10c1: 0x25c6, 0x10c2: 0x2445, 0x10c3: 0x25e9, 0x10c4: 0x258e, 0x10c5: 0x255d,
- 0x10c6: 0x2502, 0x10c7: 0x2698,
- 0x10f0: 0x2556, 0x10f1: 0x25cd, 0x10f2: 0x296a, 0x10f3: 0x2961, 0x10f4: 0x2997, 0x10f5: 0x2985,
- 0x10f6: 0x2973, 0x10f7: 0x298e, 0x10f8: 0x29a0, 0x10f9: 0x254f, 0x10fa: 0x2e44, 0x10fb: 0x2cb4,
- 0x10fc: 0x297c,
- // Block 0x44, offset 0x1100
- 0x1110: 0x0019, 0x1111: 0x04f5,
- 0x1112: 0x04f9, 0x1113: 0x0035, 0x1114: 0x0037, 0x1115: 0x0003, 0x1116: 0x003f, 0x1117: 0x0531,
- 0x1118: 0x0535, 0x1119: 0x1c9e,
- 0x1120: 0x80e6, 0x1121: 0x80e6, 0x1122: 0x80e6, 0x1123: 0x80e6,
- 0x1124: 0x80e6, 0x1125: 0x80e6, 0x1126: 0x80e6,
- 0x1130: 0x19b5, 0x1131: 0x04b5, 0x1132: 0x04b1, 0x1133: 0x007f, 0x1134: 0x007f, 0x1135: 0x0011,
- 0x1136: 0x0013, 0x1137: 0x00b7, 0x1138: 0x00bb, 0x1139: 0x0529, 0x113a: 0x052d, 0x113b: 0x051d,
- 0x113c: 0x0521, 0x113d: 0x0505, 0x113e: 0x0509, 0x113f: 0x04fd,
- // Block 0x45, offset 0x1140
- 0x1140: 0x0501, 0x1141: 0x050d, 0x1142: 0x0511, 0x1143: 0x0515, 0x1144: 0x0519,
- 0x1147: 0x0077, 0x1148: 0x007b, 0x1149: 0x424f, 0x114a: 0x424f, 0x114b: 0x424f,
- 0x114c: 0x424f, 0x114d: 0x007f, 0x114e: 0x007f, 0x114f: 0x007f, 0x1150: 0x0019, 0x1151: 0x04f5,
- 0x1152: 0x001d, 0x1154: 0x0037, 0x1155: 0x0035, 0x1156: 0x003f, 0x1157: 0x0003,
- 0x1158: 0x04b5, 0x1159: 0x0011, 0x115a: 0x0013, 0x115b: 0x00b7, 0x115c: 0x00bb, 0x115d: 0x0529,
- 0x115e: 0x052d, 0x115f: 0x0007, 0x1160: 0x000d, 0x1161: 0x0015, 0x1162: 0x0017, 0x1163: 0x001b,
- 0x1164: 0x0039, 0x1165: 0x003d, 0x1166: 0x003b, 0x1168: 0x0079, 0x1169: 0x0009,
- 0x116a: 0x000b, 0x116b: 0x0041,
- 0x1170: 0x4290, 0x1171: 0x4412, 0x1172: 0x4295, 0x1174: 0x429a,
- 0x1176: 0x429f, 0x1177: 0x4418, 0x1178: 0x42a4, 0x1179: 0x441e, 0x117a: 0x42a9, 0x117b: 0x4424,
- 0x117c: 0x42ae, 0x117d: 0x442a, 0x117e: 0x42b3, 0x117f: 0x4430,
- // Block 0x46, offset 0x1180
- 0x1180: 0x0230, 0x1181: 0x43f4, 0x1182: 0x43f4, 0x1183: 0x43fa, 0x1184: 0x43fa, 0x1185: 0x443c,
- 0x1186: 0x443c, 0x1187: 0x4400, 0x1188: 0x4400, 0x1189: 0x4448, 0x118a: 0x4448, 0x118b: 0x4448,
- 0x118c: 0x4448, 0x118d: 0x0233, 0x118e: 0x0233, 0x118f: 0x0236, 0x1190: 0x0236, 0x1191: 0x0236,
- 0x1192: 0x0236, 0x1193: 0x0239, 0x1194: 0x0239, 0x1195: 0x023c, 0x1196: 0x023c, 0x1197: 0x023c,
- 0x1198: 0x023c, 0x1199: 0x023f, 0x119a: 0x023f, 0x119b: 0x023f, 0x119c: 0x023f, 0x119d: 0x0242,
- 0x119e: 0x0242, 0x119f: 0x0242, 0x11a0: 0x0242, 0x11a1: 0x0245, 0x11a2: 0x0245, 0x11a3: 0x0245,
- 0x11a4: 0x0245, 0x11a5: 0x0248, 0x11a6: 0x0248, 0x11a7: 0x0248, 0x11a8: 0x0248, 0x11a9: 0x024b,
- 0x11aa: 0x024b, 0x11ab: 0x024e, 0x11ac: 0x024e, 0x11ad: 0x0251, 0x11ae: 0x0251, 0x11af: 0x0254,
- 0x11b0: 0x0254, 0x11b1: 0x0257, 0x11b2: 0x0257, 0x11b3: 0x0257, 0x11b4: 0x0257, 0x11b5: 0x025a,
- 0x11b6: 0x025a, 0x11b7: 0x025a, 0x11b8: 0x025a, 0x11b9: 0x025d, 0x11ba: 0x025d, 0x11bb: 0x025d,
- 0x11bc: 0x025d, 0x11bd: 0x0260, 0x11be: 0x0260, 0x11bf: 0x0260,
- // Block 0x47, offset 0x11c0
- 0x11c0: 0x0260, 0x11c1: 0x0263, 0x11c2: 0x0263, 0x11c3: 0x0263, 0x11c4: 0x0263, 0x11c5: 0x0266,
- 0x11c6: 0x0266, 0x11c7: 0x0266, 0x11c8: 0x0266, 0x11c9: 0x0269, 0x11ca: 0x0269, 0x11cb: 0x0269,
- 0x11cc: 0x0269, 0x11cd: 0x026c, 0x11ce: 0x026c, 0x11cf: 0x026c, 0x11d0: 0x026c, 0x11d1: 0x026f,
- 0x11d2: 0x026f, 0x11d3: 0x026f, 0x11d4: 0x026f, 0x11d5: 0x0272, 0x11d6: 0x0272, 0x11d7: 0x0272,
- 0x11d8: 0x0272, 0x11d9: 0x0275, 0x11da: 0x0275, 0x11db: 0x0275, 0x11dc: 0x0275, 0x11dd: 0x0278,
- 0x11de: 0x0278, 0x11df: 0x0278, 0x11e0: 0x0278, 0x11e1: 0x027b, 0x11e2: 0x027b, 0x11e3: 0x027b,
- 0x11e4: 0x027b, 0x11e5: 0x027e, 0x11e6: 0x027e, 0x11e7: 0x027e, 0x11e8: 0x027e, 0x11e9: 0x0281,
- 0x11ea: 0x0281, 0x11eb: 0x0281, 0x11ec: 0x0281, 0x11ed: 0x0284, 0x11ee: 0x0284, 0x11ef: 0x0287,
- 0x11f0: 0x0287, 0x11f1: 0x028a, 0x11f2: 0x028a, 0x11f3: 0x028a, 0x11f4: 0x028a, 0x11f5: 0x2e91,
- 0x11f6: 0x2e91, 0x11f7: 0x2e99, 0x11f8: 0x2e99, 0x11f9: 0x2ea1, 0x11fa: 0x2ea1, 0x11fb: 0x20c4,
- 0x11fc: 0x20c4,
- // Block 0x48, offset 0x1200
- 0x1200: 0x0081, 0x1201: 0x0083, 0x1202: 0x0085, 0x1203: 0x0087, 0x1204: 0x0089, 0x1205: 0x008b,
- 0x1206: 0x008d, 0x1207: 0x008f, 0x1208: 0x0091, 0x1209: 0x0093, 0x120a: 0x0095, 0x120b: 0x0097,
- 0x120c: 0x0099, 0x120d: 0x009b, 0x120e: 0x009d, 0x120f: 0x009f, 0x1210: 0x00a1, 0x1211: 0x00a3,
- 0x1212: 0x00a5, 0x1213: 0x00a7, 0x1214: 0x00a9, 0x1215: 0x00ab, 0x1216: 0x00ad, 0x1217: 0x00af,
- 0x1218: 0x00b1, 0x1219: 0x00b3, 0x121a: 0x00b5, 0x121b: 0x00b7, 0x121c: 0x00b9, 0x121d: 0x00bb,
- 0x121e: 0x00bd, 0x121f: 0x04e9, 0x1220: 0x04ed, 0x1221: 0x04f9, 0x1222: 0x050d, 0x1223: 0x0511,
- 0x1224: 0x04f5, 0x1225: 0x061d, 0x1226: 0x0615, 0x1227: 0x0539, 0x1228: 0x0541, 0x1229: 0x0549,
- 0x122a: 0x0551, 0x122b: 0x0559, 0x122c: 0x05dd, 0x122d: 0x05e5, 0x122e: 0x05ed, 0x122f: 0x0591,
- 0x1230: 0x0621, 0x1231: 0x053d, 0x1232: 0x0545, 0x1233: 0x054d, 0x1234: 0x0555, 0x1235: 0x055d,
- 0x1236: 0x0561, 0x1237: 0x0565, 0x1238: 0x0569, 0x1239: 0x056d, 0x123a: 0x0571, 0x123b: 0x0575,
- 0x123c: 0x0579, 0x123d: 0x057d, 0x123e: 0x0581, 0x123f: 0x0585,
- // Block 0x49, offset 0x1240
- 0x1240: 0x0589, 0x1241: 0x058d, 0x1242: 0x0595, 0x1243: 0x0599, 0x1244: 0x059d, 0x1245: 0x05a1,
- 0x1246: 0x05a5, 0x1247: 0x05a9, 0x1248: 0x05ad, 0x1249: 0x05b1, 0x124a: 0x05b5, 0x124b: 0x05b9,
- 0x124c: 0x05bd, 0x124d: 0x05c1, 0x124e: 0x05c5, 0x124f: 0x05c9, 0x1250: 0x05cd, 0x1251: 0x05d1,
- 0x1252: 0x05d5, 0x1253: 0x05d9, 0x1254: 0x05e1, 0x1255: 0x05e9, 0x1256: 0x05f1, 0x1257: 0x05f5,
- 0x1258: 0x05f9, 0x1259: 0x05fd, 0x125a: 0x0601, 0x125b: 0x0605, 0x125c: 0x0609, 0x125d: 0x0619,
- 0x125e: 0x49aa, 0x125f: 0x49b0, 0x1260: 0x03bd, 0x1261: 0x030d, 0x1262: 0x0311, 0x1263: 0x0435,
- 0x1264: 0x0315, 0x1265: 0x0439, 0x1266: 0x043d, 0x1267: 0x0319, 0x1268: 0x031d, 0x1269: 0x0321,
- 0x126a: 0x0441, 0x126b: 0x0445, 0x126c: 0x0449, 0x126d: 0x044d, 0x126e: 0x0451, 0x126f: 0x0455,
- 0x1270: 0x0361, 0x1271: 0x0325, 0x1272: 0x0329, 0x1273: 0x032d, 0x1274: 0x0375, 0x1275: 0x0331,
- 0x1276: 0x0335, 0x1277: 0x0339, 0x1278: 0x033d, 0x1279: 0x0341, 0x127a: 0x0345, 0x127b: 0x0349,
- 0x127c: 0x034d, 0x127d: 0x0351, 0x127e: 0x0355,
- // Block 0x4a, offset 0x1280
- 0x1280: 0x0063, 0x1281: 0x0065, 0x1282: 0x0067, 0x1283: 0x0069, 0x1284: 0x006b, 0x1285: 0x006d,
- 0x1286: 0x006f, 0x1287: 0x0071, 0x1288: 0x0073, 0x1289: 0x0075, 0x128a: 0x0083, 0x128b: 0x0085,
- 0x128c: 0x0087, 0x128d: 0x0089, 0x128e: 0x008b, 0x128f: 0x008d, 0x1290: 0x008f, 0x1291: 0x0091,
- 0x1292: 0x0093, 0x1293: 0x0095, 0x1294: 0x0097, 0x1295: 0x0099, 0x1296: 0x009b, 0x1297: 0x009d,
- 0x1298: 0x009f, 0x1299: 0x00a1, 0x129a: 0x00a3, 0x129b: 0x00a5, 0x129c: 0x00a7, 0x129d: 0x00a9,
- 0x129e: 0x00ab, 0x129f: 0x00ad, 0x12a0: 0x00af, 0x12a1: 0x00b1, 0x12a2: 0x00b3, 0x12a3: 0x00b5,
- 0x12a4: 0x00e0, 0x12a5: 0x00f5, 0x12a8: 0x0173, 0x12a9: 0x0176,
- 0x12aa: 0x0179, 0x12ab: 0x017c, 0x12ac: 0x017f, 0x12ad: 0x0182, 0x12ae: 0x0185, 0x12af: 0x0188,
- 0x12b0: 0x018b, 0x12b1: 0x018e, 0x12b2: 0x0191, 0x12b3: 0x0194, 0x12b4: 0x0197, 0x12b5: 0x019a,
- 0x12b6: 0x019d, 0x12b7: 0x01a0, 0x12b8: 0x01a3, 0x12b9: 0x0188, 0x12ba: 0x01a6, 0x12bb: 0x01a9,
- 0x12bc: 0x01ac, 0x12bd: 0x01af, 0x12be: 0x01b2, 0x12bf: 0x01b5,
- // Block 0x4b, offset 0x12c0
- 0x12c0: 0x01fd, 0x12c1: 0x0200, 0x12c2: 0x0203, 0x12c3: 0x04cd, 0x12c4: 0x01c7, 0x12c5: 0x01d0,
- 0x12c6: 0x01d6, 0x12c7: 0x01fa, 0x12c8: 0x01eb, 0x12c9: 0x01e8, 0x12ca: 0x0206, 0x12cb: 0x0209,
- 0x12ce: 0x0021, 0x12cf: 0x0023, 0x12d0: 0x0025, 0x12d1: 0x0027,
- 0x12d2: 0x0029, 0x12d3: 0x002b, 0x12d4: 0x002d, 0x12d5: 0x002f, 0x12d6: 0x0031, 0x12d7: 0x0033,
- 0x12d8: 0x0021, 0x12d9: 0x0023, 0x12da: 0x0025, 0x12db: 0x0027, 0x12dc: 0x0029, 0x12dd: 0x002b,
- 0x12de: 0x002d, 0x12df: 0x002f, 0x12e0: 0x0031, 0x12e1: 0x0033, 0x12e2: 0x0021, 0x12e3: 0x0023,
- 0x12e4: 0x0025, 0x12e5: 0x0027, 0x12e6: 0x0029, 0x12e7: 0x002b, 0x12e8: 0x002d, 0x12e9: 0x002f,
- 0x12ea: 0x0031, 0x12eb: 0x0033, 0x12ec: 0x0021, 0x12ed: 0x0023, 0x12ee: 0x0025, 0x12ef: 0x0027,
- 0x12f0: 0x0029, 0x12f1: 0x002b, 0x12f2: 0x002d, 0x12f3: 0x002f, 0x12f4: 0x0031, 0x12f5: 0x0033,
- 0x12f6: 0x0021, 0x12f7: 0x0023, 0x12f8: 0x0025, 0x12f9: 0x0027, 0x12fa: 0x0029, 0x12fb: 0x002b,
- 0x12fc: 0x002d, 0x12fd: 0x002f, 0x12fe: 0x0031, 0x12ff: 0x0033,
- // Block 0x4c, offset 0x1300
- 0x1300: 0x0233, 0x1301: 0x0236, 0x1302: 0x0242, 0x1303: 0x024b, 0x1305: 0x0284,
- 0x1306: 0x0254, 0x1307: 0x0245, 0x1308: 0x0263, 0x1309: 0x028a, 0x130a: 0x0275, 0x130b: 0x0278,
- 0x130c: 0x027b, 0x130d: 0x027e, 0x130e: 0x0257, 0x130f: 0x0269, 0x1310: 0x026f, 0x1311: 0x025d,
- 0x1312: 0x0272, 0x1313: 0x0251, 0x1314: 0x025a, 0x1315: 0x023c, 0x1316: 0x023f, 0x1317: 0x0248,
- 0x1318: 0x024e, 0x1319: 0x0260, 0x131a: 0x0266, 0x131b: 0x026c, 0x131c: 0x028d, 0x131d: 0x02de,
- 0x131e: 0x02c6, 0x131f: 0x0290, 0x1321: 0x0236, 0x1322: 0x0242,
- 0x1324: 0x0281, 0x1327: 0x0245, 0x1329: 0x028a,
- 0x132a: 0x0275, 0x132b: 0x0278, 0x132c: 0x027b, 0x132d: 0x027e, 0x132e: 0x0257, 0x132f: 0x0269,
- 0x1330: 0x026f, 0x1331: 0x025d, 0x1332: 0x0272, 0x1334: 0x025a, 0x1335: 0x023c,
- 0x1336: 0x023f, 0x1337: 0x0248, 0x1339: 0x0260, 0x133b: 0x026c,
- // Block 0x4d, offset 0x1340
- 0x1342: 0x0242,
- 0x1347: 0x0245, 0x1349: 0x028a, 0x134b: 0x0278,
- 0x134d: 0x027e, 0x134e: 0x0257, 0x134f: 0x0269, 0x1351: 0x025d,
- 0x1352: 0x0272, 0x1354: 0x025a, 0x1357: 0x0248,
- 0x1359: 0x0260, 0x135b: 0x026c, 0x135d: 0x02de,
- 0x135f: 0x0290, 0x1361: 0x0236, 0x1362: 0x0242,
- 0x1364: 0x0281, 0x1367: 0x0245, 0x1368: 0x0263, 0x1369: 0x028a,
- 0x136a: 0x0275, 0x136c: 0x027b, 0x136d: 0x027e, 0x136e: 0x0257, 0x136f: 0x0269,
- 0x1370: 0x026f, 0x1371: 0x025d, 0x1372: 0x0272, 0x1374: 0x025a, 0x1375: 0x023c,
- 0x1376: 0x023f, 0x1377: 0x0248, 0x1379: 0x0260, 0x137a: 0x0266, 0x137b: 0x026c,
- 0x137c: 0x028d, 0x137e: 0x02c6,
- // Block 0x4e, offset 0x1380
- 0x1380: 0x0233, 0x1381: 0x0236, 0x1382: 0x0242, 0x1383: 0x024b, 0x1384: 0x0281, 0x1385: 0x0284,
- 0x1386: 0x0254, 0x1387: 0x0245, 0x1388: 0x0263, 0x1389: 0x028a, 0x138b: 0x0278,
- 0x138c: 0x027b, 0x138d: 0x027e, 0x138e: 0x0257, 0x138f: 0x0269, 0x1390: 0x026f, 0x1391: 0x025d,
- 0x1392: 0x0272, 0x1393: 0x0251, 0x1394: 0x025a, 0x1395: 0x023c, 0x1396: 0x023f, 0x1397: 0x0248,
- 0x1398: 0x024e, 0x1399: 0x0260, 0x139a: 0x0266, 0x139b: 0x026c,
- 0x13a1: 0x0236, 0x13a2: 0x0242, 0x13a3: 0x024b,
- 0x13a5: 0x0284, 0x13a6: 0x0254, 0x13a7: 0x0245, 0x13a8: 0x0263, 0x13a9: 0x028a,
- 0x13ab: 0x0278, 0x13ac: 0x027b, 0x13ad: 0x027e, 0x13ae: 0x0257, 0x13af: 0x0269,
- 0x13b0: 0x026f, 0x13b1: 0x025d, 0x13b2: 0x0272, 0x13b3: 0x0251, 0x13b4: 0x025a, 0x13b5: 0x023c,
- 0x13b6: 0x023f, 0x13b7: 0x0248, 0x13b8: 0x024e, 0x13b9: 0x0260, 0x13ba: 0x0266, 0x13bb: 0x026c,
- // Block 0x4f, offset 0x13c0
- 0x13c0: 0x19bb, 0x13c1: 0x19b8, 0x13c2: 0x19be, 0x13c3: 0x19e2, 0x13c4: 0x1a06, 0x13c5: 0x1a2a,
- 0x13c6: 0x1a4e, 0x13c7: 0x1a57, 0x13c8: 0x1a5d, 0x13c9: 0x1a63, 0x13ca: 0x1a69,
- 0x13d0: 0x1bce, 0x13d1: 0x1bd2,
- 0x13d2: 0x1bd6, 0x13d3: 0x1bda, 0x13d4: 0x1bde, 0x13d5: 0x1be2, 0x13d6: 0x1be6, 0x13d7: 0x1bea,
- 0x13d8: 0x1bee, 0x13d9: 0x1bf2, 0x13da: 0x1bf6, 0x13db: 0x1bfa, 0x13dc: 0x1bfe, 0x13dd: 0x1c02,
- 0x13de: 0x1c06, 0x13df: 0x1c0a, 0x13e0: 0x1c0e, 0x13e1: 0x1c12, 0x13e2: 0x1c16, 0x13e3: 0x1c1a,
- 0x13e4: 0x1c1e, 0x13e5: 0x1c22, 0x13e6: 0x1c26, 0x13e7: 0x1c2a, 0x13e8: 0x1c2e, 0x13e9: 0x1c32,
- 0x13ea: 0x28c9, 0x13eb: 0x0047, 0x13ec: 0x0065, 0x13ed: 0x1a7e, 0x13ee: 0x1af3,
- 0x13f0: 0x0043, 0x13f1: 0x0045, 0x13f2: 0x0047, 0x13f3: 0x0049, 0x13f4: 0x004b, 0x13f5: 0x004d,
- 0x13f6: 0x004f, 0x13f7: 0x0051, 0x13f8: 0x0053, 0x13f9: 0x0055, 0x13fa: 0x0057, 0x13fb: 0x0059,
- 0x13fc: 0x005b, 0x13fd: 0x005d, 0x13fe: 0x005f, 0x13ff: 0x0061,
- // Block 0x50, offset 0x1400
- 0x1400: 0x2858, 0x1401: 0x286d, 0x1402: 0x0575,
- 0x1410: 0x0c81, 0x1411: 0x0ab9,
- 0x1412: 0x0945, 0x1413: 0x45aa, 0x1414: 0x078d, 0x1415: 0x0a61, 0x1416: 0x13a1, 0x1417: 0x0a71,
- 0x1418: 0x0799, 0x1419: 0x0d49, 0x141a: 0x0f21, 0x141b: 0x0d21, 0x141c: 0x0899, 0x141d: 0x0bdd,
- 0x141e: 0x0831, 0x141f: 0x0d29, 0x1420: 0x0885, 0x1421: 0x1189, 0x1422: 0x0ff5, 0x1423: 0x13fd,
- 0x1424: 0x0a45, 0x1425: 0x097d, 0x1426: 0x0ed5, 0x1427: 0x0c8d, 0x1428: 0x0cb9, 0x1429: 0x0731,
- 0x142a: 0x073d, 0x142b: 0x147d, 0x142c: 0x0b4d, 0x142d: 0x0759, 0x142e: 0x0961, 0x142f: 0x0cad,
- 0x1430: 0x1425, 0x1431: 0x0c85, 0x1432: 0x10e1, 0x1433: 0x111d, 0x1434: 0x0969, 0x1435: 0x0eb5,
- 0x1436: 0x0d7d, 0x1437: 0x0d79, 0x1438: 0x1009, 0x1439: 0x089d, 0x143a: 0x09c9,
- // Block 0x51, offset 0x1440
- 0x1440: 0x076d, 0x1441: 0x0765, 0x1442: 0x0775, 0x1443: 0x16a9, 0x1444: 0x07b9, 0x1445: 0x07c9,
- 0x1446: 0x07cd, 0x1447: 0x07d5, 0x1448: 0x07dd, 0x1449: 0x07e1, 0x144a: 0x07ed, 0x144b: 0x07e5,
- 0x144c: 0x0625, 0x144d: 0x16bd, 0x144e: 0x0801, 0x144f: 0x0805, 0x1450: 0x0809, 0x1451: 0x0825,
- 0x1452: 0x16ae, 0x1453: 0x0629, 0x1454: 0x0811, 0x1455: 0x0831, 0x1456: 0x16b8, 0x1457: 0x0841,
- 0x1458: 0x0849, 0x1459: 0x07a9, 0x145a: 0x0851, 0x145b: 0x0855, 0x145c: 0x1893, 0x145d: 0x0871,
- 0x145e: 0x0879, 0x145f: 0x0631, 0x1460: 0x0891, 0x1461: 0x0895, 0x1462: 0x089d, 0x1463: 0x08a1,
- 0x1464: 0x0635, 0x1465: 0x08b9, 0x1466: 0x08bd, 0x1467: 0x08c9, 0x1468: 0x08d5, 0x1469: 0x08d9,
- 0x146a: 0x08dd, 0x146b: 0x08e5, 0x146c: 0x0905, 0x146d: 0x0909, 0x146e: 0x0911, 0x146f: 0x0921,
- 0x1470: 0x0929, 0x1471: 0x092d, 0x1472: 0x092d, 0x1473: 0x092d, 0x1474: 0x16cc, 0x1475: 0x0f05,
- 0x1476: 0x0941, 0x1477: 0x0949, 0x1478: 0x16d1, 0x1479: 0x0955, 0x147a: 0x095d, 0x147b: 0x0965,
- 0x147c: 0x098d, 0x147d: 0x0979, 0x147e: 0x0985, 0x147f: 0x0989,
- // Block 0x52, offset 0x1480
- 0x1480: 0x0991, 0x1481: 0x0999, 0x1482: 0x099d, 0x1483: 0x09a5, 0x1484: 0x09ad, 0x1485: 0x09b1,
- 0x1486: 0x09b1, 0x1487: 0x09b9, 0x1488: 0x09c1, 0x1489: 0x09c5, 0x148a: 0x09d1, 0x148b: 0x09f5,
- 0x148c: 0x09d9, 0x148d: 0x09f9, 0x148e: 0x09dd, 0x148f: 0x09e5, 0x1490: 0x087d, 0x1491: 0x0a41,
- 0x1492: 0x0a09, 0x1493: 0x0a0d, 0x1494: 0x0a11, 0x1495: 0x0a05, 0x1496: 0x0a19, 0x1497: 0x0a15,
- 0x1498: 0x0a2d, 0x1499: 0x16d6, 0x149a: 0x0a49, 0x149b: 0x0a4d, 0x149c: 0x0a55, 0x149d: 0x0a61,
- 0x149e: 0x0a69, 0x149f: 0x0a85, 0x14a0: 0x16db, 0x14a1: 0x16e0, 0x14a2: 0x0a91, 0x14a3: 0x0a95,
- 0x14a4: 0x0a99, 0x14a5: 0x0a8d, 0x14a6: 0x0aa1, 0x14a7: 0x0639, 0x14a8: 0x063d, 0x14a9: 0x0aa9,
- 0x14aa: 0x0ab1, 0x14ab: 0x0ab1, 0x14ac: 0x16e5, 0x14ad: 0x0acd, 0x14ae: 0x0ad1, 0x14af: 0x0ad5,
- 0x14b0: 0x0add, 0x14b1: 0x16ea, 0x14b2: 0x0ae5, 0x14b3: 0x0ae9, 0x14b4: 0x0bc1, 0x14b5: 0x0af1,
- 0x14b6: 0x0641, 0x14b7: 0x0afd, 0x14b8: 0x0b0d, 0x14b9: 0x0b19, 0x14ba: 0x0b15, 0x14bb: 0x16f4,
- 0x14bc: 0x0b21, 0x14bd: 0x16f9, 0x14be: 0x0b2d, 0x14bf: 0x0b29,
- // Block 0x53, offset 0x14c0
- 0x14c0: 0x0b31, 0x14c1: 0x0b41, 0x14c2: 0x0b45, 0x14c3: 0x0645, 0x14c4: 0x0b55, 0x14c5: 0x0b5d,
- 0x14c6: 0x0b61, 0x14c7: 0x0b65, 0x14c8: 0x0649, 0x14c9: 0x16fe, 0x14ca: 0x064d, 0x14cb: 0x0b81,
- 0x14cc: 0x0b85, 0x14cd: 0x0b89, 0x14ce: 0x0b91, 0x14cf: 0x18c5, 0x14d0: 0x0ba9, 0x14d1: 0x1708,
- 0x14d2: 0x1708, 0x14d3: 0x1249, 0x14d4: 0x0bb9, 0x14d5: 0x0bb9, 0x14d6: 0x0651, 0x14d7: 0x172b,
- 0x14d8: 0x17fd, 0x14d9: 0x0bc9, 0x14da: 0x0bd1, 0x14db: 0x0655, 0x14dc: 0x0be5, 0x14dd: 0x0bf5,
- 0x14de: 0x0bf9, 0x14df: 0x0c01, 0x14e0: 0x0c11, 0x14e1: 0x065d, 0x14e2: 0x0659, 0x14e3: 0x0c15,
- 0x14e4: 0x170d, 0x14e5: 0x0c19, 0x14e6: 0x0c2d, 0x14e7: 0x0c31, 0x14e8: 0x0c35, 0x14e9: 0x0c31,
- 0x14ea: 0x0c41, 0x14eb: 0x0c45, 0x14ec: 0x0c55, 0x14ed: 0x0c4d, 0x14ee: 0x0c51, 0x14ef: 0x0c59,
- 0x14f0: 0x0c5d, 0x14f1: 0x0c61, 0x14f2: 0x0c6d, 0x14f3: 0x0c71, 0x14f4: 0x0c89, 0x14f5: 0x0c91,
- 0x14f6: 0x0ca1, 0x14f7: 0x0cb5, 0x14f8: 0x171c, 0x14f9: 0x0cb1, 0x14fa: 0x0ca5, 0x14fb: 0x0cbd,
- 0x14fc: 0x0cc5, 0x14fd: 0x0cd9, 0x14fe: 0x1721, 0x14ff: 0x0ce1,
- // Block 0x54, offset 0x1500
- 0x1500: 0x0cd5, 0x1501: 0x0ccd, 0x1502: 0x0661, 0x1503: 0x0ce9, 0x1504: 0x0cf1, 0x1505: 0x0cf9,
- 0x1506: 0x0ced, 0x1507: 0x0665, 0x1508: 0x0d09, 0x1509: 0x0d11, 0x150a: 0x1726, 0x150b: 0x0d3d,
- 0x150c: 0x0d71, 0x150d: 0x0d4d, 0x150e: 0x0671, 0x150f: 0x0d59, 0x1510: 0x066d, 0x1511: 0x0669,
- 0x1512: 0x0835, 0x1513: 0x0839, 0x1514: 0x0d75, 0x1515: 0x0d5d, 0x1516: 0x121d, 0x1517: 0x06d5,
- 0x1518: 0x0d81, 0x1519: 0x0d85, 0x151a: 0x0d89, 0x151b: 0x0d9d, 0x151c: 0x0d95, 0x151d: 0x173f,
- 0x151e: 0x0675, 0x151f: 0x0db1, 0x1520: 0x0da5, 0x1521: 0x0dc1, 0x1522: 0x0dc9, 0x1523: 0x1749,
- 0x1524: 0x0dcd, 0x1525: 0x0db9, 0x1526: 0x0dd5, 0x1527: 0x0679, 0x1528: 0x0dd9, 0x1529: 0x0ddd,
- 0x152a: 0x0de1, 0x152b: 0x0ded, 0x152c: 0x174e, 0x152d: 0x0df5, 0x152e: 0x067d, 0x152f: 0x0e01,
- 0x1530: 0x1753, 0x1531: 0x0e05, 0x1532: 0x0681, 0x1533: 0x0e11, 0x1534: 0x0e1d, 0x1535: 0x0e29,
- 0x1536: 0x0e2d, 0x1537: 0x1758, 0x1538: 0x16ef, 0x1539: 0x175d, 0x153a: 0x0e4d, 0x153b: 0x1762,
- 0x153c: 0x0e59, 0x153d: 0x0e61, 0x153e: 0x0e51, 0x153f: 0x0e6d,
- // Block 0x55, offset 0x1540
- 0x1540: 0x0e7d, 0x1541: 0x0e8d, 0x1542: 0x0e81, 0x1543: 0x0e85, 0x1544: 0x0e91, 0x1545: 0x0e95,
- 0x1546: 0x1767, 0x1547: 0x0e79, 0x1548: 0x0ead, 0x1549: 0x0eb1, 0x154a: 0x0685, 0x154b: 0x0ec5,
- 0x154c: 0x0ec1, 0x154d: 0x176c, 0x154e: 0x0ea5, 0x154f: 0x0ee1, 0x1550: 0x1771, 0x1551: 0x1776,
- 0x1552: 0x0ee5, 0x1553: 0x0ef9, 0x1554: 0x0ef5, 0x1555: 0x0ef1, 0x1556: 0x0689, 0x1557: 0x0efd,
- 0x1558: 0x0f0d, 0x1559: 0x0f09, 0x155a: 0x0f15, 0x155b: 0x16b3, 0x155c: 0x0f25, 0x155d: 0x177b,
- 0x155e: 0x0f31, 0x155f: 0x1785, 0x1560: 0x0f45, 0x1561: 0x0f51, 0x1562: 0x0f65, 0x1563: 0x178a,
- 0x1564: 0x0f79, 0x1565: 0x0f7d, 0x1566: 0x178f, 0x1567: 0x1794, 0x1568: 0x0f99, 0x1569: 0x0fa9,
- 0x156a: 0x068d, 0x156b: 0x0fad, 0x156c: 0x0691, 0x156d: 0x0691, 0x156e: 0x0fc5, 0x156f: 0x0fc9,
- 0x1570: 0x0fd1, 0x1571: 0x0fd5, 0x1572: 0x0fe1, 0x1573: 0x0695, 0x1574: 0x0ff9, 0x1575: 0x1799,
- 0x1576: 0x1015, 0x1577: 0x179e, 0x1578: 0x1021, 0x1579: 0x1703, 0x157a: 0x1031, 0x157b: 0x17a3,
- 0x157c: 0x17a8, 0x157d: 0x17ad, 0x157e: 0x0699, 0x157f: 0x069d,
- // Block 0x56, offset 0x1580
- 0x1580: 0x1069, 0x1581: 0x17b7, 0x1582: 0x17b2, 0x1583: 0x17bc, 0x1584: 0x17c1, 0x1585: 0x1071,
- 0x1586: 0x1075, 0x1587: 0x1075, 0x1588: 0x107d, 0x1589: 0x06a5, 0x158a: 0x1081, 0x158b: 0x06a9,
- 0x158c: 0x06ad, 0x158d: 0x17cb, 0x158e: 0x1095, 0x158f: 0x109d, 0x1590: 0x10a9, 0x1591: 0x06b1,
- 0x1592: 0x17d0, 0x1593: 0x10cd, 0x1594: 0x17d5, 0x1595: 0x17da, 0x1596: 0x10ed, 0x1597: 0x1105,
- 0x1598: 0x06b5, 0x1599: 0x110d, 0x159a: 0x1111, 0x159b: 0x1115, 0x159c: 0x17df, 0x159d: 0x17e4,
- 0x159e: 0x17e4, 0x159f: 0x112d, 0x15a0: 0x06b9, 0x15a1: 0x17e9, 0x15a2: 0x1141, 0x15a3: 0x1145,
- 0x15a4: 0x06bd, 0x15a5: 0x17ee, 0x15a6: 0x1161, 0x15a7: 0x06c1, 0x15a8: 0x1171, 0x15a9: 0x1169,
- 0x15aa: 0x1179, 0x15ab: 0x17f8, 0x15ac: 0x1191, 0x15ad: 0x06c5, 0x15ae: 0x119d, 0x15af: 0x11a5,
- 0x15b0: 0x11b5, 0x15b1: 0x06c9, 0x15b2: 0x1802, 0x15b3: 0x1807, 0x15b4: 0x06cd, 0x15b5: 0x180c,
- 0x15b6: 0x11cd, 0x15b7: 0x1811, 0x15b8: 0x11d9, 0x15b9: 0x11e5, 0x15ba: 0x11ed, 0x15bb: 0x1816,
- 0x15bc: 0x181b, 0x15bd: 0x1201, 0x15be: 0x1820, 0x15bf: 0x1209,
- // Block 0x57, offset 0x15c0
- 0x15c0: 0x1730, 0x15c1: 0x06d1, 0x15c2: 0x1221, 0x15c3: 0x1225, 0x15c4: 0x06d9, 0x15c5: 0x1229,
- 0x15c6: 0x0aa5, 0x15c7: 0x1825, 0x15c8: 0x182a, 0x15c9: 0x1735, 0x15ca: 0x173a, 0x15cb: 0x1249,
- 0x15cc: 0x124d, 0x15cd: 0x1465, 0x15ce: 0x06dd, 0x15cf: 0x1279, 0x15d0: 0x1275, 0x15d1: 0x127d,
- 0x15d2: 0x08b1, 0x15d3: 0x1281, 0x15d4: 0x1285, 0x15d5: 0x1289, 0x15d6: 0x1291, 0x15d7: 0x182f,
- 0x15d8: 0x128d, 0x15d9: 0x1295, 0x15da: 0x12a9, 0x15db: 0x12ad, 0x15dc: 0x1299, 0x15dd: 0x12b1,
- 0x15de: 0x12c5, 0x15df: 0x12d9, 0x15e0: 0x12a5, 0x15e1: 0x12b9, 0x15e2: 0x12bd, 0x15e3: 0x12c1,
- 0x15e4: 0x1834, 0x15e5: 0x183e, 0x15e6: 0x1839, 0x15e7: 0x06e1, 0x15e8: 0x12e1, 0x15e9: 0x12e5,
- 0x15ea: 0x12ed, 0x15eb: 0x1852, 0x15ec: 0x12f1, 0x15ed: 0x1843, 0x15ee: 0x06e5, 0x15ef: 0x06e9,
- 0x15f0: 0x1848, 0x15f1: 0x184d, 0x15f2: 0x06ed, 0x15f3: 0x1311, 0x15f4: 0x1315, 0x15f5: 0x1319,
- 0x15f6: 0x131d, 0x15f7: 0x1329, 0x15f8: 0x1325, 0x15f9: 0x1331, 0x15fa: 0x132d, 0x15fb: 0x133d,
- 0x15fc: 0x1335, 0x15fd: 0x1339, 0x15fe: 0x1341, 0x15ff: 0x06f1,
- // Block 0x58, offset 0x1600
- 0x1600: 0x1349, 0x1601: 0x134d, 0x1602: 0x06f5, 0x1603: 0x135d, 0x1604: 0x1361, 0x1605: 0x1857,
- 0x1606: 0x136d, 0x1607: 0x1371, 0x1608: 0x06f9, 0x1609: 0x137d, 0x160a: 0x062d, 0x160b: 0x185c,
- 0x160c: 0x1861, 0x160d: 0x06fd, 0x160e: 0x0701, 0x160f: 0x13a9, 0x1610: 0x13c1, 0x1611: 0x13dd,
- 0x1612: 0x13ed, 0x1613: 0x1866, 0x1614: 0x1401, 0x1615: 0x1405, 0x1616: 0x141d, 0x1617: 0x1429,
- 0x1618: 0x1870, 0x1619: 0x16c2, 0x161a: 0x1435, 0x161b: 0x1431, 0x161c: 0x143d, 0x161d: 0x16c7,
- 0x161e: 0x1449, 0x161f: 0x1455, 0x1620: 0x1875, 0x1621: 0x187a, 0x1622: 0x1495, 0x1623: 0x14a1,
- 0x1624: 0x14a9, 0x1625: 0x187f, 0x1626: 0x14ad, 0x1627: 0x14d5, 0x1628: 0x14e1, 0x1629: 0x14e5,
- 0x162a: 0x14dd, 0x162b: 0x14f1, 0x162c: 0x14f5, 0x162d: 0x1884, 0x162e: 0x1501, 0x162f: 0x0705,
- 0x1630: 0x1509, 0x1631: 0x1889, 0x1632: 0x0709, 0x1633: 0x1541, 0x1634: 0x0b35, 0x1635: 0x1559,
- 0x1636: 0x188e, 0x1637: 0x1898, 0x1638: 0x070d, 0x1639: 0x0711, 0x163a: 0x1581, 0x163b: 0x189d,
- 0x163c: 0x0715, 0x163d: 0x18a2, 0x163e: 0x1599, 0x163f: 0x1599,
- // Block 0x59, offset 0x1640
- 0x1640: 0x15a1, 0x1641: 0x18a7, 0x1642: 0x15b9, 0x1643: 0x0719, 0x1644: 0x15c9, 0x1645: 0x15d5,
- 0x1646: 0x15dd, 0x1647: 0x15e5, 0x1648: 0x071d, 0x1649: 0x18ac, 0x164a: 0x15f9, 0x164b: 0x1615,
- 0x164c: 0x1621, 0x164d: 0x0721, 0x164e: 0x0725, 0x164f: 0x1625, 0x1650: 0x18b1, 0x1651: 0x0729,
- 0x1652: 0x18b6, 0x1653: 0x18bb, 0x1654: 0x18c0, 0x1655: 0x1649, 0x1656: 0x072d, 0x1657: 0x165d,
- 0x1658: 0x1665, 0x1659: 0x1669, 0x165a: 0x1671, 0x165b: 0x1679, 0x165c: 0x1681, 0x165d: 0x18ca,
-}
-
-// nfkcSparseOffset: 128 entries, 256 bytes
-var nfkcSparseOffset = []uint16{0x0, 0xe, 0x12, 0x1b, 0x25, 0x35, 0x37, 0x3c, 0x47, 0x56, 0x63, 0x6b, 0x6f, 0x74, 0x76, 0x85, 0x8d, 0x94, 0x97, 0x9f, 0xa3, 0xa7, 0xa9, 0xab, 0xb4, 0xb8, 0xbf, 0xc4, 0xc7, 0xd1, 0xd3, 0xda, 0xe2, 0xe6, 0xe8, 0xeb, 0xef, 0xf5, 0x106, 0x112, 0x114, 0x11a, 0x11c, 0x11e, 0x120, 0x122, 0x124, 0x126, 0x128, 0x12b, 0x12e, 0x130, 0x133, 0x136, 0x13a, 0x143, 0x145, 0x148, 0x14a, 0x154, 0x15f, 0x16e, 0x17c, 0x18a, 0x19a, 0x1a8, 0x1af, 0x1b5, 0x1c4, 0x1c8, 0x1ca, 0x1ce, 0x1d0, 0x1d3, 0x1d5, 0x1d8, 0x1da, 0x1dd, 0x1df, 0x1e1, 0x1e3, 0x1ef, 0x1f8, 0x1ff, 0x20c, 0x20f, 0x211, 0x213, 0x215, 0x217, 0x219, 0x21c, 0x21e, 0x220, 0x222, 0x224, 0x22a, 0x22d, 0x22f, 0x231, 0x233, 0x235, 0x244, 0x246, 0x24c, 0x254, 0x25b, 0x25e, 0x26b, 0x275, 0x277, 0x279, 0x27d, 0x282, 0x28e, 0x293, 0x29c, 0x2a2, 0x2a7, 0x2ab, 0x2b0, 0x2b4, 0x2c4, 0x2d2, 0x2e0, 0x2ee, 0x2f8, 0x2fa}
-
-// nfkcSparseValues: 772 entries, 3088 bytes
-var nfkcSparseValues = [772]valueRange{
- // Block 0x0, offset 0x1
- {value: 0x0002, lo: 0x0d},
- {value: 0x0001, lo: 0xa0, hi: 0xa0},
- {value: 0x425e, lo: 0xa8, hi: 0xa8},
- {value: 0x0083, lo: 0xaa, hi: 0xaa},
- {value: 0x424a, lo: 0xaf, hi: 0xaf},
- {value: 0x0025, lo: 0xb2, hi: 0xb3},
- {value: 0x4240, lo: 0xb4, hi: 0xb4},
- {value: 0x01dc, lo: 0xb5, hi: 0xb5},
- {value: 0x4277, lo: 0xb8, hi: 0xb8},
- {value: 0x0023, lo: 0xb9, hi: 0xb9},
- {value: 0x009f, lo: 0xba, hi: 0xba},
- {value: 0x235e, lo: 0xbc, hi: 0xbc},
- {value: 0x2352, lo: 0xbd, hi: 0xbd},
- {value: 0x23f4, lo: 0xbe, hi: 0xbe},
- // Block 0x1, offset 0x2
- {value: 0x0091, lo: 0x03},
- {value: 0x46c8, lo: 0xa0, hi: 0xa1},
- {value: 0x46fa, lo: 0xaf, hi: 0xb0},
- {value: 0x8800, lo: 0xb7, hi: 0xb7},
- // Block 0x2, offset 0x3
- {value: 0x0003, lo: 0x08},
- {value: 0x8800, lo: 0x92, hi: 0x92},
- {value: 0x0091, lo: 0xb0, hi: 0xb0},
- {value: 0x011c, 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 0x4
- {value: 0x000a, lo: 0x09},
- {value: 0x4254, lo: 0x98, hi: 0x98},
- {value: 0x4259, lo: 0x99, hi: 0x9a},
- {value: 0x427c, lo: 0x9b, hi: 0x9b},
- {value: 0x4245, lo: 0x9c, hi: 0x9c},
- {value: 0x4268, lo: 0x9d, hi: 0x9d},
- {value: 0x0116, 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 0x5
- {value: 0x0000, lo: 0x0f},
- {value: 0x8800, lo: 0x83, hi: 0x83},
- {value: 0x8800, lo: 0x87, hi: 0x87},
- {value: 0x8800, lo: 0x8b, hi: 0x8b},
- {value: 0x8800, lo: 0x8d, hi: 0x8d},
- {value: 0x378f, lo: 0x90, hi: 0x90},
- {value: 0x379b, lo: 0x91, hi: 0x91},
- {value: 0x3789, lo: 0x93, hi: 0x93},
- {value: 0x8800, lo: 0x96, hi: 0x96},
- {value: 0x3801, lo: 0x97, hi: 0x97},
- {value: 0x37cb, lo: 0x9c, hi: 0x9c},
- {value: 0x37b3, lo: 0x9d, hi: 0x9d},
- {value: 0x37dd, lo: 0x9e, hi: 0x9e},
- {value: 0x8800, lo: 0xb4, hi: 0xb5},
- {value: 0x3807, lo: 0xb6, hi: 0xb6},
- {value: 0x380d, lo: 0xb7, hi: 0xb7},
- // Block 0x5, offset 0x6
- {value: 0x0000, lo: 0x01},
- {value: 0x80e6, lo: 0x83, hi: 0x87},
- // Block 0x6, offset 0x7
- {value: 0x0001, lo: 0x04},
- {value: 0x8018, lo: 0x81, hi: 0x82},
- {value: 0x80e6, lo: 0x84, hi: 0x84},
- {value: 0x80dc, lo: 0x85, hi: 0x85},
- {value: 0x8012, lo: 0x87, hi: 0x87},
- // Block 0x7, offset 0x8
- {value: 0x0000, lo: 0x0a},
- {value: 0x80e6, lo: 0x90, hi: 0x97},
- {value: 0x801e, lo: 0x98, hi: 0x98},
- {value: 0x801f, lo: 0x99, hi: 0x99},
- {value: 0x8020, lo: 0x9a, hi: 0x9a},
- {value: 0x382b, lo: 0xa2, hi: 0xa2},
- {value: 0x3831, lo: 0xa3, hi: 0xa3},
- {value: 0x383d, lo: 0xa4, hi: 0xa4},
- {value: 0x3837, lo: 0xa5, hi: 0xa5},
- {value: 0x3843, lo: 0xa6, hi: 0xa6},
- {value: 0x8800, lo: 0xa7, hi: 0xa7},
- // Block 0x8, offset 0x9
- {value: 0x0000, lo: 0x0e},
- {value: 0x3855, lo: 0x80, hi: 0x80},
- {value: 0x8800, lo: 0x81, hi: 0x81},
- {value: 0x3849, lo: 0x82, hi: 0x82},
- {value: 0x8800, lo: 0x92, hi: 0x92},
- {value: 0x384f, lo: 0x93, hi: 0x93},
- {value: 0x8800, lo: 0x95, hi: 0x95},
- {value: 0x80e6, lo: 0x96, hi: 0x9c},
- {value: 0x80e6, lo: 0x9f, hi: 0xa2},
- {value: 0x80dc, lo: 0xa3, hi: 0xa3},
- {value: 0x80e6, lo: 0xa4, hi: 0xa4},
- {value: 0x80e6, lo: 0xa7, hi: 0xa8},
- {value: 0x80dc, lo: 0xaa, hi: 0xaa},
- {value: 0x80e6, lo: 0xab, hi: 0xac},
- {value: 0x80dc, lo: 0xad, hi: 0xad},
- // Block 0x9, offset 0xa
- {value: 0x0000, lo: 0x0c},
- {value: 0x8024, lo: 0x91, hi: 0x91},
- {value: 0x80e6, lo: 0xb0, hi: 0xb0},
- {value: 0x80dc, lo: 0xb1, hi: 0xb1},
- {value: 0x80e6, lo: 0xb2, hi: 0xb3},
- {value: 0x80dc, lo: 0xb4, hi: 0xb4},
- {value: 0x80e6, lo: 0xb5, hi: 0xb6},
- {value: 0x80dc, lo: 0xb7, hi: 0xb9},
- {value: 0x80e6, lo: 0xba, hi: 0xba},
- {value: 0x80dc, lo: 0xbb, hi: 0xbc},
- {value: 0x80e6, lo: 0xbd, hi: 0xbd},
- {value: 0x80dc, lo: 0xbe, hi: 0xbe},
- {value: 0x80e6, lo: 0xbf, hi: 0xbf},
- // Block 0xa, offset 0xb
- {value: 0x000a, lo: 0x07},
- {value: 0x80e6, lo: 0x80, hi: 0x80},
- {value: 0x80e6, lo: 0x81, hi: 0x81},
- {value: 0x80dc, lo: 0x82, hi: 0x83},
- {value: 0x80dc, lo: 0x84, hi: 0x85},
- {value: 0x80dc, lo: 0x86, hi: 0x87},
- {value: 0x80dc, lo: 0x88, hi: 0x89},
- {value: 0x80e6, lo: 0x8a, hi: 0x8a},
- // Block 0xb, offset 0xc
- {value: 0x0000, lo: 0x03},
- {value: 0x80e6, lo: 0xab, hi: 0xb1},
- {value: 0x80dc, lo: 0xb2, hi: 0xb2},
- {value: 0x80e6, lo: 0xb3, hi: 0xb3},
- // Block 0xc, offset 0xd
- {value: 0x0000, lo: 0x04},
- {value: 0x80e6, lo: 0x96, hi: 0x99},
- {value: 0x80e6, lo: 0x9b, hi: 0xa3},
- {value: 0x80e6, lo: 0xa5, hi: 0xa7},
- {value: 0x80e6, lo: 0xa9, hi: 0xad},
- // Block 0xd, offset 0xe
- {value: 0x0000, lo: 0x01},
- {value: 0x80dc, lo: 0x99, hi: 0x9b},
- // Block 0xe, offset 0xf
- {value: 0x0000, lo: 0x0e},
- {value: 0x80e6, lo: 0xa4, hi: 0xa5},
- {value: 0x80dc, lo: 0xa6, hi: 0xa6},
- {value: 0x80e6, lo: 0xa7, hi: 0xa8},
- {value: 0x80dc, lo: 0xa9, hi: 0xa9},
- {value: 0x80e6, lo: 0xaa, hi: 0xac},
- {value: 0x80dc, lo: 0xad, hi: 0xaf},
- {value: 0x801b, lo: 0xb0, hi: 0xb0},
- {value: 0x801c, lo: 0xb1, hi: 0xb1},
- {value: 0x801d, lo: 0xb2, hi: 0xb2},
- {value: 0x80e6, lo: 0xb3, hi: 0xb5},
- {value: 0x80dc, lo: 0xb6, hi: 0xb6},
- {value: 0x80e6, lo: 0xb7, hi: 0xb8},
- {value: 0x80dc, lo: 0xb9, hi: 0xba},
- {value: 0x80e6, lo: 0xbb, hi: 0xbe},
- // Block 0xf, offset 0x10
- {value: 0x0000, lo: 0x07},
- {value: 0x8800, lo: 0xa8, hi: 0xa8},
- {value: 0x3ec2, lo: 0xa9, hi: 0xa9},
- {value: 0x8800, lo: 0xb0, hi: 0xb0},
- {value: 0x3eca, lo: 0xb1, hi: 0xb1},
- {value: 0x8800, lo: 0xb3, hi: 0xb3},
- {value: 0x3ed2, lo: 0xb4, hi: 0xb4},
- {value: 0x8607, lo: 0xbc, hi: 0xbc},
- // Block 0x10, offset 0x11
- {value: 0x0008, lo: 0x06},
- {value: 0x8009, lo: 0x8d, hi: 0x8d},
- {value: 0x80e6, lo: 0x91, hi: 0x91},
- {value: 0x80dc, lo: 0x92, hi: 0x92},
- {value: 0x80e6, lo: 0x93, hi: 0x93},
- {value: 0x80e6, lo: 0x94, hi: 0x94},
- {value: 0x4502, lo: 0x98, hi: 0x9f},
- // Block 0x11, offset 0x12
- {value: 0x0000, lo: 0x02},
- {value: 0x8007, lo: 0xbc, hi: 0xbc},
- {value: 0x8600, lo: 0xbe, hi: 0xbe},
- // Block 0x12, offset 0x13
- {value: 0x0007, lo: 0x07},
- {value: 0x8800, lo: 0x87, hi: 0x87},
- {value: 0x18cf, lo: 0x8b, hi: 0x8c},
- {value: 0x8009, lo: 0x8d, hi: 0x8d},
- {value: 0x8600, lo: 0x97, hi: 0x97},
- {value: 0x4542, lo: 0x9c, hi: 0x9c},
- {value: 0x454a, lo: 0x9d, hi: 0x9d},
- {value: 0x4552, lo: 0x9f, hi: 0x9f},
- // Block 0x13, offset 0x14
- {value: 0x0000, lo: 0x03},
- {value: 0x457a, lo: 0xb3, hi: 0xb3},
- {value: 0x4582, lo: 0xb6, hi: 0xb6},
- {value: 0x8007, lo: 0xbc, hi: 0xbc},
- // Block 0x14, offset 0x15
- {value: 0x0008, lo: 0x03},
- {value: 0x8009, lo: 0x8d, hi: 0x8d},
- {value: 0x455a, lo: 0x99, hi: 0x9b},
- {value: 0x4572, lo: 0x9e, hi: 0x9e},
- // Block 0x15, offset 0x16
- {value: 0x0000, lo: 0x01},
- {value: 0x8007, lo: 0xbc, hi: 0xbc},
- // Block 0x16, offset 0x17
- {value: 0x0000, lo: 0x01},
- {value: 0x8009, lo: 0x8d, hi: 0x8d},
- // Block 0x17, offset 0x18
- {value: 0x0000, lo: 0x08},
- {value: 0x8800, lo: 0x87, hi: 0x87},
- {value: 0x18e4, lo: 0x88, hi: 0x88},
- {value: 0x18dd, lo: 0x8b, hi: 0x8b},
- {value: 0x18eb, lo: 0x8c, hi: 0x8c},
- {value: 0x8009, lo: 0x8d, hi: 0x8d},
- {value: 0x8600, lo: 0x96, hi: 0x97},
- {value: 0x458a, lo: 0x9c, hi: 0x9c},
- {value: 0x4592, lo: 0x9d, hi: 0x9d},
- // Block 0x18, offset 0x19
- {value: 0x0000, lo: 0x03},
- {value: 0x8800, lo: 0x92, hi: 0x92},
- {value: 0x18f2, lo: 0x94, hi: 0x94},
- {value: 0x8600, lo: 0xbe, hi: 0xbe},
- // Block 0x19, offset 0x1a
- {value: 0x0000, lo: 0x06},
- {value: 0x8800, lo: 0x86, hi: 0x87},
- {value: 0x18f9, lo: 0x8a, hi: 0x8a},
- {value: 0x1907, lo: 0x8b, hi: 0x8b},
- {value: 0x1900, lo: 0x8c, hi: 0x8c},
- {value: 0x8009, lo: 0x8d, hi: 0x8d},
- {value: 0x8600, lo: 0x97, hi: 0x97},
- // Block 0x1a, offset 0x1b
- {value: 0x0607, lo: 0x04},
- {value: 0x8800, lo: 0x86, hi: 0x86},
- {value: 0x3eda, lo: 0x88, hi: 0x88},
- {value: 0x8009, lo: 0x8d, hi: 0x8d},
- {value: 0x8054, lo: 0x95, hi: 0x96},
- // Block 0x1b, offset 0x1c
- {value: 0x0000, lo: 0x02},
- {value: 0x8007, lo: 0xbc, hi: 0xbc},
- {value: 0x8800, lo: 0xbf, hi: 0xbf},
- // Block 0x1c, offset 0x1d
- {value: 0x0000, lo: 0x09},
- {value: 0x190e, lo: 0x80, hi: 0x80},
- {value: 0x8600, lo: 0x82, hi: 0x82},
- {value: 0x8800, lo: 0x86, hi: 0x86},
- {value: 0x1915, lo: 0x87, hi: 0x87},
- {value: 0x191c, lo: 0x88, hi: 0x88},
- {value: 0x2e66, lo: 0x8a, hi: 0x8a},
- {value: 0x19a5, lo: 0x8b, hi: 0x8b},
- {value: 0x8009, lo: 0x8d, hi: 0x8d},
- {value: 0x8600, lo: 0x95, hi: 0x96},
- // Block 0x1d, offset 0x1e
- {value: 0x0000, lo: 0x01},
- {value: 0x8600, lo: 0xbe, hi: 0xbe},
- // Block 0x1e, offset 0x1f
- {value: 0x0000, lo: 0x06},
- {value: 0x8800, lo: 0x86, hi: 0x87},
- {value: 0x1923, lo: 0x8a, hi: 0x8a},
- {value: 0x1931, lo: 0x8b, hi: 0x8b},
- {value: 0x192a, lo: 0x8c, hi: 0x8c},
- {value: 0x8009, lo: 0x8d, hi: 0x8d},
- {value: 0x8600, lo: 0x97, hi: 0x97},
- // Block 0x1f, offset 0x20
- {value: 0x0007, lo: 0x07},
- {value: 0x8609, lo: 0x8a, hi: 0x8a},
- {value: 0x8600, lo: 0x8f, hi: 0x8f},
- {value: 0x8800, lo: 0x99, hi: 0x99},
- {value: 0x3ee2, lo: 0x9a, hi: 0x9a},
- {value: 0x2e6d, lo: 0x9c, hi: 0x9d},
- {value: 0x1938, lo: 0x9e, hi: 0x9e},
- {value: 0x8600, lo: 0x9f, hi: 0x9f},
- // Block 0x20, offset 0x21
- {value: 0x0000, lo: 0x03},
- {value: 0x2763, lo: 0xb3, hi: 0xb3},
- {value: 0x8067, lo: 0xb8, hi: 0xb9},
- {value: 0x8009, lo: 0xba, hi: 0xba},
- // Block 0x21, offset 0x22
- {value: 0x0000, lo: 0x01},
- {value: 0x806b, lo: 0x88, hi: 0x8b},
- // Block 0x22, offset 0x23
- {value: 0x0000, lo: 0x02},
- {value: 0x2778, lo: 0xb3, hi: 0xb3},
- {value: 0x8076, lo: 0xb8, hi: 0xb9},
- // Block 0x23, offset 0x24
- {value: 0x0000, lo: 0x03},
- {value: 0x807a, lo: 0x88, hi: 0x8b},
- {value: 0x276a, lo: 0x9c, hi: 0x9c},
- {value: 0x2771, lo: 0x9d, hi: 0x9d},
- // Block 0x24, offset 0x25
- {value: 0x0000, lo: 0x05},
- {value: 0x0305, lo: 0x8c, hi: 0x8c},
- {value: 0x80dc, lo: 0x98, hi: 0x99},
- {value: 0x80dc, lo: 0xb5, hi: 0xb5},
- {value: 0x80dc, lo: 0xb7, hi: 0xb7},
- {value: 0x80d8, lo: 0xb9, hi: 0xb9},
- // Block 0x25, offset 0x26
- {value: 0x0000, lo: 0x10},
- {value: 0x2786, lo: 0x83, hi: 0x83},
- {value: 0x278d, lo: 0x8d, hi: 0x8d},
- {value: 0x2794, lo: 0x92, hi: 0x92},
- {value: 0x279b, lo: 0x97, hi: 0x97},
- {value: 0x27a2, lo: 0x9c, hi: 0x9c},
- {value: 0x277f, lo: 0xa9, hi: 0xa9},
- {value: 0x8081, lo: 0xb1, hi: 0xb1},
- {value: 0x8082, lo: 0xb2, hi: 0xb2},
- {value: 0x49b6, lo: 0xb3, hi: 0xb3},
- {value: 0x8084, lo: 0xb4, hi: 0xb4},
- {value: 0x49bf, lo: 0xb5, hi: 0xb5},
- {value: 0x459a, lo: 0xb6, hi: 0xb6},
- {value: 0x45da, lo: 0xb7, hi: 0xb7},
- {value: 0x45a2, lo: 0xb8, hi: 0xb8},
- {value: 0x45e5, lo: 0xb9, hi: 0xb9},
- {value: 0x8082, lo: 0xba, hi: 0xbd},
- // Block 0x26, offset 0x27
- {value: 0x0000, lo: 0x0b},
- {value: 0x8082, lo: 0x80, hi: 0x80},
- {value: 0x49c8, lo: 0x81, hi: 0x81},
- {value: 0x80e6, lo: 0x82, hi: 0x83},
- {value: 0x8009, lo: 0x84, hi: 0x84},
- {value: 0x80e6, lo: 0x86, hi: 0x87},
- {value: 0x27b0, lo: 0x93, hi: 0x93},
- {value: 0x27b7, lo: 0x9d, hi: 0x9d},
- {value: 0x27be, lo: 0xa2, hi: 0xa2},
- {value: 0x27c5, lo: 0xa7, hi: 0xa7},
- {value: 0x27cc, lo: 0xac, hi: 0xac},
- {value: 0x27a9, lo: 0xb9, hi: 0xb9},
- // Block 0x27, offset 0x28
- {value: 0x0000, lo: 0x01},
- {value: 0x80dc, lo: 0x86, hi: 0x86},
- // Block 0x28, offset 0x29
- {value: 0x0000, lo: 0x05},
- {value: 0x8800, lo: 0xa5, hi: 0xa5},
- {value: 0x193f, lo: 0xa6, hi: 0xa6},
- {value: 0x8600, lo: 0xae, hi: 0xae},
- {value: 0x8007, lo: 0xb7, hi: 0xb7},
- {value: 0x8009, lo: 0xb9, hi: 0xba},
- // Block 0x29, offset 0x2a
- {value: 0x0000, lo: 0x01},
- {value: 0x80dc, lo: 0x8d, hi: 0x8d},
- // Block 0x2a, offset 0x2b
- {value: 0x0000, lo: 0x01},
- {value: 0x0309, lo: 0xbc, hi: 0xbc},
- // Block 0x2b, offset 0x2c
- {value: 0x0000, lo: 0x01},
- {value: 0x8800, lo: 0x80, hi: 0x92},
- // Block 0x2c, offset 0x2d
- {value: 0x0000, lo: 0x01},
- {value: 0x8e00, lo: 0xa1, hi: 0xb5},
- // Block 0x2d, offset 0x2e
- {value: 0x0000, lo: 0x01},
- {value: 0x8600, lo: 0xa8, hi: 0xbf},
- // Block 0x2e, offset 0x2f
- {value: 0x0000, lo: 0x01},
- {value: 0x8600, lo: 0x80, hi: 0x82},
- // Block 0x2f, offset 0x30
- {value: 0x0000, lo: 0x01},
- {value: 0x80e6, lo: 0x9d, hi: 0x9f},
- // Block 0x30, offset 0x31
- {value: 0x0000, lo: 0x02},
- {value: 0x8009, lo: 0x94, hi: 0x94},
- {value: 0x8009, lo: 0xb4, hi: 0xb4},
- // Block 0x31, offset 0x32
- {value: 0x0000, lo: 0x02},
- {value: 0x8009, lo: 0x92, hi: 0x92},
- {value: 0x80e6, lo: 0x9d, hi: 0x9d},
- // Block 0x32, offset 0x33
- {value: 0x0000, lo: 0x01},
- {value: 0x80e4, lo: 0xa9, hi: 0xa9},
- // Block 0x33, offset 0x34
- {value: 0x0008, lo: 0x02},
- {value: 0x80de, lo: 0xb9, hi: 0xba},
- {value: 0x80dc, lo: 0xbb, hi: 0xbb},
- // Block 0x34, offset 0x35
- {value: 0x0000, lo: 0x02},
- {value: 0x80e6, lo: 0x97, hi: 0x97},
- {value: 0x80dc, lo: 0x98, hi: 0x98},
- // Block 0x35, offset 0x36
- {value: 0x0000, lo: 0x03},
- {value: 0x8009, lo: 0xa0, hi: 0xa0},
- {value: 0x80e6, lo: 0xb5, hi: 0xbc},
- {value: 0x80dc, lo: 0xbf, hi: 0xbf},
- // Block 0x36, offset 0x37
- {value: 0x0000, lo: 0x08},
- {value: 0x197e, lo: 0x80, hi: 0x80},
- {value: 0x1985, lo: 0x81, hi: 0x81},
- {value: 0x8800, lo: 0x82, hi: 0x82},
- {value: 0x198c, lo: 0x83, hi: 0x83},
- {value: 0x8009, lo: 0x84, hi: 0x84},
- {value: 0x80e6, lo: 0xab, hi: 0xab},
- {value: 0x80dc, lo: 0xac, hi: 0xac},
- {value: 0x80e6, lo: 0xad, hi: 0xb3},
- // Block 0x37, offset 0x38
- {value: 0x0000, lo: 0x01},
- {value: 0x8009, lo: 0xaa, hi: 0xab},
- // Block 0x38, offset 0x39
- {value: 0x0000, lo: 0x02},
- {value: 0x8007, lo: 0xa6, hi: 0xa6},
- {value: 0x8009, lo: 0xb2, hi: 0xb3},
- // Block 0x39, offset 0x3a
- {value: 0x0000, lo: 0x01},
- {value: 0x8007, lo: 0xb7, hi: 0xb7},
- // Block 0x3a, offset 0x3b
- {value: 0x0000, lo: 0x09},
- {value: 0x80e6, lo: 0x90, hi: 0x92},
- {value: 0x8001, lo: 0x94, hi: 0x94},
- {value: 0x80dc, lo: 0x95, hi: 0x99},
- {value: 0x80e6, lo: 0x9a, hi: 0x9b},
- {value: 0x80dc, lo: 0x9c, hi: 0x9f},
- {value: 0x80e6, lo: 0xa0, hi: 0xa0},
- {value: 0x8001, lo: 0xa2, hi: 0xa8},
- {value: 0x80dc, lo: 0xad, hi: 0xad},
- {value: 0x80e6, lo: 0xb4, hi: 0xb4},
- // Block 0x3b, offset 0x3c
- {value: 0x0002, lo: 0x0a},
- {value: 0x0043, lo: 0xac, hi: 0xac},
- {value: 0x00d4, lo: 0xad, hi: 0xad},
- {value: 0x0045, lo: 0xae, hi: 0xae},
- {value: 0x0049, lo: 0xb0, hi: 0xb1},
- {value: 0x00e9, lo: 0xb2, hi: 0xb2},
- {value: 0x004f, lo: 0xb3, hi: 0xba},
- {value: 0x005f, lo: 0xbc, hi: 0xbc},
- {value: 0x00f2, lo: 0xbd, hi: 0xbd},
- {value: 0x0061, lo: 0xbe, hi: 0xbe},
- {value: 0x0065, lo: 0xbf, hi: 0xbf},
- // Block 0x3c, offset 0x3d
- {value: 0x0000, lo: 0x0e},
- {value: 0x80e6, lo: 0x80, hi: 0x81},
- {value: 0x80dc, lo: 0x82, hi: 0x82},
- {value: 0x80e6, lo: 0x83, hi: 0x89},
- {value: 0x80dc, lo: 0x8a, hi: 0x8a},
- {value: 0x80e6, lo: 0x8b, hi: 0x8c},
- {value: 0x80ea, lo: 0x8d, hi: 0x8d},
- {value: 0x80d6, lo: 0x8e, hi: 0x8e},
- {value: 0x80dc, lo: 0x8f, hi: 0x8f},
- {value: 0x80ca, lo: 0x90, hi: 0x90},
- {value: 0x80e6, lo: 0x91, hi: 0xa6},
- {value: 0x80e9, lo: 0xbc, hi: 0xbc},
- {value: 0x80dc, lo: 0xbd, hi: 0xbd},
- {value: 0x80e6, lo: 0xbe, hi: 0xbe},
- {value: 0x80dc, lo: 0xbf, hi: 0xbf},
- // Block 0x3d, offset 0x3e
- {value: 0x0000, lo: 0x0d},
- {value: 0x0001, lo: 0x80, hi: 0x8a},
- {value: 0x04ad, lo: 0x91, hi: 0x91},
- {value: 0x4281, lo: 0x97, hi: 0x97},
- {value: 0x001d, lo: 0xa4, hi: 0xa4},
- {value: 0x19b5, lo: 0xa5, hi: 0xa5},
- {value: 0x1c9e, lo: 0xa6, hi: 0xa6},
- {value: 0x0001, lo: 0xaf, hi: 0xaf},
- {value: 0x283c, lo: 0xb3, hi: 0xb3},
- {value: 0x29a9, lo: 0xb4, hi: 0xb4},
- {value: 0x2843, lo: 0xb6, hi: 0xb6},
- {value: 0x29b3, lo: 0xb7, hi: 0xb7},
- {value: 0x19af, lo: 0xbc, hi: 0xbc},
- {value: 0x424f, lo: 0xbe, hi: 0xbe},
- // Block 0x3e, offset 0x3f
- {value: 0x0002, lo: 0x0d},
- {value: 0x1a75, lo: 0x87, hi: 0x87},
- {value: 0x1a72, lo: 0x88, hi: 0x88},
- {value: 0x19b2, lo: 0x89, hi: 0x89},
- {value: 0x2b46, 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: 0x04d9, lo: 0xbb, hi: 0xbb},
- {value: 0x003b, lo: 0xbc, hi: 0xbc},
- {value: 0x0011, lo: 0xbd, hi: 0xbe},
- {value: 0x009d, lo: 0xbf, hi: 0xbf},
- // Block 0x3f, offset 0x40
- {value: 0x0002, lo: 0x0f},
- {value: 0x0021, lo: 0x80, hi: 0x89},
- {value: 0x0017, lo: 0x8a, hi: 0x8a},
- {value: 0x04d9, 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: 0x0107, 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: 0x1adb, lo: 0xa8, hi: 0xa8},
- // Block 0x40, offset 0x41
- {value: 0x0000, lo: 0x0d},
- {value: 0x80e6, lo: 0x90, hi: 0x91},
- {value: 0x8001, lo: 0x92, hi: 0x93},
- {value: 0x80e6, lo: 0x94, hi: 0x97},
- {value: 0x8001, lo: 0x98, hi: 0x9a},
- {value: 0x80e6, lo: 0x9b, hi: 0x9c},
- {value: 0x80e6, lo: 0xa1, hi: 0xa1},
- {value: 0x8001, lo: 0xa5, hi: 0xa6},
- {value: 0x80e6, lo: 0xa7, hi: 0xa7},
- {value: 0x80dc, lo: 0xa8, hi: 0xa8},
- {value: 0x80e6, lo: 0xa9, hi: 0xa9},
- {value: 0x8001, lo: 0xaa, hi: 0xab},
- {value: 0x80dc, lo: 0xac, hi: 0xaf},
- {value: 0x80e6, lo: 0xb0, hi: 0xb0},
- // Block 0x41, offset 0x42
- {value: 0x0007, lo: 0x06},
- {value: 0x22c2, lo: 0x89, hi: 0x89},
- {value: 0x8800, lo: 0x90, hi: 0x90},
- {value: 0x8800, lo: 0x92, hi: 0x92},
- {value: 0x8800, lo: 0x94, hi: 0x94},
- {value: 0x3ba3, lo: 0x9a, hi: 0x9b},
- {value: 0x3bb1, lo: 0xae, hi: 0xae},
- // Block 0x42, offset 0x43
- {value: 0x000e, lo: 0x05},
- {value: 0x3bb8, lo: 0x8d, hi: 0x8e},
- {value: 0x3bbf, lo: 0x8f, hi: 0x8f},
- {value: 0x8800, lo: 0x90, hi: 0x90},
- {value: 0x8800, lo: 0x92, hi: 0x92},
- {value: 0x8800, lo: 0x94, hi: 0x94},
- // Block 0x43, offset 0x44
- {value: 0x0173, lo: 0x0e},
- {value: 0x8800, lo: 0x83, hi: 0x83},
- {value: 0x3bcd, lo: 0x84, hi: 0x84},
- {value: 0x8800, lo: 0x88, hi: 0x88},
- {value: 0x3bd4, lo: 0x89, hi: 0x89},
- {value: 0x8800, lo: 0x8b, hi: 0x8b},
- {value: 0x3bdb, lo: 0x8c, hi: 0x8c},
- {value: 0x8800, lo: 0xa3, hi: 0xa3},
- {value: 0x3be2, lo: 0xa4, hi: 0xa4},
- {value: 0x8800, lo: 0xa5, hi: 0xa5},
- {value: 0x3be9, lo: 0xa6, hi: 0xa6},
- {value: 0x284a, lo: 0xac, hi: 0xad},
- {value: 0x2851, lo: 0xaf, hi: 0xaf},
- {value: 0x29c7, lo: 0xb0, hi: 0xb0},
- {value: 0x8800, lo: 0xbc, hi: 0xbc},
- // Block 0x44, offset 0x45
- {value: 0x0007, lo: 0x03},
- {value: 0x3c52, lo: 0xa0, hi: 0xa1},
- {value: 0x3c7c, lo: 0xa2, hi: 0xa3},
- {value: 0x3ca6, lo: 0xaa, hi: 0xad},
- // Block 0x45, offset 0x46
- {value: 0x0004, lo: 0x01},
- {value: 0x04fd, lo: 0xa9, hi: 0xaa},
- // Block 0x46, offset 0x47
- {value: 0x0002, lo: 0x03},
- {value: 0x0057, lo: 0x80, hi: 0x8f},
- {value: 0x0083, lo: 0x90, hi: 0xa9},
- {value: 0x0021, lo: 0xaa, hi: 0xaa},
- // Block 0x47, offset 0x48
- {value: 0x0000, lo: 0x01},
- {value: 0x2b53, lo: 0x8c, hi: 0x8c},
- // Block 0x48, offset 0x49
- {value: 0x0263, lo: 0x02},
- {value: 0x1cce, lo: 0xb4, hi: 0xb4},
- {value: 0x1a6f, lo: 0xb5, hi: 0xb6},
- // Block 0x49, offset 0x4a
- {value: 0x0000, lo: 0x01},
- {value: 0x44c3, lo: 0x9c, hi: 0x9c},
- // Block 0x4a, offset 0x4b
- {value: 0x0000, lo: 0x02},
- {value: 0x0095, lo: 0xbc, hi: 0xbc},
- {value: 0x006d, lo: 0xbd, hi: 0xbd},
- // Block 0x4b, offset 0x4c
- {value: 0x0000, lo: 0x01},
- {value: 0x80e6, lo: 0xaf, hi: 0xb1},
- // Block 0x4c, offset 0x4d
- {value: 0x0000, lo: 0x02},
- {value: 0x04f1, lo: 0xaf, hi: 0xaf},
- {value: 0x8009, lo: 0xbf, hi: 0xbf},
- // Block 0x4d, offset 0x4e
- {value: 0x0000, lo: 0x01},
- {value: 0x80e6, lo: 0xa0, hi: 0xbf},
- // Block 0x4e, offset 0x4f
- {value: 0x0000, lo: 0x01},
- {value: 0x0e35, lo: 0x9f, hi: 0x9f},
- // Block 0x4f, offset 0x50
- {value: 0x0000, lo: 0x01},
- {value: 0x169d, lo: 0xb3, hi: 0xb3},
- // Block 0x50, offset 0x51
- {value: 0x0004, lo: 0x0b},
- {value: 0x1605, lo: 0x80, hi: 0x82},
- {value: 0x161d, lo: 0x83, hi: 0x83},
- {value: 0x1635, lo: 0x84, hi: 0x85},
- {value: 0x1645, lo: 0x86, hi: 0x89},
- {value: 0x1659, lo: 0x8a, hi: 0x8c},
- {value: 0x166d, lo: 0x8d, hi: 0x8d},
- {value: 0x1675, lo: 0x8e, hi: 0x8e},
- {value: 0x167d, lo: 0x8f, hi: 0x90},
- {value: 0x1689, lo: 0x91, hi: 0x93},
- {value: 0x1699, lo: 0x94, hi: 0x94},
- {value: 0x16a1, lo: 0x95, hi: 0x95},
- // Block 0x51, offset 0x52
- {value: 0x0004, lo: 0x08},
- {value: 0x0001, lo: 0x80, hi: 0x80},
- {value: 0x80da, lo: 0xaa, hi: 0xaa},
- {value: 0x80e4, lo: 0xab, hi: 0xac},
- {value: 0x80de, lo: 0xad, hi: 0xad},
- {value: 0x80e0, lo: 0xae, hi: 0xae},
- {value: 0x80e0, lo: 0xaf, hi: 0xaf},
- {value: 0x0525, lo: 0xb6, hi: 0xb6},
- {value: 0x08f9, lo: 0xb8, hi: 0xba},
- // Block 0x52, offset 0x53
- {value: 0x0004, lo: 0x06},
- {value: 0x030d, lo: 0xb1, hi: 0xb2},
- {value: 0x0435, lo: 0xb3, hi: 0xb3},
- {value: 0x0315, lo: 0xb4, hi: 0xb4},
- {value: 0x0439, lo: 0xb5, hi: 0xb6},
- {value: 0x0319, lo: 0xb7, hi: 0xb9},
- {value: 0x0441, lo: 0xba, hi: 0xbf},
- // Block 0x53, offset 0x54
- {value: 0x0004, lo: 0x0c},
- {value: 0x0361, lo: 0x80, hi: 0x80},
- {value: 0x0325, lo: 0x81, hi: 0x83},
- {value: 0x0375, lo: 0x84, hi: 0x84},
- {value: 0x0331, lo: 0x85, hi: 0x8e},
- {value: 0x03c1, lo: 0x8f, hi: 0xa3},
- {value: 0x03bd, lo: 0xa4, hi: 0xa4},
- {value: 0x0359, lo: 0xa5, hi: 0xa6},
- {value: 0x0459, lo: 0xa7, hi: 0xad},
- {value: 0x0365, lo: 0xae, hi: 0xae},
- {value: 0x0475, lo: 0xaf, hi: 0xb0},
- {value: 0x0369, lo: 0xb1, hi: 0xb3},
- {value: 0x0379, lo: 0xb4, hi: 0xbf},
- // Block 0x54, offset 0x55
- {value: 0x0000, lo: 0x02},
- {value: 0x80e6, lo: 0xaf, hi: 0xaf},
- {value: 0x80e6, lo: 0xb4, hi: 0xbd},
- // Block 0x55, offset 0x56
- {value: 0x0000, lo: 0x01},
- {value: 0x80e6, lo: 0x9f, hi: 0x9f},
- // Block 0x56, offset 0x57
- {value: 0x0000, lo: 0x01},
- {value: 0x80e6, lo: 0xb0, hi: 0xb1},
- // Block 0x57, offset 0x58
- {value: 0x0000, lo: 0x01},
- {value: 0x16a5, lo: 0xb0, hi: 0xb0},
- // Block 0x58, offset 0x59
- {value: 0x000c, lo: 0x01},
- {value: 0x00da, lo: 0xb8, hi: 0xb9},
- // Block 0x59, offset 0x5a
- {value: 0x0000, lo: 0x01},
- {value: 0x8009, lo: 0x86, hi: 0x86},
- // Block 0x5a, offset 0x5b
- {value: 0x0000, lo: 0x02},
- {value: 0x8009, lo: 0x84, hi: 0x84},
- {value: 0x80e6, lo: 0xa0, hi: 0xb1},
- // Block 0x5b, offset 0x5c
- {value: 0x0000, lo: 0x01},
- {value: 0x80dc, lo: 0xab, hi: 0xad},
- // Block 0x5c, offset 0x5d
- {value: 0x0000, lo: 0x01},
- {value: 0x8009, lo: 0x93, hi: 0x93},
- // Block 0x5d, offset 0x5e
- {value: 0x0000, lo: 0x01},
- {value: 0x8007, lo: 0xb3, hi: 0xb3},
- // Block 0x5e, offset 0x5f
- {value: 0x0000, lo: 0x01},
- {value: 0x8009, lo: 0x80, hi: 0x80},
- // Block 0x5f, offset 0x60
- {value: 0x0000, lo: 0x05},
- {value: 0x80e6, lo: 0xb0, hi: 0xb0},
- {value: 0x80e6, lo: 0xb2, hi: 0xb3},
- {value: 0x80dc, lo: 0xb4, hi: 0xb4},
- {value: 0x80e6, lo: 0xb7, hi: 0xb8},
- {value: 0x80e6, lo: 0xbe, hi: 0xbf},
- // Block 0x60, offset 0x61
- {value: 0x0000, lo: 0x02},
- {value: 0x80e6, lo: 0x81, hi: 0x81},
- {value: 0x8009, lo: 0xb6, hi: 0xb6},
- // Block 0x61, offset 0x62
- {value: 0x0000, lo: 0x01},
- {value: 0x8009, lo: 0xad, hi: 0xad},
- // Block 0x62, offset 0x63
- {value: 0x0000, lo: 0x01},
- {value: 0x8100, lo: 0x80, hi: 0xbf},
- // Block 0x63, offset 0x64
- {value: 0x0000, lo: 0x01},
- {value: 0x8100, lo: 0x80, hi: 0xa3},
- // Block 0x64, offset 0x65
- {value: 0x0002, lo: 0x01},
- {value: 0x0003, lo: 0x81, hi: 0xbf},
- // Block 0x65, offset 0x66
- {value: 0x0004, lo: 0x0e},
- {value: 0x03c1, lo: 0x82, hi: 0x87},
- {value: 0x03d9, lo: 0x8a, hi: 0x8f},
- {value: 0x03f1, lo: 0x92, hi: 0x97},
- {value: 0x0409, lo: 0x9a, hi: 0x9c},
- {value: 0x00bf, lo: 0xa0, hi: 0xa0},
- {value: 0x00c2, lo: 0xa1, hi: 0xa1},
- {value: 0x00cb, lo: 0xa2, hi: 0xa2},
- {value: 0x424a, lo: 0xa3, hi: 0xa3},
- {value: 0x00c8, lo: 0xa4, hi: 0xa4},
- {value: 0x00c5, lo: 0xa5, hi: 0xa5},
- {value: 0x04b9, lo: 0xa6, hi: 0xa6},
- {value: 0x04dd, lo: 0xa8, hi: 0xa8},
- {value: 0x04bd, lo: 0xa9, hi: 0xac},
- {value: 0x04e1, lo: 0xad, hi: 0xae},
- // Block 0x66, offset 0x67
- {value: 0x0000, lo: 0x01},
- {value: 0x80dc, lo: 0xbd, hi: 0xbd},
- // Block 0x67, offset 0x68
- {value: 0x00db, lo: 0x05},
- {value: 0x80dc, lo: 0x8d, hi: 0x8d},
- {value: 0x80e6, lo: 0x8f, hi: 0x8f},
- {value: 0x80e6, lo: 0xb8, hi: 0xb8},
- {value: 0x8001, lo: 0xb9, hi: 0xba},
- {value: 0x8009, lo: 0xbf, hi: 0xbf},
- // Block 0x68, offset 0x69
- {value: 0x05fe, lo: 0x07},
- {value: 0x8800, lo: 0x99, hi: 0x99},
- {value: 0x4222, lo: 0x9a, hi: 0x9a},
- {value: 0x8800, lo: 0x9b, hi: 0x9b},
- {value: 0x422c, lo: 0x9c, hi: 0x9c},
- {value: 0x8800, lo: 0xa5, hi: 0xa5},
- {value: 0x4236, lo: 0xab, hi: 0xab},
- {value: 0x8009, lo: 0xb9, hi: 0xba},
- // Block 0x69, offset 0x6a
- {value: 0x0000, lo: 0x06},
- {value: 0x80e6, lo: 0x80, hi: 0x82},
- {value: 0x8600, lo: 0xa7, hi: 0xa7},
- {value: 0x1993, lo: 0xae, hi: 0xae},
- {value: 0x199c, lo: 0xaf, hi: 0xaf},
- {value: 0x8800, lo: 0xb1, hi: 0xb2},
- {value: 0x8009, lo: 0xb3, hi: 0xb4},
- // Block 0x6a, offset 0x6b
- {value: 0x0000, lo: 0x02},
- {value: 0x8009, lo: 0xb6, hi: 0xb6},
- {value: 0x8007, lo: 0xb7, hi: 0xb7},
- // Block 0x6b, offset 0x6c
- {value: 0x0000, lo: 0x0c},
- {value: 0x45b2, lo: 0x9e, hi: 0x9e},
- {value: 0x45bc, lo: 0x9f, hi: 0x9f},
- {value: 0x45f0, lo: 0xa0, hi: 0xa0},
- {value: 0x45fe, lo: 0xa1, hi: 0xa1},
- {value: 0x460c, lo: 0xa2, hi: 0xa2},
- {value: 0x461a, lo: 0xa3, hi: 0xa3},
- {value: 0x4628, lo: 0xa4, hi: 0xa4},
- {value: 0x80d8, lo: 0xa5, hi: 0xa6},
- {value: 0x8001, lo: 0xa7, hi: 0xa9},
- {value: 0x80e2, lo: 0xad, hi: 0xad},
- {value: 0x80d8, lo: 0xae, hi: 0xb2},
- {value: 0x80dc, lo: 0xbb, hi: 0xbf},
- // Block 0x6c, offset 0x6d
- {value: 0x0000, lo: 0x09},
- {value: 0x80dc, lo: 0x80, hi: 0x82},
- {value: 0x80e6, lo: 0x85, hi: 0x89},
- {value: 0x80dc, lo: 0x8a, hi: 0x8b},
- {value: 0x80e6, lo: 0xaa, hi: 0xad},
- {value: 0x45c6, lo: 0xbb, hi: 0xbb},
- {value: 0x45d0, lo: 0xbc, hi: 0xbc},
- {value: 0x4636, lo: 0xbd, hi: 0xbd},
- {value: 0x4652, lo: 0xbe, hi: 0xbe},
- {value: 0x4644, lo: 0xbf, hi: 0xbf},
- // Block 0x6d, offset 0x6e
- {value: 0x0000, lo: 0x01},
- {value: 0x4660, lo: 0x80, hi: 0x80},
- // Block 0x6e, offset 0x6f
- {value: 0x0000, lo: 0x01},
- {value: 0x80e6, lo: 0x82, hi: 0x84},
- // Block 0x6f, offset 0x70
- {value: 0x0002, lo: 0x03},
- {value: 0x0043, lo: 0x80, hi: 0x99},
- {value: 0x0083, lo: 0x9a, hi: 0xb3},
- {value: 0x0043, lo: 0xb4, hi: 0xbf},
- // Block 0x70, offset 0x71
- {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 0x71, offset 0x72
- {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 0x72, offset 0x73
- {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 0x73, offset 0x74
- {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 0x74, offset 0x75
- {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 0x75, offset 0x76
- {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 0x76, offset 0x77
- {value: 0x0002, lo: 0x03},
- {value: 0x008f, lo: 0x80, hi: 0x93},
- {value: 0x0043, lo: 0x94, hi: 0xad},
- {value: 0x0083, lo: 0xae, hi: 0xbf},
- // Block 0x77, offset 0x78
- {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 0x78, offset 0x79
- {value: 0x0002, lo: 0x03},
- {value: 0x004b, lo: 0x80, hi: 0x95},
- {value: 0x0083, lo: 0x96, hi: 0xaf},
- {value: 0x0043, lo: 0xb0, hi: 0xbf},
- // Block 0x79, offset 0x7a
- {value: 0x0003, lo: 0x0f},
- {value: 0x01b8, lo: 0x80, hi: 0x80},
- {value: 0x04d1, lo: 0x81, hi: 0x81},
- {value: 0x01bb, lo: 0x82, hi: 0x9a},
- {value: 0x04cd, 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: 0x04d1, lo: 0xbb, hi: 0xbb},
- {value: 0x01bb, lo: 0xbc, hi: 0xbf},
- // Block 0x7a, offset 0x7b
- {value: 0x0003, lo: 0x0d},
- {value: 0x01c7, lo: 0x80, hi: 0x94},
- {value: 0x04cd, 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: 0x04d1, lo: 0xb5, hi: 0xb5},
- {value: 0x01bb, lo: 0xb6, hi: 0xbf},
- // Block 0x7b, offset 0x7c
- {value: 0x0003, lo: 0x0d},
- {value: 0x01d9, lo: 0x80, hi: 0x8e},
- {value: 0x04cd, 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: 0x04d1, lo: 0xaf, hi: 0xaf},
- {value: 0x01bb, lo: 0xb0, hi: 0xbf},
- // Block 0x7c, offset 0x7d
- {value: 0x0003, lo: 0x0d},
- {value: 0x01eb, lo: 0x80, hi: 0x88},
- {value: 0x04cd, 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: 0x04d1, lo: 0xa9, hi: 0xa9},
- {value: 0x01bb, lo: 0xaa, hi: 0xbf},
- // Block 0x7d, offset 0x7e
- {value: 0x0002, lo: 0x09},
- {value: 0x0063, lo: 0x80, hi: 0x89},
- {value: 0x1a93, lo: 0x8a, hi: 0x8a},
- {value: 0x1ac3, lo: 0x8b, hi: 0x8b},
- {value: 0x1ade, lo: 0x8c, hi: 0x8c},
- {value: 0x1ae4, lo: 0x8d, hi: 0x8d},
- {value: 0x1d02, lo: 0x8e, hi: 0x8e},
- {value: 0x1af0, lo: 0x8f, hi: 0x8f},
- {value: 0x1abd, lo: 0xaa, hi: 0xaa},
- {value: 0x1ac0, lo: 0xab, hi: 0xab},
- // Block 0x7e, offset 0x7f
- {value: 0x0000, lo: 0x01},
- {value: 0x1a81, lo: 0x90, hi: 0x90},
- // Block 0x7f, offset 0x80
- {value: 0x0028, lo: 0x09},
- {value: 0x2a0d, lo: 0x80, hi: 0x80},
- {value: 0x29d1, lo: 0x81, hi: 0x81},
- {value: 0x29db, lo: 0x82, hi: 0x82},
- {value: 0x29ef, lo: 0x83, hi: 0x84},
- {value: 0x29f9, lo: 0x85, hi: 0x86},
- {value: 0x29e5, lo: 0x87, hi: 0x87},
- {value: 0x2a03, lo: 0x88, hi: 0x88},
- {value: 0x0be1, lo: 0x90, hi: 0x90},
- {value: 0x0959, lo: 0x91, hi: 0x91},
-}
-
-// nfkcLookup: 1216 bytes
-// Block 0 is the null block.
-var nfkcLookup = [1216]uint8{
- // Block 0x0, offset 0x0
- // Block 0x1, offset 0x40
- // Block 0x2, offset 0x80
- // Block 0x3, offset 0xc0
- 0x0c2: 0x58, 0x0c3: 0x01, 0x0c4: 0x02, 0x0c5: 0x03, 0x0c6: 0x59, 0x0c7: 0x04,
- 0x0c8: 0x05, 0x0ca: 0x5a, 0x0cb: 0x5b, 0x0cc: 0x06, 0x0cd: 0x07, 0x0ce: 0x08, 0x0cf: 0x09,
- 0x0d0: 0x0a, 0x0d1: 0x5c, 0x0d2: 0x5d, 0x0d3: 0x0b, 0x0d6: 0x0c, 0x0d7: 0x5e,
- 0x0d8: 0x5f, 0x0d9: 0x0d, 0x0db: 0x60, 0x0dc: 0x61, 0x0dd: 0x62, 0x0df: 0x63,
- 0x0e0: 0x02, 0x0e1: 0x03, 0x0e2: 0x04, 0x0e3: 0x05,
- 0x0ea: 0x06, 0x0eb: 0x07, 0x0ec: 0x07, 0x0ed: 0x08, 0x0ef: 0x09,
- 0x0f0: 0x10,
- // Block 0x4, offset 0x100
- 0x120: 0x64, 0x121: 0x65, 0x123: 0x66, 0x124: 0x67, 0x125: 0x68, 0x126: 0x69, 0x127: 0x6a,
- 0x128: 0x6b, 0x129: 0x6c, 0x12a: 0x6d, 0x12b: 0x6e, 0x12c: 0x69, 0x12d: 0x6f, 0x12e: 0x70, 0x12f: 0x71,
- 0x131: 0x72, 0x132: 0x73, 0x133: 0x74, 0x134: 0x75, 0x135: 0x76, 0x137: 0x77,
- 0x138: 0x78, 0x139: 0x79, 0x13a: 0x7a, 0x13b: 0x7b, 0x13c: 0x7c, 0x13d: 0x7d, 0x13e: 0x7e, 0x13f: 0x7f,
- // Block 0x5, offset 0x140
- 0x140: 0x80, 0x142: 0x81, 0x143: 0x82, 0x144: 0x83, 0x145: 0x84, 0x146: 0x85, 0x147: 0x86,
- 0x14d: 0x87,
- 0x15c: 0x88, 0x15f: 0x89,
- 0x162: 0x8a, 0x164: 0x8b,
- 0x168: 0x8c, 0x169: 0x8d, 0x16c: 0x0e, 0x16d: 0x8e, 0x16e: 0x8f, 0x16f: 0x90,
- 0x170: 0x91, 0x173: 0x92, 0x174: 0x93, 0x175: 0x0f, 0x176: 0x10, 0x177: 0x94,
- 0x178: 0x11, 0x179: 0x12, 0x17a: 0x13, 0x17b: 0x14, 0x17c: 0x15, 0x17d: 0x16, 0x17e: 0x17, 0x17f: 0x18,
- // Block 0x6, offset 0x180
- 0x180: 0x95, 0x181: 0x96, 0x182: 0x97, 0x183: 0x98, 0x184: 0x19, 0x185: 0x1a, 0x186: 0x99, 0x187: 0x9a,
- 0x188: 0x9b, 0x189: 0x1b, 0x18a: 0x1c, 0x18b: 0x9c, 0x18c: 0x9d,
- 0x191: 0x1d, 0x192: 0x1e, 0x193: 0x9e,
- 0x1a8: 0x9f, 0x1a9: 0xa0, 0x1ab: 0xa1,
- 0x1b1: 0xa2, 0x1b3: 0xa3, 0x1b5: 0xa4, 0x1b7: 0xa5,
- 0x1ba: 0xa6, 0x1bb: 0xa7, 0x1bc: 0x1f, 0x1bd: 0x20, 0x1be: 0x21, 0x1bf: 0xa8,
- // Block 0x7, offset 0x1c0
- 0x1c0: 0xa9, 0x1c1: 0x22, 0x1c2: 0x23, 0x1c3: 0x24, 0x1c4: 0xaa, 0x1c5: 0xab, 0x1c6: 0x25,
- 0x1c8: 0x26, 0x1c9: 0x27, 0x1ca: 0x28, 0x1cb: 0x29, 0x1cc: 0x2a, 0x1cd: 0x2b, 0x1ce: 0x2c, 0x1cf: 0x2d,
- // Block 0x8, offset 0x200
- 0x219: 0xac, 0x21a: 0xad, 0x21b: 0xae, 0x21d: 0xaf, 0x21f: 0xb0,
- 0x220: 0xb1, 0x223: 0xb2, 0x224: 0xb3, 0x225: 0xb4, 0x226: 0xb5, 0x227: 0xb6,
- 0x22a: 0xb7, 0x22b: 0xb8, 0x22f: 0xb9,
- 0x230: 0xba, 0x231: 0xba, 0x232: 0xba, 0x233: 0xba, 0x234: 0xba, 0x235: 0xba, 0x236: 0xba, 0x237: 0xba,
- 0x238: 0xba, 0x239: 0xba, 0x23a: 0xba, 0x23b: 0xba, 0x23c: 0xba, 0x23d: 0xba, 0x23e: 0xba, 0x23f: 0xba,
- // Block 0x9, offset 0x240
- 0x240: 0xba, 0x241: 0xba, 0x242: 0xba, 0x243: 0xba, 0x244: 0xba, 0x245: 0xba, 0x246: 0xba, 0x247: 0xba,
- 0x248: 0xba, 0x249: 0xba, 0x24a: 0xba, 0x24b: 0xba, 0x24c: 0xba, 0x24d: 0xba, 0x24e: 0xba, 0x24f: 0xba,
- 0x250: 0xba, 0x251: 0xba, 0x252: 0xba, 0x253: 0xba, 0x254: 0xba, 0x255: 0xba, 0x256: 0xba, 0x257: 0xba,
- 0x258: 0xba, 0x259: 0xba, 0x25a: 0xba, 0x25b: 0xba, 0x25c: 0xba, 0x25d: 0xba, 0x25e: 0xba, 0x25f: 0xba,
- 0x260: 0xba, 0x261: 0xba, 0x262: 0xba, 0x263: 0xba, 0x264: 0xba, 0x265: 0xba, 0x266: 0xba, 0x267: 0xba,
- 0x268: 0xba, 0x269: 0xba, 0x26a: 0xba, 0x26b: 0xba, 0x26c: 0xba, 0x26d: 0xba, 0x26e: 0xba, 0x26f: 0xba,
- 0x270: 0xba, 0x271: 0xba, 0x272: 0xba, 0x273: 0xba, 0x274: 0xba, 0x275: 0xba, 0x276: 0xba, 0x277: 0xba,
- 0x278: 0xba, 0x279: 0xba, 0x27a: 0xba, 0x27b: 0xba, 0x27c: 0xba, 0x27d: 0xba, 0x27e: 0xba, 0x27f: 0xba,
- // Block 0xa, offset 0x280
- 0x280: 0xba, 0x281: 0xba, 0x282: 0xba, 0x283: 0xba, 0x284: 0xba, 0x285: 0xba, 0x286: 0xba, 0x287: 0xba,
- 0x288: 0xba, 0x289: 0xba, 0x28a: 0xba, 0x28b: 0xba, 0x28c: 0xba, 0x28d: 0xba, 0x28e: 0xba, 0x28f: 0xba,
- 0x290: 0xba, 0x291: 0xba, 0x292: 0xba, 0x293: 0xba, 0x294: 0xba, 0x295: 0xba, 0x296: 0xba, 0x297: 0xba,
- 0x298: 0xba, 0x299: 0xba, 0x29a: 0xba, 0x29b: 0xba, 0x29c: 0xba, 0x29d: 0xba, 0x29e: 0xbb,
- // Block 0xb, offset 0x2c0
- 0x2e4: 0x2e, 0x2e5: 0x2f, 0x2e6: 0x30, 0x2e7: 0x31,
- 0x2e8: 0x32, 0x2e9: 0x33, 0x2ea: 0x34, 0x2eb: 0x35, 0x2ec: 0x36, 0x2ed: 0x37, 0x2ee: 0x38, 0x2ef: 0x39,
- 0x2f0: 0x3a, 0x2f1: 0x3b, 0x2f2: 0x3c, 0x2f3: 0x3d, 0x2f4: 0x3e, 0x2f5: 0x3f, 0x2f6: 0x40, 0x2f7: 0x41,
- 0x2f8: 0x42, 0x2f9: 0x43, 0x2fa: 0x44, 0x2fb: 0x45, 0x2fc: 0xbc, 0x2fd: 0x46, 0x2fe: 0x47, 0x2ff: 0xbd,
- // Block 0xc, offset 0x300
- 0x307: 0xbe,
- 0x328: 0xbf,
- // Block 0xd, offset 0x340
- 0x341: 0xb1, 0x342: 0xc0, 0x344: 0xc1, 0x347: 0xb6,
- 0x35a: 0xc2,
- // Block 0xe, offset 0x380
- 0x385: 0xc3, 0x386: 0xc4, 0x387: 0xc5,
- 0x389: 0xc6,
- 0x390: 0xc7, 0x391: 0xc8, 0x392: 0xc9, 0x393: 0xca, 0x394: 0xcb, 0x395: 0xcc, 0x396: 0xcd, 0x397: 0xce,
- 0x398: 0xcf, 0x399: 0xd0, 0x39a: 0x48, 0x39b: 0xd1, 0x39c: 0xd2, 0x39d: 0xd3, 0x39e: 0xd4, 0x39f: 0x49,
- // Block 0xf, offset 0x3c0
- 0x3f8: 0x4a, 0x3f9: 0x4b, 0x3fa: 0x4c,
- // Block 0x10, offset 0x400
- 0x404: 0x4d, 0x405: 0xd5, 0x406: 0xd6,
- 0x408: 0x4e, 0x409: 0xd7,
- // Block 0x11, offset 0x440
- 0x460: 0x4f, 0x461: 0x50, 0x462: 0x51, 0x463: 0x52, 0x464: 0x53, 0x465: 0x54, 0x466: 0x55, 0x467: 0x56,
- 0x468: 0x57,
- // Block 0x12, offset 0x480
- 0x490: 0x0a, 0x491: 0x0b,
- 0x49d: 0x0c, 0x49e: 0x0d, 0x49f: 0x0e,
- 0x4af: 0x0f,
-}
-
-var nfkcTrie = trie{nfkcLookup[:], nfkcValues[:], nfkcSparseValues[:], nfkcSparseOffset[:], 88}
-
-// recompMap: 7464 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,
-}
-
-// Total size of tables: 50KB (51625 bytes)
diff --git a/src/pkg/exp/norm/trie.go b/src/pkg/exp/norm/trie.go
deleted file mode 100644
index 82267a8d3..000000000
--- a/src/pkg/exp/norm/trie.go
+++ /dev/null
@@ -1,232 +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 norm
-
-type valueRange struct {
- value uint16 // header: value:stride
- lo, hi byte // header: lo:n
-}
-
-type trie struct {
- index []uint8
- values []uint16
- sparse []valueRange
- sparseOffset []uint16
- cutoff uint8 // indices >= cutoff are sparse
-}
-
-// 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 *trie) lookupValue(n uint8, b byte) uint16 {
- if n < t.cutoff {
- return t.values[uint16(n)<<6+uint16(b)]
- }
- offset := t.sparseOffset[n-t.cutoff]
- header := t.sparse[offset]
- lo := offset + 1
- hi := lo + uint16(header.lo)
- for lo < hi {
- m := lo + (hi-lo)/2
- r := t.sparse[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
-}
-
-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
- t6 = 0xFC // 1111 1100
- te = 0xFE // 1111 1110
-)
-
-// 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 *trie) lookup(s []byte) (v uint16, sz int) {
- c0 := s[0]
- switch {
- case c0 < tx:
- return t.values[c0], 1
- case c0 < t2:
- return 0, 1
- case c0 < t3:
- if len(s) < 2 {
- return 0, 0
- }
- i := t.index[c0]
- c1 := s[1]
- if c1 < tx || t2 <= c1 {
- return 0, 1
- }
- return t.lookupValue(i, c1), 2
- case c0 < t4:
- if len(s) < 3 {
- return 0, 0
- }
- i := t.index[c0]
- c1 := s[1]
- if c1 < tx || t2 <= c1 {
- return 0, 1
- }
- o := uint16(i)<<6 + uint16(c1)
- i = t.index[o]
- c2 := s[2]
- if c2 < tx || t2 <= c2 {
- return 0, 2
- }
- return t.lookupValue(i, c2), 3
- case c0 < t5:
- if len(s) < 4 {
- return 0, 0
- }
- i := t.index[c0]
- c1 := s[1]
- if c1 < tx || t2 <= c1 {
- return 0, 1
- }
- o := uint16(i)<<6 + uint16(c1)
- i = t.index[o]
- c2 := s[2]
- if c2 < tx || t2 <= c2 {
- return 0, 2
- }
- o = uint16(i)<<6 + uint16(c2)
- i = t.index[o]
- c3 := s[3]
- if c3 < tx || t2 <= c3 {
- return 0, 3
- }
- return t.lookupValue(i, c3), 4
- }
- // Illegal rune
- return 0, 1
-}
-
-// 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 *trie) lookupString(s string) (v uint16, sz int) {
- c0 := s[0]
- switch {
- case c0 < tx:
- return t.values[c0], 1
- case c0 < t2:
- return 0, 1
- case c0 < t3:
- if len(s) < 2 {
- return 0, 0
- }
- i := t.index[c0]
- c1 := s[1]
- if c1 < tx || t2 <= c1 {
- return 0, 1
- }
- return t.lookupValue(i, c1), 2
- case c0 < t4:
- if len(s) < 3 {
- return 0, 0
- }
- i := t.index[c0]
- c1 := s[1]
- if c1 < tx || t2 <= c1 {
- return 0, 1
- }
- o := uint16(i)<<6 + uint16(c1)
- i = t.index[o]
- c2 := s[2]
- if c2 < tx || t2 <= c2 {
- return 0, 2
- }
- return t.lookupValue(i, c2), 3
- case c0 < t5:
- if len(s) < 4 {
- return 0, 0
- }
- i := t.index[c0]
- c1 := s[1]
- if c1 < tx || t2 <= c1 {
- return 0, 1
- }
- o := uint16(i)<<6 + uint16(c1)
- i = t.index[o]
- c2 := s[2]
- if c2 < tx || t2 <= c2 {
- return 0, 2
- }
- o = uint16(i)<<6 + uint16(c2)
- i = t.index[o]
- c3 := s[3]
- if c3 < tx || t2 <= c3 {
- return 0, 3
- }
- return t.lookupValue(i, c3), 4
- }
- // Illegal rune
- return 0, 1
-}
-
-// lookupUnsafe returns the trie value for the first UTF-8 encoding in s.
-// s must hold a full encoding.
-func (t *trie) lookupUnsafe(s []byte) uint16 {
- c0 := s[0]
- if c0 < tx {
- return t.values[c0]
- }
- if c0 < t2 {
- return 0
- }
- i := t.index[c0]
- if c0 < t3 {
- return t.lookupValue(i, s[1])
- }
- i = t.index[uint16(i)<<6+uint16(s[1])]
- if c0 < t4 {
- return t.lookupValue(i, s[2])
- }
- i = t.index[uint16(i)<<6+uint16(s[2])]
- if c0 < t5 {
- return t.lookupValue(i, s[3])
- }
- return 0
-}
-
-// lookupStringUnsafe returns the trie value for the first UTF-8 encoding in s.
-// s must hold a full encoding.
-func (t *trie) lookupStringUnsafe(s string) uint16 {
- c0 := s[0]
- if c0 < tx {
- return t.values[c0]
- }
- if c0 < t2 {
- return 0
- }
- i := t.index[c0]
- if c0 < t3 {
- return t.lookupValue(i, s[1])
- }
- i = t.index[uint16(i)<<6+uint16(s[1])]
- if c0 < t4 {
- return t.lookupValue(i, s[2])
- }
- i = t.index[uint16(i)<<6+uint16(s[2])]
- if c0 < t5 {
- return t.lookupValue(i, s[3])
- }
- return 0
-}
diff --git a/src/pkg/exp/norm/trie_test.go b/src/pkg/exp/norm/trie_test.go
deleted file mode 100644
index 1a75cc705..000000000
--- a/src/pkg/exp/norm/trie_test.go
+++ /dev/null
@@ -1,152 +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 norm
-
-import (
- "testing"
- "unicode/utf8"
-)
-
-// Test data is located in triedata_test.go; generated by maketesttables.
-var testdata = testdataTrie
-
-type rangeTest struct {
- block uint8
- lookup byte
- result uint16
- table []valueRange
- offsets []uint16
-}
-
-var range1Off = []uint16{0, 2}
-var range1 = []valueRange{
- {0, 1, 0},
- {1, 0x80, 0x80},
- {0, 2, 0},
- {1, 0x80, 0x80},
- {9, 0xff, 0xff},
-}
-
-var rangeTests = []rangeTest{
- {10, 0x80, 1, range1, range1Off},
- {10, 0x00, 0, range1, range1Off},
- {11, 0x80, 1, range1, range1Off},
- {11, 0xff, 9, range1, range1Off},
- {11, 0x00, 0, range1, range1Off},
-}
-
-func TestLookupSparse(t *testing.T) {
- for i, test := range rangeTests {
- n := trie{sparse: test.table, sparseOffset: test.offsets, cutoff: 10}
- v := n.lookupValue(test.block, test.lookup)
- if v != test.result {
- t.Errorf("LookupSparse:%d: found %X; want %X", i, v, test.result)
- }
- }
-}
-
-// Test cases for illegal runes.
-type trietest struct {
- size int
- bytes []byte
-}
-
-var tests = []trietest{
- // illegal runes
- {1, []byte{0x80}},
- {1, []byte{0xFF}},
- {1, []byte{t2, tx - 1}},
- {1, []byte{t2, t2}},
- {2, []byte{t3, tx, tx - 1}},
- {2, []byte{t3, tx, t2}},
- {1, []byte{t3, tx - 1, tx}},
- {3, []byte{t4, tx, tx, tx - 1}},
- {3, []byte{t4, tx, tx, t2}},
- {1, []byte{t4, t2, tx, tx - 1}},
- {2, []byte{t4, tx, t2, tx - 1}},
-
- // short runes
- {0, []byte{t2}},
- {0, []byte{t3, tx}},
- {0, []byte{t4, tx, tx}},
-
- // we only support UTF-8 up to utf8.UTFMax bytes (4 bytes)
- {1, []byte{t5, tx, tx, tx, tx}},
- {1, []byte{t6, tx, tx, tx, tx, tx}},
-}
-
-func mkUTF8(r rune) ([]byte, int) {
- var b [utf8.UTFMax]byte
- sz := utf8.EncodeRune(b[:], r)
- return b[:sz], sz
-}
-
-func TestLookup(t *testing.T) {
- for i, tt := range testRunes {
- b, szg := mkUTF8(tt)
- v, szt := testdata.lookup(b)
- if int(v) != i {
- t.Errorf("lookup(%U): found value %#x, expected %#x", tt, v, i)
- }
- if szt != szg {
- t.Errorf("lookup(%U): found size %d, expected %d", tt, szt, szg)
- }
- }
- for i, tt := range tests {
- v, sz := testdata.lookup(tt.bytes)
- if v != 0 {
- t.Errorf("lookup of illegal rune, case %d: found value %#x, expected 0", i, v)
- }
- if sz != tt.size {
- t.Errorf("lookup of illegal rune, case %d: found size %d, expected %d", i, sz, tt.size)
- }
- }
- // Verify defaults.
- if v, _ := testdata.lookup([]byte{0xC1, 0x8C}); v != 0 {
- t.Errorf("lookup of non-existing rune should be 0; found %X", v)
- }
-}
-
-func TestLookupUnsafe(t *testing.T) {
- for i, tt := range testRunes {
- b, _ := mkUTF8(tt)
- v := testdata.lookupUnsafe(b)
- if int(v) != i {
- t.Errorf("lookupUnsafe(%U): found value %#x, expected %#x", i, v, i)
- }
- }
-}
-
-func TestLookupString(t *testing.T) {
- for i, tt := range testRunes {
- b, szg := mkUTF8(tt)
- v, szt := testdata.lookupString(string(b))
- if int(v) != i {
- t.Errorf("lookup(%U): found value %#x, expected %#x", i, v, i)
- }
- if szt != szg {
- t.Errorf("lookup(%U): found size %d, expected %d", i, szt, szg)
- }
- }
- for i, tt := range tests {
- v, sz := testdata.lookupString(string(tt.bytes))
- if int(v) != 0 {
- t.Errorf("lookup of illegal rune, case %d: found value %#x, expected 0", i, v)
- }
- if sz != tt.size {
- t.Errorf("lookup of illegal rune, case %d: found size %d, expected %d", i, sz, tt.size)
- }
- }
-}
-
-func TestLookupStringUnsafe(t *testing.T) {
- for i, tt := range testRunes {
- b, _ := mkUTF8(tt)
- v := testdata.lookupStringUnsafe(string(b))
- if int(v) != i {
- t.Errorf("lookupUnsafe(%U): found value %#x, expected %#x", i, v, i)
- }
- }
-}
diff --git a/src/pkg/exp/norm/triedata_test.go b/src/pkg/exp/norm/triedata_test.go
deleted file mode 100644
index d6c832d46..000000000
--- a/src/pkg/exp/norm/triedata_test.go
+++ /dev/null
@@ -1,85 +0,0 @@
-// Generated by running
-// maketesttables
-// DO NOT EDIT
-
-package norm
-
-var testRunes = []int32{1, 12, 127, 128, 256, 2047, 2048, 2457, 65535, 65536, 65793, 1114111, 512, 513, 514, 528, 533}
-
-// testdataValues: 192 entries, 384 bytes
-// Block 2 is the null block.
-var testdataValues = [192]uint16{
- // Block 0x0, offset 0x0
- 0x000c: 0x0001,
- // Block 0x1, offset 0x40
- 0x007f: 0x0002,
- // Block 0x2, offset 0x80
-}
-
-// testdataSparseOffset: 10 entries, 20 bytes
-var testdataSparseOffset = []uint16{0x0, 0x2, 0x4, 0x8, 0xa, 0xc, 0xe, 0x10, 0x12, 0x14}
-
-// testdataSparseValues: 22 entries, 88 bytes
-var testdataSparseValues = [22]valueRange{
- // Block 0x0, offset 0x1
- {value: 0x0000, lo: 0x01},
- {value: 0x0003, lo: 0x80, hi: 0x80},
- // Block 0x1, offset 0x2
- {value: 0x0000, lo: 0x01},
- {value: 0x0004, lo: 0x80, hi: 0x80},
- // Block 0x2, offset 0x3
- {value: 0x0001, lo: 0x03},
- {value: 0x000c, lo: 0x80, hi: 0x82},
- {value: 0x000f, lo: 0x90, hi: 0x90},
- {value: 0x0010, lo: 0x95, hi: 0x95},
- // Block 0x3, offset 0x4
- {value: 0x0000, lo: 0x01},
- {value: 0x0005, lo: 0xbf, hi: 0xbf},
- // Block 0x4, offset 0x5
- {value: 0x0000, lo: 0x01},
- {value: 0x0006, lo: 0x80, hi: 0x80},
- // Block 0x5, offset 0x6
- {value: 0x0000, lo: 0x01},
- {value: 0x0007, lo: 0x99, hi: 0x99},
- // Block 0x6, offset 0x7
- {value: 0x0000, lo: 0x01},
- {value: 0x0008, lo: 0xbf, hi: 0xbf},
- // Block 0x7, offset 0x8
- {value: 0x0000, lo: 0x01},
- {value: 0x0009, lo: 0x80, hi: 0x80},
- // Block 0x8, offset 0x9
- {value: 0x0000, lo: 0x01},
- {value: 0x000a, lo: 0x81, hi: 0x81},
- // Block 0x9, offset 0xa
- {value: 0x0000, lo: 0x01},
- {value: 0x000b, lo: 0xbf, hi: 0xbf},
-}
-
-// testdataLookup: 640 bytes
-// Block 0 is the null block.
-var testdataLookup = [640]uint8{
- // Block 0x0, offset 0x0
- // Block 0x1, offset 0x40
- // Block 0x2, offset 0x80
- // Block 0x3, offset 0xc0
- 0x0c2: 0x01, 0x0c4: 0x02,
- 0x0c8: 0x03,
- 0x0df: 0x04,
- 0x0e0: 0x02,
- 0x0ef: 0x03,
- 0x0f0: 0x05, 0x0f4: 0x07,
- // Block 0x4, offset 0x100
- 0x120: 0x05, 0x126: 0x06,
- // Block 0x5, offset 0x140
- 0x17f: 0x07,
- // Block 0x6, offset 0x180
- 0x180: 0x08, 0x184: 0x09,
- // Block 0x7, offset 0x1c0
- 0x1d0: 0x04,
- // Block 0x8, offset 0x200
- 0x23f: 0x0a,
- // Block 0x9, offset 0x240
- 0x24f: 0x06,
-}
-
-var testdataTrie = trie{testdataLookup[:], testdataValues[:], testdataSparseValues[:], testdataSparseOffset[:], 1}
diff --git a/src/pkg/exp/norm/triegen.go b/src/pkg/exp/norm/triegen.go
deleted file mode 100644
index 52c88b039..000000000
--- a/src/pkg/exp/norm/triegen.go
+++ /dev/null
@@ -1,317 +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 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"
- "hash/crc32"
- "log"
- "unicode/utf8"
-)
-
-const (
- blockSize = 64
- blockOffset = 2 // Subtract two blocks to compensate for the 0x80 added to continuation bytes.
- maxSparseEntries = 16
-)
-
-// Intermediate trie structure
-type trieNode struct {
- table [256]*trieNode
- value int
- b byte
- leaf bool
-}
-
-func newNode() *trieNode {
- return new(trieNode)
-}
-
-func (n trieNode) String() string {
- s := fmt.Sprint("trieNode{table: { non-nil at index: ")
- for i, v := range n.table {
- if v != nil {
- s += fmt.Sprintf("%d, ", i)
- }
- }
- s += fmt.Sprintf("}, value:%#x, b:%#x leaf:%v}", n.value, n.b, n.leaf)
- return s
-}
-
-func (n trieNode) isInternal() bool {
- internal := true
- for i := 0; i < 256; i++ {
- if nn := n.table[i]; nn != nil {
- if !internal && !nn.leaf {
- log.Fatalf("triegen: isInternal: node contains both leaf and non-leaf children (%v)", n)
- }
- internal = internal && !nn.leaf
- }
- }
- return internal
-}
-
-func (n trieNode) mostFrequentStride() int {
- counts := make(map[int]int)
- v := 0
- for _, t := range n.table[0x80 : 0x80+blockSize] {
- if t != nil {
- if stride := t.value - v; v != 0 && stride >= 0 {
- counts[stride]++
- }
- v = t.value
- } else {
- v = 0
- }
- }
- var maxs, maxc int
- for stride, cnt := range counts {
- if cnt > maxc || (cnt == maxc && stride < maxs) {
- maxs, maxc = stride, cnt
- }
- }
- return maxs
-}
-
-func (n trieNode) countSparseEntries() int {
- stride := n.mostFrequentStride()
- var count, v int
- for _, t := range n.table[0x80 : 0x80+blockSize] {
- tv := 0
- if t != nil {
- tv = t.value
- }
- if tv-v != stride {
- if tv != 0 {
- count++
- }
- }
- v = tv
- }
- return count
-}
-
-func (n *trieNode) insert(r rune, value uint16) {
- var p [utf8.UTFMax]byte
- sz := utf8.EncodeRune(p[:], r)
-
- for i := 0; i < sz; i++ {
- if n.leaf {
- log.Fatalf("triegen: insert: node (%#v) should not be a leaf", n)
- }
- nn := n.table[p[i]]
- if nn == nil {
- nn = newNode()
- nn.b = p[i]
- n.table[p[i]] = nn
- }
- n = nn
- }
- n.value = int(value)
- n.leaf = true
-}
-
-type nodeIndex struct {
- lookupBlocks []*trieNode
- valueBlocks []*trieNode
- sparseBlocks []*trieNode
- sparseOffset []uint16
- sparseCount int
-
- lookupBlockIdx map[uint32]int
- valueBlockIdx map[uint32]int
-}
-
-func newIndex() *nodeIndex {
- index := &nodeIndex{}
- index.lookupBlocks = make([]*trieNode, 0)
- index.valueBlocks = make([]*trieNode, 0)
- index.sparseBlocks = make([]*trieNode, 0)
- index.sparseOffset = make([]uint16, 1)
- index.lookupBlockIdx = make(map[uint32]int)
- index.valueBlockIdx = make(map[uint32]int)
- return index
-}
-
-func computeOffsets(index *nodeIndex, n *trieNode) int {
- if n.leaf {
- return n.value
- }
- hasher := crc32.New(crc32.MakeTable(crc32.IEEE))
- // We only index continuation bytes.
- for i := 0; i < blockSize; i++ {
- v := 0
- if nn := n.table[0x80+i]; nn != nil {
- v = computeOffsets(index, nn)
- }
- hasher.Write([]byte{uint8(v >> 8), uint8(v)})
- }
- h := hasher.Sum32()
- if n.isInternal() {
- v, ok := index.lookupBlockIdx[h]
- if !ok {
- v = len(index.lookupBlocks) - blockOffset
- index.lookupBlocks = append(index.lookupBlocks, n)
- index.lookupBlockIdx[h] = v
- }
- n.value = v
- } else {
- v, ok := index.valueBlockIdx[h]
- if !ok {
- if c := n.countSparseEntries(); c > maxSparseEntries {
- v = len(index.valueBlocks) - blockOffset
- index.valueBlocks = append(index.valueBlocks, n)
- index.valueBlockIdx[h] = v
- } else {
- v = -len(index.sparseOffset)
- index.sparseBlocks = append(index.sparseBlocks, n)
- index.sparseOffset = append(index.sparseOffset, uint16(index.sparseCount))
- index.sparseCount += c + 1
- index.valueBlockIdx[h] = v
- }
- }
- n.value = v
- }
- return n.value
-}
-
-func printValueBlock(nr int, n *trieNode, offset int) {
- boff := nr * blockSize
- fmt.Printf("\n// Block %#x, offset %#x", nr, boff)
- var printnewline bool
- for i := 0; i < blockSize; i++ {
- if i%6 == 0 {
- printnewline = true
- }
- v := 0
- if nn := n.table[i+offset]; nn != nil {
- v = nn.value
- }
- if v != 0 {
- if printnewline {
- fmt.Printf("\n")
- printnewline = false
- }
- fmt.Printf("%#04x:%#04x, ", boff+i, v)
- }
- }
-}
-
-func printSparseBlock(nr int, n *trieNode) {
- boff := -n.value
- fmt.Printf("\n// Block %#x, offset %#x", nr, boff)
- v := 0
- //stride := f(n)
- stride := n.mostFrequentStride()
- c := n.countSparseEntries()
- fmt.Printf("\n{value:%#04x,lo:%#02x},", stride, uint8(c))
- for i, nn := range n.table[0x80 : 0x80+blockSize] {
- nv := 0
- if nn != nil {
- nv = nn.value
- }
- if nv-v != stride {
- if v != 0 {
- fmt.Printf(",hi:%#02x},", 0x80+i-1)
- }
- if nv != 0 {
- fmt.Printf("\n{value:%#04x,lo:%#02x", nv, nn.b)
- }
- }
- v = nv
- }
- if v != 0 {
- fmt.Printf(",hi:%#02x},", 0x80+blockSize-1)
- }
-}
-
-func printLookupBlock(nr int, n *trieNode, offset, cutoff int) {
- boff := nr * blockSize
- fmt.Printf("\n// Block %#x, offset %#x", nr, boff)
- var printnewline bool
- for i := 0; i < blockSize; i++ {
- if i%8 == 0 {
- printnewline = true
- }
- v := 0
- if nn := n.table[i+offset]; nn != nil {
- v = nn.value
- }
- if v != 0 {
- if v < 0 {
- v = -v - 1 + cutoff
- }
- if printnewline {
- fmt.Printf("\n")
- printnewline = false
- }
- fmt.Printf("%#03x:%#02x, ", boff+i, v)
- }
- }
-}
-
-// printTables returns the size in bytes of the generated tables.
-func (t *trieNode) printTables(name string) int {
- index := newIndex()
- // Values for 7-bit ASCII are stored in first two block, followed by nil block.
- index.valueBlocks = append(index.valueBlocks, nil, nil, nil)
- // First byte of multi-byte UTF-8 codepoints are indexed in 4th block.
- index.lookupBlocks = append(index.lookupBlocks, nil, nil, nil, nil)
- // Index starter bytes of multi-byte UTF-8.
- for i := 0xC0; i < 0x100; i++ {
- if t.table[i] != nil {
- computeOffsets(index, t.table[i])
- }
- }
-
- nv := len(index.valueBlocks) * blockSize
- fmt.Printf("// %sValues: %d entries, %d bytes\n", name, nv, nv*2)
- fmt.Printf("// Block 2 is the null block.\n")
- fmt.Printf("var %sValues = [%d]uint16 {", name, nv)
- printValueBlock(0, t, 0)
- printValueBlock(1, t, 64)
- printValueBlock(2, newNode(), 0)
- for i := 3; i < len(index.valueBlocks); i++ {
- printValueBlock(i, index.valueBlocks[i], 0x80)
- }
- fmt.Print("\n}\n\n")
-
- ls := len(index.sparseBlocks)
- fmt.Printf("// %sSparseOffset: %d entries, %d bytes\n", name, ls, ls*2)
- fmt.Printf("var %sSparseOffset = %#v\n\n", name, index.sparseOffset[1:])
-
- ns := index.sparseCount
- fmt.Printf("// %sSparseValues: %d entries, %d bytes\n", name, ns, ns*4)
- fmt.Printf("var %sSparseValues = [%d]valueRange {", name, ns)
- for i, n := range index.sparseBlocks {
- printSparseBlock(i, n)
- }
- fmt.Print("\n}\n\n")
-
- cutoff := len(index.valueBlocks) - blockOffset
- ni := len(index.lookupBlocks) * blockSize
- fmt.Printf("// %sLookup: %d bytes\n", name, ni)
- fmt.Printf("// Block 0 is the null block.\n")
- fmt.Printf("var %sLookup = [%d]uint8 {", name, ni)
- printLookupBlock(0, newNode(), 0, cutoff)
- printLookupBlock(1, newNode(), 0, cutoff)
- printLookupBlock(2, newNode(), 0, cutoff)
- printLookupBlock(3, t, 0xC0, cutoff)
- for i := 4; i < len(index.lookupBlocks); i++ {
- printLookupBlock(i, index.lookupBlocks[i], 0x80, cutoff)
- }
- fmt.Print("\n}\n\n")
- fmt.Printf("var %sTrie = trie{ %sLookup[:], %sValues[:], %sSparseValues[:], %sSparseOffset[:], %d}\n\n",
- name, name, name, name, name, cutoff)
- return nv*2 + ns*4 + ni + ls*2
-}
diff --git a/src/pkg/fmt/doc.go b/src/pkg/fmt/doc.go
index 3cd02d7ed..b8dd995c7 100644
--- a/src/pkg/fmt/doc.go
+++ b/src/pkg/fmt/doc.go
@@ -138,6 +138,16 @@
by a single character (the verb) and end with a parenthesized
description.
+ If an Error or String method triggers a panic when called by a
+ print routine, the fmt package reformats the error message
+ from the panic, decorating it with an indication that it came
+ through the fmt package. For example, if a String method
+ calls panic("bad"), the resulting formatted message will look
+ like
+ %s(PANIC=bad)
+
+ The %s just shows the print verb in use when the failure
+ occurred.
Scanning
diff --git a/src/pkg/fmt/fmt_test.go b/src/pkg/fmt/fmt_test.go
index af4b5c8f8..20b723a99 100644
--- a/src/pkg/fmt/fmt_test.go
+++ b/src/pkg/fmt/fmt_test.go
@@ -9,6 +9,7 @@ import (
. "fmt"
"io"
"math"
+ "runtime"
"strings"
"testing"
"time"
@@ -496,6 +497,9 @@ var fmttests = []struct {
// causing +2+0i and +3+0i instead of 2+0i and 3+0i.
{"%v", []complex64{1, 2, 3}, "[(1+0i) (2+0i) (3+0i)]"},
{"%v", []complex128{1, 2, 3}, "[(1+0i) (2+0i) (3+0i)]"},
+
+ // Incomplete format specification caused crash.
+ {"%.", 3, "%!.(int=3)"},
}
func TestSprintf(t *testing.T) {
@@ -601,6 +605,9 @@ var mallocTest = []struct {
var _ bytes.Buffer
func TestCountMallocs(t *testing.T) {
+ if runtime.GOMAXPROCS(0) > 1 {
+ t.Skip("skipping; GOMAXPROCS>1")
+ }
for _, mt := range mallocTest {
mallocs := testing.AllocsPerRun(100, mt.fn)
if got, max := mallocs, float64(mt.count); got > max {
diff --git a/src/pkg/fmt/print.go b/src/pkg/fmt/print.go
index 7d7aa93b2..5f37fd120 100644
--- a/src/pkg/fmt/print.go
+++ b/src/pkg/fmt/print.go
@@ -47,7 +47,7 @@ type State interface {
}
// Formatter is the interface implemented by values with a custom formatter.
-// The implementation of Format may call Sprintf or Fprintf(f) etc.
+// The implementation of Format may call Sprint(f) or Fprint(f) etc.
// to generate its output.
type Formatter interface {
Format(f State, c rune)
@@ -56,7 +56,8 @@ type Formatter interface {
// Stringer is implemented by any value that has a String method,
// which defines the ``native'' format for that value.
// The String method is used to print values passed as an operand
-// to a %s or %v format or to an unformatted printer such as Print.
+// to any format that accepts a string or to an unformatted printer
+// such as Print.
type Stringer interface {
String() string
}
@@ -1071,7 +1072,7 @@ func (p *pp) doPrintf(format string, a []interface{}) {
p.fmt.wid, p.fmt.widPresent, i = parsenum(format, i, end)
}
// do we have precision?
- if i < end && format[i] == '.' {
+ if i+1 < end && format[i] == '.' {
if format[i+1] == '*' {
p.fmt.prec, p.fmt.precPresent, i, fieldnum = intFromArg(a, end, i+1, fieldnum)
if !p.fmt.precPresent {
diff --git a/src/pkg/go/ast/filter.go b/src/pkg/go/ast/filter.go
index 4db5814cb..71c9ed776 100644
--- a/src/pkg/go/ast/filter.go
+++ b/src/pkg/go/ast/filter.go
@@ -284,6 +284,27 @@ const (
FilterImportDuplicates
)
+// nameOf returns the function (foo) or method name (foo.bar) for
+// the given function declaration. If the AST is incorrect for the
+// receiver, it assumes a function instead.
+//
+func nameOf(f *FuncDecl) string {
+ if r := f.Recv; r != nil && len(r.List) == 1 {
+ // looks like a correct receiver declaration
+ t := r.List[0].Type
+ // dereference pointer receiver types
+ if p, _ := t.(*StarExpr); p != nil {
+ t = p.X
+ }
+ // the receiver type must be a type name
+ if p, _ := t.(*Ident); p != nil {
+ return p.Name + "." + f.Name.Name
+ }
+ // otherwise assume a function instead
+ }
+ return f.Name.Name
+}
+
// separator is an empty //-style comment that is interspersed between
// different comment groups when they are concatenated into a single group
//
@@ -348,7 +369,7 @@ func MergePackageFiles(pkg *Package, mode MergeMode) *File {
var decls []Decl
if ndecls > 0 {
decls = make([]Decl, ndecls)
- funcs := make(map[string]int) // map of global function name -> decls index
+ funcs := make(map[string]int) // map of func name -> decls index
i := 0 // current index
n := 0 // number of filtered entries
for _, filename := range filenames {
@@ -365,7 +386,7 @@ func MergePackageFiles(pkg *Package, mode MergeMode) *File {
// entities (const, type, vars) if
// multiple declarations are common.
if f, isFun := d.(*FuncDecl); isFun {
- name := f.Name.Name
+ name := nameOf(f)
if j, exists := funcs[name]; exists {
// function declared already
if decls[j] != nil && decls[j].(*FuncDecl).Doc == nil {
diff --git a/src/pkg/go/ast/filter_test.go b/src/pkg/go/ast/filter_test.go
new file mode 100644
index 000000000..9fd86cb46
--- /dev/null
+++ b/src/pkg/go/ast/filter_test.go
@@ -0,0 +1,86 @@
+// 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.
+
+// To avoid a cyclic dependency with go/parser, this file is in a separate package.
+
+package ast_test
+
+import (
+ "bytes"
+ "go/ast"
+ "go/format"
+ "go/parser"
+ "go/token"
+ "testing"
+)
+
+const input = `package p
+
+type t1 struct{}
+type t2 struct{}
+
+func f1() {}
+func f1() {}
+func f2() {}
+
+func (*t1) f1() {}
+func (t1) f1() {}
+func (t1) f2() {}
+
+func (t2) f1() {}
+func (t2) f2() {}
+func (x *t2) f2() {}
+`
+
+// Calling ast.MergePackageFiles with ast.FilterFuncDuplicates
+// keeps a duplicate entry with attached documentation in favor
+// of one without, and it favors duplicate entries appearing
+// later in the source over ones appearing earlier. This is why
+// (*t2).f2 is kept and t2.f2 is eliminated in this test case.
+//
+const golden = `package p
+
+type t1 struct{}
+type t2 struct{}
+
+func f1() {}
+func f2() {}
+
+func (t1) f1() {}
+func (t1) f2() {}
+
+func (t2) f1() {}
+
+func (x *t2) f2() {}
+`
+
+func TestFilterDuplicates(t *testing.T) {
+ // parse input
+ fset := token.NewFileSet()
+ file, err := parser.ParseFile(fset, "", input, 0)
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ // create package
+ files := map[string]*ast.File{"": file}
+ pkg, err := ast.NewPackage(fset, files, nil, nil)
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ // filter
+ merged := ast.MergePackageFiles(pkg, ast.FilterFuncDuplicates)
+
+ // pretty-print
+ var buf bytes.Buffer
+ if err := format.Node(&buf, fset, merged); err != nil {
+ t.Fatal(err)
+ }
+ output := buf.String()
+
+ if output != golden {
+ t.Errorf("incorrect output:\n%s", output)
+ }
+}
diff --git a/src/pkg/go/ast/print.go b/src/pkg/go/ast/print.go
index 4a1ce480f..f15dc11dc 100644
--- a/src/pkg/go/ast/print.go
+++ b/src/pkg/go/ast/print.go
@@ -34,7 +34,7 @@ func NotNilFilter(_ string, v reflect.Value) bool {
//
// A non-nil FieldFilter f may be provided to control the output:
// struct fields for which f(fieldname, fieldvalue) is true are
-// are printed; all others are filtered from the output. Unexported
+// 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) {
diff --git a/src/pkg/go/build/build.go b/src/pkg/go/build/build.go
index 16c3da458..cc89afb21 100644
--- a/src/pkg/go/build/build.go
+++ b/src/pkg/go/build/build.go
@@ -27,15 +27,31 @@ import (
// A Context specifies the supporting context for a build.
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
- BuildTags []string // additional tags to recognize in +build lines
- InstallTag string // package install directory suffix
- UseAllFiles bool // use files regardless of +build lines, file names
- Compiler string // compiler to assume when computing target paths
+ 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
+
+ // The build and release tags specify build constraints
+ // that should be considered satisfied when processing +build lines.
+ // Clients creating a new context may customize BuildTags, which
+ // defaults to empty, but it is usually an error to customize ReleaseTags,
+ // which defaults to the list of Go releases the current release is compatible with.
+ // In addition to the BuildTags and ReleaseTags, build constraints
+ // consider the values of GOARCH and GOOS as satisfied tags.
+ BuildTags []string
+ ReleaseTags []string
+
+ // The install suffix specifies a suffix to use in the name of the installation
+ // directory. By default it is empty, but custom builds that need to keep
+ // their outputs separate can set InstallSuffix to do so. For example, when
+ // using the race detector, the go command uses InstallSuffix = "race", so
+ // that on a Linux/386 system, packages are written to a directory named
+ // "linux_386_race" instead of the usual "linux_386".
+ InstallSuffix string
// By default, Import uses the operating system's file system calls
// to read directories and files. To read from other sources,
@@ -196,8 +212,8 @@ func (ctxt *Context) gopath() []string {
// Do not get confused by this common mistake.
continue
}
- if strings.Contains(p, "~") && runtime.GOOS != "windows" {
- // Path segments containing ~ on Unix are almost always
+ if strings.HasPrefix(p, "~") {
+ // Path segments starting with ~ on Unix are almost always
// users who have incorrectly quoted ~ while setting GOPATH,
// preventing it from expanding to $HOME.
// The situation is made more confusing by the fact that
@@ -246,6 +262,7 @@ var cgoEnabled = map[string]bool{
"darwin/amd64": true,
"freebsd/386": true,
"freebsd/amd64": true,
+ "freebsd/arm": true,
"linux/386": true,
"linux/amd64": true,
"linux/arm": true,
@@ -267,13 +284,30 @@ func defaultContext() Context {
c.GOPATH = envOr("GOPATH", "")
c.Compiler = runtime.Compiler
+ // Each major Go release in the Go 1.x series should add a tag here.
+ // Old tags should not be removed. That is, the go1.x tag is present
+ // 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".
+ //
+ // When we reach Go 1.3 the line will read
+ // c.ReleaseTags = []string{"go1.1", "go1.2", "go1.3"}
+ // and so on.
+ c.ReleaseTags = []string{"go1.1"}
+
switch os.Getenv("CGO_ENABLED") {
case "1":
c.CgoEnabled = true
case "0":
c.CgoEnabled = false
default:
- c.CgoEnabled = cgoEnabled[c.GOOS+"/"+c.GOARCH]
+ // golang.org/issue/5141
+ // cgo should be disabled for cross compilation builds
+ if runtime.GOARCH == c.GOARCH && runtime.GOOS == c.GOOS {
+ c.CgoEnabled = cgoEnabled[c.GOOS+"/"+c.GOARCH]
+ break
+ }
+ c.CgoEnabled = false
}
return c
@@ -397,11 +431,11 @@ func (ctxt *Context) Import(path string, srcDir string, mode ImportMode) (*Packa
dir, elem := pathpkg.Split(p.ImportPath)
pkga = "pkg/gccgo/" + dir + "lib" + elem + ".a"
case "gc":
- tag := ""
- if ctxt.InstallTag != "" {
- tag = "_" + ctxt.InstallTag
+ suffix := ""
+ if ctxt.InstallSuffix != "" {
+ suffix = "_" + ctxt.InstallSuffix
}
- pkga = "pkg/" + ctxt.GOOS + "_" + ctxt.GOARCH + tag + "/" + p.ImportPath + ".a"
+ pkga = "pkg/" + ctxt.GOOS + "_" + ctxt.GOARCH + suffix + "/" + p.ImportPath + ".a"
default:
// Save error for end of function.
pkgerr = fmt.Errorf("import %q: unknown compiler %q", path, ctxt.Compiler)
@@ -458,7 +492,7 @@ func (ctxt *Context) Import(path string, srcDir string, mode ImportMode) (*Packa
return p, fmt.Errorf("import %q: cannot import absolute path", path)
}
- // tried records the location of unsucsessful package lookups
+ // tried records the location of unsuccessful package lookups
var tried struct {
goroot string
gopath []string
@@ -970,8 +1004,8 @@ func splitQuoted(s string) (r []string, err error) {
// !cgo (if cgo is disabled)
// ctxt.Compiler
// !ctxt.Compiler
-// tag (if tag is listed in ctxt.BuildTags)
-// !tag (if tag is not listed in ctxt.BuildTags)
+// tag (if tag is listed in ctxt.BuildTags or ctxt.ReleaseTags)
+// !tag (if tag is not listed in ctxt.BuildTags or ctxt.ReleaseTags)
// a comma-separated list of any of these
//
func (ctxt *Context) match(name string) bool {
@@ -989,10 +1023,10 @@ func (ctxt *Context) match(name string) bool {
return len(name) > 1 && !ctxt.match(name[1:])
}
- // Tags must be letters, digits, underscores.
+ // Tags must be letters, digits, underscores or dots.
// Unlike in Go identifiers, all digits are fine (e.g., "386").
for _, c := range name {
- if !unicode.IsLetter(c) && !unicode.IsDigit(c) && c != '_' {
+ if !unicode.IsLetter(c) && !unicode.IsDigit(c) && c != '_' && c != '.' {
return false
}
}
@@ -1011,6 +1045,11 @@ func (ctxt *Context) match(name string) bool {
return true
}
}
+ for _, tag := range ctxt.ReleaseTags {
+ if tag == name {
+ return true
+ }
+ }
return false
}
diff --git a/src/pkg/go/build/deps_test.go b/src/pkg/go/build/deps_test.go
index 9a715ba60..71b1bcf06 100644
--- a/src/pkg/go/build/deps_test.go
+++ b/src/pkg/go/build/deps_test.go
@@ -47,7 +47,7 @@ var pkgDeps = map[string][]string{
"math": {"unsafe"},
"math/cmplx": {"math"},
"math/rand": {"L0", "math"},
- "sort": {"math"},
+ "sort": {},
"strconv": {"L0", "unicode/utf8", "math"},
"unicode/utf16": {},
"unicode/utf8": {},
diff --git a/src/pkg/go/build/doc.go b/src/pkg/go/build/doc.go
index c562d05d0..b5fc071d6 100644
--- a/src/pkg/go/build/doc.go
+++ b/src/pkg/go/build/doc.go
@@ -91,14 +91,22 @@
//
// - the target operating system, as spelled by runtime.GOOS
// - the target architecture, as spelled by runtime.GOARCH
-// - the compiler being used, currently either "gc" or "gccgo"
+// - the compiler being used, either "gc" or "gccgo"
// - "cgo", if ctxt.CgoEnabled is true
+// - "go1.1", from Go version 1.1 onward
// - any additional words listed in ctxt.BuildTags
//
// If a file's name, after stripping the extension and a possible _test suffix,
-// matches *_GOOS, *_GOARCH, or *_GOOS_GOARCH for any known operating
-// system and architecture values, then the file is considered to have an implicit
-// build constraint requiring those terms.
+// matches any of the following patterns:
+// *_GOOS
+// *_GOARCH
+// *_GOOS_GOARCH
+// (example: source_windows_amd64.go) or the literals:
+// GOOS
+// GOARCH
+// (example: windows.go) where GOOS and GOARCH represent any known operating
+// system and architecture values respectively, then the file is considered to
+// have an implicit build constraint requiring those terms.
//
// To keep a file from being considered for the build:
//
diff --git a/src/pkg/go/doc/doc.go b/src/pkg/go/doc/doc.go
index 65b1b83eb..4264940a0 100644
--- a/src/pkg/go/doc/doc.go
+++ b/src/pkg/go/doc/doc.go
@@ -17,17 +17,11 @@ type Package struct {
ImportPath string
Imports []string
Filenames []string
+ Notes map[string][]*Note
// DEPRECATED. For backward compatibility Bugs is still populated,
// but all new code should use Notes instead.
Bugs []string
- // Notes such as TODO(userid): or SECURITY(userid):
- // along the lines of BUG(userid). Any marker with 2 or more upper
- // case [A-Z] letters is recognised.
- // BUG is explicitly not included in these notes but will
- // be in a subsequent change when the Bugs field above is removed.
- Notes map[string][]string
-
// declarations
Consts []*Value
Types []*Type
@@ -70,6 +64,16 @@ type Func struct {
Level int // embedding level; 0 means not embedded
}
+// A Note represents a marked comment starting with "MARKER(uid): note body".
+// Any note with a marker of 2 or more upper case [A-Z] letters and a uid of
+// at least one character is recognized. The ":" following the uid is optional.
+// Notes are collected in the Package.Notes map indexed by the notes marker.
+type Note struct {
+ Pos, End token.Pos // position range of the comment containing the marker
+ UID string // uid found with the marker
+ Body string // note body text
+}
+
// Mode values control the operation of New.
type Mode int
@@ -97,8 +101,8 @@ func New(pkg *ast.Package, importPath string, mode Mode) *Package {
ImportPath: importPath,
Imports: sortedKeys(r.imports),
Filenames: r.filenames,
- Bugs: r.bugs,
Notes: r.notes,
+ Bugs: noteBodies(r.notes["BUG"]),
Consts: sortedValues(r.values, token.CONST),
Types: sortedTypes(r.types, mode&AllMethods != 0),
Vars: sortedValues(r.values, token.VAR),
diff --git a/src/pkg/go/doc/example.go b/src/pkg/go/doc/example.go
index 693ad5b94..2761083c7 100644
--- a/src/pkg/go/doc/example.go
+++ b/src/pkg/go/doc/example.go
@@ -166,6 +166,13 @@ func playExample(file *ast.File, body *ast.BlockStmt) *ast.File {
ast.Inspect(e.X, inspectFunc)
return false
}
+ // For key value expressions, only inspect the value
+ // as the key should be resolved by the type of the
+ // composite literal.
+ if e, ok := n.(*ast.KeyValueExpr); ok {
+ ast.Inspect(e.Value, inspectFunc)
+ return false
+ }
if id, ok := n.(*ast.Ident); ok {
if id.Obj == nil {
unresolved[id.Name] = true
diff --git a/src/pkg/go/doc/example_test.go b/src/pkg/go/doc/example_test.go
index b70efd93d..e0477e3f6 100644
--- a/src/pkg/go/doc/example_test.go
+++ b/src/pkg/go/doc/example_test.go
@@ -18,6 +18,7 @@ const exampleTestFile = `
package foo_test
import (
+ "flag"
"fmt"
"log"
"os/exec"
@@ -35,6 +36,38 @@ func ExampleImport() {
}
fmt.Printf("The date is %s\n", out)
}
+
+func ExampleKeyValue() {
+ v := struct {
+ a string
+ b int
+ }{
+ a: "A",
+ b: 1,
+ }
+ fmt.Print(v)
+ // Output: a: "A", b: 1
+}
+
+func ExampleKeyValueImport() {
+ f := flag.Flag{
+ Name: "play",
+ }
+ fmt.Print(f)
+ // Output: Name: "play"
+}
+
+var keyValueTopDecl = struct {
+ a string
+ b int
+}{
+ a: "B",
+ b: 2,
+}
+
+func ExampleKeyValueTopDecl() {
+ fmt.Print(keyValueTopDecl)
+}
`
var exampleTestCases = []struct {
@@ -49,6 +82,20 @@ var exampleTestCases = []struct {
Name: "Import",
Play: exampleImportPlay,
},
+ {
+ Name: "KeyValue",
+ Play: exampleKeyValuePlay,
+ Output: "a: \"A\", b: 1\n",
+ },
+ {
+ Name: "KeyValueImport",
+ Play: exampleKeyValueImportPlay,
+ Output: "Name: \"play\"\n",
+ },
+ {
+ Name: "KeyValueTopDecl",
+ Play: "<nil>",
+ },
}
const exampleHelloPlay = `package main
@@ -78,6 +125,39 @@ func main() {
}
`
+const exampleKeyValuePlay = `package main
+
+import (
+ "fmt"
+)
+
+func main() {
+ v := struct {
+ a string
+ b int
+ }{
+ a: "A",
+ b: 1,
+ }
+ fmt.Print(v)
+}
+`
+
+const exampleKeyValueImportPlay = `package main
+
+import (
+ "flag"
+ "fmt"
+)
+
+func main() {
+ f := flag.Flag{
+ Name: "play",
+ }
+ fmt.Print(f)
+}
+`
+
func TestExamples(t *testing.T) {
fs := token.NewFileSet()
file, err := parser.ParseFile(fs, "test.go", strings.NewReader(exampleTestFile), parser.ParseComments)
diff --git a/src/pkg/go/doc/filter.go b/src/pkg/go/doc/filter.go
index 02b66ccef..a6f243f33 100644
--- a/src/pkg/go/doc/filter.go
+++ b/src/pkg/go/doc/filter.go
@@ -94,7 +94,7 @@ func filterTypes(a []*Type, f Filter) []*Type {
}
// Filter eliminates documentation for names that don't pass through the filter f.
-// TODO: Recognize "Type.Method" as a name.
+// TODO(gri): Recognize "Type.Method" as a name.
//
func (p *Package) Filter(f Filter) {
p.Consts = filterValues(p.Consts, f)
diff --git a/src/pkg/go/doc/reader.go b/src/pkg/go/doc/reader.go
index dd6a57299..4fa6fd9d5 100644
--- a/src/pkg/go/doc/reader.go
+++ b/src/pkg/go/doc/reader.go
@@ -148,8 +148,7 @@ type reader struct {
// package properties
doc string // package documentation, if any
filenames []string
- bugs []string
- notes map[string][]string
+ notes map[string][]*Note
// declarations
imports map[string]int
@@ -401,21 +400,55 @@ func (r *reader) readFunc(fun *ast.FuncDecl) {
}
var (
- noteMarker = regexp.MustCompile(`^/[/*][ \t]*([A-Z][A-Z]+)\(.+\):[ \t]*(.*)`) // MARKER(uid)
- noteContent = regexp.MustCompile(`[^ \n\r\t]+`) // at least one non-whitespace char
+ noteMarker = `([A-Z][A-Z]+)\(([^)]+)\):?` // MARKER(uid), MARKER at least 2 chars, uid at least 1 char
+ noteMarkerRx = regexp.MustCompile(`^[ \t]*` + noteMarker) // MARKER(uid) at text start
+ noteCommentRx = regexp.MustCompile(`^/[/*][ \t]*` + noteMarker) // MARKER(uid) at comment start
)
-func readNote(c *ast.CommentGroup) (marker, annotation string) {
- text := c.List[0].Text
- if m := noteMarker.FindStringSubmatch(text); m != nil {
- if btxt := m[2]; noteContent.MatchString(btxt) {
- // non-empty MARKER comment; collect comment without the MARKER prefix
- list := append([]*ast.Comment(nil), c.List...) // make a copy
- list[0].Text = m[2]
- return m[1], (&ast.CommentGroup{List: list}).Text()
+// readNote collects a single note from a sequence of comments.
+//
+func (r *reader) readNote(list []*ast.Comment) {
+ text := (&ast.CommentGroup{List: list}).Text()
+ if m := noteMarkerRx.FindStringSubmatchIndex(text); m != nil {
+ // The note body starts after the marker.
+ // We remove any formatting so that we don't
+ // get spurious line breaks/indentation when
+ // showing the TODO body.
+ body := clean(text[m[1]:])
+ if body != "" {
+ marker := text[m[2]:m[3]]
+ r.notes[marker] = append(r.notes[marker], &Note{
+ Pos: list[0].Pos(),
+ End: list[len(list)-1].End(),
+ UID: text[m[4]:m[5]],
+ Body: body,
+ })
+ }
+ }
+}
+
+// readNotes extracts notes from comments.
+// A note must start at the beginning of a comment with "MARKER(uid):"
+// and is followed by the note body (e.g., "// BUG(gri): fix this").
+// The note ends at the end of the comment group or at the start of
+// another note in the same comment group, whichever comes first.
+//
+func (r *reader) readNotes(comments []*ast.CommentGroup) {
+ for _, group := range comments {
+ i := -1 // comment index of most recent note start, valid if >= 0
+ list := group.List
+ for j, c := range list {
+ if noteCommentRx.MatchString(c.Text) {
+ if i >= 0 {
+ r.readNote(list[i:j])
+ }
+ i = j
+ }
+ }
+ if i >= 0 {
+ r.readNote(list[i:])
}
}
- return "", ""
}
// readFile adds the AST for a source file to the reader.
@@ -484,14 +517,7 @@ func (r *reader) readFile(src *ast.File) {
}
// collect MARKER(...): annotations
- for _, c := range src.Comments {
- if marker, text := readNote(c); marker != "" {
- r.notes[marker] = append(r.notes[marker], text)
- if marker == "BUG" {
- r.bugs = append(r.bugs, text)
- }
- }
- }
+ r.readNotes(src.Comments)
src.Comments = nil // consumed unassociated comments - remove from AST
}
@@ -502,7 +528,7 @@ func (r *reader) readPackage(pkg *ast.Package, mode Mode) {
r.mode = mode
r.types = make(map[string]*namedType)
r.funcs = make(methodSet)
- r.notes = make(map[string][]string)
+ r.notes = make(map[string][]*Note)
// sort package files before reading them so that the
// result does not depend on map iteration order
@@ -533,10 +559,13 @@ func customizeRecv(f *Func, recvTypeName string, embeddedIsPtr bool, level int)
// copy existing receiver field and set new type
newField := *f.Decl.Recv.List[0]
+ origPos := newField.Type.Pos()
_, origRecvIsPtr := newField.Type.(*ast.StarExpr)
- var typ ast.Expr = ast.NewIdent(recvTypeName)
+ newIdent := &ast.Ident{NamePos: origPos, Name: recvTypeName}
+ var typ ast.Expr = newIdent
if !embeddedIsPtr && origRecvIsPtr {
- typ = &ast.StarExpr{X: typ}
+ newIdent.NamePos++ // '*' is one character
+ typ = &ast.StarExpr{Star: origPos, X: newIdent}
}
newField.Type = typ
@@ -761,6 +790,17 @@ func sortedFuncs(m methodSet, allMethods bool) []*Func {
return list
}
+// noteBodies returns a list of note body strings given a list of notes.
+// This is only used to populate the deprecated Package.Bugs field.
+//
+func noteBodies(notes []*Note) []string {
+ var list []string
+ for _, n := range notes {
+ list = append(list, n.Body)
+ }
+ return list
+}
+
// ----------------------------------------------------------------------------
// Predeclared identifiers
diff --git a/src/pkg/go/doc/testdata/a.0.golden b/src/pkg/go/doc/testdata/a.0.golden
index ae3756c84..cd98f4e0e 100644
--- a/src/pkg/go/doc/testdata/a.0.golden
+++ b/src/pkg/go/doc/testdata/a.0.golden
@@ -9,16 +9,24 @@ FILENAMES
testdata/a1.go
BUGS .Bugs is now deprecated, please use .Notes instead
- // bug0
- // bug1
+ // bug0
+ // bug1
BUGS
- // bug0
- // bug1
+ // bug0 (uid: uid)
+ // bug1 (uid: uid)
+
+NOTES
+ // 1 of 4 - this is the first line of note 1 - note 1 continues on ... (uid: foo)
+ // 2 of 4 (uid: foo)
+ // 3 of 4 (uid: bar)
+ // 4 of 4 - this is the last line of note 4 (uid: bar)
+ // This note which contains a (parenthesized) subphrase must ... (uid: bam)
+ // The ':' after the marker and uid is optional. (uid: xxx)
SECBUGS
- // sec hole 0 need to fix asap
+ // sec hole 0 need to fix asap (uid: uid)
TODOS
- // todo0
- // todo1
+ // todo0 (uid: uid)
+ // todo1 (uid: uid)
diff --git a/src/pkg/go/doc/testdata/a.1.golden b/src/pkg/go/doc/testdata/a.1.golden
index ae3756c84..cd98f4e0e 100644
--- a/src/pkg/go/doc/testdata/a.1.golden
+++ b/src/pkg/go/doc/testdata/a.1.golden
@@ -9,16 +9,24 @@ FILENAMES
testdata/a1.go
BUGS .Bugs is now deprecated, please use .Notes instead
- // bug0
- // bug1
+ // bug0
+ // bug1
BUGS
- // bug0
- // bug1
+ // bug0 (uid: uid)
+ // bug1 (uid: uid)
+
+NOTES
+ // 1 of 4 - this is the first line of note 1 - note 1 continues on ... (uid: foo)
+ // 2 of 4 (uid: foo)
+ // 3 of 4 (uid: bar)
+ // 4 of 4 - this is the last line of note 4 (uid: bar)
+ // This note which contains a (parenthesized) subphrase must ... (uid: bam)
+ // The ':' after the marker and uid is optional. (uid: xxx)
SECBUGS
- // sec hole 0 need to fix asap
+ // sec hole 0 need to fix asap (uid: uid)
TODOS
- // todo0
- // todo1
+ // todo0 (uid: uid)
+ // todo1 (uid: uid)
diff --git a/src/pkg/go/doc/testdata/a.2.golden b/src/pkg/go/doc/testdata/a.2.golden
index ae3756c84..cd98f4e0e 100644
--- a/src/pkg/go/doc/testdata/a.2.golden
+++ b/src/pkg/go/doc/testdata/a.2.golden
@@ -9,16 +9,24 @@ FILENAMES
testdata/a1.go
BUGS .Bugs is now deprecated, please use .Notes instead
- // bug0
- // bug1
+ // bug0
+ // bug1
BUGS
- // bug0
- // bug1
+ // bug0 (uid: uid)
+ // bug1 (uid: uid)
+
+NOTES
+ // 1 of 4 - this is the first line of note 1 - note 1 continues on ... (uid: foo)
+ // 2 of 4 (uid: foo)
+ // 3 of 4 (uid: bar)
+ // 4 of 4 - this is the last line of note 4 (uid: bar)
+ // This note which contains a (parenthesized) subphrase must ... (uid: bam)
+ // The ':' after the marker and uid is optional. (uid: xxx)
SECBUGS
- // sec hole 0 need to fix asap
+ // sec hole 0 need to fix asap (uid: uid)
TODOS
- // todo0
- // todo1
+ // todo0 (uid: uid)
+ // todo1 (uid: uid)
diff --git a/src/pkg/go/doc/testdata/a0.go b/src/pkg/go/doc/testdata/a0.go
index 71af470ee..2420c8a48 100644
--- a/src/pkg/go/doc/testdata/a0.go
+++ b/src/pkg/go/doc/testdata/a0.go
@@ -15,3 +15,26 @@ package a
// SECBUG(uid): sec hole 0
// need to fix asap
+
+// Multiple notes may be in the same comment group and should be
+// recognized individually. Notes may start in the middle of a
+// comment group as long as they start at the beginning of an
+// individual comment.
+//
+// NOTE(foo): 1 of 4 - this is the first line of note 1
+// - note 1 continues on this 2nd line
+// - note 1 continues on this 3rd line
+// NOTE(foo): 2 of 4
+// NOTE(bar): 3 of 4
+/* NOTE(bar): 4 of 4 */
+// - this is the last line of note 4
+//
+//
+
+// NOTE(bam): This note which contains a (parenthesized) subphrase
+// must appear in its entirety.
+
+// NOTE(xxx) The ':' after the marker and uid is optional.
+
+// NOTE(): NO uid - should not show up.
+// NOTE() NO uid - should not show up.
diff --git a/src/pkg/go/doc/testdata/template.txt b/src/pkg/go/doc/testdata/template.txt
index d3882b6b9..26482f7c2 100644
--- a/src/pkg/go/doc/testdata/template.txt
+++ b/src/pkg/go/doc/testdata/template.txt
@@ -64,5 +64,5 @@ BUGS .Bugs is now deprecated, please use .Notes instead
{{range .}} {{synopsis .}}
{{end}}{{end}}{{with .Notes}}{{range $marker, $content := .}}
{{$marker}}S
-{{range $content}} {{synopsis .}}
+{{range $content}} {{synopsis .Body}} (uid: {{.UID}})
{{end}}{{end}}{{end}} \ No newline at end of file
diff --git a/src/pkg/go/format/format.go b/src/pkg/go/format/format.go
index 65b0e4e4b..3d00a645d 100644
--- a/src/pkg/go/format/format.go
+++ b/src/pkg/go/format/format.go
@@ -69,15 +69,14 @@ func Node(dst io.Writer, fset *token.FileSet, node interface{}) error {
return config.Fprint(dst, fset, node)
}
-// Source formats src in canonical gofmt style and writes the result to dst
-// or returns an I/O or syntax error. src is expected to be a syntactically
+// Source formats src in canonical gofmt style and returns the result
+// or an (I/O or syntax) error. src is expected to be a syntactically
// correct Go source file, or a list of Go declarations or statements.
//
// If src is a partial source file, the leading and trailing space of src
// is applied to the result (such that it has the same leading and trailing
-// space as src), and the formatted src is indented by the same amount as
-// the first line of src containing code. Imports are not sorted for partial
-// source files.
+// space as src), and the result is indented by the same amount as the first
+// line of src containing code. Imports are not sorted for partial source files.
//
func Source(src []byte) ([]byte, error) {
fset := token.NewFileSet()
diff --git a/src/pkg/go/parser/error_test.go b/src/pkg/go/parser/error_test.go
index b59fda11a..d4d4f909d 100644
--- a/src/pkg/go/parser/error_test.go
+++ b/src/pkg/go/parser/error_test.go
@@ -89,8 +89,6 @@ func expectedErrors(t *testing.T, filename string, src []byte) map[token.Pos]str
prev = pos
}
}
-
- panic("unreachable")
}
// compareErrors compares the map of expected error messages with the list
diff --git a/src/pkg/go/parser/interface.go b/src/pkg/go/parser/interface.go
index 39affdd6b..149257ca6 100644
--- a/src/pkg/go/parser/interface.go
+++ b/src/pkg/go/parser/interface.go
@@ -162,16 +162,27 @@ func ParseDir(fset *token.FileSet, path string, filter func(os.FileInfo) bool, m
}
// ParseExpr is a convenience function for obtaining the AST of an expression x.
-// The position information recorded in the AST is undefined.
+// The position information recorded in the AST is undefined. The filename used
+// in error messages is the empty string.
//
func ParseExpr(x string) (ast.Expr, error) {
- // parse x within the context of a complete package for correct scopes;
- // use //line directive for correct positions in error messages and put
- // x alone on a separate line (handles line comments), followed by a ';'
- // to force an error if the expression is incomplete
- file, err := ParseFile(token.NewFileSet(), "", "package p;func _(){_=\n//line :1\n"+x+"\n;}", 0)
- if err != nil {
- return nil, err
+ var p parser
+ p.init(token.NewFileSet(), "", []byte(x), 0)
+
+ // Set up pkg-level scopes to avoid nil-pointer errors.
+ // This is not needed for a correct expression x as the
+ // parser will be ok with a nil topScope, but be cautious
+ // in case of an erroneous x.
+ p.openScope()
+ p.pkgScope = p.topScope
+ e := p.parseRhsOrType()
+ p.closeScope()
+ assert(p.topScope == nil, "unbalanced scopes")
+
+ if p.errors.Len() > 0 {
+ p.errors.Sort()
+ return nil, p.errors.Err()
}
- return file.Decls[0].(*ast.FuncDecl).Body.List[0].(*ast.AssignStmt).Rhs[0], nil
+
+ return e, nil
}
diff --git a/src/pkg/go/parser/parser.go b/src/pkg/go/parser/parser.go
index a021a5abe..f4a690a6f 100644
--- a/src/pkg/go/parser/parser.go
+++ b/src/pkg/go/parser/parser.go
@@ -48,7 +48,8 @@ type parser struct {
syncCnt int // number of calls to syncXXX without progress
// Non-syntactic parser control
- exprLev int // < 0: in control clause, >= 0: in expression
+ exprLev int // < 0: in control clause, >= 0: in expression
+ inRhs bool // if set, the parser is parsing a rhs expression
// Ordinary identifier scopes
pkgScope *ast.Scope // pkgScope.Outer == nil
@@ -539,6 +540,8 @@ func (p *parser) parseExprList(lhs bool) (list []ast.Expr) {
}
func (p *parser) parseLhsList() []ast.Expr {
+ old := p.inRhs
+ p.inRhs = false
list := p.parseExprList(true)
switch p.tok {
case token.DEFINE:
@@ -560,11 +563,16 @@ func (p *parser) parseLhsList() []ast.Expr {
p.resolve(x)
}
}
+ p.inRhs = old
return list
}
func (p *parser) parseRhsList() []ast.Expr {
- return p.parseExprList(false)
+ old := p.inRhs
+ p.inRhs = true
+ list := p.parseExprList(false)
+ p.inRhs = old
+ return list
}
// ----------------------------------------------------------------------------
@@ -1505,6 +1513,14 @@ func (p *parser) parseUnaryExpr(lhs bool) ast.Expr {
return p.parsePrimaryExpr(lhs)
}
+func (p *parser) tokPrec() (token.Token, int) {
+ tok := p.tok
+ if p.inRhs && tok == token.ASSIGN {
+ tok = token.EQL
+ }
+ return tok, tok.Precedence()
+}
+
// If lhs is set and the result is an identifier, it is not resolved.
func (p *parser) parseBinaryExpr(lhs bool, prec1 int) ast.Expr {
if p.trace {
@@ -1512,10 +1528,13 @@ func (p *parser) parseBinaryExpr(lhs bool, prec1 int) ast.Expr {
}
x := p.parseUnaryExpr(lhs)
- for prec := p.tok.Precedence(); prec >= prec1; prec-- {
- for p.tok.Precedence() == prec {
- pos, op := p.pos, p.tok
- p.next()
+ 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
@@ -1541,11 +1560,19 @@ func (p *parser) parseExpr(lhs bool) ast.Expr {
}
func (p *parser) parseRhs() ast.Expr {
- return p.checkExpr(p.parseExpr(false))
+ old := p.inRhs
+ p.inRhs = true
+ x := p.checkExpr(p.parseExpr(false))
+ p.inRhs = old
+ return x
}
func (p *parser) parseRhsOrType() ast.Expr {
- return p.checkExprOrType(p.parseExpr(false))
+ old := p.inRhs
+ p.inRhs = true
+ x := p.checkExprOrType(p.parseExpr(false))
+ p.inRhs = old
+ return x
}
// ----------------------------------------------------------------------------
@@ -2091,7 +2118,7 @@ func (p *parser) parseStmt() (s ast.Stmt) {
// ----------------------------------------------------------------------------
// Declarations
-type parseSpecFunction func(p *parser, doc *ast.CommentGroup, keyword token.Token, iota int) ast.Spec
+type parseSpecFunction func(doc *ast.CommentGroup, keyword token.Token, iota int) ast.Spec
func isValidImport(lit string) bool {
const illegalChars = `!"#$%&'()*,:;<=>?[\]^{|}` + "`\uFFFD"
@@ -2210,12 +2237,12 @@ func (p *parser) parseGenDecl(keyword token.Token, f parseSpecFunction) *ast.Gen
lparen = p.pos
p.next()
for iota := 0; p.tok != token.RPAREN && p.tok != token.EOF; iota++ {
- list = append(list, f(p, p.leadComment, keyword, iota))
+ list = append(list, f(p.leadComment, keyword, iota))
}
rparen = p.expect(token.RPAREN)
p.expectSemi()
} else {
- list = append(list, f(p, nil, keyword, 0))
+ list = append(list, f(nil, keyword, 0))
}
return &ast.GenDecl{
@@ -2316,10 +2343,10 @@ func (p *parser) parseDecl(sync func(*parser)) ast.Decl {
var f parseSpecFunction
switch p.tok {
case token.CONST, token.VAR:
- f = (*parser).parseValueSpec
+ f = p.parseValueSpec
case token.TYPE:
- f = (*parser).parseTypeSpec
+ f = p.parseTypeSpec
case token.FUNC:
return p.parseFuncDecl()
@@ -2371,7 +2398,7 @@ func (p *parser) parseFile() *ast.File {
if p.mode&PackageClauseOnly == 0 {
// import decls
for p.tok == token.IMPORT {
- decls = append(decls, p.parseGenDecl(token.IMPORT, (*parser).parseImportSpec))
+ decls = append(decls, p.parseGenDecl(token.IMPORT, p.parseImportSpec))
}
if p.mode&ImportsOnly == 0 {
diff --git a/src/pkg/go/parser/parser_test.go b/src/pkg/go/parser/parser_test.go
index 1960377b0..48813d106 100644
--- a/src/pkg/go/parser/parser_test.go
+++ b/src/pkg/go/parser/parser_test.go
@@ -68,7 +68,7 @@ func TestParseDir(t *testing.T) {
func TestParseExpr(t *testing.T) {
// just kicking the tires:
- // a valid expression
+ // a valid arithmetic expression
src := "a + b"
x, err := ParseExpr(src)
if err != nil {
@@ -79,6 +79,17 @@ func TestParseExpr(t *testing.T) {
t.Errorf("ParseExpr(%s): got %T, expected *ast.BinaryExpr", src, x)
}
+ // a valid type expression
+ src = "struct{x *int}"
+ x, err = ParseExpr(src)
+ if err != nil {
+ t.Fatalf("ParseExpr(%s): %v", src, err)
+ }
+ // sanity check
+ if _, ok := x.(*ast.StructType); !ok {
+ t.Errorf("ParseExpr(%s): got %T, expected *ast.StructType", src, x)
+ }
+
// an invalid expression
src = "a + *"
_, err = ParseExpr(src)
diff --git a/src/pkg/go/parser/short_test.go b/src/pkg/go/parser/short_test.go
index c62f7e050..62277c0d2 100644
--- a/src/pkg/go/parser/short_test.go
+++ b/src/pkg/go/parser/short_test.go
@@ -71,6 +71,9 @@ var invalids = []string{
`package p; func f() { _ = (<-<- /* ERROR "expected 'chan'" */ chan int)(nil) };`,
`package p; func f() { _ = (<-chan<-chan<-chan<-chan<-chan<- /* ERROR "expected channel type" */ int)(nil) };`,
`package p; func f() { var t []int; t /* ERROR "expected identifier on left side of :=" */ [0] := 0 };`,
+ `package p; func f() { if x := g(); x = /* ERROR "expected '=='" */ 0 {}};`,
+ `package p; func f() { _ = x = /* ERROR "expected '=='" */ 0 {}};`,
+ `package p; func f() { _ = 1 == func()int { var x bool; x = x = /* ERROR "expected '=='" */ true; return x }() };`,
}
func TestInvalid(t *testing.T) {
diff --git a/src/pkg/go/printer/nodes.go b/src/pkg/go/printer/nodes.go
index ee0bbf1ed..7cd068e22 100644
--- a/src/pkg/go/printer/nodes.go
+++ b/src/pkg/go/printer/nodes.go
@@ -271,12 +271,12 @@ func (p *printer) parameters(fields *ast.FieldList) {
// if there are multiple parameter names for this par
// or the type is on a separate line)
var parLineBeg int
- var parLineEnd = p.lineFor(par.Type.Pos())
if len(par.Names) > 0 {
parLineBeg = p.lineFor(par.Names[0].Pos())
} else {
- parLineBeg = parLineEnd
+ parLineBeg = p.lineFor(par.Type.Pos())
}
+ var parLineEnd = p.lineFor(par.Type.End())
// separating "," if needed
needsLinebreak := 0 < prevLine && prevLine < parLineBeg
if i > 0 {
diff --git a/src/pkg/go/printer/printer.go b/src/pkg/go/printer/printer.go
index 3c8d23e65..e06d2edfb 100644
--- a/src/pkg/go/printer/printer.go
+++ b/src/pkg/go/printer/printer.go
@@ -395,35 +395,6 @@ func (p *printer) writeCommentPrefix(pos, next token.Position, prev, comment *as
}
}
-// Split comment text into lines
-// (using strings.Split(text, "\n") is significantly slower for
-// this specific purpose, as measured with: go test -bench=Print)
-//
-func split(text string) []string {
- // count lines (comment text never ends in a newline)
- n := 1
- for i := 0; i < len(text); i++ {
- if text[i] == '\n' {
- n++
- }
- }
-
- // split
- lines := make([]string, n)
- n = 0
- i := 0
- for j := 0; j < len(text); j++ {
- if text[j] == '\n' {
- lines[n] = text[i:j] // exclude newline
- i = j + 1 // discard newline
- n++
- }
- }
- lines[n] = text[i:]
-
- return lines
-}
-
// Returns true if s contains only white space
// (only tabs and blanks can appear in the printer's context).
//
@@ -616,7 +587,7 @@ func (p *printer) writeComment(comment *ast.Comment) {
// for /*-style comments, print line by line and let the
// write function take care of the proper indentation
- lines := split(text)
+ lines := strings.Split(text, "\n")
// The comment started in the first column but is going
// to be indented. For an idempotent result, add indentation
diff --git a/src/pkg/go/printer/testdata/declarations.golden b/src/pkg/go/printer/testdata/declarations.golden
index 0ad72d349..0331615e5 100644
--- a/src/pkg/go/printer/testdata/declarations.golden
+++ b/src/pkg/go/printer/testdata/declarations.golden
@@ -912,3 +912,28 @@ func _(x chan (<-chan int))
func _(x chan<- (chan int))
func _(x chan<- (chan int))
func _(x chan<- (chan int))
+
+// don't introduce comma after last parameter if the closing ) is on the same line
+// even if the parameter type itself is multi-line (test cases from issue 4533)
+func _(...interface{})
+func _(...interface {
+ m()
+ n()
+}) // no extra comma between } and )
+
+func (t *T) _(...interface{})
+func (t *T) _(...interface {
+ m()
+ n()
+}) // no extra comma between } and )
+
+func _(interface{})
+func _(interface {
+ m()
+}) // no extra comma between } and )
+
+func _(struct{})
+func _(struct {
+ x int
+ y int
+}) // no extra comma between } and )
diff --git a/src/pkg/go/printer/testdata/declarations.input b/src/pkg/go/printer/testdata/declarations.input
index 455c0c6c1..dbdbdfe74 100644
--- a/src/pkg/go/printer/testdata/declarations.input
+++ b/src/pkg/go/printer/testdata/declarations.input
@@ -921,3 +921,28 @@ func _(x ((((chan(<-chan int))))))
func _(x chan<-(chan int))
func _(x (chan<-(chan int)))
func _(x ((((chan<-(chan int))))))
+
+// don't introduce comma after last parameter if the closing ) is on the same line
+// even if the parameter type itself is multi-line (test cases from issue 4533)
+func _(...interface{})
+func _(...interface {
+ m()
+ n()
+}) // no extra comma between } and )
+
+func (t *T) _(...interface{})
+func (t *T) _(...interface {
+ m()
+ n()
+}) // no extra comma between } and )
+
+func _(interface{})
+func _(interface {
+ m()
+}) // no extra comma between } and )
+
+func _(struct{})
+func _(struct {
+ x int
+ y int
+}) // no extra comma between } and )
diff --git a/src/pkg/go/scanner/scanner.go b/src/pkg/go/scanner/scanner.go
index 3322c58b3..1e259d5ed 100644
--- a/src/pkg/go/scanner/scanner.go
+++ b/src/pkg/go/scanner/scanner.go
@@ -48,6 +48,8 @@ type Scanner struct {
ErrorCount int // number of errors encountered
}
+const bom = 0xFEFF // byte order mark, only permitted as very first character
+
// Read the next Unicode char into s.ch.
// s.ch < 0 means end-of-file.
//
@@ -67,6 +69,8 @@ func (s *Scanner) next() {
r, w = utf8.DecodeRune(s.src[s.rdOffset:])
if r == utf8.RuneError && w == 1 {
s.error(s.offset, "illegal UTF-8 encoding")
+ } else if r == bom && s.offset > 0 {
+ s.error(s.offset, "illegal byte order mark")
}
}
s.rdOffset += w
@@ -125,8 +129,8 @@ func (s *Scanner) Init(file *token.File, src []byte, err ErrorHandler, mode Mode
s.ErrorCount = 0
s.next()
- if s.ch == '\uFEFF' {
- s.next() // ignore BOM
+ if s.ch == bom {
+ s.next() // ignore BOM at file beginning
}
}
@@ -713,7 +717,10 @@ scanAgain:
case '|':
tok = s.switch3(token.OR, token.OR_ASSIGN, '|', token.LOR)
default:
- s.error(s.file.Offset(pos), fmt.Sprintf("illegal character %#U", ch))
+ // next reports unexpected BOMs - don't repeat
+ if ch != bom {
+ s.error(s.file.Offset(pos), fmt.Sprintf("illegal character %#U", ch))
+ }
insertSemi = s.insertSemi // preserve insertSemi info
tok = token.ILLEGAL
lit = string(ch)
diff --git a/src/pkg/go/scanner/scanner_test.go b/src/pkg/go/scanner/scanner_test.go
index 1c19053e6..8c64c2b95 100644
--- a/src/pkg/go/scanner/scanner_test.go
+++ b/src/pkg/go/scanner/scanner_test.go
@@ -695,7 +695,10 @@ var errors = []struct {
{"0X", token.INT, 0, "illegal hexadecimal number"},
{"\"abc\x00def\"", token.STRING, 4, "illegal character NUL"},
{"\"abc\x80def\"", token.STRING, 4, "illegal UTF-8 encoding"},
- {"\ufeff\ufeff", token.ILLEGAL, 3, "illegal character U+FEFF"}, // only first BOM is ignored
+ {"\ufeff\ufeff", token.ILLEGAL, 3, "illegal byte order mark"}, // only first BOM is ignored
+ {"//\ufeff", token.COMMENT, 2, "illegal byte order mark"}, // only first BOM is ignored
+ {"'\ufeff" + `'`, token.CHAR, 1, "illegal byte order mark"}, // only first BOM is ignored
+ {`"` + "abc\ufeffdef" + `"`, token.STRING, 4, "illegal byte order mark"}, // only first BOM is ignored
}
func TestScanErrors(t *testing.T) {
diff --git a/src/pkg/go/token/token.go b/src/pkg/go/token/token.go
index 84b6314d5..865f63f4a 100644
--- a/src/pkg/go/token/token.go
+++ b/src/pkg/go/token/token.go
@@ -243,8 +243,8 @@ func (tok Token) String() string {
// A set of constants for precedence-based expression parsing.
// Non-operators have lowest precedence, followed by operators
// starting with precedence 1 up to unary operators. The highest
-// precedence corresponds serves as "catch-all" precedence for
-// selector, indexing, and other operator and delimiter tokens.
+// precedence serves as "catch-all" precedence for selector,
+// indexing, and other operator and delimiter tokens.
//
const (
LowestPrec = 0 // non-operators
diff --git a/src/pkg/go/types/api.go b/src/pkg/go/types/api.go
deleted file mode 100644
index 13b453faa..000000000
--- a/src/pkg/go/types/api.go
+++ /dev/null
@@ -1,105 +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 types declares the data structures for representing
-// Go types and implements typechecking of package files.
-//
-// WARNING: THE TYPES API IS SUBJECT TO CHANGE.
-//
-package types
-
-import (
- "go/ast"
- "go/token"
-)
-
-// A Context specifies the supporting context for type checking.
-// An empty Context is a ready-to-use default context.
-type Context struct {
- // If Error != nil, it is called with each error found
- // during type checking. The error strings of errors with
- // detailed position information are formatted as follows:
- // filename:line:column: message
- Error func(err error)
-
- // If Ident != nil, it is called for each identifier id
- // denoting an Object in the files provided to Check, and
- // obj is the denoted object.
- // Ident is not called for fields and methods in struct or
- // interface types or composite literals, or for blank (_)
- // or dot (.) identifiers in dot-imports.
- // TODO(gri) Consider making Fields and Methods ordinary
- // Objects - than we could lift this restriction.
- Ident func(id *ast.Ident, obj Object)
-
- // If Expr != nil, it is called exactly once for each expression x
- // that is type-checked: typ is the expression type, and val is the
- // value if x is constant, val is nil otherwise.
- //
- // If x is a literal value (constant, composite literal), typ is always
- // the dynamic type of x (never an interface type). Otherwise, typ is x's
- // static type (possibly an interface type).
- //
- // Constants are represented as follows:
- //
- // bool -> bool
- // numeric -> int64, *big.Int, *big.Rat, Complex
- // string -> string
- // nil -> NilType
- //
- // Constant values are normalized, that is, they are represented
- // using the "smallest" possible type that can represent the value.
- // For instance, 1.0 is represented as an int64 because it can be
- // represented accurately as an int64.
- Expr func(x ast.Expr, typ Type, val interface{})
-
- // If Import != nil, it is called for each imported package.
- // Otherwise, GcImporter is called.
- Import Importer
-
- // If Alignof != nil, it is called to determine the alignment
- // of the given type. Otherwise DefaultAlignmentof is called.
- // Alignof must implement the alignment guarantees required by
- // the spec.
- Alignof func(Type) int64
-
- // If Offsetsof != nil, it is called to determine the offsets
- // of the given struct fields, in bytes. Otherwise DefaultOffsetsof
- // is called. Offsetsof must implement the offset guarantees
- // required by the spec.
- Offsetsof func(fields []*Field) []int64
-
- // If Sizeof != nil, it is called to determine the size of the
- // given type. Otherwise, DefaultSizeof is called. Sizeof must
- // implement the size guarantees required by the spec.
- Sizeof func(Type) int64
-}
-
-// An Importer resolves import paths to Package objects.
-// The imports map records the packages already imported,
-// 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
-// Importer should load the package data for the given path into
-// a new *Package, record pkg in the imports map, and then
-// return pkg.
-type Importer func(imports map[string]*Package, path string) (pkg *Package, err error)
-
-// Check resolves and typechecks a set of package files within the given
-// context. It returns the package and the first error encountered, if
-// any. If the context's Error handler is nil, Check terminates as soon
-// as the first error is encountered; otherwise it continues until the
-// entire package is checked. If there are errors, the package may be
-// only partially type-checked, and the resulting package may be incomplete
-// (missing objects, imports, etc.).
-func (ctxt *Context) Check(fset *token.FileSet, files []*ast.File) (*Package, error) {
- return check(ctxt, fset, files)
-}
-
-// Check is shorthand for ctxt.Check where ctxt is a default (empty) context.
-func Check(fset *token.FileSet, files []*ast.File) (*Package, error) {
- var ctxt Context
- return ctxt.Check(fset, files)
-}
diff --git a/src/pkg/go/types/builtins.go b/src/pkg/go/types/builtins.go
deleted file mode 100644
index ad9259118..000000000
--- a/src/pkg/go/types/builtins.go
+++ /dev/null
@@ -1,455 +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.
-
-// This file implements typechecking of builtin function calls.
-
-package types
-
-import (
- "go/ast"
- "go/token"
-)
-
-// builtin typechecks a built-in call. The built-in type is bin, and iota is the current
-// value of iota or -1 if iota doesn't have a value in the current context. The result
-// of the call is returned via x. If the call has type errors, the returned x is marked
-// as invalid (x.mode == invalid).
-//
-func (check *checker) builtin(x *operand, call *ast.CallExpr, bin *builtin, iota int) {
- args := call.Args
- id := bin.id
-
- // declare before goto's
- var arg0 ast.Expr // first argument, if present
-
- // check argument count
- n := len(args)
- msg := ""
- if n < bin.nargs {
- msg = "not enough"
- } else if !bin.isVariadic && n > bin.nargs {
- msg = "too many"
- }
- if msg != "" {
- check.invalidOp(call.Pos(), msg+" arguments for %s (expected %d, found %d)", call, bin.nargs, n)
- goto Error
- }
-
- // common case: evaluate first argument if present;
- // if it is an expression, x has the expression value
- if n > 0 {
- arg0 = args[0]
- switch id {
- case _Make, _New, _Print, _Println, _Offsetof, _Trace:
- // respective cases below do the work
- default:
- // argument must be an expression
- check.expr(x, arg0, nil, iota)
- if x.mode == invalid {
- goto Error
- }
- }
- }
-
- switch id {
- case _Append:
- if _, ok := underlying(x.typ).(*Slice); !ok {
- check.invalidArg(x.pos(), "%s is not a typed slice", x)
- goto Error
- }
- resultTyp := x.typ
- for _, arg := range args[1:] {
- check.expr(x, arg, nil, iota)
- if x.mode == invalid {
- goto Error
- }
- // TODO(gri) check assignability
- }
- x.mode = value
- x.typ = resultTyp
-
- case _Cap, _Len:
- mode := invalid
- var val interface{}
- switch typ := implicitArrayDeref(underlying(x.typ)).(type) {
- case *Basic:
- if isString(typ) && id == _Len {
- if x.mode == constant {
- mode = constant
- val = int64(len(x.val.(string)))
- } else {
- mode = value
- }
- }
-
- case *Array:
- mode = value
- // spec: "The expressions len(s) and cap(s) are constants
- // if the type of s is an array or pointer to an array and
- // the expression s does not contain channel receives or
- // function calls; in this case s is not evaluated."
- if !check.containsCallsOrReceives(arg0) {
- mode = constant
- val = typ.Len
- }
-
- case *Slice, *Chan:
- mode = value
-
- case *Map:
- if id == _Len {
- mode = value
- }
- }
-
- if mode == invalid {
- check.invalidArg(x.pos(), "%s for %s", x, bin.name)
- goto Error
- }
- x.mode = mode
- x.typ = Typ[Int]
- x.val = val
-
- case _Close:
- ch, ok := underlying(x.typ).(*Chan)
- if !ok {
- check.invalidArg(x.pos(), "%s is not a channel", x)
- goto Error
- }
- if ch.Dir&ast.SEND == 0 {
- check.invalidArg(x.pos(), "%s must not be a receive-only channel", x)
- goto Error
- }
- x.mode = novalue
-
- case _Complex:
- if !check.complexArg(x) {
- goto Error
- }
-
- var y operand
- check.expr(&y, args[1], nil, iota)
- if y.mode == invalid {
- goto Error
- }
- if !check.complexArg(&y) {
- goto Error
- }
-
- check.convertUntyped(x, y.typ)
- if x.mode == invalid {
- goto Error
- }
- check.convertUntyped(&y, x.typ)
- if y.mode == invalid {
- goto Error
- }
-
- if !IsIdentical(x.typ, y.typ) {
- check.invalidArg(x.pos(), "mismatched types %s and %s", x.typ, y.typ)
- goto Error
- }
-
- typ := underlying(x.typ).(*Basic)
- if x.mode == constant && y.mode == constant {
- x.val = binaryOpConst(x.val, toImagConst(y.val), token.ADD, typ)
- } else {
- x.mode = value
- }
-
- switch typ.Kind {
- case Float32:
- x.typ = Typ[Complex64]
- case Float64:
- x.typ = Typ[Complex128]
- case UntypedInt, UntypedRune, UntypedFloat:
- x.typ = Typ[UntypedComplex]
- default:
- check.invalidArg(x.pos(), "float32 or float64 arguments expected")
- goto Error
- }
-
- case _Copy:
- var y operand
- check.expr(&y, args[1], nil, iota)
- if y.mode == invalid {
- goto Error
- }
-
- var dst, src Type
- if t, ok := underlying(x.typ).(*Slice); ok {
- dst = t.Elt
- }
- switch t := underlying(y.typ).(type) {
- case *Basic:
- if isString(y.typ) {
- src = Typ[Byte]
- }
- case *Slice:
- src = t.Elt
- }
-
- if dst == nil || src == nil {
- check.invalidArg(x.pos(), "copy expects slice arguments; found %s and %s", x, &y)
- goto Error
- }
-
- if !IsIdentical(dst, src) {
- check.invalidArg(x.pos(), "arguments to copy %s and %s have different element types %s and %s", x, &y, dst, src)
- goto Error
- }
-
- x.mode = value
- x.typ = Typ[Int]
-
- case _Delete:
- m, ok := underlying(x.typ).(*Map)
- if !ok {
- check.invalidArg(x.pos(), "%s is not a map", x)
- goto Error
- }
- check.expr(x, args[1], nil, iota)
- if x.mode == invalid {
- goto Error
- }
- if !x.isAssignable(check.ctxt, m.Key) {
- check.invalidArg(x.pos(), "%s is not assignable to %s", x, m.Key)
- goto Error
- }
- x.mode = novalue
-
- case _Imag, _Real:
- if !isComplex(x.typ) {
- check.invalidArg(x.pos(), "%s must be a complex number", x)
- goto Error
- }
- if x.mode == constant {
- // nothing to do for x.val == 0
- if !isZeroConst(x.val) {
- c := x.val.(Complex)
- if id == _Real {
- x.val = c.Re
- } else {
- x.val = c.Im
- }
- }
- } else {
- x.mode = value
- }
- k := Invalid
- switch underlying(x.typ).(*Basic).Kind {
- case Complex64:
- k = Float32
- case Complex128:
- k = Float64
- case UntypedComplex:
- k = UntypedFloat
- default:
- unreachable()
- }
- x.typ = Typ[k]
-
- case _Make:
- resultTyp := check.typ(arg0, false)
- if resultTyp == Typ[Invalid] {
- goto Error
- }
- var min int // minimum number of arguments
- switch underlying(resultTyp).(type) {
- case *Slice:
- min = 2
- case *Map, *Chan:
- min = 1
- default:
- check.invalidArg(arg0.Pos(), "cannot make %s; type must be slice, map, or channel", arg0)
- goto Error
- }
- if n := len(args); n < min || min+1 < n {
- check.errorf(call.Pos(), "%s expects %d or %d arguments; found %d", call, min, min+1, n)
- goto Error
- }
- var sizes []interface{} // constant integer arguments, if any
- for _, arg := range args[1:] {
- check.expr(x, arg, nil, iota)
- if x.isInteger(check.ctxt) {
- if x.mode == constant {
- if isNegConst(x.val) {
- check.invalidArg(x.pos(), "%s must not be negative", x)
- // safe to continue
- } else {
- sizes = append(sizes, x.val) // x.val >= 0
- }
- }
- } else {
- check.invalidArg(x.pos(), "%s must be an integer", x)
- // safe to continue
- }
- }
- if len(sizes) == 2 && compareConst(sizes[0], sizes[1], token.GTR) {
- check.invalidArg(args[1].Pos(), "length and capacity swapped")
- // safe to continue
- }
- x.mode = variable
- x.typ = resultTyp
-
- case _New:
- resultTyp := check.typ(arg0, false)
- if resultTyp == Typ[Invalid] {
- goto Error
- }
- x.mode = variable
- x.typ = &Pointer{Base: resultTyp}
-
- case _Panic:
- x.mode = novalue
-
- case _Print, _Println:
- for _, arg := range args {
- check.expr(x, arg, nil, -1)
- if x.mode == invalid {
- goto Error
- }
- }
- x.mode = novalue
-
- case _Recover:
- x.mode = value
- x.typ = new(Interface)
-
- case _Alignof:
- x.mode = constant
- x.val = check.ctxt.alignof(x.typ)
- x.typ = Typ[Uintptr]
-
- case _Offsetof:
- arg, ok := unparen(arg0).(*ast.SelectorExpr)
- if !ok {
- check.invalidArg(arg0.Pos(), "%s is not a selector expression", arg0)
- goto Error
- }
- check.expr(x, arg.X, nil, -1)
- if x.mode == invalid {
- goto Error
- }
- sel := arg.Sel.Name
- res := lookupField(x.typ, QualifiedName{check.pkg, arg.Sel.Name})
- if res.index == nil {
- check.invalidArg(x.pos(), "%s has no single field %s", x, sel)
- goto Error
- }
- offs := check.ctxt.offsetof(deref(x.typ), res.index)
- if offs < 0 {
- check.invalidArg(x.pos(), "field %s is embedded via a pointer in %s", sel, x)
- goto Error
- }
- x.mode = constant
- x.val = offs
- x.typ = Typ[Uintptr]
-
- case _Sizeof:
- x.mode = constant
- x.val = check.ctxt.sizeof(x.typ)
- x.typ = Typ[Uintptr]
-
- case _Assert:
- // assert(pred) causes a typechecker error if pred is false.
- // The result of assert is the value of pred if there is no error.
- // Note: assert is only available in self-test mode.
- if x.mode != constant || !isBoolean(x.typ) {
- check.invalidArg(x.pos(), "%s is not a boolean constant", x)
- goto Error
- }
- pred, ok := x.val.(bool)
- if !ok {
- check.errorf(x.pos(), "internal error: value of %s should be a boolean constant", x)
- goto Error
- }
- if !pred {
- check.errorf(call.Pos(), "%s failed", call)
- // compile-time assertion failure - safe to continue
- }
-
- case _Trace:
- // trace(x, y, z, ...) dumps the positions, expressions, and
- // values of its arguments. The result of trace is the value
- // of the first argument.
- // Note: trace is only available in self-test mode.
- if len(args) == 0 {
- check.dump("%s: trace() without arguments", call.Pos())
- x.mode = novalue
- x.expr = call
- return
- }
- var t operand
- x1 := x
- for _, arg := range args {
- check.rawExpr(x1, arg, nil, iota, true) // permit trace for types, e.g.: new(trace(T))
- check.dump("%s: %s", x1.pos(), x1)
- x1 = &t // use incoming x only for first argument
- }
-
- default:
- check.invalidAST(call.Pos(), "unknown builtin id %d", id)
- goto Error
- }
-
- x.expr = call
- return
-
-Error:
- x.mode = invalid
- x.expr = call
-}
-
-// implicitArrayDeref returns A if typ is of the form *A and A is an array;
-// otherwise it returns typ.
-//
-func implicitArrayDeref(typ Type) Type {
- if p, ok := typ.(*Pointer); ok {
- if a, ok := underlying(p.Base).(*Array); ok {
- return a
- }
- }
- return typ
-}
-
-// containsCallsOrReceives reports if x contains function calls or channel receives.
-// Expects that x was type-checked already.
-//
-func (check *checker) containsCallsOrReceives(x ast.Expr) (found bool) {
- ast.Inspect(x, func(x ast.Node) bool {
- switch x := x.(type) {
- case *ast.CallExpr:
- // calls and conversions look the same
- if !check.conversions[x] {
- found = true
- }
- case *ast.UnaryExpr:
- if x.Op == token.ARROW {
- found = true
- }
- }
- return !found // no need to continue if found
- })
- return
-}
-
-// unparen removes any parentheses surrounding an expression and returns
-// the naked expression.
-//
-func unparen(x ast.Expr) ast.Expr {
- if p, ok := x.(*ast.ParenExpr); ok {
- return unparen(p.X)
- }
- return x
-}
-
-func (check *checker) complexArg(x *operand) bool {
- t, _ := underlying(x.typ).(*Basic)
- if t != nil && (t.Info&IsFloat != 0 || t.Kind == UntypedInt || t.Kind == UntypedRune) {
- return true
- }
- check.invalidArg(x.pos(), "%s must be a float32, float64, or an untyped non-complex numeric constant", x)
- return false
-}
diff --git a/src/pkg/go/types/check.go b/src/pkg/go/types/check.go
deleted file mode 100644
index f7b87e30c..000000000
--- a/src/pkg/go/types/check.go
+++ /dev/null
@@ -1,507 +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.
-
-// This file implements the Check function, which typechecks a package.
-
-package types
-
-import (
- "fmt"
- "go/ast"
- "go/token"
-)
-
-// debugging support
-const (
- debug = true // leave on during development
- trace = false // turn on for detailed type resolution traces
-)
-
-type checker struct {
- ctxt *Context
- fset *token.FileSet
- files []*ast.File
-
- // lazily initialized
- pkg *Package // current package
- firsterr error // first error encountered
- idents map[*ast.Ident]Object // maps identifiers to their unique object
- objects map[*ast.Object]Object // maps *ast.Objects to their unique object
- initspecs map[*ast.ValueSpec]*ast.ValueSpec // "inherited" type and initialization expressions for constant declarations
- methods map[*TypeName]*Scope // maps type names to associated methods
- conversions map[*ast.CallExpr]bool // set of type-checked conversions (to distinguish from calls)
-
- // untyped expressions
- // TODO(gri): Consider merging the untyped and constants map. Should measure
- // the ratio between untyped non-constant and untyped constant expressions
- // to make an informed decision.
- untyped map[ast.Expr]*Basic // map of expressions of untyped type
- constants map[ast.Expr]interface{} // map of untyped constant expressions; each key also appears in untyped
- shiftOps map[ast.Expr]bool // map of lhs shift operands with delayed type-checking
-
- // functions
- funclist []function // list of functions/methods with correct signatures and non-empty bodies
- funcsig *Signature // signature of currently typechecked function
- pos []token.Pos // stack of expr positions; debugging support, used if trace is set
-}
-
-func (check *checker) register(id *ast.Ident, obj Object) {
- // When an expression is evaluated more than once (happens
- // in rare cases, e.g. for statement expressions, see
- // comment in stmt.go), the object has been registered
- // before. Don't do anything in that case.
- if alt := check.idents[id]; alt != nil {
- assert(alt == obj)
- return
- }
- check.idents[id] = obj
- if f := check.ctxt.Ident; f != nil {
- f(id, obj)
- }
-}
-
-// lookup returns the unique Object denoted by the identifier.
-// For identifiers without assigned *ast.Object, it uses the
-// checker.idents map; for identifiers with an *ast.Object it
-// uses the checker.objects map.
-//
-// TODO(gri) Once identifier resolution is done entirely by
-// the typechecker, only the idents map is needed.
-//
-func (check *checker) lookup(ident *ast.Ident) Object {
- obj := check.idents[ident]
- astObj := ident.Obj
-
- if obj != nil {
- assert(astObj == nil || check.objects[astObj] == nil || check.objects[astObj] == obj)
- return obj
- }
-
- if astObj == nil {
- return nil
- }
-
- if obj = check.objects[astObj]; obj == nil {
- obj = newObj(check.pkg, astObj)
- check.objects[astObj] = obj
- }
- check.register(ident, obj)
-
- return obj
-}
-
-type function struct {
- obj *Func // for debugging/tracing only
- sig *Signature
- body *ast.BlockStmt
-}
-
-// later adds a function with non-empty body to the list of functions
-// that need to be processed after all package-level declarations
-// are typechecked.
-//
-func (check *checker) later(f *Func, sig *Signature, body *ast.BlockStmt) {
- // functions implemented elsewhere (say in assembly) have no body
- if body != nil {
- check.funclist = append(check.funclist, function{f, sig, body})
- }
-}
-
-func (check *checker) declareIdent(scope *Scope, ident *ast.Ident, obj Object) {
- assert(check.lookup(ident) == nil) // identifier already declared or resolved
- check.register(ident, obj)
- if ident.Name != "_" {
- if alt := scope.Insert(obj); alt != nil {
- prevDecl := ""
- if pos := alt.GetPos(); pos.IsValid() {
- prevDecl = fmt.Sprintf("\n\tprevious declaration at %s", check.fset.Position(pos))
- }
- check.errorf(ident.Pos(), fmt.Sprintf("%s redeclared in this block%s", ident.Name, prevDecl))
- }
- }
-}
-
-func (check *checker) valueSpec(pos token.Pos, obj Object, lhs []*ast.Ident, spec *ast.ValueSpec, iota int) {
- if len(lhs) == 0 {
- check.invalidAST(pos, "missing lhs in declaration")
- return
- }
-
- // determine type for all of lhs, if any
- // (but only set it for the object we typecheck!)
- var typ Type
- if spec.Type != nil {
- typ = check.typ(spec.Type, false)
- }
-
- // len(lhs) > 0
- rhs := spec.Values
- if len(lhs) == len(rhs) {
- // check only lhs and rhs corresponding to obj
- var l, r ast.Expr
- for i, name := range lhs {
- if check.lookup(name) == obj {
- l = lhs[i]
- r = rhs[i]
- break
- }
- }
- assert(l != nil)
- switch obj := obj.(type) {
- case *Const:
- obj.Type = typ
- case *Var:
- obj.Type = typ
- default:
- unreachable()
- }
- check.assign1to1(l, r, nil, true, iota)
- return
- }
-
- // there must be a type or initialization expressions
- if typ == nil && len(rhs) == 0 {
- check.invalidAST(pos, "missing type or initialization expression")
- typ = Typ[Invalid]
- }
-
- // if we have a type, mark all of lhs
- if typ != nil {
- for _, name := range lhs {
- switch obj := check.lookup(name).(type) {
- case *Const:
- obj.Type = typ
- case *Var:
- obj.Type = typ
- default:
- unreachable()
- }
- }
- }
-
- // check initial values, if any
- if len(rhs) > 0 {
- // TODO(gri) should try to avoid this conversion
- lhx := make([]ast.Expr, len(lhs))
- for i, e := range lhs {
- lhx[i] = e
- }
- check.assignNtoM(lhx, rhs, true, iota)
- }
-}
-
-// object typechecks an object by assigning it a type.
-//
-func (check *checker) object(obj Object, cycleOk bool) {
- switch obj := obj.(type) {
- case *Package:
- // nothing to do
- case *Const:
- if obj.Type != nil {
- return // already checked
- }
- // The obj.Val field for constants is initialized to its respective
- // iota value by the parser.
- // The object's fields can be in one of the following states:
- // Type != nil => the constant value is Val
- // Type == nil => the constant is not typechecked yet, and Val can be:
- // Val is int => Val is the value of iota for this declaration
- // Val == nil => the object's expression is being evaluated
- if obj.Val == nil {
- check.errorf(obj.GetPos(), "illegal cycle in initialization of %s", obj.Name)
- obj.Type = Typ[Invalid]
- return
- }
- spec := obj.spec
- iota := obj.Val.(int)
- obj.Val = nil // mark obj as "visited" for cycle detection
- // determine spec for type and initialization expressions
- init := spec
- if len(init.Values) == 0 {
- init = check.initspecs[spec]
- }
- check.valueSpec(spec.Pos(), obj, spec.Names, init, iota)
-
- case *Var:
- if obj.Type != nil {
- return // already checked
- }
- if obj.visited {
- check.errorf(obj.GetPos(), "illegal cycle in initialization of %s", obj.Name)
- obj.Type = Typ[Invalid]
- return
- }
- switch d := obj.decl.(type) {
- case *ast.Field:
- unreachable() // function parameters are always typed when collected
- case *ast.ValueSpec:
- obj.visited = true
- check.valueSpec(d.Pos(), obj, d.Names, d, 0)
- case *ast.AssignStmt:
- // If we reach here, we have a short variable declaration
- // where the rhs didn't typecheck and thus the lhs has no
- // types.
- obj.visited = true
- obj.Type = Typ[Invalid]
- default:
- unreachable() // see also function newObj
- }
-
- case *TypeName:
- if obj.Type != nil {
- return // already checked
- }
- typ := &NamedType{Obj: obj}
- obj.Type = typ // "mark" object so recursion terminates
- typ.Underlying = underlying(check.typ(obj.spec.Type, cycleOk))
- // typecheck associated method signatures
- if scope := check.methods[obj]; scope != nil {
- switch t := typ.Underlying.(type) {
- case *Struct:
- // struct fields must not conflict with methods
- for _, f := range t.Fields {
- if m := scope.Lookup(f.Name); m != nil {
- check.errorf(m.GetPos(), "type %s has both field and method named %s", obj.Name, f.Name)
- // ok to continue
- }
- }
- case *Interface:
- // methods cannot be associated with an interface type
- for _, m := range scope.Entries {
- recv := m.(*Func).decl.Recv.List[0].Type
- check.errorf(recv.Pos(), "invalid receiver type %s (%s is an interface type)", obj.Name, obj.Name)
- // ok to continue
- }
- }
- // typecheck method signatures
- var methods []*Method
- for _, obj := range scope.Entries {
- m := obj.(*Func)
- sig := check.typ(m.decl.Type, cycleOk).(*Signature)
- params, _ := check.collectParams(m.decl.Recv, false)
- sig.Recv = params[0] // the parser/assocMethod ensure there is exactly one parameter
- m.Type = sig
- methods = append(methods, &Method{QualifiedName{check.pkg, m.Name}, sig})
- check.later(m, sig, m.decl.Body)
- }
- typ.Methods = methods
- delete(check.methods, obj) // we don't need this scope anymore
- }
-
- case *Func:
- if obj.Type != nil {
- return // already checked
- }
- fdecl := obj.decl
- // methods are typechecked when their receivers are typechecked
- if fdecl.Recv == nil {
- sig := check.typ(fdecl.Type, cycleOk).(*Signature)
- if obj.Name == "init" && (len(sig.Params) != 0 || len(sig.Results) != 0) {
- check.errorf(fdecl.Pos(), "func init must have no arguments and no return values")
- // ok to continue
- }
- obj.Type = sig
- check.later(obj, sig, fdecl.Body)
- }
-
- default:
- unreachable()
- }
-}
-
-// assocInitvals associates "inherited" initialization expressions
-// with the corresponding *ast.ValueSpec in the check.initspecs map
-// for constant declarations without explicit initialization expressions.
-//
-func (check *checker) assocInitvals(decl *ast.GenDecl) {
- var last *ast.ValueSpec
- for _, s := range decl.Specs {
- if s, ok := s.(*ast.ValueSpec); ok {
- if len(s.Values) > 0 {
- last = s
- } else {
- check.initspecs[s] = last
- }
- }
- }
- if last == nil {
- check.invalidAST(decl.Pos(), "no initialization values provided")
- }
-}
-
-// assocMethod associates a method declaration with the respective
-// receiver base type. meth.Recv must exist.
-//
-func (check *checker) assocMethod(meth *ast.FuncDecl) {
- // The receiver type is one of the following (enforced by parser):
- // - *ast.Ident
- // - *ast.StarExpr{*ast.Ident}
- // - *ast.BadExpr (parser error)
- typ := meth.Recv.List[0].Type
- if ptr, ok := typ.(*ast.StarExpr); ok {
- typ = ptr.X
- }
- // determine receiver base type name
- ident, ok := typ.(*ast.Ident)
- if !ok {
- // not an identifier - parser reported error already
- return // ignore this method
- }
- // determine receiver base type object
- var tname *TypeName
- if obj := check.lookup(ident); obj != nil {
- obj, ok := obj.(*TypeName)
- if !ok {
- check.errorf(ident.Pos(), "%s is not a type", ident.Name)
- return // ignore this method
- }
- if obj.spec == nil {
- check.errorf(ident.Pos(), "cannot define method on non-local type %s", ident.Name)
- return // ignore this method
- }
- tname = obj
- } else {
- // identifier not declared/resolved - parser reported error already
- return // ignore this method
- }
- // declare method in receiver base type scope
- scope := check.methods[tname]
- if scope == nil {
- scope = new(Scope)
- check.methods[tname] = scope
- }
- check.declareIdent(scope, meth.Name, &Func{Pkg: check.pkg, Name: meth.Name.Name, decl: meth})
-}
-
-func (check *checker) decl(decl ast.Decl) {
- switch d := decl.(type) {
- case *ast.BadDecl:
- // ignore
- case *ast.GenDecl:
- for _, spec := range d.Specs {
- switch s := spec.(type) {
- case *ast.ImportSpec:
- // nothing to do (handled by check.resolve)
- case *ast.ValueSpec:
- for _, name := range s.Names {
- check.object(check.lookup(name), false)
- }
- case *ast.TypeSpec:
- check.object(check.lookup(s.Name), false)
- default:
- check.invalidAST(s.Pos(), "unknown ast.Spec node %T", s)
- }
- }
- case *ast.FuncDecl:
- // methods are checked when their respective base types are checked
- if d.Recv != nil {
- return
- }
- obj := check.lookup(d.Name)
- // Initialization functions don't have an object associated with them
- // since they are not in any scope. Create a dummy object for them.
- if d.Name.Name == "init" {
- assert(obj == nil) // all other functions should have an object
- obj = &Func{Pkg: check.pkg, Name: d.Name.Name, decl: d}
- check.register(d.Name, obj)
- }
- check.object(obj, false)
- default:
- check.invalidAST(d.Pos(), "unknown ast.Decl node %T", d)
- }
-}
-
-// A bailout panic is raised to indicate early termination.
-type bailout struct{}
-
-func check(ctxt *Context, fset *token.FileSet, files []*ast.File) (pkg *Package, err error) {
- // initialize checker
- check := checker{
- ctxt: ctxt,
- fset: fset,
- files: files,
- idents: make(map[*ast.Ident]Object),
- objects: make(map[*ast.Object]Object),
- initspecs: make(map[*ast.ValueSpec]*ast.ValueSpec),
- methods: make(map[*TypeName]*Scope),
- conversions: make(map[*ast.CallExpr]bool),
- untyped: make(map[ast.Expr]*Basic),
- constants: make(map[ast.Expr]interface{}),
- shiftOps: make(map[ast.Expr]bool),
- }
-
- // set results and handle panics
- defer func() {
- pkg = check.pkg
- switch p := recover().(type) {
- case nil, bailout:
- // normal return or early exit
- err = check.firsterr
- default:
- // unexpected panic: don't crash clients
- if debug {
- check.dump("INTERNAL PANIC: %v", p)
- panic(p)
- }
- // TODO(gri) add a test case for this scenario
- err = fmt.Errorf("types internal error: %v", p)
- }
- }()
-
- // resolve identifiers
- imp := ctxt.Import
- if imp == nil {
- imp = GcImport
- }
- methods := check.resolve(imp)
-
- // associate methods with types
- for _, m := range methods {
- check.assocMethod(m)
- }
-
- // typecheck all declarations
- for _, f := range check.files {
- for _, d := range f.Decls {
- check.decl(d)
- }
- }
-
- // typecheck all function/method bodies
- // (funclist may grow when checking statements - do not use range clause!)
- for i := 0; i < len(check.funclist); i++ {
- f := check.funclist[i]
- if trace {
- s := "<function literal>"
- if f.obj != nil {
- s = f.obj.Name
- }
- fmt.Println("---", s)
- }
- check.funcsig = f.sig
- check.stmtList(f.body.List)
- }
-
- // remaining untyped expressions must indeed be untyped
- if debug {
- for x, typ := range check.untyped {
- if !isUntyped(typ) {
- check.dump("%s: %s (type %s) is not untyped", x.Pos(), x, typ)
- panic(0)
- }
- }
- }
-
- // notify client of any untyped types left
- // TODO(gri) Consider doing this before and
- // after function body checking for smaller
- // map size and more immediate feedback.
- if ctxt.Expr != nil {
- for x, typ := range check.untyped {
- ctxt.Expr(x, typ, check.constants[x])
- }
- }
-
- return
-}
diff --git a/src/pkg/go/types/check_test.go b/src/pkg/go/types/check_test.go
deleted file mode 100644
index 470f3a1a9..000000000
--- a/src/pkg/go/types/check_test.go
+++ /dev/null
@@ -1,259 +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.
-
-// This file implements a typechecker test harness. The packages specified
-// in tests are typechecked. Error messages reported by the typechecker are
-// compared against the error messages expected in the test files.
-//
-// Expected errors are indicated in the test files by putting a comment
-// of the form /* ERROR "rx" */ immediately following an offending token.
-// The harness will verify that an error matching the regular expression
-// rx is reported at that source position. Consecutive comments may be
-// used to indicate multiple errors for the same token position.
-//
-// For instance, the following test file indicates that a "not declared"
-// error should be reported for the undeclared variable x:
-//
-// package p
-// func f() {
-// _ = x /* ERROR "not declared" */ + 1
-// }
-
-package types
-
-import (
- "flag"
- "fmt"
- "go/ast"
- "go/parser"
- "go/scanner"
- "go/token"
- "io/ioutil"
- "os"
- "regexp"
- "testing"
-)
-
-var listErrors = flag.Bool("list", false, "list errors")
-
-// The test filenames do not end in .go so that they are invisible
-// to gofmt since they contain comments that must not change their
-// positions relative to surrounding tokens.
-
-var tests = []struct {
- name string
- files []string
-}{
- {"decls0", []string{"testdata/decls0.src"}},
- {"decls1", []string{"testdata/decls1.src"}},
- {"decls2", []string{"testdata/decls2a.src", "testdata/decls2b.src"}},
- {"decls3", []string{"testdata/decls3.src"}},
- {"const0", []string{"testdata/const0.src"}},
- {"expr0", []string{"testdata/expr0.src"}},
- {"expr1", []string{"testdata/expr1.src"}},
- {"expr2", []string{"testdata/expr2.src"}},
- {"expr3", []string{"testdata/expr3.src"}},
- {"builtins", []string{"testdata/builtins.src"}},
- {"conversions", []string{"testdata/conversions.src"}},
- {"stmt0", []string{"testdata/stmt0.src"}},
-}
-
-var fset = token.NewFileSet()
-
-func getFile(filename string) (file *token.File) {
- fset.Iterate(func(f *token.File) bool {
- if f.Name() == filename {
- file = f
- return false // end iteration
- }
- return true
- })
- return file
-}
-
-// Positioned errors are of the form filename:line:column: message .
-var posMsgRx = regexp.MustCompile(`^(.*:[0-9]+:[0-9]+): *(.*)`)
-
-// splitError splits an error's error message into a position string
-// and the actual error message. If there's no position information,
-// pos is the empty string, and msg is the entire error message.
-//
-func splitError(err error) (pos, msg string) {
- msg = err.Error()
- if m := posMsgRx.FindStringSubmatch(msg); len(m) == 3 {
- pos = m[1]
- msg = m[2]
- }
- return
-}
-
-func parseFiles(t *testing.T, testname string, filenames []string) ([]*ast.File, []error) {
- var files []*ast.File
- var errlist []error
- for _, filename := range filenames {
- file, err := parser.ParseFile(fset, filename, nil, parser.DeclarationErrors|parser.AllErrors)
- if file == nil {
- t.Fatalf("%s: could not parse file %s", testname, filename)
- }
- files = append(files, file)
- if err != nil {
- if list, _ := err.(scanner.ErrorList); len(list) > 0 {
- for _, err := range list {
- errlist = append(errlist, err)
- }
- } else {
- errlist = append(errlist, err)
- }
- }
- }
- return files, errlist
-}
-
-// ERROR comments must be of the form /* ERROR "rx" */ and rx is
-// a regular expression that matches the expected error message.
-//
-var errRx = regexp.MustCompile(`^/\* *ERROR *"([^"]*)" *\*/$`)
-
-// errMap collects the regular expressions of ERROR comments found
-// in files and returns them as a map of error positions to error messages.
-//
-func errMap(t *testing.T, testname string, files []*ast.File) map[string][]string {
- errmap := make(map[string][]string)
-
- for _, file := range files {
- filename := fset.Position(file.Package).Filename
- src, err := ioutil.ReadFile(filename)
- if err != nil {
- t.Fatalf("%s: could not read %s", testname, filename)
- }
-
- var s scanner.Scanner
- // file was parsed already - do not add it again to the file
- // set otherwise the position information returned here will
- // not match the position information collected by the parser
- s.Init(getFile(filename), src, nil, scanner.ScanComments)
- var prev string // position string of last non-comment, non-semicolon token
-
- scanFile:
- for {
- pos, tok, lit := s.Scan()
- switch tok {
- case token.EOF:
- break scanFile
- case token.COMMENT:
- s := errRx.FindStringSubmatch(lit)
- if len(s) == 2 {
- errmap[prev] = append(errmap[prev], string(s[1]))
- }
- case token.SEMICOLON:
- // ignore automatically inserted semicolon
- if lit == "\n" {
- continue scanFile
- }
- fallthrough
- default:
- prev = fset.Position(pos).String()
- }
- }
- }
-
- return errmap
-}
-
-func eliminate(t *testing.T, errmap map[string][]string, errlist []error) {
- for _, err := range errlist {
- pos, msg := splitError(err)
- list := errmap[pos]
- index := -1 // list index of matching message, if any
- // we expect one of the messages in list to match the error at pos
- for i, msg := range list {
- rx, err := regexp.Compile(msg)
- if err != nil {
- t.Errorf("%s: %v", pos, err)
- continue
- }
- if rx.MatchString(msg) {
- index = i
- break
- }
- }
- if index >= 0 {
- // eliminate from list
- if n := len(list) - 1; n > 0 {
- // not the last entry - swap in last element and shorten list by 1
- list[index] = list[n]
- errmap[pos] = list[:n]
- } else {
- // last entry - remove list from map
- delete(errmap, pos)
- }
- } else {
- t.Errorf("%s: no error expected: %q", pos, msg)
- }
-
- }
-}
-
-func checkFiles(t *testing.T, testname string, testfiles []string) {
- // parse files and collect parser errors
- files, errlist := parseFiles(t, testname, testfiles)
-
- // typecheck and collect typechecker errors
- var ctxt Context
- ctxt.Error = func(err error) { errlist = append(errlist, err) }
- ctxt.Check(fset, files)
-
- if *listErrors {
- t.Errorf("--- %s: %d errors found:", testname, len(errlist))
- for _, err := range errlist {
- t.Error(err)
- }
- return
- }
-
- // match and eliminate errors
- // we are expecting the following errors
- // (collect these after parsing the files so that
- // they are found in the file set)
- errmap := errMap(t, testname, files)
- eliminate(t, errmap, errlist)
-
- // there should be no expected errors left
- if len(errmap) > 0 {
- t.Errorf("--- %s: %d source positions with expected (but not reported) errors:", testname, len(errmap))
- for pos, list := range errmap {
- for _, rx := range list {
- t.Errorf("%s: %q", pos, rx)
- }
- }
- }
-}
-
-var testBuiltinsDeclared = false
-
-func TestCheck(t *testing.T) {
- // Declare builtins for testing.
- // Not done in an init func to avoid an init race with
- // the construction of the Universe var.
- if !testBuiltinsDeclared {
- testBuiltinsDeclared = true
- // Pkg == nil for Universe objects
- def(&Func{Name: "assert", Type: &builtin{_Assert, "assert", 1, false, true}})
- def(&Func{Name: "trace", Type: &builtin{_Trace, "trace", 0, true, true}})
- }
-
- // For easy debugging w/o changing the testing code,
- // if there is a local test file, only test that file.
- const testfile = "testdata/test.go"
- if fi, err := os.Stat(testfile); err == nil && !fi.IsDir() {
- fmt.Printf("WARNING: Testing only %s (remove it to run all tests)\n", testfile)
- checkFiles(t, testfile, []string{testfile})
- return
- }
-
- // Otherwise, run all the tests.
- for _, test := range tests {
- checkFiles(t, test.name, test.files)
- }
-}
diff --git a/src/pkg/go/types/const.go b/src/pkg/go/types/const.go
deleted file mode 100644
index 503652e75..000000000
--- a/src/pkg/go/types/const.go
+++ /dev/null
@@ -1,718 +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.
-
-// This file implements operations on constant values.
-
-package types
-
-import (
- "fmt"
- "go/token"
- "math/big"
- "strconv"
-)
-
-// TODO(gri) At the moment, constants are different types
-// passed around as interface{} values. Introduce a Const
-// interface and use methods instead of xConst functions.
-
-// Representation of constant values.
-//
-// bool -> bool (true, false)
-// numeric -> int64, *big.Int, *big.Rat, Complex (ordered by increasing data structure "size")
-// string -> string
-// nil -> NilType (nilConst)
-//
-// Numeric constants are normalized after each operation such
-// that they are represented by the "smallest" data structure
-// required to represent the constant, independent of actual
-// type. Non-numeric constants are always normalized.
-
-// Representation of complex numbers.
-type Complex struct {
- Re, Im *big.Rat
-}
-
-func (c Complex) String() string {
- if c.Re.Sign() == 0 {
- return fmt.Sprintf("%si", c.Im)
- }
- // normalized complex values always have an imaginary part
- return fmt.Sprintf("(%s + %si)", c.Re, c.Im)
-}
-
-// Representation of nil.
-type NilType struct{}
-
-func (NilType) String() string {
- return "nil"
-}
-
-// Frequently used values.
-var (
- nilConst = NilType{}
- zeroConst = int64(0)
-)
-
-// int64 bounds
-var (
- minInt64 = big.NewInt(-1 << 63)
- maxInt64 = big.NewInt(1<<63 - 1)
-)
-
-// normalizeIntConst returns the smallest constant representation
-// for the specific value of x; either an int64 or a *big.Int value.
-//
-func normalizeIntConst(x *big.Int) interface{} {
- if minInt64.Cmp(x) <= 0 && x.Cmp(maxInt64) <= 0 {
- return x.Int64()
- }
- return x
-}
-
-// normalizeRatConst returns the smallest constant representation
-// for the specific value of x; either an int64, *big.Int,
-// or *big.Rat value.
-//
-func normalizeRatConst(x *big.Rat) interface{} {
- if x.IsInt() {
- return normalizeIntConst(x.Num())
- }
- return x
-}
-
-// newComplex returns the smallest constant representation
-// for the specific value re + im*i; either an int64, *big.Int,
-// *big.Rat, or complex value.
-//
-func newComplex(re, im *big.Rat) interface{} {
- if im.Sign() == 0 {
- return normalizeRatConst(re)
- }
- return Complex{re, im}
-}
-
-// makeRuneConst returns the int64 code point for the rune literal
-// lit. The result is nil if lit is not a correct rune literal.
-//
-func makeRuneConst(lit string) interface{} {
- if n := len(lit); n >= 2 {
- if code, _, _, err := strconv.UnquoteChar(lit[1:n-1], '\''); err == nil {
- return int64(code)
- }
- }
- return nil
-}
-
-// makeRuneConst returns the smallest integer constant representation
-// (int64, *big.Int) for the integer literal lit. The result is nil if
-// lit is not a correct integer literal.
-//
-func makeIntConst(lit string) interface{} {
- if x, err := strconv.ParseInt(lit, 0, 64); err == nil {
- return x
- }
- if x, ok := new(big.Int).SetString(lit, 0); ok {
- return x
- }
- return nil
-}
-
-// makeFloatConst returns the smallest floating-point constant representation
-// (int64, *big.Int, *big.Rat) for the floating-point literal lit. The result
-// is nil if lit is not a correct floating-point literal.
-//
-func makeFloatConst(lit string) interface{} {
- if x, ok := new(big.Rat).SetString(lit); ok {
- return normalizeRatConst(x)
- }
- return nil
-}
-
-// makeComplexConst returns the complex constant representation (Complex) for
-// the imaginary literal lit. The result is nil if lit is not a correct imaginary
-// literal.
-//
-func makeComplexConst(lit string) interface{} {
- n := len(lit)
- if n > 0 && lit[n-1] == 'i' {
- if im, ok := new(big.Rat).SetString(lit[0 : n-1]); ok {
- return newComplex(big.NewRat(0, 1), im)
- }
- }
- return nil
-}
-
-// makeStringConst returns the string constant representation (string) for
-// the string literal lit. The result is nil if lit is not a correct string
-// literal.
-//
-func makeStringConst(lit string) interface{} {
- if s, err := strconv.Unquote(lit); err == nil {
- return s
- }
- return nil
-}
-
-// toImagConst returns the constant Complex(0, x) for a non-complex x.
-func toImagConst(x interface{}) interface{} {
- var im *big.Rat
- switch x := x.(type) {
- case int64:
- im = big.NewRat(x, 1)
- case *big.Int:
- im = new(big.Rat).SetFrac(x, int1)
- case *big.Rat:
- im = x
- default:
- unreachable()
- }
- return Complex{rat0, im}
-}
-
-// isZeroConst reports whether the value of constant x is 0.
-// x must be normalized.
-//
-func isZeroConst(x interface{}) bool {
- i, ok := x.(int64) // good enough since constants are normalized
- return ok && i == 0
-}
-
-// isNegConst reports whether the value of constant x is < 0.
-// x must be a non-complex numeric value.
-//
-func isNegConst(x interface{}) bool {
- switch x := x.(type) {
- case int64:
- return x < 0
- case *big.Int:
- return x.Sign() < 0
- case *big.Rat:
- return x.Sign() < 0
- }
- unreachable()
- return false
-}
-
-// isRepresentableConst reports whether the value of constant x can
-// be represented as a value of the basic type Typ[as] without loss
-// of precision.
-//
-func isRepresentableConst(x interface{}, ctxt *Context, as BasicKind) bool {
- switch x := x.(type) {
- case bool:
- return as == Bool || as == UntypedBool
-
- case int64:
- switch as {
- case Int:
- var s = uint(ctxt.sizeof(Typ[as])) * 8
- return int64(-1)<<(s-1) <= x && x <= int64(1)<<(s-1)-1
- case Int8:
- const s = 8
- return -1<<(s-1) <= x && x <= 1<<(s-1)-1
- case Int16:
- const s = 16
- return -1<<(s-1) <= x && x <= 1<<(s-1)-1
- case Int32:
- const s = 32
- return -1<<(s-1) <= x && x <= 1<<(s-1)-1
- case Int64:
- return true
- case Uint, Uintptr:
- var s = uint(ctxt.sizeof(Typ[as])) * 8
- return 0 <= x && x <= int64(1)<<(s-1)-1
- case Uint8:
- const s = 8
- return 0 <= x && x <= 1<<s-1
- case Uint16:
- const s = 16
- return 0 <= x && x <= 1<<s-1
- case Uint32:
- const s = 32
- return 0 <= x && x <= 1<<s-1
- case Uint64:
- return 0 <= x
- case Float32:
- return true // TODO(gri) fix this
- case Float64:
- return true // TODO(gri) fix this
- case Complex64:
- return true // TODO(gri) fix this
- case Complex128:
- return true // TODO(gri) fix this
- case UntypedInt, UntypedFloat, UntypedComplex:
- return true
- }
-
- case *big.Int:
- switch as {
- case Uint, Uintptr:
- var s = uint(ctxt.sizeof(Typ[as])) * 8
- return x.Sign() >= 0 && x.BitLen() <= int(s)
- case Uint64:
- return x.Sign() >= 0 && x.BitLen() <= 64
- case Float32:
- return true // TODO(gri) fix this
- case Float64:
- return true // TODO(gri) fix this
- case Complex64:
- return true // TODO(gri) fix this
- case Complex128:
- return true // TODO(gri) fix this
- case UntypedInt, UntypedFloat, UntypedComplex:
- return true
- }
-
- case *big.Rat:
- switch as {
- case Float32:
- return true // TODO(gri) fix this
- case Float64:
- return true // TODO(gri) fix this
- case Complex64:
- return true // TODO(gri) fix this
- case Complex128:
- return true // TODO(gri) fix this
- case UntypedFloat, UntypedComplex:
- return true
- }
-
- case Complex:
- switch as {
- case Complex64:
- return true // TODO(gri) fix this
- case Complex128:
- return true // TODO(gri) fix this
- case UntypedComplex:
- return true
- }
-
- case string:
- return as == String || as == UntypedString
-
- case NilType:
- return as == UntypedNil || as == UnsafePointer
-
- default:
- unreachable()
- }
-
- return false
-}
-
-var (
- int1 = big.NewInt(1)
- rat0 = big.NewRat(0, 1)
-)
-
-// complexity returns a measure of representation complexity for constant x.
-func complexity(x interface{}) int {
- switch x.(type) {
- case bool, string, NilType:
- return 1
- case int64:
- return 2
- case *big.Int:
- return 3
- case *big.Rat:
- return 4
- case Complex:
- return 5
- }
- unreachable()
- return 0
-}
-
-// matchConst returns the matching representation (same type) with the
-// smallest complexity for two constant values x and y. They must be
-// of the same "kind" (boolean, numeric, string, or NilType).
-//
-func matchConst(x, y interface{}) (_, _ interface{}) {
- if complexity(x) > complexity(y) {
- y, x = matchConst(y, x)
- return x, y
- }
- // complexity(x) <= complexity(y)
-
- switch x := x.(type) {
- case bool, Complex, string, NilType:
- return x, y
-
- case int64:
- switch y := y.(type) {
- case int64:
- return x, y
- case *big.Int:
- return big.NewInt(x), y
- case *big.Rat:
- return big.NewRat(x, 1), y
- case Complex:
- return Complex{big.NewRat(x, 1), rat0}, y
- }
-
- case *big.Int:
- switch y := y.(type) {
- case *big.Int:
- return x, y
- case *big.Rat:
- return new(big.Rat).SetFrac(x, int1), y
- case Complex:
- return Complex{new(big.Rat).SetFrac(x, int1), rat0}, y
- }
-
- case *big.Rat:
- switch y := y.(type) {
- case *big.Rat:
- return x, y
- case Complex:
- return Complex{x, rat0}, y
- }
- }
-
- unreachable()
- return nil, nil
-}
-
-// is32bit reports whether x can be represented using 32 bits.
-func is32bit(x int64) bool {
- return -1<<31 <= x && x <= 1<<31-1
-}
-
-// is63bit reports whether x can be represented using 63 bits.
-func is63bit(x int64) bool {
- return -1<<62 <= x && x <= 1<<62-1
-}
-
-// unaryOpConst returns the result of the constant evaluation op x where x is of the given type.
-func unaryOpConst(x interface{}, ctxt *Context, op token.Token, typ *Basic) interface{} {
- switch op {
- case token.ADD:
- return x // nothing to do
- case token.SUB:
- switch x := x.(type) {
- case int64:
- if z := -x; z != x {
- return z // no overflow
- }
- // overflow - need to convert to big.Int
- return normalizeIntConst(new(big.Int).Neg(big.NewInt(x)))
- case *big.Int:
- return normalizeIntConst(new(big.Int).Neg(x))
- case *big.Rat:
- return normalizeRatConst(new(big.Rat).Neg(x))
- case Complex:
- return newComplex(new(big.Rat).Neg(x.Re), new(big.Rat).Neg(x.Im))
- }
- case token.XOR:
- var z big.Int
- switch x := x.(type) {
- case int64:
- z.Not(big.NewInt(x))
- case *big.Int:
- z.Not(x)
- default:
- unreachable()
- }
- // For unsigned types, the result will be negative and
- // thus "too large": We must limit the result size to
- // the type's size.
- if typ.Info&IsUnsigned != 0 {
- s := uint(ctxt.sizeof(typ)) * 8
- z.AndNot(&z, new(big.Int).Lsh(big.NewInt(-1), s)) // z &^= (-1)<<s
- }
- return normalizeIntConst(&z)
- case token.NOT:
- return !x.(bool)
- }
- unreachable()
- return nil
-}
-
-// binaryOpConst returns the result of the constant evaluation x op y;
-// both operands must be of the same constant "kind" (boolean, numeric, or string).
-// If typ is an integer type, division (op == token.QUO) is using integer division
-// (and the result is guaranteed to be integer) rather than floating-point
-// division. Division by zero leads to a run-time panic.
-//
-func binaryOpConst(x, y interface{}, op token.Token, typ *Basic) interface{} {
- x, y = matchConst(x, y)
-
- switch x := x.(type) {
- case bool:
- y := y.(bool)
- switch op {
- case token.LAND:
- return x && y
- case token.LOR:
- return x || y
- }
-
- case int64:
- y := y.(int64)
- switch op {
- case token.ADD:
- // TODO(gri) can do better than this
- if is63bit(x) && is63bit(y) {
- return x + y
- }
- return normalizeIntConst(new(big.Int).Add(big.NewInt(x), big.NewInt(y)))
- case token.SUB:
- // TODO(gri) can do better than this
- if is63bit(x) && is63bit(y) {
- return x - y
- }
- return normalizeIntConst(new(big.Int).Sub(big.NewInt(x), big.NewInt(y)))
- case token.MUL:
- // TODO(gri) can do better than this
- if is32bit(x) && is32bit(y) {
- return x * y
- }
- return normalizeIntConst(new(big.Int).Mul(big.NewInt(x), big.NewInt(y)))
- case token.REM:
- return x % y
- case token.QUO:
- if typ.Info&IsInteger != 0 {
- return x / y
- }
- return normalizeRatConst(new(big.Rat).SetFrac(big.NewInt(x), big.NewInt(y)))
- case token.AND:
- return x & y
- case token.OR:
- return x | y
- case token.XOR:
- return x ^ y
- case token.AND_NOT:
- return x &^ y
- }
-
- case *big.Int:
- y := y.(*big.Int)
- var z big.Int
- switch op {
- case token.ADD:
- z.Add(x, y)
- case token.SUB:
- z.Sub(x, y)
- case token.MUL:
- z.Mul(x, y)
- case token.REM:
- z.Rem(x, y)
- case token.QUO:
- if typ.Info&IsInteger != 0 {
- z.Quo(x, y)
- } else {
- return normalizeRatConst(new(big.Rat).SetFrac(x, y))
- }
- case token.AND:
- z.And(x, y)
- case token.OR:
- z.Or(x, y)
- case token.XOR:
- z.Xor(x, y)
- case token.AND_NOT:
- z.AndNot(x, y)
- default:
- unreachable()
- }
- return normalizeIntConst(&z)
-
- case *big.Rat:
- y := y.(*big.Rat)
- var z big.Rat
- switch op {
- case token.ADD:
- z.Add(x, y)
- case token.SUB:
- z.Sub(x, y)
- case token.MUL:
- z.Mul(x, y)
- case token.QUO:
- z.Quo(x, y)
- default:
- unreachable()
- }
- return normalizeRatConst(&z)
-
- case Complex:
- y := y.(Complex)
- a, b := x.Re, x.Im
- c, d := y.Re, y.Im
- var re, im big.Rat
- switch op {
- case token.ADD:
- // (a+c) + i(b+d)
- re.Add(a, c)
- im.Add(b, d)
- case token.SUB:
- // (a-c) + i(b-d)
- re.Sub(a, c)
- im.Sub(b, d)
- case token.MUL:
- // (ac-bd) + i(bc+ad)
- var ac, bd, bc, ad big.Rat
- ac.Mul(a, c)
- bd.Mul(b, d)
- bc.Mul(b, c)
- ad.Mul(a, d)
- re.Sub(&ac, &bd)
- im.Add(&bc, &ad)
- case token.QUO:
- // (ac+bd)/s + i(bc-ad)/s, with s = cc + dd
- var ac, bd, bc, ad, s big.Rat
- ac.Mul(a, c)
- bd.Mul(b, d)
- bc.Mul(b, c)
- ad.Mul(a, d)
- s.Add(c.Mul(c, c), d.Mul(d, d))
- re.Add(&ac, &bd)
- re.Quo(&re, &s)
- im.Sub(&bc, &ad)
- im.Quo(&im, &s)
- default:
- unreachable()
- }
- return newComplex(&re, &im)
-
- case string:
- if op == token.ADD {
- return x + y.(string)
- }
- }
-
- unreachable()
- return nil
-}
-
-// shiftConst returns the result of the constant evaluation x op s
-// where op is token.SHL or token.SHR (<< or >>). x must be an
-// integer constant.
-//
-func shiftConst(x interface{}, s uint, op token.Token) interface{} {
- switch x := x.(type) {
- case int64:
- switch op {
- case token.SHL:
- z := big.NewInt(x)
- return normalizeIntConst(z.Lsh(z, s))
- case token.SHR:
- return x >> s
- }
-
- case *big.Int:
- var z big.Int
- switch op {
- case token.SHL:
- return normalizeIntConst(z.Lsh(x, s))
- case token.SHR:
- return normalizeIntConst(z.Rsh(x, s))
- }
- }
-
- unreachable()
- return nil
-}
-
-// compareConst returns the result of the constant comparison x op y;
-// both operands must be of the same "kind" (boolean, numeric, string,
-// or NilType).
-//
-func compareConst(x, y interface{}, op token.Token) (z bool) {
- x, y = matchConst(x, y)
-
- // x == y => x == y
- // x != y => x != y
- // x > y => y < x
- // x >= y => u <= x
- swap := false
- switch op {
- case token.GTR:
- swap = true
- op = token.LSS
- case token.GEQ:
- swap = true
- op = token.LEQ
- }
-
- // x == y => x == y
- // x != y => !(x == y)
- // x < y => x < y
- // x <= y => !(y < x)
- negate := false
- switch op {
- case token.NEQ:
- negate = true
- op = token.EQL
- case token.LEQ:
- swap = !swap
- negate = true
- op = token.LSS
- }
-
- if negate {
- defer func() { z = !z }()
- }
-
- if swap {
- x, y = y, x
- }
-
- switch x := x.(type) {
- case bool:
- if op == token.EQL {
- return x == y.(bool)
- }
-
- case int64:
- y := y.(int64)
- switch op {
- case token.EQL:
- return x == y
- case token.LSS:
- return x < y
- }
-
- case *big.Int:
- s := x.Cmp(y.(*big.Int))
- switch op {
- case token.EQL:
- return s == 0
- case token.LSS:
- return s < 0
- }
-
- case *big.Rat:
- s := x.Cmp(y.(*big.Rat))
- switch op {
- case token.EQL:
- return s == 0
- case token.LSS:
- return s < 0
- }
-
- case Complex:
- y := y.(Complex)
- if op == token.EQL {
- return x.Re.Cmp(y.Re) == 0 && x.Im.Cmp(y.Im) == 0
- }
-
- case string:
- y := y.(string)
- switch op {
- case token.EQL:
- return x == y
- case token.LSS:
- return x < y
- }
-
- case NilType:
- if op == token.EQL {
- return x == y.(NilType)
- }
- }
-
- fmt.Printf("x = %s (%T), y = %s (%T)\n", x, x, y, y)
- unreachable()
- return
-}
diff --git a/src/pkg/go/types/conversions.go b/src/pkg/go/types/conversions.go
deleted file mode 100644
index fcbaf7717..000000000
--- a/src/pkg/go/types/conversions.go
+++ /dev/null
@@ -1,129 +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.
-
-// This file implements typechecking of conversions.
-
-package types
-
-import (
- "go/ast"
-)
-
-// conversion typechecks the type conversion conv to type typ. iota is the current
-// value of iota or -1 if iota doesn't have a value in the current context. The result
-// of the conversion is returned via x. If the conversion has type errors, the returned
-// x is marked as invalid (x.mode == invalid).
-//
-func (check *checker) conversion(x *operand, conv *ast.CallExpr, typ Type, iota int) {
- // all conversions have one argument
- if len(conv.Args) != 1 {
- check.invalidOp(conv.Pos(), "%s conversion requires exactly one argument", conv)
- goto Error
- }
-
- // evaluate argument
- check.expr(x, conv.Args[0], nil, iota)
- if x.mode == invalid {
- goto Error
- }
-
- if x.mode == constant && isConstType(typ) {
- // constant conversion
- // TODO(gri) implement this
- } else {
- // non-constant conversion
- if !x.isConvertible(check.ctxt, typ) {
- check.invalidOp(conv.Pos(), "cannot convert %s to %s", x, typ)
- goto Error
- }
- x.mode = value
- }
-
- check.conversions[conv] = true // for cap/len checking
- x.expr = conv
- x.typ = typ
- return
-
-Error:
- x.mode = invalid
-}
-
-func (x *operand) isConvertible(ctxt *Context, T Type) bool {
- // "x is assignable to T"
- if x.isAssignable(ctxt, T) {
- return true
- }
-
- // "x's type and T have identical underlying types"
- V := x.typ
- Vu := underlying(V)
- Tu := underlying(T)
- if IsIdentical(Vu, Tu) {
- return true
- }
-
- // "x's type and T are unnamed pointer types and their pointer base types have identical underlying types"
- if V, ok := V.(*Pointer); ok {
- if T, ok := T.(*Pointer); ok {
- if IsIdentical(underlying(V.Base), underlying(T.Base)) {
- return true
- }
- }
- }
-
- // "x's type and T are both integer or floating point types"
- if (isInteger(V) || isFloat(V)) && (isInteger(T) || isFloat(T)) {
- return true
- }
-
- // "x's type and T are both complex types"
- if isComplex(V) && isComplex(T) {
- return true
- }
-
- // "x is an integer or a slice of bytes or runes and T is a string type"
- if (isInteger(V) || isBytesOrRunes(Vu)) && isString(T) {
- return true
- }
-
- // "x is a string and T is a slice of bytes or runes"
- if isString(V) && isBytesOrRunes(Tu) {
- return true
- }
-
- // package unsafe:
- // "any pointer or value of underlying type uintptr can be converted into a unsafe.Pointer"
- if (isPointer(Vu) || isUintptr(Vu)) && isUnsafePointer(T) {
- return true
- }
- // "and vice versa"
- if isUnsafePointer(V) && (isPointer(Tu) || isUintptr(Tu)) {
- return true
- }
-
- return false
-}
-
-func isUintptr(typ Type) bool {
- t, ok := typ.(*Basic)
- return ok && t.Kind == Uintptr
-}
-
-func isUnsafePointer(typ Type) bool {
- t, ok := typ.(*Basic)
- return ok && t.Kind == UnsafePointer
-}
-
-func isPointer(typ Type) bool {
- _, ok := typ.(*Pointer)
- return ok
-}
-
-func isBytesOrRunes(typ Type) bool {
- if s, ok := typ.(*Slice); ok {
- t, ok := underlying(s.Elt).(*Basic)
- return ok && (t.Kind == Byte || t.Kind == Rune)
- }
- return false
-}
diff --git a/src/pkg/go/types/errors.go b/src/pkg/go/types/errors.go
deleted file mode 100644
index 62ee54791..000000000
--- a/src/pkg/go/types/errors.go
+++ /dev/null
@@ -1,335 +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.
-
-// This file implements various error reporters.
-
-package types
-
-import (
- "bytes"
- "fmt"
- "go/ast"
- "go/token"
-)
-
-// TODO(gri) eventually assert and unimplemented should disappear.
-func assert(p bool) {
- if !p {
- panic("assertion failed")
- }
-}
-
-func unreachable() {
- panic("unreachable")
-}
-
-func (check *checker) printTrace(format string, args []interface{}) {
- const dots = ". . . . . . . . . . . . . . . . . . . . "
- n := len(check.pos) - 1
- i := 3 * n
- for i > len(dots) {
- fmt.Print(dots)
- i -= len(dots)
- }
- // i <= len(dots)
- fmt.Printf("%s:\t", check.fset.Position(check.pos[n]))
- fmt.Print(dots[0:i])
- fmt.Println(check.formatMsg(format, args))
-}
-
-func (check *checker) trace(pos token.Pos, format string, args ...interface{}) {
- check.pos = append(check.pos, pos)
- check.printTrace(format, args)
-}
-
-func (check *checker) untrace(format string, args ...interface{}) {
- if len(format) > 0 {
- check.printTrace(format, args)
- }
- check.pos = check.pos[:len(check.pos)-1]
-}
-
-func (check *checker) formatMsg(format string, args []interface{}) string {
- for i, arg := range args {
- switch a := arg.(type) {
- case token.Pos:
- args[i] = check.fset.Position(a).String()
- case ast.Expr:
- args[i] = exprString(a)
- case Type:
- args[i] = typeString(a)
- case operand:
- panic("internal error: should always pass *operand")
- }
- }
- return fmt.Sprintf(format, args...)
-}
-
-// dump is only needed for debugging
-func (check *checker) dump(format string, args ...interface{}) {
- fmt.Println(check.formatMsg(format, args))
-}
-
-func (check *checker) err(err error) {
- if check.firsterr == nil {
- check.firsterr = err
- }
- f := check.ctxt.Error
- if f == nil {
- panic(bailout{}) // report only first error
- }
- f(err)
-}
-
-func (check *checker) errorf(pos token.Pos, format string, args ...interface{}) {
- check.err(fmt.Errorf("%s: %s", check.fset.Position(pos), check.formatMsg(format, args)))
-}
-
-func (check *checker) invalidAST(pos token.Pos, format string, args ...interface{}) {
- check.errorf(pos, "invalid AST: "+format, args...)
-}
-
-func (check *checker) invalidArg(pos token.Pos, format string, args ...interface{}) {
- check.errorf(pos, "invalid argument: "+format, args...)
-}
-
-func (check *checker) invalidOp(pos token.Pos, format string, args ...interface{}) {
- check.errorf(pos, "invalid operation: "+format, args...)
-}
-
-// exprString returns a (simplified) string representation for an expression.
-func exprString(expr ast.Expr) string {
- var buf bytes.Buffer
- writeExpr(&buf, expr)
- return buf.String()
-}
-
-// TODO(gri) Need to merge with typeString since some expressions are types (try: ([]int)(a))
-func writeExpr(buf *bytes.Buffer, expr ast.Expr) {
- switch x := expr.(type) {
- case *ast.Ident:
- buf.WriteString(x.Name)
-
- case *ast.BasicLit:
- buf.WriteString(x.Value)
-
- case *ast.FuncLit:
- buf.WriteString("(func literal)")
-
- case *ast.CompositeLit:
- buf.WriteString("(composite literal)")
-
- case *ast.ParenExpr:
- buf.WriteByte('(')
- writeExpr(buf, x.X)
- buf.WriteByte(')')
-
- case *ast.SelectorExpr:
- writeExpr(buf, x.X)
- buf.WriteByte('.')
- buf.WriteString(x.Sel.Name)
-
- case *ast.IndexExpr:
- writeExpr(buf, x.X)
- buf.WriteByte('[')
- writeExpr(buf, x.Index)
- buf.WriteByte(']')
-
- case *ast.SliceExpr:
- writeExpr(buf, x.X)
- buf.WriteByte('[')
- if x.Low != nil {
- writeExpr(buf, x.Low)
- }
- buf.WriteByte(':')
- if x.High != nil {
- writeExpr(buf, x.High)
- }
- buf.WriteByte(']')
-
- case *ast.TypeAssertExpr:
- writeExpr(buf, x.X)
- buf.WriteString(".(...)")
-
- case *ast.CallExpr:
- writeExpr(buf, x.Fun)
- buf.WriteByte('(')
- for i, arg := range x.Args {
- if i > 0 {
- buf.WriteString(", ")
- }
- writeExpr(buf, arg)
- }
- buf.WriteByte(')')
-
- case *ast.StarExpr:
- buf.WriteByte('*')
- writeExpr(buf, x.X)
-
- case *ast.UnaryExpr:
- buf.WriteString(x.Op.String())
- writeExpr(buf, x.X)
-
- case *ast.BinaryExpr:
- // The AST preserves source-level parentheses so there is
- // no need to introduce parentheses here for correctness.
- writeExpr(buf, x.X)
- buf.WriteByte(' ')
- buf.WriteString(x.Op.String())
- buf.WriteByte(' ')
- writeExpr(buf, x.Y)
-
- default:
- fmt.Fprintf(buf, "<expr %T>", x)
- }
-}
-
-// typeString returns a string representation for typ.
-func typeString(typ Type) string {
- var buf bytes.Buffer
- writeType(&buf, typ)
- return buf.String()
-}
-
-func writeParams(buf *bytes.Buffer, params []*Var, isVariadic bool) {
- buf.WriteByte('(')
- for i, par := range params {
- if i > 0 {
- buf.WriteString(", ")
- }
- if par.Name != "" {
- buf.WriteString(par.Name)
- buf.WriteByte(' ')
- }
- if isVariadic && i == len(params)-1 {
- buf.WriteString("...")
- }
- writeType(buf, par.Type)
- }
- buf.WriteByte(')')
-}
-
-func writeSignature(buf *bytes.Buffer, sig *Signature) {
- writeParams(buf, sig.Params, sig.IsVariadic)
- if len(sig.Results) == 0 {
- // no result
- return
- }
-
- buf.WriteByte(' ')
- if len(sig.Results) == 1 && sig.Results[0].Name == "" {
- // single unnamed result
- writeType(buf, sig.Results[0].Type.(Type))
- return
- }
-
- // multiple or named result(s)
- writeParams(buf, sig.Results, false)
-}
-
-func writeType(buf *bytes.Buffer, typ Type) {
- switch t := typ.(type) {
- case nil:
- buf.WriteString("<nil>")
-
- case *Basic:
- buf.WriteString(t.Name)
-
- case *Array:
- fmt.Fprintf(buf, "[%d]", t.Len)
- writeType(buf, t.Elt)
-
- case *Slice:
- buf.WriteString("[]")
- writeType(buf, t.Elt)
-
- case *Struct:
- buf.WriteString("struct{")
- for i, f := range t.Fields {
- if i > 0 {
- buf.WriteString("; ")
- }
- if !f.IsAnonymous {
- buf.WriteString(f.Name)
- buf.WriteByte(' ')
- }
- writeType(buf, f.Type)
- if f.Tag != "" {
- fmt.Fprintf(buf, " %q", f.Tag)
- }
- }
- buf.WriteByte('}')
-
- case *Pointer:
- buf.WriteByte('*')
- writeType(buf, t.Base)
-
- case *Result:
- writeParams(buf, t.Values, false)
-
- case *Signature:
- buf.WriteString("func")
- writeSignature(buf, t)
-
- case *builtin:
- fmt.Fprintf(buf, "<type of %s>", t.name)
-
- case *Interface:
- buf.WriteString("interface{")
- for i, m := range t.Methods {
- if i > 0 {
- buf.WriteString("; ")
- }
- buf.WriteString(m.Name)
- writeSignature(buf, m.Type)
- }
- buf.WriteByte('}')
-
- case *Map:
- buf.WriteString("map[")
- writeType(buf, t.Key)
- buf.WriteByte(']')
- writeType(buf, t.Elt)
-
- case *Chan:
- var s string
- switch t.Dir {
- case ast.SEND:
- s = "chan<- "
- case ast.RECV:
- s = "<-chan "
- default:
- s = "chan "
- }
- buf.WriteString(s)
- writeType(buf, t.Elt)
-
- case *NamedType:
- s := "<NamedType w/o object>"
- if obj := t.Obj; obj != nil {
- if obj.Pkg != nil && obj.Pkg.Path != "" {
- buf.WriteString(obj.Pkg.Path)
- buf.WriteString(".")
- }
- s = t.Obj.GetName()
- }
- buf.WriteString(s)
-
- default:
- fmt.Fprintf(buf, "<type %T>", t)
- }
-}
-
-func (t *Array) String() string { return typeString(t) }
-func (t *Basic) String() string { return typeString(t) }
-func (t *Chan) String() string { return typeString(t) }
-func (t *Interface) String() string { return typeString(t) }
-func (t *Map) String() string { return typeString(t) }
-func (t *NamedType) String() string { return typeString(t) }
-func (t *Pointer) String() string { return typeString(t) }
-func (t *Result) String() string { return typeString(t) }
-func (t *Signature) String() string { return typeString(t) }
-func (t *Slice) String() string { return typeString(t) }
-func (t *Struct) String() string { return typeString(t) }
-func (t *builtin) String() string { return typeString(t) }
diff --git a/src/pkg/go/types/exportdata.go b/src/pkg/go/types/exportdata.go
deleted file mode 100644
index 1f6a3c725..000000000
--- a/src/pkg/go/types/exportdata.go
+++ /dev/null
@@ -1,111 +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.
-
-// This file implements FindGcExportData.
-
-package types
-
-import (
- "bufio"
- "errors"
- "fmt"
- "io"
- "strconv"
- "strings"
-)
-
-func readGopackHeader(r *bufio.Reader) (name string, size int, err error) {
- // See $GOROOT/include/ar.h.
- hdr := make([]byte, 16+12+6+6+8+10+2)
- _, err = io.ReadFull(r, hdr)
- if err != nil {
- return
- }
- // leave for debugging
- if false {
- fmt.Printf("header: %s", hdr)
- }
- 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")
- return
- }
- name = strings.TrimSpace(string(hdr[:16]))
- return
-}
-
-// FindGcExportData positions the reader r at the beginning of the
-// export data section of an underlying GC-created object/archive
-// file by reading from it. The reader must be positioned at the
-// start of the file before calling this function.
-//
-func FindGcExportData(r *bufio.Reader) (err error) {
- // Read first line to make sure this is an object file.
- line, err := r.ReadSlice('\n')
- if err != nil {
- return
- }
- if string(line) == "!<arch>\n" {
- // Archive file. Scan to __.PKGDEF, which should
- // be second archive entry.
- var name string
- var size int
-
- // First entry should be __.GOSYMDEF.
- // Older archives used __.SYMDEF, so allow that too.
- // Read and discard.
- if name, size, err = readGopackHeader(r); err != nil {
- return
- }
- if name != "__.SYMDEF" && name != "__.GOSYMDEF" {
- err = errors.New("go archive does not begin with __.SYMDEF or __.GOSYMDEF")
- return
- }
- 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
- }
-
- // Second entry should be __.PKGDEF.
- if name, size, err = readGopackHeader(r); err != nil {
- return
- }
- if name != "__.PKGDEF" {
- err = errors.New("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 {
- return
- }
- }
-
- // 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")
- return
- }
-
- // Skip over object header to export data.
- // Begins after first line with $$.
- for line[0] != '$' {
- if line, err = r.ReadSlice('\n'); err != nil {
- return
- }
- }
-
- return
-}
diff --git a/src/pkg/go/types/expr.go b/src/pkg/go/types/expr.go
deleted file mode 100644
index 86d782d48..000000000
--- a/src/pkg/go/types/expr.go
+++ /dev/null
@@ -1,1520 +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.
-
-// This file implements typechecking of expressions.
-
-package types
-
-import (
- "go/ast"
- "go/token"
- "strconv"
-)
-
-// TODO(gri) Cleanups
-// - don't print error messages referring to invalid types (they are likely spurious errors)
-// - simplify invalid handling: maybe just use Typ[Invalid] as marker, get rid of invalid Mode for values?
-// - rethink error handling: should all callers check if x.mode == valid after making a call?
-// - at the moment, iota is passed around almost everywhere - in many places we know it cannot be used
-// - use "" or "_" consistently for anonymous identifiers? (e.g. reeceivers that have no name)
-// - consider storing error messages in invalid operands for better error messages/debugging output
-
-// TODO(gri) API issues
-// - clients need access to builtins type information
-// - API tests are missing (e.g., identifiers should be handled as expressions in callbacks)
-
-func (check *checker) collectParams(list *ast.FieldList, variadicOk bool) (params []*Var, isVariadic bool) {
- if list == nil {
- return
- }
- var last *Var
- for i, field := range list.List {
- ftype := field.Type
- if t, _ := ftype.(*ast.Ellipsis); t != nil {
- ftype = t.Elt
- if variadicOk && i == len(list.List)-1 {
- isVariadic = true
- } else {
- check.invalidAST(field.Pos(), "... not permitted")
- // ok to continue
- }
- }
- // the parser ensures that f.Tag is nil and we don't
- // care if a constructed AST contains a non-nil tag
- typ := check.typ(ftype, true)
- if len(field.Names) > 0 {
- // named parameter
- for _, name := range field.Names {
- par := check.lookup(name).(*Var)
- par.Type = typ
- last = par
- copy := *par
- params = append(params, &copy)
- }
- } else {
- // anonymous parameter
- par := &Var{Type: typ}
- last = nil // not accessible inside function
- params = append(params, par)
- }
- }
- // For a variadic function, change the last parameter's object type
- // from T to []T (this is the type used inside the function), but
- // keep the params list unchanged (this is the externally visible type).
- if isVariadic && last != nil {
- last.Type = &Slice{Elt: last.Type}
- }
- return
-}
-
-func (check *checker) collectMethods(list *ast.FieldList) (methods []*Method) {
- if list == nil {
- return
- }
- for _, f := range list.List {
- typ := check.typ(f.Type, len(f.Names) > 0) // cycles are not ok for embedded interfaces
- // the parser ensures that f.Tag is nil and we don't
- // care if a constructed AST contains a non-nil tag
- if len(f.Names) > 0 {
- // methods (the parser ensures that there's only one
- // and we don't care if a constructed AST has more)
- sig, ok := typ.(*Signature)
- if !ok {
- check.invalidAST(f.Type.Pos(), "%s is not a method signature", typ)
- continue
- }
- for _, name := range f.Names {
- methods = append(methods, &Method{QualifiedName{check.pkg, name.Name}, sig})
- }
- } else {
- // embedded interface
- utyp := underlying(typ)
- if ityp, ok := utyp.(*Interface); ok {
- methods = append(methods, ityp.Methods...)
- } else if utyp != Typ[Invalid] {
- // if utyp is invalid, don't complain (the root cause was reported before)
- check.errorf(f.Type.Pos(), "%s is not an interface type", typ)
- }
- }
- }
- // Check for double declarations.
- // The parser inserts methods into an interface-local scope, so local
- // double declarations are reported by the parser already. We need to
- // check again for conflicts due to embedded interfaces. This will lead
- // to a 2nd error message if the double declaration was reported before
- // by the parser.
- // TODO(gri) clean this up a bit
- seen := make(map[string]bool)
- for _, m := range methods {
- if seen[m.Name] {
- check.errorf(list.Pos(), "multiple methods named %s", m.Name)
- return // keep multiple entries, lookup will only return the first entry
- }
- seen[m.Name] = true
- }
- return
-}
-
-func (check *checker) tag(t *ast.BasicLit) string {
- if t != nil {
- if t.Kind == token.STRING {
- if val, err := strconv.Unquote(t.Value); err == nil {
- return val
- }
- }
- check.invalidAST(t.Pos(), "incorrect tag syntax: %q", t.Value)
- }
- return ""
-}
-
-func (check *checker) collectFields(list *ast.FieldList, cycleOk bool) (fields []*Field) {
- if list == nil {
- return
- }
-
- var typ Type // current field typ
- var tag string // current field tag
- add := func(name string, isAnonymous bool) {
- fields = append(fields, &Field{QualifiedName{check.pkg, name}, typ, tag, isAnonymous})
- }
-
- for _, f := range list.List {
- typ = check.typ(f.Type, cycleOk)
- tag = check.tag(f.Tag)
- if len(f.Names) > 0 {
- // named fields
- for _, name := range f.Names {
- add(name.Name, false)
- }
- } else {
- // anonymous field
- switch t := deref(typ).(type) {
- case *Basic:
- add(t.Name, true)
- case *NamedType:
- add(t.Obj.GetName(), true)
- default:
- if typ != Typ[Invalid] {
- check.invalidAST(f.Type.Pos(), "anonymous field type %s must be named", typ)
- }
- }
- }
- }
-
- return
-}
-
-type opPredicates map[token.Token]func(Type) bool
-
-var unaryOpPredicates = opPredicates{
- token.ADD: isNumeric,
- token.SUB: isNumeric,
- token.XOR: isInteger,
- token.NOT: isBoolean,
-}
-
-func (check *checker) op(m opPredicates, x *operand, op token.Token) bool {
- if pred := m[op]; pred != nil {
- if !pred(x.typ) {
- check.invalidOp(x.pos(), "operator %s not defined for %s", op, x)
- return false
- }
- } else {
- check.invalidAST(x.pos(), "unknown operator %s", op)
- return false
- }
- return true
-}
-
-func (check *checker) unary(x *operand, op token.Token) {
- switch op {
- case token.AND:
- // spec: "As an exception to the addressability
- // requirement x may also be a composite literal."
- if _, ok := unparen(x.expr).(*ast.CompositeLit); ok {
- x.mode = variable
- }
- if x.mode != variable {
- check.invalidOp(x.pos(), "cannot take address of %s", x)
- goto Error
- }
- x.typ = &Pointer{Base: x.typ}
- return
-
- case token.ARROW:
- typ, ok := underlying(x.typ).(*Chan)
- if !ok {
- check.invalidOp(x.pos(), "cannot receive from non-channel %s", x)
- goto Error
- }
- if typ.Dir&ast.RECV == 0 {
- check.invalidOp(x.pos(), "cannot receive from send-only channel %s", x)
- goto Error
- }
- x.mode = valueok
- x.typ = typ.Elt
- return
- }
-
- if !check.op(unaryOpPredicates, x, op) {
- goto Error
- }
-
- if x.mode == constant {
- typ := underlying(x.typ).(*Basic)
- x.val = unaryOpConst(x.val, check.ctxt, op, typ)
- // Typed constants must be representable in
- // their type after each constant operation.
- check.isRepresentable(x, typ)
- return
- }
-
- x.mode = value
- // x.typ remains unchanged
- return
-
-Error:
- x.mode = invalid
-}
-
-func isShift(op token.Token) bool {
- return op == token.SHL || op == token.SHR
-}
-
-func isComparison(op token.Token) bool {
- // Note: tokens are not ordered well to make this much easier
- switch op {
- case token.EQL, token.NEQ, token.LSS, token.LEQ, token.GTR, token.GEQ:
- return true
- }
- return false
-}
-
-// isRepresentable checks that a constant operand is representable in the given type.
-func (check *checker) isRepresentable(x *operand, typ *Basic) {
- if x.mode != constant || isUntyped(typ) {
- return
- }
-
- if !isRepresentableConst(x.val, check.ctxt, typ.Kind) {
- var msg string
- if isNumeric(x.typ) && isNumeric(typ) {
- msg = "%s overflows %s"
- } else {
- msg = "cannot convert %s to %s"
- }
- check.errorf(x.pos(), msg, x, typ)
- x.mode = invalid
- }
-}
-
-// updateExprType updates the type of all untyped nodes in the
-// expression tree of x to typ. If shiftOp is set, x is the lhs
-// of a shift expression. In that case, and if x is in the set
-// of shift operands with delayed type checking, and typ is not
-// an untyped type, updateExprType will check if typ is an
-// integer type.
-// If Context.Expr != nil, it is called for all nodes that are
-// now assigned their final (not untyped) type.
-func (check *checker) updateExprType(x ast.Expr, typ Type, shiftOp bool) {
- switch x := x.(type) {
- case *ast.BadExpr,
- *ast.FuncLit,
- *ast.CompositeLit,
- *ast.SelectorExpr,
- *ast.IndexExpr,
- *ast.SliceExpr,
- *ast.TypeAssertExpr,
- *ast.CallExpr,
- *ast.StarExpr,
- *ast.KeyValueExpr,
- *ast.ArrayType,
- *ast.StructType,
- *ast.FuncType,
- *ast.InterfaceType,
- *ast.MapType,
- *ast.ChanType:
- // these expression are never untyped - nothing to do
- return
-
- case *ast.Ident, *ast.BasicLit:
- // update type
-
- case *ast.ParenExpr:
- check.updateExprType(x.X, typ, false)
-
- case *ast.UnaryExpr:
- check.updateExprType(x.X, typ, false)
-
- case *ast.BinaryExpr:
- if isComparison(x.Op) {
- // result type is independent of operand types
- } else if isShift(x.Op) {
- // result type depends only on lhs operand
- check.updateExprType(x.X, typ, true)
- } else {
- // operand types match result type
- check.updateExprType(x.X, typ, false)
- check.updateExprType(x.Y, typ, false)
- }
-
- case *ast.Ellipsis:
- unreachable()
- default:
- unreachable()
- }
-
- // TODO(gri) t should always exist, shouldn't it?
- if t := check.untyped[x]; t != nil {
- if isUntyped(typ) {
- check.untyped[x] = typ.(*Basic)
- } else {
- // notify clients of final type for x
- if f := check.ctxt.Expr; f != nil {
- f(x, typ, check.constants[x])
- }
- delete(check.untyped, x)
- delete(check.constants, x)
- // check delayed shift
- // Note: Using shiftOp is an optimization: it prevents
- // map lookups when we know x is not a shiftOp in the
- // first place.
- if shiftOp && check.shiftOps[x] {
- if !isInteger(typ) {
- check.invalidOp(x.Pos(), "shifted operand %s (type %s) must be integer", x, typ)
- }
- delete(check.shiftOps, x)
- }
- }
- }
-}
-
-// convertUntyped attempts to set the type of an untyped value to the target type.
-func (check *checker) convertUntyped(x *operand, target Type) {
- if x.mode == invalid || !isUntyped(x.typ) {
- return
- }
-
- // TODO(gri) Sloppy code - clean up. This function is central
- // to assignment and expression checking.
-
- if isUntyped(target) {
- // both x and target are untyped
- xkind := x.typ.(*Basic).Kind
- tkind := target.(*Basic).Kind
- if isNumeric(x.typ) && isNumeric(target) {
- if xkind < tkind {
- x.typ = target
- check.updateExprType(x.expr, target, false)
- }
- } else if xkind != tkind {
- goto Error
- }
- return
- }
-
- // typed target
- switch t := underlying(target).(type) {
- case nil:
- // We may reach here due to previous type errors.
- // Be conservative and don't crash.
- x.mode = invalid
- return
- case *Basic:
- check.isRepresentable(x, t)
- if x.mode == invalid {
- return // error already reported
- }
- case *Interface:
- if !x.isNil() && len(t.Methods) > 0 /* empty interfaces are ok */ {
- goto Error
- }
- // Update operand types to the default type rather then
- // the target (interface) type: values must have concrete
- // dynamic types. If the value is nil, keep it untyped
- // (this is important for tools such as go vet which need
- // the dynamic type for argument checking of say, print
- // functions)
- if x.isNil() {
- target = Typ[UntypedNil]
- } else {
- // cannot assign untyped values to non-empty interfaces
- if len(t.Methods) > 0 {
- goto Error
- }
- target = defaultType(x.typ)
- }
- case *Pointer, *Signature, *Slice, *Map, *Chan:
- if !x.isNil() {
- goto Error
- }
- // keep nil untyped - see comment for interfaces, above
- target = Typ[UntypedNil]
- default:
- if debug {
- check.dump("convertUntyped(x = %v, target = %v)", x, target)
- }
- unreachable()
- }
-
- x.typ = target
- check.updateExprType(x.expr, target, false)
- return
-
-Error:
- check.errorf(x.pos(), "cannot convert %s to %s", x, target)
- x.mode = invalid
-}
-
-func (check *checker) comparison(x, y *operand, op token.Token) {
- // TODO(gri) deal with interface vs non-interface comparison
-
- valid := false
- if x.isAssignable(check.ctxt, y.typ) || y.isAssignable(check.ctxt, x.typ) {
- switch op {
- case token.EQL, token.NEQ:
- valid = isComparable(x.typ) ||
- x.isNil() && hasNil(y.typ) ||
- y.isNil() && hasNil(x.typ)
- case token.LSS, token.LEQ, token.GTR, token.GEQ:
- valid = isOrdered(x.typ)
- default:
- unreachable()
- }
- }
-
- if !valid {
- check.invalidOp(x.pos(), "cannot compare %s %s %s", x, op, y)
- x.mode = invalid
- return
- }
-
- if x.mode == constant && y.mode == constant {
- x.val = compareConst(x.val, y.val, op)
- } else {
- x.mode = value
- }
-
- x.typ = Typ[UntypedBool]
-}
-
-func (check *checker) shift(x, y *operand, op token.Token) {
- // spec: "The right operand in a shift expression must have unsigned
- // integer type or be an untyped constant that can be converted to
- // unsigned integer type."
- switch {
- case isInteger(y.typ) && isUnsigned(y.typ):
- // nothing to do
- case y.mode == constant && isUntyped(y.typ):
- check.convertUntyped(x, Typ[UntypedInt])
- default:
- check.invalidOp(y.pos(), "shift count %s must be unsigned integer", y)
- x.mode = invalid
- return
- }
-
- if x.mode == constant {
- if y.mode == constant {
- // constant shift - lhs must be (representable as) an integer
- if isUntyped(x.typ) {
- if !isRepresentableConst(x.val, check.ctxt, UntypedInt) {
- check.invalidOp(x.pos(), "shifted operand %s must be integer", x)
- x.mode = invalid
- return
- }
- x.typ = Typ[UntypedInt]
- }
- assert(x.isInteger(check.ctxt))
-
- // rhs must be within reasonable bounds
- const stupidShift = 1024
- s, ok := y.val.(int64)
- if !ok || s < 0 || s >= stupidShift {
- check.invalidOp(y.pos(), "%s: stupid shift", y)
- x.mode = invalid
- return
- }
-
- // everything's ok
- x.val = shiftConst(x.val, uint(s), op)
- return
- }
-
- // non-constant shift with constant lhs
- if isUntyped(x.typ) {
- // spec: "If the left operand of a non-constant shift expression is
- // an untyped constant, the type of the constant is what it would be
- // if the shift expression were replaced by its left operand alone;
- // the type is int if it cannot be determined from the context (for
- // instance, if the shift expression is an operand in a comparison
- // against an untyped constant)".
-
- // delay operand checking until we know the type
- check.shiftOps[x.expr] = true
- x.mode = value
- return
- }
- }
-
- // non-constant shift - lhs must be an integer
- if !isInteger(x.typ) {
- check.invalidOp(x.pos(), "shifted operand %s must be integer", x)
- x.mode = invalid
- return
- }
-
- // non-constant shift
- x.mode = value
-}
-
-var binaryOpPredicates = opPredicates{
- token.ADD: func(typ Type) bool { return isNumeric(typ) || isString(typ) },
- token.SUB: isNumeric,
- token.MUL: isNumeric,
- token.QUO: isNumeric,
- token.REM: isInteger,
-
- token.AND: isInteger,
- token.OR: isInteger,
- token.XOR: isInteger,
- token.AND_NOT: isInteger,
-
- token.LAND: isBoolean,
- token.LOR: isBoolean,
-}
-
-func (check *checker) binary(x *operand, lhs, rhs ast.Expr, op token.Token, iota int) {
- var y operand
-
- check.expr(x, lhs, nil, iota)
- check.expr(&y, rhs, nil, iota)
-
- if x.mode == invalid {
- return
- }
- if y.mode == invalid {
- x.mode = invalid
- x.expr = y.expr
- return
- }
-
- if isShift(op) {
- check.shift(x, &y, op)
- return
- }
-
- check.convertUntyped(x, y.typ)
- if x.mode == invalid {
- return
- }
- check.convertUntyped(&y, x.typ)
- if y.mode == invalid {
- x.mode = invalid
- return
- }
-
- if isComparison(op) {
- check.comparison(x, &y, op)
- return
- }
-
- if !IsIdentical(x.typ, y.typ) {
- check.invalidOp(x.pos(), "mismatched types %s and %s", x.typ, y.typ)
- x.mode = invalid
- return
- }
-
- if !check.op(binaryOpPredicates, x, op) {
- x.mode = invalid
- return
- }
-
- if (op == token.QUO || op == token.REM) && y.mode == constant && isZeroConst(y.val) {
- check.invalidOp(y.pos(), "division by zero")
- x.mode = invalid
- return
- }
-
- if x.mode == constant && y.mode == constant {
- typ := underlying(x.typ).(*Basic)
- x.val = binaryOpConst(x.val, y.val, op, typ)
- // Typed constants must be representable in
- // their type after each constant operation.
- check.isRepresentable(x, typ)
- return
- }
-
- x.mode = value
- // x.typ is unchanged
-}
-
-// index checks an index expression for validity. If length >= 0, it is the upper
-// bound for the index. The result is a valid index >= 0, or a negative value.
-//
-func (check *checker) index(index ast.Expr, length int64, iota int) int64 {
- var x operand
-
- check.expr(&x, index, nil, iota)
- if !x.isInteger(check.ctxt) {
- check.errorf(x.pos(), "index %s must be integer", &x)
- return -1
- }
- if x.mode != constant {
- return -1 // we cannot check more
- }
- // The spec doesn't require int64 indices, but perhaps it should.
- i, ok := x.val.(int64)
- if !ok {
- check.errorf(x.pos(), "stupid index %s", &x)
- return -1
- }
- if i < 0 {
- check.errorf(x.pos(), "index %s must not be negative", &x)
- return -1
- }
- if length >= 0 && i >= length {
- check.errorf(x.pos(), "index %s is out of bounds (>= %d)", &x, length)
- return -1
- }
-
- return i
-}
-
-// compositeLitKey resolves unresolved composite literal keys.
-// For details, see comment in go/parser/parser.go, method parseElement.
-func (check *checker) compositeLitKey(key ast.Expr) {
- if ident, ok := key.(*ast.Ident); ok && ident.Obj == nil {
- if obj := check.pkg.Scope.Lookup(ident.Name); obj != nil {
- check.register(ident, obj)
- } else if obj := Universe.Lookup(ident.Name); obj != nil {
- check.register(ident, obj)
- } else {
- check.errorf(ident.Pos(), "undeclared name: %s", ident.Name)
- }
- }
-}
-
-// indexElts checks the elements (elts) of an array or slice composite literal
-// against the literal's element type (typ), and the element indices against
-// the literal length if known (length >= 0). It returns the length of the
-// literal (maximum index value + 1).
-//
-func (check *checker) indexedElts(elts []ast.Expr, typ Type, length int64, iota int) int64 {
- visited := make(map[int64]bool, len(elts))
- var index, max int64
- for _, e := range elts {
- // determine and check index
- validIndex := false
- eval := e
- if kv, _ := e.(*ast.KeyValueExpr); kv != nil {
- check.compositeLitKey(kv.Key)
- if i := check.index(kv.Key, length, iota); i >= 0 {
- index = i
- validIndex = true
- }
- eval = kv.Value
- } else if length >= 0 && index >= length {
- check.errorf(e.Pos(), "index %d is out of bounds (>= %d)", index, length)
- } else {
- validIndex = true
- }
-
- // if we have a valid index, check for duplicate entries
- if validIndex {
- if visited[index] {
- check.errorf(e.Pos(), "duplicate index %d in array or slice literal", index)
- }
- visited[index] = true
- }
- index++
- if index > max {
- max = index
- }
-
- // check element against composite literal element type
- var x operand
- check.expr(&x, eval, typ, iota)
- if !check.assignment(&x, typ) && x.mode != invalid {
- check.errorf(x.pos(), "cannot use %s as %s value in array or slice literal", &x, typ)
- }
- }
- return max
-}
-
-// argument typechecks passing an argument arg (if arg != nil) or
-// x (if arg == nil) to the i'th parameter of the given signature.
-// If passSlice is set, the argument is followed by ... in the call.
-//
-func (check *checker) argument(sig *Signature, i int, arg ast.Expr, x *operand, passSlice bool) {
- // determine parameter
- var par *Var
- n := len(sig.Params)
- if i < n {
- par = sig.Params[i]
- } else if sig.IsVariadic {
- par = sig.Params[n-1]
- } else {
- check.errorf(arg.Pos(), "too many arguments")
- return
- }
-
- // determine argument
- var z operand
- z.mode = variable
- z.expr = nil // TODO(gri) can we do better here? (for good error messages)
- z.typ = par.Type
-
- if arg != nil {
- check.expr(x, arg, z.typ, -1)
- }
- if x.mode == invalid {
- return // ignore this argument
- }
-
- // check last argument of the form x...
- if passSlice {
- if i+1 != n {
- check.errorf(x.pos(), "can only use ... with matching parameter")
- return // ignore this argument
- }
- // spec: "If the final argument is assignable to a slice type []T,
- // it may be passed unchanged as the value for a ...T parameter if
- // the argument is followed by ..."
- z.typ = &Slice{Elt: z.typ} // change final parameter type to []T
- }
-
- if !check.assignment(x, z.typ) && x.mode != invalid {
- check.errorf(x.pos(), "cannot pass argument %s to %s", x, &z)
- }
-}
-
-var emptyResult Result
-
-func (check *checker) callExpr(x *operand) {
- var typ Type
- var val interface{}
- switch x.mode {
- case invalid:
- return // nothing to do
- case novalue:
- typ = &emptyResult
- case constant:
- typ = x.typ
- val = x.val
- default:
- typ = x.typ
- }
-
- // if the operand is untyped, delay notification
- // until it becomes typed or until the end of
- // type checking
- if isUntyped(typ) {
- check.untyped[x.expr] = typ.(*Basic)
- if val != nil {
- check.constants[x.expr] = val
- }
- return
- }
-
- // TODO(gri) ensure that literals always report
- // their dynamic (never interface) type.
- // This is not the case yet.
-
- if check.ctxt.Expr != nil {
- check.ctxt.Expr(x.expr, typ, val)
- }
-}
-
-// rawExpr typechecks expression e and initializes x with the expression
-// value or type. If an error occurred, x.mode is set to invalid.
-// If hint != nil, it is the type of a composite literal element.
-// iota >= 0 indicates that the expression is part of a constant declaration.
-// cycleOk indicates whether it is ok for a type expression to refer to itself.
-//
-func (check *checker) rawExpr(x *operand, e ast.Expr, hint Type, iota int, cycleOk bool) {
- if trace {
- c := ""
- if cycleOk {
- c = " ⨁"
- }
- check.trace(e.Pos(), "%s (%s, %d%s)", e, typeString(hint), iota, c)
- defer check.untrace("=> %s", x)
- }
-
- defer check.callExpr(x)
-
- switch e := e.(type) {
- case *ast.BadExpr:
- goto Error // error was reported before
-
- case *ast.Ident:
- if e.Name == "_" {
- check.invalidOp(e.Pos(), "cannot use _ as value or type")
- goto Error
- }
- obj := check.lookup(e)
- if obj == nil {
- goto Error // error was reported before
- }
- check.object(obj, cycleOk)
- switch obj := obj.(type) {
- case *Package:
- check.errorf(e.Pos(), "use of package %s not in selector", obj.Name)
- goto Error
- case *Const:
- if obj.Val == nil {
- goto Error // cycle detected
- }
- x.mode = constant
- if obj == universeIota {
- if iota < 0 {
- check.invalidAST(e.Pos(), "cannot use iota outside constant declaration")
- goto Error
- }
- x.val = int64(iota)
- } else {
- x.val = obj.Val
- }
- case *TypeName:
- x.mode = typexpr
- if !cycleOk && underlying(obj.Type) == nil {
- check.errorf(obj.spec.Pos(), "illegal cycle in declaration of %s", obj.Name)
- x.expr = e
- x.typ = Typ[Invalid]
- return // don't goto Error - need x.mode == typexpr
- }
- case *Var:
- x.mode = variable
- case *Func:
- x.mode = value
- default:
- unreachable()
- }
- x.typ = obj.GetType()
-
- case *ast.Ellipsis:
- // ellipses are handled explicitly where they are legal
- // (array composite literals and parameter lists)
- check.errorf(e.Pos(), "invalid use of '...'")
- goto Error
-
- case *ast.BasicLit:
- x.setConst(e.Kind, e.Value)
- if x.mode == invalid {
- check.invalidAST(e.Pos(), "invalid literal %v", e.Value)
- goto Error
- }
-
- case *ast.FuncLit:
- if sig, ok := check.typ(e.Type, false).(*Signature); ok {
- x.mode = value
- x.typ = sig
- check.later(nil, sig, e.Body)
- } else {
- check.invalidAST(e.Pos(), "invalid function literal %s", e)
- goto Error
- }
-
- case *ast.CompositeLit:
- typ := hint
- openArray := false
- if e.Type != nil {
- // [...]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, Elt: check.typ(atyp.Elt, cycleOk)}
- openArray = true
- }
- }
- if typ == nil {
- typ = check.typ(e.Type, false)
- }
- }
- if typ == nil {
- check.errorf(e.Pos(), "missing type in composite literal")
- goto Error
- }
-
- switch utyp := underlying(deref(typ)).(type) {
- case *Struct:
- if len(e.Elts) == 0 {
- break
- }
- fields := utyp.Fields
- if _, ok := e.Elts[0].(*ast.KeyValueExpr); ok {
- // all elements must have keys
- visited := make([]bool, len(fields))
- for _, e := range e.Elts {
- kv, _ := e.(*ast.KeyValueExpr)
- if kv == nil {
- check.errorf(e.Pos(), "mixture of field:value and value elements in struct literal")
- continue
- }
- key, _ := kv.Key.(*ast.Ident)
- if key == nil {
- check.errorf(kv.Pos(), "invalid field name %s in struct literal", kv.Key)
- continue
- }
- i := utyp.fieldIndex(QualifiedName{check.pkg, key.Name})
- if i < 0 {
- check.errorf(kv.Pos(), "unknown field %s in struct literal", key.Name)
- continue
- }
- // 0 <= i < len(fields)
- if visited[i] {
- check.errorf(kv.Pos(), "duplicate field name %s in struct literal", key.Name)
- continue
- }
- visited[i] = true
- check.expr(x, kv.Value, nil, iota)
- etyp := fields[i].Type
- if !check.assignment(x, etyp) {
- if x.mode != invalid {
- check.errorf(x.pos(), "cannot use %s as %s value in struct literal", x, etyp)
- }
- continue
- }
- }
- } else {
- // no element must have a key
- for i, e := range e.Elts {
- if kv, _ := e.(*ast.KeyValueExpr); kv != nil {
- check.errorf(kv.Pos(), "mixture of field:value and value elements in struct literal")
- continue
- }
- check.expr(x, e, nil, iota)
- if i >= len(fields) {
- check.errorf(x.pos(), "too many values in struct literal")
- break // cannot continue
- }
- // i < len(fields)
- etyp := fields[i].Type
- if !check.assignment(x, etyp) {
- if x.mode != invalid {
- check.errorf(x.pos(), "cannot use %s as %s value in struct literal", x, etyp)
- }
- continue
- }
- }
- if len(e.Elts) < len(fields) {
- check.errorf(e.Rbrace, "too few values in struct literal")
- // ok to continue
- }
- }
-
- case *Array:
- n := check.indexedElts(e.Elts, utyp.Elt, utyp.Len, iota)
- // if we have an "open" [...]T array, set the length now that we know it
- if openArray {
- utyp.Len = n
- }
-
- case *Slice:
- check.indexedElts(e.Elts, utyp.Elt, -1, iota)
-
- case *Map:
- visited := make(map[interface{}]bool, len(e.Elts))
- for _, e := range e.Elts {
- kv, _ := e.(*ast.KeyValueExpr)
- if kv == nil {
- check.errorf(e.Pos(), "missing key in map literal")
- continue
- }
- check.compositeLitKey(kv.Key)
- check.expr(x, kv.Key, nil, iota)
- if !check.assignment(x, utyp.Key) {
- if x.mode != invalid {
- check.errorf(x.pos(), "cannot use %s as %s key in map literal", x, utyp.Key)
- }
- continue
- }
- if x.mode == constant {
- if visited[x.val] {
- check.errorf(x.pos(), "duplicate key %s in map literal", x.val)
- continue
- }
- visited[x.val] = true
- }
- check.expr(x, kv.Value, utyp.Elt, iota)
- if !check.assignment(x, utyp.Elt) {
- if x.mode != invalid {
- check.errorf(x.pos(), "cannot use %s as %s value in map literal", x, utyp.Elt)
- }
- continue
- }
- }
-
- default:
- check.errorf(e.Pos(), "%s is not a valid composite literal type", typ)
- goto Error
- }
-
- x.mode = value
- x.typ = typ
-
- case *ast.ParenExpr:
- check.rawExpr(x, e.X, nil, iota, cycleOk)
-
- case *ast.SelectorExpr:
- sel := e.Sel.Name
- // If the identifier refers to a package, handle everything here
- // so we don't need a "package" mode for operands: package names
- // can only appear in qualified identifiers which are mapped to
- // selector expressions.
- if ident, ok := e.X.(*ast.Ident); ok {
- if pkg, ok := check.lookup(ident).(*Package); ok {
- exp := pkg.Scope.Lookup(sel)
- // gcimported package scopes contain non-exported
- // objects such as types used in partially exported
- // objects - do not accept them
- if exp == nil || !ast.IsExported(exp.GetName()) {
- check.errorf(e.Pos(), "cannot refer to unexported %s", e)
- goto Error
- }
- check.register(e.Sel, exp)
- // Simplified version of the code for *ast.Idents:
- // - imported packages use types.Scope and types.Objects
- // - imported objects are always fully initialized
- switch exp := exp.(type) {
- case *Const:
- assert(exp.Val != nil)
- x.mode = constant
- x.typ = exp.Type
- x.val = exp.Val
- case *TypeName:
- x.mode = typexpr
- x.typ = exp.Type
- case *Var:
- x.mode = variable
- x.typ = exp.Type
- case *Func:
- x.mode = value
- x.typ = exp.Type
- default:
- unreachable()
- }
- x.expr = e
- return
- }
- }
-
- check.exprOrType(x, e.X, iota, false)
- if x.mode == invalid {
- goto Error
- }
- res := lookupField(x.typ, QualifiedName{check.pkg, sel})
- if res.mode == invalid {
- check.invalidOp(e.Pos(), "%s has no single field or method %s", x, sel)
- goto Error
- }
- if x.mode == typexpr {
- // method expression
- sig, ok := res.typ.(*Signature)
- if !ok {
- check.invalidOp(e.Pos(), "%s has no method %s", x, sel)
- goto Error
- }
- // the receiver type becomes the type of the first function
- // argument of the method expression's function type
- // TODO(gri) at the moment, method sets don't correctly track
- // pointer vs non-pointer receivers => typechecker is too lenient
- x.mode = value
- x.typ = &Signature{
- Params: append([]*Var{{Type: x.typ}}, sig.Params...),
- Results: sig.Results,
- IsVariadic: sig.IsVariadic,
- }
- } else {
- // regular selector
- x.mode = res.mode
- x.typ = res.typ
- }
-
- case *ast.IndexExpr:
- check.expr(x, e.X, nil, iota)
- if x.mode == invalid {
- goto Error
- }
-
- valid := false
- length := int64(-1) // valid if >= 0
- switch typ := underlying(x.typ).(type) {
- case *Basic:
- if isString(typ) {
- valid = true
- if x.mode == constant {
- length = int64(len(x.val.(string)))
- }
- // an indexed string always yields a byte value
- // (not a constant) even if the string and the
- // index are constant
- x.mode = value
- x.typ = Typ[Byte]
- }
-
- case *Array:
- valid = true
- length = typ.Len
- if x.mode != variable {
- x.mode = value
- }
- x.typ = typ.Elt
-
- case *Pointer:
- if typ, _ := underlying(typ.Base).(*Array); typ != nil {
- valid = true
- length = typ.Len
- x.mode = variable
- x.typ = typ.Elt
- }
-
- case *Slice:
- valid = true
- x.mode = variable
- x.typ = typ.Elt
-
- case *Map:
- var key operand
- check.expr(&key, e.Index, nil, iota)
- if !check.assignment(&key, typ.Key) {
- if key.mode != invalid {
- check.invalidOp(key.pos(), "cannot use %s as map index of type %s", &key, typ.Key)
- }
- goto Error
- }
- x.mode = valueok
- x.typ = typ.Elt
- x.expr = e
- return
- }
-
- if !valid {
- check.invalidOp(x.pos(), "cannot index %s", x)
- goto Error
- }
-
- if e.Index == nil {
- check.invalidAST(e.Pos(), "missing index expression for %s", x)
- return
- }
-
- check.index(e.Index, length, iota)
- // ok to continue
-
- case *ast.SliceExpr:
- check.expr(x, e.X, nil, iota)
- if x.mode == invalid {
- goto Error
- }
-
- valid := false
- length := int64(-1) // valid if >= 0
- switch typ := underlying(x.typ).(type) {
- case *Basic:
- if isString(typ) {
- valid = true
- if x.mode == constant {
- length = int64(len(x.val.(string))) + 1 // +1 for slice
- }
- // a sliced string always yields a string value
- // of the same type as the original string (not
- // a constant) even if the string and the indices
- // are constant
- x.mode = value
- // x.typ doesn't change, but if it is an untyped
- // string it becomes string (see also issue 4913).
- if typ.Kind == UntypedString {
- x.typ = Typ[String]
- }
- }
-
- case *Array:
- valid = true
- length = typ.Len + 1 // +1 for slice
- if x.mode != variable {
- check.invalidOp(x.pos(), "cannot slice %s (value not addressable)", x)
- goto Error
- }
- x.typ = &Slice{Elt: typ.Elt}
-
- case *Pointer:
- if typ, _ := underlying(typ.Base).(*Array); typ != nil {
- valid = true
- length = typ.Len + 1 // +1 for slice
- x.mode = variable
- x.typ = &Slice{Elt: typ.Elt}
- }
-
- case *Slice:
- valid = true
- x.mode = variable
- // x.typ doesn't change
- }
-
- if !valid {
- check.invalidOp(x.pos(), "cannot slice %s", x)
- goto Error
- }
-
- lo := int64(0)
- if e.Low != nil {
- lo = check.index(e.Low, length, iota)
- }
-
- hi := int64(-1)
- if e.High != nil {
- hi = check.index(e.High, length, iota)
- } else if length >= 0 {
- hi = length
- }
-
- if lo >= 0 && hi >= 0 && lo > hi {
- check.errorf(e.Low.Pos(), "inverted slice range: %d > %d", lo, hi)
- // ok to continue
- }
-
- case *ast.TypeAssertExpr:
- check.expr(x, e.X, nil, iota)
- if x.mode == invalid {
- goto Error
- }
- var T *Interface
- if T, _ = underlying(x.typ).(*Interface); T == nil {
- check.invalidOp(x.pos(), "%s is not an interface", x)
- goto Error
- }
- // x.(type) expressions are handled explicitly in type switches
- if e.Type == nil {
- check.errorf(e.Pos(), "use of .(type) outside type switch")
- goto Error
- }
- typ := check.typ(e.Type, false)
- if typ == Typ[Invalid] {
- goto Error
- }
- if method, wrongType := missingMethod(typ, T); method != nil {
- var msg string
- if wrongType {
- msg = "%s cannot have dynamic type %s (wrong type for method %s)"
- } else {
- msg = "%s cannot have dynamic type %s (missing method %s)"
- }
- check.errorf(e.Type.Pos(), msg, x, typ, method.Name)
- // ok to continue
- }
- x.mode = valueok
- x.expr = e
- x.typ = typ
-
- case *ast.CallExpr:
- check.exprOrType(x, e.Fun, iota, false)
- if x.mode == invalid {
- goto Error
- } else if x.mode == typexpr {
- check.conversion(x, e, x.typ, iota)
- } else if sig, ok := underlying(x.typ).(*Signature); ok {
- // check parameters
-
- // If we have a trailing ... at the end of the parameter
- // list, the last argument must match the parameter type
- // []T of a variadic function parameter x ...T.
- passSlice := false
- if e.Ellipsis.IsValid() {
- if sig.IsVariadic {
- passSlice = true
- } else {
- check.errorf(e.Ellipsis, "cannot use ... in call to %s", e.Fun)
- // ok to continue
- }
- }
-
- // If we have a single argument that is a function call
- // we need to handle it separately. Determine if this
- // is the case without checking the argument.
- var call *ast.CallExpr
- if len(e.Args) == 1 {
- call, _ = unparen(e.Args[0]).(*ast.CallExpr)
- }
-
- n := 0 // parameter count
- if call != nil {
- // We have a single argument that is a function call.
- check.expr(x, call, nil, -1)
- if x.mode == invalid {
- goto Error // TODO(gri): we can do better
- }
- if t, _ := x.typ.(*Result); t != nil {
- // multiple result values
- n = len(t.Values)
- for i, obj := range t.Values {
- x.mode = value
- x.expr = nil // TODO(gri) can we do better here? (for good error messages)
- x.typ = obj.Type
- check.argument(sig, i, nil, x, passSlice && i+1 == n)
- }
- } else {
- // single result value
- n = 1
- check.argument(sig, 0, nil, x, passSlice)
- }
-
- } else {
- // We don't have a single argument or it is not a function call.
- n = len(e.Args)
- for i, arg := range e.Args {
- check.argument(sig, i, arg, x, passSlice && i+1 == n)
- }
- }
-
- // determine if we have enough arguments
- if sig.IsVariadic {
- // a variadic function accepts an "empty"
- // last argument: count one extra
- n++
- }
- if n < len(sig.Params) {
- check.errorf(e.Fun.Pos(), "too few arguments in call to %s", e.Fun)
- // ok to continue
- }
-
- // determine result
- switch len(sig.Results) {
- case 0:
- x.mode = novalue
- case 1:
- x.mode = value
- x.typ = sig.Results[0].Type
- default:
- x.mode = value
- x.typ = &Result{Values: sig.Results}
- }
-
- } else if bin, ok := x.typ.(*builtin); ok {
- check.builtin(x, e, bin, iota)
-
- } else {
- check.invalidOp(x.pos(), "cannot call non-function %s", x)
- goto Error
- }
-
- case *ast.StarExpr:
- check.exprOrType(x, e.X, iota, true)
- switch x.mode {
- case invalid:
- goto Error
- case typexpr:
- x.typ = &Pointer{Base: x.typ}
- default:
- if typ, ok := underlying(x.typ).(*Pointer); ok {
- x.mode = variable
- x.typ = typ.Base
- } else {
- check.invalidOp(x.pos(), "cannot indirect %s", x)
- goto Error
- }
- }
-
- case *ast.UnaryExpr:
- check.expr(x, e.X, nil, iota)
- if x.mode == invalid {
- goto Error
- }
- check.unary(x, e.Op)
- if x.mode == invalid {
- goto Error
- }
-
- case *ast.BinaryExpr:
- check.binary(x, e.X, e.Y, e.Op, iota)
- if x.mode == invalid {
- goto Error
- }
-
- case *ast.KeyValueExpr:
- // key:value expressions are handled in composite literals
- check.invalidAST(e.Pos(), "no key:value expected")
- goto Error
-
- case *ast.ArrayType:
- if e.Len != nil {
- check.expr(x, e.Len, nil, iota)
- if x.mode == invalid {
- goto Error
- }
- if x.mode != constant {
- if x.mode != invalid {
- check.errorf(x.pos(), "array length %s must be constant", x)
- }
- goto Error
- }
- n, ok := x.val.(int64)
- if !ok || n < 0 {
- check.errorf(x.pos(), "invalid array length %s", x)
- goto Error
- }
- x.typ = &Array{Len: n, Elt: check.typ(e.Elt, cycleOk)}
- } else {
- x.typ = &Slice{Elt: check.typ(e.Elt, true)}
- }
- x.mode = typexpr
-
- case *ast.StructType:
- x.mode = typexpr
- x.typ = &Struct{Fields: check.collectFields(e.Fields, cycleOk)}
-
- case *ast.FuncType:
- params, isVariadic := check.collectParams(e.Params, true)
- results, _ := check.collectParams(e.Results, false)
- x.mode = typexpr
- x.typ = &Signature{Recv: nil, Params: params, Results: results, IsVariadic: isVariadic}
-
- case *ast.InterfaceType:
- x.mode = typexpr
- x.typ = &Interface{Methods: check.collectMethods(e.Methods)}
-
- case *ast.MapType:
- x.mode = typexpr
- x.typ = &Map{Key: check.typ(e.Key, true), Elt: check.typ(e.Value, true)}
-
- case *ast.ChanType:
- x.mode = typexpr
- x.typ = &Chan{Dir: e.Dir, Elt: check.typ(e.Value, true)}
-
- default:
- if debug {
- check.dump("expr = %v (%T)", e, e)
- }
- unreachable()
- }
-
- // everything went well
- x.expr = e
- return
-
-Error:
- x.mode = invalid
- x.expr = e
-}
-
-// exprOrType is like rawExpr but reports an error if e doesn't represents a value or type.
-func (check *checker) exprOrType(x *operand, e ast.Expr, iota int, cycleOk bool) {
- check.rawExpr(x, e, nil, iota, cycleOk)
- if x.mode == novalue {
- check.errorf(x.pos(), "%s used as value or type", x)
- x.mode = invalid
- }
-}
-
-// expr is like rawExpr but reports an error if e doesn't represents a value.
-func (check *checker) expr(x *operand, e ast.Expr, hint Type, iota int) {
- check.rawExpr(x, e, hint, iota, false)
- switch x.mode {
- case novalue:
- check.errorf(x.pos(), "%s used as value", x)
- x.mode = invalid
- case typexpr:
- check.errorf(x.pos(), "%s is not an expression", x)
- x.mode = invalid
- }
-}
-
-func (check *checker) rawTyp(e ast.Expr, cycleOk, nilOk bool) Type {
- var x operand
- check.rawExpr(&x, e, nil, -1, cycleOk)
- switch x.mode {
- case invalid:
- // ignore - error reported before
- case novalue:
- check.errorf(x.pos(), "%s used as type", &x)
- case typexpr:
- return x.typ
- case constant:
- if nilOk && x.isNil() {
- return nil
- }
- fallthrough
- default:
- check.errorf(x.pos(), "%s is not a type", &x)
- }
- return Typ[Invalid]
-}
-
-// typOrNil is like rawExpr but reports an error if e doesn't represents a type or the predeclared value nil.
-// It returns e's type, nil, or Typ[Invalid] if an error occurred.
-//
-func (check *checker) typOrNil(e ast.Expr, cycleOk bool) Type {
- return check.rawTyp(e, cycleOk, true)
-}
-
-// typ is like rawExpr but reports an error if e doesn't represents a type.
-// It returns e's type, or Typ[Invalid] if an error occurred.
-//
-func (check *checker) typ(e ast.Expr, cycleOk bool) Type {
- return check.rawTyp(e, cycleOk, false)
-}
diff --git a/src/pkg/go/types/gcimporter.go b/src/pkg/go/types/gcimporter.go
deleted file mode 100644
index 7f968eb8d..000000000
--- a/src/pkg/go/types/gcimporter.go
+++ /dev/null
@@ -1,950 +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.
-
-// This file implements an Importer for gc-generated object files.
-
-package types
-
-import (
- "bufio"
- "errors"
- "fmt"
- "go/ast"
- "go/build"
- "go/token"
- "io"
- "math/big"
- "os"
- "path/filepath"
- "strconv"
- "strings"
- "text/scanner"
-)
-
-var pkgExts = [...]string{".a", ".5", ".6", ".8"}
-
-// FindPkg returns the filename and unique package id for an import
-// path based on package information provided by build.Import (using
-// the build.Default build.Context).
-// If no file was found, an empty filename is returned.
-//
-func FindPkg(path, srcDir string) (filename, id string) {
- if len(path) == 0 {
- return
- }
-
- id = path
- var noext string
- switch {
- default:
- // "x" -> "$GOPATH/pkg/$GOOS_$GOARCH/x.ext", "x"
- // Don't require the source files to be present.
- bp, _ := build.Import(path, srcDir, build.FindOnly|build.AllowBinary)
- if bp.PkgObj == "" {
- return
- }
- noext = strings.TrimSuffix(bp.PkgObj, ".a")
-
- case build.IsLocalImport(path):
- // "./x" -> "/this/directory/x.ext", "/this/directory/x"
- noext = filepath.Join(srcDir, path)
- id = noext
-
- case filepath.IsAbs(path):
- // for completeness only - go/build.Import
- // does not support absolute imports
- // "/x" -> "/x.ext", "/x"
- noext = path
- }
-
- // try extensions
- for _, ext := range pkgExts {
- filename = noext + ext
- if f, err := os.Stat(filename); err == nil && !f.IsDir() {
- return
- }
- }
-
- filename = "" // not found
- return
-}
-
-// GcImportData imports a package by reading the gc-generated export data,
-// adds the corresponding package object to the imports map indexed by id,
-// and returns the object.
-//
-// The imports 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 imports[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 GcImportData(imports map[string]*Package, filename, id string, data *bufio.Reader) (pkg *Package, err error) {
- // support for gcParser error handling
- defer func() {
- if r := recover(); r != nil {
- err = r.(importError) // will re-panic if r is not an importError
- }
- }()
-
- var p gcParser
- p.init(filename, id, data, imports)
- pkg = p.parseExport()
-
- return
-}
-
-// GcImport imports a gc-generated package given its import path, adds the
-// corresponding package object to the imports map, and returns the object.
-// Local import paths are interpreted relative to the current working directory.
-// The imports map must contains all packages already imported.
-// GcImport satisfies the ast.Importer signature.
-//
-func GcImport(imports map[string]*Package, path string) (pkg *Package, err error) {
- if path == "unsafe" {
- return Unsafe, nil
- }
-
- srcDir := "."
- if build.IsLocalImport(path) {
- srcDir, err = os.Getwd()
- if err != nil {
- return
- }
- }
-
- filename, id := FindPkg(path, srcDir)
- if filename == "" {
- err = errors.New("can't find import: " + id)
- return
- }
-
- // no need to re-import if the package was imported completely before
- if pkg = imports[id]; pkg != nil && pkg.Complete {
- return
- }
-
- // open file
- f, err := os.Open(filename)
- if err != nil {
- return
- }
- defer func() {
- f.Close()
- if err != nil {
- // add file name to error
- err = fmt.Errorf("reading export data: %s: %v", filename, err)
- }
- }()
-
- buf := bufio.NewReader(f)
- if err = FindGcExportData(buf); err != nil {
- return
- }
-
- pkg, err = GcImportData(imports, filename, id, buf)
-
- return
-}
-
-// ----------------------------------------------------------------------------
-// gcParser
-
-// gcParser parses the exports inside a gc compiler-produced
-// object/archive file and populates its scope with the results.
-type gcParser 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
- imports map[string]*Package // package id -> package object
-}
-
-func (p *gcParser) init(filename, id string, src io.Reader, imports map[string]*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.imports = imports
- // leave for debugging
- if false {
- // check consistency of imports map
- for _, pkg := range imports {
- if pkg.Name == "" {
- fmt.Printf("no package name for %s\n", pkg.Path)
- }
- }
- }
-}
-
-func (p *gcParser) 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 = ""
- }
- // leave for debugging
- if false {
- fmt.Printf("%s: %q -> %q\n", scanner.TokenString(p.tok), p.scanner.TokenText(), p.lit)
- }
-}
-
-func declConst(pkg *Package, name string) *Const {
- // the constant may have been imported before - if it exists
- // already in the respective scope, return that constant
- scope := pkg.Scope
- if obj := scope.Lookup(name); obj != nil {
- return obj.(*Const)
- }
- // otherwise create a new constant and insert it into the scope
- obj := &Const{Pkg: pkg, Name: name}
- scope.Insert(obj)
- return obj
-}
-
-func declTypeName(pkg *Package, name string) *TypeName {
- scope := pkg.Scope
- if obj := scope.Lookup(name); obj != nil {
- return obj.(*TypeName)
- }
- obj := &TypeName{Pkg: pkg, Name: name}
- // a named type may be referred to before the underlying type
- // is known - set it up
- obj.Type = &NamedType{Obj: obj}
- scope.Insert(obj)
- return obj
-}
-
-func declVar(pkg *Package, name string) *Var {
- scope := pkg.Scope
- if obj := scope.Lookup(name); obj != nil {
- return obj.(*Var)
- }
- obj := &Var{Pkg: pkg, Name: name}
- scope.Insert(obj)
- return obj
-}
-
-func declFunc(pkg *Package, name string) *Func {
- scope := pkg.Scope
- if obj := scope.Lookup(name); obj != nil {
- return obj.(*Func)
- }
- obj := &Func{Pkg: pkg, Name: name}
- 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 *gcParser) 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 *gcParser) errorf(format string, args ...interface{}) {
- p.error(fmt.Sprintf(format, args...))
-}
-
-func (p *gcParser) 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 *gcParser) 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 *gcParser) 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 *gcParser) 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 *gcParser) parsePackageName() string {
- return p.expect(scanner.Ident)
-}
-
-// dotIdentifier = ( ident | '·' ) { ident | int | '·' } .
-func (p *gcParser) 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 *gcParser) parseQualifiedName() (id, name string) {
- p.expect('@')
- id = p.parsePackageId()
- p.expect('.')
- name = p.parseDotIdent()
- return
-}
-
-// getPkg returns the package for a given id. If the package is
-// not found but we have a package name, create the package and
-// add it to the p.imports map.
-//
-func (p *gcParser) getPkg(id, name string) *Package {
- // package unsafe is not in the imports map - handle explicitly
- if id == "unsafe" {
- return Unsafe
- }
- pkg := p.imports[id]
- if pkg == nil && name != "" {
- pkg = &Package{Name: name, Path: id, Scope: new(Scope)}
- p.imports[id] = pkg
- }
- return pkg
-}
-
-// parseExportedName is like parseQualifiedName, but
-// the package id is resolved to an imported *Package.
-//
-func (p *gcParser) parseExportedName() (pkg *Package, name string) {
- id, name := p.parseQualifiedName()
- pkg = p.getPkg(id, "")
- if pkg == nil {
- p.errorf("%s package not found", id)
- }
- return
-}
-
-// ----------------------------------------------------------------------------
-// Types
-
-// BasicType = identifier .
-//
-func (p *gcParser) parseBasicType() Type {
- id := p.expect(scanner.Ident)
- obj := Universe.Lookup(id)
- if obj, ok := obj.(*TypeName); ok {
- return obj.Type
- }
- p.errorf("not a basic type: %s", id)
- return nil
-}
-
-// ArrayType = "[" int_lit "]" Type .
-//
-func (p *gcParser) parseArrayType() Type {
- // "[" already consumed and lookahead known not to be "]"
- lit := p.expect(scanner.Int)
- p.expect(']')
- elt := p.parseType()
- n, err := strconv.ParseInt(lit, 10, 64)
- if err != nil {
- p.error(err)
- }
- return &Array{Len: n, Elt: elt}
-}
-
-// MapType = "map" "[" Type "]" Type .
-//
-func (p *gcParser) parseMapType() Type {
- p.expectKeyword("map")
- p.expect('[')
- key := p.parseType()
- p.expect(']')
- elt := p.parseType()
- return &Map{Key: key, Elt: elt}
-}
-
-// Name = identifier | "?" | QualifiedName .
-//
-// If materializePkg is set, a package is returned for fully qualified names.
-// That package may be a fake package (without name, scope, and not in the
-// p.imports map), created for the sole purpose of providing a package path
-// for QualifiedNames. Fake packages are created when the package id is not
-// found in the p.imports map; we cannot create a real package in that case
-// because we don't have a package name.
-//
-// TODO(gri): consider changing QualifiedIdents to (path, name) pairs to
-// simplify this code.
-//
-func (p *gcParser) parseName(materializePkg bool) (pkg *Package, name string) {
- switch p.tok {
- case scanner.Ident:
- name = p.lit
- p.next()
- case '?':
- // anonymous
- p.next()
- case '@':
- // exported name prefixed with package path
- var id string
- id, name = p.parseQualifiedName()
- if materializePkg {
- // we don't have a package name - if the package
- // doesn't exist yet, create a fake package instead
- pkg = p.getPkg(id, "")
- if pkg == nil {
- pkg = &Package{Path: id}
- }
- }
- default:
- p.error("name expected")
- }
- return
-}
-
-// Field = Name Type [ string_lit ] .
-//
-func (p *gcParser) parseField() *Field {
- var f Field
- f.Pkg, f.Name = p.parseName(true)
- f.Type = p.parseType()
- if p.tok == scanner.String {
- f.Tag = p.expect(scanner.String)
- }
- if f.Name == "" {
- // anonymous field - typ must be T or *T and T must be a type name
- if typ, ok := deref(f.Type).(*NamedType); ok && typ.Obj != nil {
- f.Name = typ.Obj.GetName()
- f.IsAnonymous = true
- } else {
- p.errorf("anonymous field expected")
- }
- }
- return &f
-}
-
-// StructType = "struct" "{" [ FieldList ] "}" .
-// FieldList = Field { ";" Field } .
-//
-func (p *gcParser) parseStructType() Type {
- var fields []*Field
-
- p.expectKeyword("struct")
- p.expect('{')
- for p.tok != '}' {
- if len(fields) > 0 {
- p.expect(';')
- }
- fields = append(fields, p.parseField())
- }
- p.expect('}')
-
- return &Struct{Fields: fields}
-}
-
-// Parameter = ( identifier | "?" ) [ "..." ] Type [ string_lit ] .
-//
-func (p *gcParser) parseParameter() (par *Var, isVariadic bool) {
- _, name := p.parseName(false)
- if name == "" {
- name = "_" // cannot access unnamed identifiers
- }
- if p.tok == '.' {
- p.expectSpecial("...")
- isVariadic = true
- }
- typ := p.parseType()
- // ignore argument tag (e.g. "noescape")
- if p.tok == scanner.String {
- p.next()
- }
- par = &Var{Name: name, Type: typ} // Pkg == nil
- return
-}
-
-// Parameters = "(" [ ParameterList ] ")" .
-// ParameterList = { Parameter "," } Parameter .
-//
-func (p *gcParser) parseParameters() (list []*Var, isVariadic bool) {
- p.expect('(')
- for p.tok != ')' {
- 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 *gcParser) parseSignature() *Signature {
- params, isVariadic := p.parseParameters()
-
- // optional result type
- var results []*Var
- if p.tok == '(' {
- var variadic bool
- results, variadic = p.parseParameters()
- if variadic {
- p.error("... not permitted on result type")
- }
- }
-
- return &Signature{Params: params, Results: results, IsVariadic: 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 *gcParser) parseInterfaceType() Type {
- var methods []*Method
-
- p.expectKeyword("interface")
- p.expect('{')
- for p.tok != '}' {
- if len(methods) > 0 {
- p.expect(';')
- }
- pkg, name := p.parseName(true)
- typ := p.parseSignature()
- methods = append(methods, &Method{QualifiedName{pkg, name}, typ})
- }
- p.expect('}')
-
- return &Interface{Methods: methods}
-}
-
-// ChanType = ( "chan" [ "<-" ] | "<-" "chan" ) Type .
-//
-func (p *gcParser) parseChanType() Type {
- dir := ast.SEND | ast.RECV
- if p.tok == scanner.Ident {
- p.expectKeyword("chan")
- if p.tok == '<' {
- p.expectSpecial("<-")
- dir = ast.SEND
- }
- } else {
- p.expectSpecial("<-")
- p.expectKeyword("chan")
- dir = ast.RECV
- }
- elt := p.parseType()
- return &Chan{Dir: dir, Elt: elt}
-}
-
-// 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 *gcParser) parseType() Type {
- switch p.tok {
- case scanner.Ident:
- switch p.lit {
- default:
- return p.parseBasicType()
- case "struct":
- return p.parseStructType()
- case "func":
- // FuncType
- p.next()
- return p.parseSignature()
- case "interface":
- return p.parseInterfaceType()
- case "map":
- return p.parseMapType()
- case "chan":
- return p.parseChanType()
- }
- case '@':
- // TypeName
- pkg, name := p.parseExportedName()
- return declTypeName(pkg, name).Type
- case '[':
- p.next() // look ahead
- if p.tok == ']' {
- // SliceType
- p.next()
- return &Slice{Elt: p.parseType()}
- }
- return p.parseArrayType()
- case '*':
- // PointerType
- p.next()
- return &Pointer{Base: p.parseType()}
- case '<':
- return p.parseChanType()
- case '(':
- // "(" Type ")"
- p.next()
- typ := p.parseType()
- 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 *gcParser) parseImportDecl() {
- p.expectKeyword("import")
- name := p.parsePackageName()
- p.getPkg(p.parsePackageId(), name)
-}
-
-// int_lit = [ "+" | "-" ] { "0" ... "9" } .
-//
-func (p *gcParser) parseInt() (neg bool, val string) {
- switch p.tok {
- case '-':
- neg = true
- fallthrough
- case '+':
- p.next()
- }
- val = p.expect(scanner.Int)
- return
-}
-
-// number = int_lit [ "p" int_lit ] .
-//
-func (p *gcParser) parseNumber() (x operand) {
- x.mode = constant
-
- // mantissa
- neg, val := p.parseInt()
- mant, ok := new(big.Int).SetString(val, 0)
- assert(ok)
- if neg {
- mant.Neg(mant)
- }
-
- if p.lit == "p" {
- // exponent (base 2)
- p.next()
- neg, val = p.parseInt()
- exp64, err := strconv.ParseUint(val, 10, 0)
- if err != nil {
- p.error(err)
- }
- exp := uint(exp64)
- if neg {
- denom := big.NewInt(1)
- denom.Lsh(denom, exp)
- x.typ = Typ[UntypedFloat]
- x.val = normalizeRatConst(new(big.Rat).SetFrac(mant, denom))
- return
- }
- if exp > 0 {
- mant.Lsh(mant, exp)
- }
- x.typ = Typ[UntypedFloat]
- x.val = normalizeIntConst(mant)
- return
- }
-
- x.typ = Typ[UntypedInt]
- x.val = normalizeIntConst(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 *gcParser) parseConstDecl() {
- p.expectKeyword("const")
- pkg, name := p.parseExportedName()
- obj := declConst(pkg, name)
- var x operand
- if p.tok != '=' {
- obj.Type = p.parseType()
- }
- p.expect('=')
- switch p.tok {
- case scanner.Ident:
- // bool_lit
- if p.lit != "true" && p.lit != "false" {
- p.error("expected true or false")
- }
- x.typ = Typ[UntypedBool]
- x.val = p.lit == "true"
- p.next()
-
- case '-', scanner.Int:
- // int_lit
- x = p.parseNumber()
-
- case '(':
- // complex_lit or rune_lit
- p.next()
- if p.tok == scanner.Char {
- p.next()
- p.expect('+')
- x = p.parseNumber()
- x.typ = Typ[UntypedRune]
- p.expect(')')
- break
- }
- re := p.parseNumber()
- p.expect('+')
- im := p.parseNumber()
- p.expectKeyword("i")
- p.expect(')')
- x.typ = Typ[UntypedComplex]
- // TODO(gri) fix this
- _, _ = re, im
- x.val = zeroConst
-
- case scanner.Char:
- // rune_lit
- x.setConst(token.CHAR, p.lit)
- p.next()
-
- case scanner.String:
- // string_lit
- x.setConst(token.STRING, p.lit)
- p.next()
-
- default:
- p.errorf("expected literal got %s", scanner.TokenString(p.tok))
- }
- if obj.Type == nil {
- obj.Type = x.typ
- }
- assert(x.val != nil)
- obj.Val = x.val
-}
-
-// TypeDecl = "type" ExportedName Type .
-//
-func (p *gcParser) 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()
-
- if name := obj.Type.(*NamedType); name.Underlying == nil {
- name.Underlying = typ
- }
-}
-
-// VarDecl = "var" ExportedName Type .
-//
-func (p *gcParser) parseVarDecl() {
- p.expectKeyword("var")
- pkg, name := p.parseExportedName()
- obj := declVar(pkg, name)
- obj.Type = p.parseType()
-}
-
-// Func = Signature [ Body ] .
-// Body = "{" ... "}" .
-//
-func (p *gcParser) parseFunc() *Signature {
- sig := p.parseSignature()
- 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 *gcParser) parseMethodDecl() {
- // "func" already consumed
- p.expect('(')
- recv, _ := p.parseParameter() // receiver
- p.expect(')')
-
- // determine receiver base type object
- typ := recv.Type
- if ptr, ok := typ.(*Pointer); ok {
- typ = ptr.Base
- }
- base := typ.(*NamedType)
-
- // parse method name, signature, and possibly inlined body
- pkg, name := p.parseName(true) // unexported method names in imports are qualified with their package.
- sig := p.parseFunc()
- sig.Recv = recv
-
- // add method to type unless type was imported before
- // and method exists already
- // TODO(gri) investigate if this can be avoided
- for _, m := range base.Methods {
- if m.Name == name {
- return // method was added before
- }
- }
- base.Methods = append(base.Methods, &Method{QualifiedName{pkg, name}, sig})
-}
-
-// FuncDecl = "func" ExportedName Func .
-//
-func (p *gcParser) parseFuncDecl() {
- // "func" already consumed
- pkg, name := p.parseExportedName()
- typ := p.parseFunc()
- declFunc(pkg, name).Type = typ
-}
-
-// Decl = [ ImportDecl | ConstDecl | TypeDecl | VarDecl | FuncDecl | MethodDecl ] "\n" .
-//
-func (p *gcParser) parseDecl() {
- 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 *gcParser) parseExport() *Package {
- p.expectKeyword("package")
- name := p.parsePackageName()
- if p.tok != '\n' {
- // A package is safe if it was compiled with the -u flag,
- // which disables the unsafe package.
- // TODO(gri) remember "safe" package
- p.expectKeyword("safe")
- }
- 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)
- }
-
- // package was imported completely and without errors
- pkg.Complete = true
-
- return pkg
-}
diff --git a/src/pkg/go/types/gcimporter_test.go b/src/pkg/go/types/gcimporter_test.go
deleted file mode 100644
index b793eb4cb..000000000
--- a/src/pkg/go/types/gcimporter_test.go
+++ /dev/null
@@ -1,180 +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 types
-
-import (
- "go/ast"
- "go/build"
- "io/ioutil"
- "os"
- "os/exec"
- "path/filepath"
- "runtime"
- "strings"
- "testing"
- "time"
-)
-
-var gcPath string // Go compiler path
-
-func init() {
- // determine compiler
- var gc string
- switch runtime.GOARCH {
- case "386":
- gc = "8g"
- case "amd64":
- gc = "6g"
- case "arm":
- gc = "5g"
- default:
- gcPath = "unknown-GOARCH-compiler"
- return
- }
- gcPath = filepath.Join(build.ToolDir, gc)
-}
-
-func compile(t *testing.T, dirname, filename string) string {
- cmd := exec.Command(gcPath, filename)
- cmd.Dir = dirname
- out, err := cmd.CombinedOutput()
- if err != nil {
- t.Logf("%s", out)
- t.Fatalf("%s %s failed: %s", gcPath, filename, err)
- }
- archCh, _ := build.ArchChar(runtime.GOARCH)
- // filename should end with ".go"
- return filepath.Join(dirname, filename[:len(filename)-2]+archCh)
-}
-
-// Use the same global imports map for all tests. The effect is
-// as if all tested packages were imported into a single package.
-var imports = make(map[string]*Package)
-
-func testPath(t *testing.T, path string) bool {
- t0 := time.Now()
- _, err := GcImport(imports, path)
- if err != nil {
- t.Errorf("testPath(%s): %s", path, err)
- return false
- }
- t.Logf("testPath(%s): %v", path, time.Since(t0))
- return true
-}
-
-const maxTime = 30 * time.Second
-
-func testDir(t *testing.T, dir string, endTime time.Time) (nimports int) {
- dirname := filepath.Join(runtime.GOROOT(), "pkg", runtime.GOOS+"_"+runtime.GOARCH, dir)
- list, err := ioutil.ReadDir(dirname)
- if err != nil {
- t.Fatalf("testDir(%s): %s", dirname, err)
- }
- for _, f := range list {
- if time.Now().After(endTime) {
- t.Log("testing time used up")
- return
- }
- switch {
- case !f.IsDir():
- // try extensions
- for _, ext := range pkgExts {
- if strings.HasSuffix(f.Name(), ext) {
- name := f.Name()[0 : len(f.Name())-len(ext)] // remove extension
- if testPath(t, filepath.Join(dir, name)) {
- nimports++
- }
- }
- }
- case f.IsDir():
- nimports += testDir(t, filepath.Join(dir, f.Name()), endTime)
- }
- }
- return
-}
-
-func TestGcImport(t *testing.T) {
- // On cross-compile builds, the path will not exist.
- // Need to use GOHOSTOS, which is not available.
- if _, err := os.Stat(gcPath); err != nil {
- t.Skipf("skipping test: %v", err)
- }
-
- if outFn := compile(t, "testdata", "exports.go"); outFn != "" {
- defer os.Remove(outFn)
- }
-
- nimports := 0
- if testPath(t, "./testdata/exports") {
- nimports++
- }
- nimports += testDir(t, "", time.Now().Add(maxTime)) // installed packages
- t.Logf("tested %d imports", nimports)
-}
-
-var importedObjectTests = []struct {
- name string
- kind ast.ObjKind
- typ string
-}{
- {"unsafe.Pointer", ast.Typ, "Pointer"},
- {"math.Pi", ast.Con, "untyped float"},
- {"io.Reader", ast.Typ, "interface{Read(p []byte) (n int, err error)}"},
- {"io.ReadWriter", ast.Typ, "interface{Read(p []byte) (n int, err error); Write(p []byte) (n int, err error)}"},
- {"math.Sin", ast.Fun, "func(x·2 float64) (_ float64)"},
- // TODO(gri) add more tests
-}
-
-func TestGcImportedTypes(t *testing.T) {
- // This package does not yet know how to read gccgo export data.
- if runtime.Compiler == "gccgo" {
- return
- }
- for _, test := range importedObjectTests {
- s := strings.Split(test.name, ".")
- if len(s) != 2 {
- t.Fatal("inconsistent test data")
- }
- importPath := s[0]
- objName := s[1]
-
- pkg, err := GcImport(imports, importPath)
- if err != nil {
- t.Error(err)
- continue
- }
-
- obj := pkg.Scope.Lookup(objName)
-
- // TODO(gri) should define an accessor on Object
- var kind ast.ObjKind
- var typ Type
- switch obj := obj.(type) {
- case *Const:
- kind = ast.Con
- typ = obj.Type
- case *TypeName:
- kind = ast.Typ
- typ = obj.Type
- case *Var:
- kind = ast.Var
- typ = obj.Type
- case *Func:
- kind = ast.Fun
- typ = obj.Type
- default:
- unreachable()
- }
-
- if kind != test.kind {
- t.Errorf("%s: got kind = %q; want %q", test.name, kind, test.kind)
- }
-
- str := typeString(underlying(typ))
- if str != test.typ {
- t.Errorf("%s: got type = %q; want %q", test.name, typ, test.typ)
- }
- }
-}
diff --git a/src/pkg/go/types/objects.go b/src/pkg/go/types/objects.go
deleted file mode 100644
index 02291d34c..000000000
--- a/src/pkg/go/types/objects.go
+++ /dev/null
@@ -1,186 +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 types
-
-import (
- "go/ast"
- "go/token"
-)
-
-// An Object describes a named language entity such as a package,
-// constant, type, variable, function (incl. methods), or label.
-// All objects implement the Object interface.
-//
-type Object interface {
- GetPkg() *Package
- GetName() string
- GetType() Type
- GetPos() token.Pos
-
- anObject()
-}
-
-// A Package represents the contents (objects) of a Go package.
-type Package struct {
- Name string
- Path string // import path, "" for current (non-imported) package
- Scope *Scope // package-level scope
- Imports map[string]*Package // map of import paths to imported packages
- Complete bool // if set, this package was imported completely
-
- spec *ast.ImportSpec
-}
-
-// A Const represents a declared constant.
-type Const struct {
- Pkg *Package
- Name string
- Type Type
- Val interface{}
-
- spec *ast.ValueSpec
-}
-
-// A TypeName represents a declared type.
-type TypeName struct {
- Pkg *Package
- Name string
- Type Type // *NamedType or *Basic
-
- spec *ast.TypeSpec
-}
-
-// A Variable represents a declared variable (including function parameters and results).
-type Var struct {
- Pkg *Package // nil for parameters
- Name string
- Type Type
-
- visited bool // for initialization cycle detection
- decl interface{}
-}
-
-// A Func represents a declared function.
-type Func struct {
- Pkg *Package
- Name string
- Type Type // *Signature or *Builtin
-
- decl *ast.FuncDecl
-}
-
-func (obj *Package) GetPkg() *Package { return obj }
-func (obj *Const) GetPkg() *Package { return obj.Pkg }
-func (obj *TypeName) GetPkg() *Package { return obj.Pkg }
-func (obj *Var) GetPkg() *Package { return obj.Pkg }
-func (obj *Func) GetPkg() *Package { return obj.Pkg }
-
-func (obj *Package) GetName() string { return obj.Name }
-func (obj *Const) GetName() string { return obj.Name }
-func (obj *TypeName) GetName() string { return obj.Name }
-func (obj *Var) GetName() string { return obj.Name }
-func (obj *Func) GetName() string { return obj.Name }
-
-func (obj *Package) GetType() Type { return Typ[Invalid] }
-func (obj *Const) GetType() Type { return obj.Type }
-func (obj *TypeName) GetType() Type { return obj.Type }
-func (obj *Var) GetType() Type { return obj.Type }
-func (obj *Func) GetType() Type { return obj.Type }
-
-func (obj *Package) GetPos() token.Pos {
- if obj.spec != nil {
- return obj.spec.Pos()
- }
- return token.NoPos
-}
-
-func (obj *Const) GetPos() token.Pos {
- for _, n := range obj.spec.Names {
- if n.Name == obj.Name {
- return n.Pos()
- }
- }
- return token.NoPos
-}
-func (obj *TypeName) GetPos() token.Pos {
- if obj.spec != nil {
- return obj.spec.Pos()
- }
- return token.NoPos
-}
-
-func (obj *Var) GetPos() token.Pos {
- switch d := obj.decl.(type) {
- case *ast.Field:
- for _, n := range d.Names {
- if n.Name == obj.Name {
- return n.Pos()
- }
- }
- case *ast.ValueSpec:
- for _, n := range d.Names {
- if n.Name == obj.Name {
- return n.Pos()
- }
- }
- case *ast.AssignStmt:
- for _, x := range d.Lhs {
- if ident, isIdent := x.(*ast.Ident); isIdent && ident.Name == obj.Name {
- return ident.Pos()
- }
- }
- }
- return token.NoPos
-}
-func (obj *Func) GetPos() token.Pos {
- if obj.decl != nil && obj.decl.Name != nil {
- return obj.decl.Name.Pos()
- }
- return token.NoPos
-}
-
-func (*Package) anObject() {}
-func (*Const) anObject() {}
-func (*TypeName) anObject() {}
-func (*Var) anObject() {}
-func (*Func) anObject() {}
-
-// newObj returns a new Object for a given *ast.Object.
-// It does not canonicalize them (it always returns a new one).
-// For canonicalization, see check.lookup.
-//
-// TODO(gri) Once we do identifier resolution completely in
-// in the typechecker, this functionality can go.
-//
-func newObj(pkg *Package, astObj *ast.Object) Object {
- assert(pkg != nil)
- name := astObj.Name
- typ, _ := astObj.Type.(Type)
- switch astObj.Kind {
- case ast.Bad:
- // ignore
- case ast.Pkg:
- unreachable()
- case ast.Con:
- return &Const{Pkg: pkg, Name: name, Type: typ, Val: astObj.Data, spec: astObj.Decl.(*ast.ValueSpec)}
- case ast.Typ:
- return &TypeName{Pkg: pkg, Name: name, Type: typ, spec: astObj.Decl.(*ast.TypeSpec)}
- case ast.Var:
- switch astObj.Decl.(type) {
- case *ast.Field: // function parameters
- case *ast.ValueSpec: // proper variable declarations
- case *ast.AssignStmt: // short variable declarations
- default:
- unreachable() // everything else is not ok
- }
- return &Var{Pkg: pkg, Name: name, Type: typ, decl: astObj.Decl}
- case ast.Fun:
- return &Func{Pkg: pkg, Name: name, Type: typ, decl: astObj.Decl.(*ast.FuncDecl)}
- case ast.Lbl:
- unreachable() // for now
- }
- unreachable()
- return nil
-}
diff --git a/src/pkg/go/types/operand.go b/src/pkg/go/types/operand.go
deleted file mode 100644
index 982ffef8d..000000000
--- a/src/pkg/go/types/operand.go
+++ /dev/null
@@ -1,411 +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.
-
-// This file defines operands and associated operations.
-
-package types
-
-import (
- "bytes"
- "fmt"
- "go/ast"
- "go/token"
-)
-
-// An operandMode specifies the (addressing) mode of an operand.
-type operandMode int
-
-const (
- invalid operandMode = iota // operand is invalid (due to an earlier error) - ignore
- novalue // operand represents no value (result of a function call w/o result)
- typexpr // operand is a type
- constant // operand is a constant; the operand's typ is a Basic type
- variable // operand is an addressable variable
- value // operand is a computed value
- valueok // like mode == value, but operand may be used in a comma,ok expression
-)
-
-var operandModeString = [...]string{
- invalid: "invalid",
- novalue: "no value",
- typexpr: "type",
- constant: "constant",
- variable: "variable",
- value: "value",
- valueok: "value,ok",
-}
-
-// An operand represents an intermediate value during type checking.
-// Operands have an (addressing) mode, the expression evaluating to
-// the operand, the operand's type, and for constants a constant value.
-//
-type operand struct {
- mode operandMode
- expr ast.Expr
- typ Type
- val interface{}
-}
-
-// pos returns the position of the expression corresponding to x.
-// If x is invalid the position is token.NoPos.
-//
-func (x *operand) pos() token.Pos {
- // x.expr may not be set if x is invalid
- if x.expr == nil {
- return token.NoPos
- }
- return x.expr.Pos()
-}
-
-func (x *operand) String() string {
- if x.mode == invalid {
- return "invalid operand"
- }
- var buf bytes.Buffer
- if x.expr != nil {
- buf.WriteString(exprString(x.expr))
- buf.WriteString(" (")
- }
- buf.WriteString(operandModeString[x.mode])
- if x.mode == constant {
- format := " %v"
- if isString(x.typ) {
- format = " %q"
- }
- fmt.Fprintf(&buf, format, x.val)
- }
- if x.mode != novalue && (x.mode != constant || !isUntyped(x.typ)) {
- fmt.Fprintf(&buf, " of type %s", typeString(x.typ))
- }
- if x.expr != nil {
- buf.WriteByte(')')
- }
- return buf.String()
-}
-
-// setConst sets x to the untyped constant for literal lit.
-func (x *operand) setConst(tok token.Token, lit string) {
- x.mode = invalid
-
- var kind BasicKind
- var val interface{}
- switch tok {
- case token.INT:
- kind = UntypedInt
- val = makeIntConst(lit)
-
- case token.FLOAT:
- kind = UntypedFloat
- val = makeFloatConst(lit)
-
- case token.IMAG:
- kind = UntypedComplex
- val = makeComplexConst(lit)
-
- case token.CHAR:
- kind = UntypedRune
- val = makeRuneConst(lit)
-
- case token.STRING:
- kind = UntypedString
- val = makeStringConst(lit)
- }
-
- if val != nil {
- x.mode = constant
- x.typ = Typ[kind]
- x.val = val
- }
-}
-
-// isNil reports whether x is the predeclared nil constant.
-func (x *operand) isNil() bool {
- return x.mode == constant && x.val == nilConst
-}
-
-// TODO(gri) The functions operand.isAssignable, checker.convertUntyped,
-// checker.isRepresentable, and checker.assignOperand are
-// overlapping in functionality. Need to simplify and clean up.
-
-// isAssignable reports whether x is assignable to a variable of type T.
-func (x *operand) isAssignable(ctxt *Context, T Type) bool {
- if x.mode == invalid || T == Typ[Invalid] {
- return true // avoid spurious errors
- }
-
- V := x.typ
-
- // x's type is identical to T
- if IsIdentical(V, T) {
- return true
- }
-
- Vu := underlying(V)
- Tu := underlying(T)
-
- // x's type V and T have identical underlying types
- // and at least one of V or T is not a named type
- if IsIdentical(Vu, Tu) {
- return !isNamed(V) || !isNamed(T)
- }
-
- // T is an interface type and x implements T
- if Ti, ok := Tu.(*Interface); ok {
- if m, _ := missingMethod(x.typ, Ti); m == nil {
- return true
- }
- }
-
- // x is a bidirectional channel value, T is a channel
- // type, x's type V and T have identical element types,
- // and at least one of V or T is not a named type
- if Vc, ok := Vu.(*Chan); ok && Vc.Dir == ast.SEND|ast.RECV {
- if Tc, ok := Tu.(*Chan); ok && IsIdentical(Vc.Elt, Tc.Elt) {
- return !isNamed(V) || !isNamed(T)
- }
- }
-
- // x is the predeclared identifier nil and T is a pointer,
- // function, slice, map, channel, or interface type
- if x.isNil() {
- switch t := Tu.(type) {
- case *Basic:
- if t.Kind == UnsafePointer {
- return true
- }
- case *Pointer, *Signature, *Slice, *Map, *Chan, *Interface:
- return true
- }
- return false
- }
-
- // x is an untyped constant representable by a value of type T
- // TODO(gri) This is borrowing from checker.convertUntyped and
- // checker.isRepresentable. Need to clean up.
- if isUntyped(Vu) {
- switch t := Tu.(type) {
- case *Basic:
- if x.mode == constant {
- return isRepresentableConst(x.val, ctxt, t.Kind)
- }
- // The result of a comparison is an untyped boolean,
- // but may not be a constant.
- if Vb, _ := Vu.(*Basic); Vb != nil {
- return Vb.Kind == UntypedBool && isBoolean(Tu)
- }
- case *Interface:
- return x.isNil() || len(t.Methods) == 0
- case *Pointer, *Signature, *Slice, *Map, *Chan:
- return x.isNil()
- }
- }
-
- return false
-}
-
-// isInteger reports whether x is a (typed or untyped) integer value.
-func (x *operand) isInteger(ctxt *Context) bool {
- return x.mode == invalid ||
- isInteger(x.typ) ||
- x.mode == constant && isRepresentableConst(x.val, ctxt, UntypedInt)
-}
-
-// lookupResult represents the result of a struct field/method lookup.
-type lookupResult struct {
- mode operandMode
- typ Type
- index []int // field index sequence; nil for methods
-}
-
-type embeddedType struct {
- typ *NamedType
- index []int // field index sequence
- multiples bool // if set, typ is embedded multiple times at the same level
-}
-
-// lookupFieldBreadthFirst searches all types in list for a single entry (field
-// or method) of the given name from the given package. If such a field is found,
-// the result describes the field mode and type; otherwise the result mode is invalid.
-// (This function is similar in structure to FieldByNameFunc in reflect/type.go)
-//
-func lookupFieldBreadthFirst(list []embeddedType, name QualifiedName) (res lookupResult) {
- // visited records the types that have been searched already.
- visited := make(map[*NamedType]bool)
-
- // embedded types of the next lower level
- var next []embeddedType
-
- // potentialMatch is invoked every time a match is found.
- potentialMatch := func(multiples bool, mode operandMode, typ Type) bool {
- if multiples || res.mode != invalid {
- // name appeared already at this level - annihilate
- res.mode = invalid
- return false
- }
- // first appearance of name
- res.mode = mode
- res.typ = typ
- res.index = nil
- return true
- }
-
- // Search the current level if there is any work to do and collect
- // embedded types of the next lower level in the next list.
- for len(list) > 0 {
- // The res.mode indicates whether we have found a match already
- // on this level (mode != invalid), or not (mode == invalid).
- assert(res.mode == invalid)
-
- // start with empty next list (don't waste underlying array)
- next = next[:0]
-
- // look for name in all types at this level
- for _, e := range list {
- typ := e.typ
- if visited[typ] {
- continue
- }
- visited[typ] = true
-
- // look for a matching attached method
- for _, m := range typ.Methods {
- if name.IsSame(m.QualifiedName) {
- assert(m.Type != nil)
- if !potentialMatch(e.multiples, value, m.Type) {
- return // name collision
- }
- }
- }
-
- switch t := typ.Underlying.(type) {
- case *Struct:
- // look for a matching field and collect embedded types
- for i, f := range t.Fields {
- if name.IsSame(f.QualifiedName) {
- assert(f.Type != nil)
- if !potentialMatch(e.multiples, variable, f.Type) {
- return // name collision
- }
- var index []int
- index = append(index, e.index...) // copy e.index
- index = append(index, i)
- res.index = index
- continue
- }
- // Collect embedded struct fields for searching the next
- // lower level, but only if we have not seen a match yet
- // (if we have a match it is either the desired field or
- // we have a name collision on the same level; in either
- // case we don't need to look further).
- // Embedded fields are always of the form T or *T where
- // T is a named type. If typ appeared multiple times at
- // this level, f.Type appears multiple times at the next
- // level.
- if f.IsAnonymous && res.mode == invalid {
- // Ignore embedded basic types - only user-defined
- // named types can have methods or have struct fields.
- if t, _ := deref(f.Type).(*NamedType); t != nil {
- var index []int
- index = append(index, e.index...) // copy e.index
- index = append(index, i)
- next = append(next, embeddedType{t, index, e.multiples})
- }
- }
- }
-
- case *Interface:
- // look for a matching method
- for _, m := range t.Methods {
- if name.IsSame(m.QualifiedName) {
- assert(m.Type != nil)
- if !potentialMatch(e.multiples, value, m.Type) {
- return // name collision
- }
- }
- }
- }
- }
-
- if res.mode != invalid {
- // we found a single match on this level
- return
- }
-
- // No match and no collision so far.
- // Compute the list to search for the next level.
- list = list[:0] // don't waste underlying array
- for _, e := range next {
- // Instead of adding the same type multiple times, look for
- // it in the list and mark it as multiple if it was added
- // before.
- // We use a sequential search (instead of a map for next)
- // because the lists tend to be small, can easily be reused,
- // and explicit search appears to be faster in this case.
- if alt := findType(list, e.typ); alt != nil {
- alt.multiples = true
- } else {
- list = append(list, e)
- }
- }
-
- }
-
- return
-}
-
-func findType(list []embeddedType, typ *NamedType) *embeddedType {
- for i := range list {
- if p := &list[i]; p.typ == typ {
- return p
- }
- }
- return nil
-}
-
-func lookupField(typ Type, name QualifiedName) lookupResult {
- typ = deref(typ)
-
- if t, ok := typ.(*NamedType); ok {
- for _, m := range t.Methods {
- if name.IsSame(m.QualifiedName) {
- assert(m.Type != nil)
- return lookupResult{value, m.Type, nil}
- }
- }
- typ = t.Underlying
- }
-
- switch t := typ.(type) {
- case *Struct:
- var next []embeddedType
- for i, f := range t.Fields {
- if name.IsSame(f.QualifiedName) {
- return lookupResult{variable, f.Type, []int{i}}
- }
- if f.IsAnonymous {
- // Possible optimization: If the embedded type
- // is a pointer to the current type we could
- // ignore it.
- // Ignore embedded basic types - only user-defined
- // named types can have methods or have struct fields.
- if t, _ := deref(f.Type).(*NamedType); t != nil {
- next = append(next, embeddedType{t, []int{i}, false})
- }
- }
- }
- if len(next) > 0 {
- return lookupFieldBreadthFirst(next, name)
- }
-
- case *Interface:
- for _, m := range t.Methods {
- if name.IsSame(m.QualifiedName) {
- return lookupResult{value, m.Type, nil}
- }
- }
- }
-
- // not found
- return lookupResult{mode: invalid}
-}
diff --git a/src/pkg/go/types/predicates.go b/src/pkg/go/types/predicates.go
deleted file mode 100644
index a99c91a4e..000000000
--- a/src/pkg/go/types/predicates.go
+++ /dev/null
@@ -1,303 +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.
-
-// This file implements commonly used type predicates.
-
-package types
-
-func isNamed(typ Type) bool {
- if _, ok := typ.(*Basic); ok {
- return ok
- }
- _, ok := typ.(*NamedType)
- return ok
-}
-
-func isBoolean(typ Type) bool {
- t, ok := underlying(typ).(*Basic)
- return ok && t.Info&IsBoolean != 0
-}
-
-func isInteger(typ Type) bool {
- t, ok := underlying(typ).(*Basic)
- return ok && t.Info&IsInteger != 0
-}
-
-func isUnsigned(typ Type) bool {
- t, ok := underlying(typ).(*Basic)
- return ok && t.Info&IsUnsigned != 0
-}
-
-func isFloat(typ Type) bool {
- t, ok := underlying(typ).(*Basic)
- return ok && t.Info&IsFloat != 0
-}
-
-func isComplex(typ Type) bool {
- t, ok := underlying(typ).(*Basic)
- return ok && t.Info&IsComplex != 0
-}
-
-func isNumeric(typ Type) bool {
- t, ok := underlying(typ).(*Basic)
- return ok && t.Info&IsNumeric != 0
-}
-
-func isString(typ Type) bool {
- t, ok := underlying(typ).(*Basic)
- return ok && t.Info&IsString != 0
-}
-
-func isUntyped(typ Type) bool {
- t, ok := underlying(typ).(*Basic)
- return ok && t.Info&IsUntyped != 0
-}
-
-func isOrdered(typ Type) bool {
- t, ok := underlying(typ).(*Basic)
- return ok && t.Info&IsOrdered != 0
-}
-
-func isConstType(typ Type) bool {
- t, ok := underlying(typ).(*Basic)
- return ok && t.Info&IsConstType != 0
-}
-
-func isComparable(typ Type) bool {
- switch t := underlying(typ).(type) {
- case *Basic:
- return t.Kind != Invalid && t.Kind != UntypedNil
- case *Pointer, *Interface, *Chan:
- // assumes types are equal for pointers and channels
- return true
- case *Struct:
- for _, f := range t.Fields {
- if !isComparable(f.Type) {
- return false
- }
- }
- return true
- case *Array:
- return isComparable(t.Elt)
- }
- return false
-}
-
-func hasNil(typ Type) bool {
- switch underlying(typ).(type) {
- case *Slice, *Pointer, *Signature, *Interface, *Map, *Chan:
- return true
- }
- return false
-}
-
-// IsIdentical returns true if x and y are identical.
-func IsIdentical(x, y Type) bool {
- if x == y {
- return true
- }
-
- switch x := x.(type) {
- case *Basic:
- // Basic types are singletons except for the rune and byte
- // aliases, thus we cannot solely rely on the x == y check
- // above.
- if y, ok := y.(*Basic); ok {
- return x.Kind == y.Kind
- }
-
- case *Array:
- // 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 && IsIdentical(x.Elt, y.Elt)
- }
-
- case *Slice:
- // Two slice types are identical if they have identical element types.
- if y, ok := y.(*Slice); ok {
- return IsIdentical(x.Elt, y.Elt)
- }
-
- case *Struct:
- // Two struct types are identical if they have the same sequence of fields,
- // and if corresponding fields have the same names, and identical types,
- // and identical tags. Two anonymous fields are considered to have the same
- // name. Lower-case field names from different packages are always different.
- if y, ok := y.(*Struct); ok {
- if len(x.Fields) == len(y.Fields) {
- for i, f := range x.Fields {
- g := y.Fields[i]
- if !f.QualifiedName.IsSame(g.QualifiedName) ||
- !IsIdentical(f.Type, g.Type) ||
- f.Tag != g.Tag ||
- f.IsAnonymous != g.IsAnonymous {
- return false
- }
- }
- return true
- }
- }
-
- case *Pointer:
- // Two pointer types are identical if they have identical base types.
- if y, ok := y.(*Pointer); ok {
- return IsIdentical(x.Base, y.Base)
- }
-
- case *Signature:
- // Two function types are identical if they have the same number of parameters
- // and result values, corresponding parameter and result types are identical,
- // and either both functions are variadic or neither is. Parameter and result
- // names are not required to match.
- if y, ok := y.(*Signature); ok {
- return identicalTypes(x.Params, y.Params) &&
- identicalTypes(x.Results, y.Results) &&
- x.IsVariadic == y.IsVariadic
- }
-
- case *Interface:
- // Two interface types are identical if they have the same set of methods with
- // the same names and identical function types. Lower-case method names from
- // different packages are always different. The order of the methods is irrelevant.
- if y, ok := y.(*Interface); ok {
- return identicalMethods(x.Methods, y.Methods) // methods are sorted
- }
-
- case *Map:
- // Two map types are identical if they have identical key and value types.
- if y, ok := y.(*Map); ok {
- return IsIdentical(x.Key, y.Key) && IsIdentical(x.Elt, y.Elt)
- }
-
- 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 && IsIdentical(x.Elt, y.Elt)
- }
-
- case *NamedType:
- // Two named types are identical if their type names originate
- // in the same type declaration.
- if y, ok := y.(*NamedType); ok {
- return x.Obj == y.Obj
- }
- }
-
- return false
-}
-
-// identicalTypes returns true if both lists a and b have the
-// same length and corresponding objects have identical types.
-func identicalTypes(a, b []*Var) bool {
- if len(a) != len(b) {
- return false
- }
- for i, x := range a {
- y := b[i]
- if !IsIdentical(x.Type, y.Type) {
- return false
- }
- }
- return true
-}
-
-// identicalMethods returns true if both lists a and b have the
-// same length and corresponding methods have identical types.
-// TODO(gri) make this more efficient
-func identicalMethods(a, b []*Method) bool {
- if len(a) != len(b) {
- return false
- }
- m := make(map[QualifiedName]*Method)
- for _, x := range a {
- assert(m[x.QualifiedName] == nil) // method list must not have duplicate entries
- m[x.QualifiedName] = x
- }
- for _, y := range b {
- if x := m[y.QualifiedName]; x == nil || !IsIdentical(x.Type, y.Type) {
- return false
- }
- }
- return true
-}
-
-// underlying returns the underlying type of typ.
-func underlying(typ Type) Type {
- // Basic types are representing themselves directly even though they are named.
- if typ, ok := typ.(*NamedType); ok {
- return typ.Underlying // underlying types are never NamedTypes
- }
- return typ
-}
-
-// deref returns a pointer's base type; otherwise it returns typ.
-func deref(typ Type) Type {
- if typ, ok := underlying(typ).(*Pointer); ok {
- return typ.Base
- }
- return typ
-}
-
-// defaultType returns the default "typed" type for an "untyped" type;
-// it returns the incoming type for all other types. If there is no
-// corresponding untyped type, the result is Typ[Invalid].
-//
-func defaultType(typ Type) Type {
- if t, ok := typ.(*Basic); ok {
- k := Invalid
- switch t.Kind {
- // case UntypedNil:
- // There is no default type for nil. For a good error message,
- // catch this case before calling this function.
- case UntypedBool:
- k = Bool
- case UntypedInt:
- k = Int
- case UntypedRune:
- k = Rune
- case UntypedFloat:
- k = Float64
- case UntypedComplex:
- k = Complex128
- case UntypedString:
- k = String
- }
- typ = Typ[k]
- }
- return typ
-}
-
-// missingMethod returns (nil, false) if typ implements T, otherwise
-// it returns the first missing method required by T and whether it
-// is missing or simply has the wrong type.
-//
-func missingMethod(typ Type, T *Interface) (method *Method, wrongType bool) {
- // TODO(gri): this needs to correctly compare method names (taking package into account)
- // TODO(gri): distinguish pointer and non-pointer receivers
- // an interface type implements T if it has no methods with conflicting signatures
- // Note: This is stronger than the current spec. Should the spec require this?
- if ityp, _ := underlying(typ).(*Interface); ityp != nil {
- for _, m := range T.Methods {
- res := lookupField(ityp, m.QualifiedName) // TODO(gri) no need to go via lookupField
- if res.mode != invalid && !IsIdentical(res.typ, m.Type) {
- return m, true
- }
- }
- return
- }
-
- // a concrete type implements T if it implements all methods of T.
- for _, m := range T.Methods {
- res := lookupField(typ, m.QualifiedName)
- if res.mode == invalid {
- return m, false
- }
- if !IsIdentical(res.typ, m.Type) {
- return m, true
- }
- }
- return
-}
diff --git a/src/pkg/go/types/resolve.go b/src/pkg/go/types/resolve.go
deleted file mode 100644
index 43db60708..000000000
--- a/src/pkg/go/types/resolve.go
+++ /dev/null
@@ -1,197 +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 types
-
-import (
- "fmt"
- "go/ast"
- "go/token"
- "strconv"
-)
-
-func (check *checker) declareObj(scope, altScope *Scope, obj Object, dotImport token.Pos) {
- alt := scope.Insert(obj)
- if alt == nil && altScope != nil {
- // see if there is a conflicting declaration in altScope
- alt = altScope.Lookup(obj.GetName())
- }
- if alt != nil {
- prevDecl := ""
-
- // for dot-imports, local declarations are declared first - swap messages
- if dotImport.IsValid() {
- if pos := alt.GetPos(); pos.IsValid() {
- check.errorf(pos, fmt.Sprintf("%s redeclared in this block by dot-import at %s",
- obj.GetName(), check.fset.Position(dotImport)))
- return
- }
-
- // get by w/o other position
- check.errorf(dotImport, fmt.Sprintf("dot-import redeclares %s", obj.GetName()))
- return
- }
-
- if pos := alt.GetPos(); pos.IsValid() {
- prevDecl = fmt.Sprintf("\n\tother declaration at %s", check.fset.Position(pos))
- }
- check.errorf(obj.GetPos(), fmt.Sprintf("%s redeclared in this block%s", obj.GetName(), prevDecl))
- }
-}
-
-func (check *checker) resolveIdent(scope *Scope, ident *ast.Ident) bool {
- for ; scope != nil; scope = scope.Outer {
- if obj := scope.Lookup(ident.Name); obj != nil {
- check.register(ident, obj)
- return true
- }
- }
- return false
-}
-
-func (check *checker) resolve(importer Importer) (methods []*ast.FuncDecl) {
- pkg := &Package{Scope: &Scope{Outer: Universe}, Imports: make(map[string]*Package)}
- check.pkg = pkg
-
- // complete package scope
- i := 0
- for _, file := range check.files {
- // package names must match
- switch name := file.Name.Name; {
- case pkg.Name == "":
- pkg.Name = name
- case name != pkg.Name:
- check.errorf(file.Package, "package %s; expected %s", name, pkg.Name)
- continue // ignore this file
- }
-
- // keep this file
- check.files[i] = file
- i++
-
- // the package identifier denotes the current package
- check.register(file.Name, pkg)
-
- // insert top-level file objects in package scope
- // (the parser took care of declaration errors)
- for _, decl := range file.Decls {
- switch d := decl.(type) {
- case *ast.BadDecl:
- // ignore
- case *ast.GenDecl:
- if d.Tok == token.CONST {
- check.assocInitvals(d)
- }
- for _, spec := range d.Specs {
- switch s := spec.(type) {
- case *ast.ImportSpec:
- // handled separately below
- case *ast.ValueSpec:
- for _, name := range s.Names {
- if name.Name == "_" {
- continue
- }
- pkg.Scope.Insert(check.lookup(name))
- }
- case *ast.TypeSpec:
- if s.Name.Name == "_" {
- continue
- }
- pkg.Scope.Insert(check.lookup(s.Name))
- default:
- check.invalidAST(s.Pos(), "unknown ast.Spec node %T", s)
- }
- }
- case *ast.FuncDecl:
- if d.Recv != nil {
- // collect method
- methods = append(methods, d)
- continue
- }
- if d.Name.Name == "_" || d.Name.Name == "init" {
- continue // blank (_) and init functions are inaccessible
- }
- pkg.Scope.Insert(check.lookup(d.Name))
- default:
- check.invalidAST(d.Pos(), "unknown ast.Decl node %T", d)
- }
- }
- }
- check.files = check.files[0:i]
-
- // complete file scopes with imports and resolve identifiers
- for _, file := range check.files {
- // build file scope by processing all imports
- importErrors := false
- fileScope := &Scope{Outer: pkg.Scope}
- for _, spec := range file.Imports {
- if importer == nil {
- importErrors = true
- continue
- }
- path, _ := strconv.Unquote(spec.Path.Value)
- imp, err := importer(pkg.Imports, path)
- if err != nil {
- check.errorf(spec.Path.Pos(), "could not import %s (%s)", path, err)
- importErrors = true
- continue
- }
- // TODO(gri) If a local package name != "." is provided,
- // global identifier resolution could proceed even if the
- // import failed. Consider adjusting the logic here a bit.
-
- // local name overrides imported package name
- name := imp.Name
- if spec.Name != nil {
- name = spec.Name.Name
- }
-
- // add import to file scope
- if name == "." {
- // merge imported scope with file scope
- for _, obj := range imp.Scope.Entries {
- // gcimported package scopes contain non-exported
- // objects such as types used in partially exported
- // objects - do not accept them
- if ast.IsExported(obj.GetName()) {
- check.declareObj(fileScope, pkg.Scope, obj, spec.Pos())
- }
- }
- // TODO(gri) consider registering the "." identifier
- // if we have Context.Ident callbacks for say blank
- // (_) identifiers
- // check.register(spec.Name, pkg)
- } else if name != "_" {
- // declare imported package object in file scope
- // (do not re-use imp in the file scope but create
- // a new object instead; the Decl field is different
- // for different files)
- obj := &Package{Name: name, Scope: imp.Scope, spec: spec}
- check.declareObj(fileScope, pkg.Scope, obj, token.NoPos)
- }
- }
-
- // resolve identifiers
- if importErrors {
- // don't use the universe scope without correct imports
- // (objects in the universe may be shadowed by imports;
- // with missing imports, identifiers might get resolved
- // incorrectly to universe objects)
- pkg.Scope.Outer = nil
- }
- i := 0
- for _, ident := range file.Unresolved {
- if !check.resolveIdent(fileScope, ident) {
- check.errorf(ident.Pos(), "undeclared name: %s", ident.Name)
- file.Unresolved[i] = ident
- i++
- }
-
- }
- file.Unresolved = file.Unresolved[0:i]
- pkg.Scope.Outer = Universe // reset outer scope (is nil if there were importErrors)
- }
-
- return
-}
diff --git a/src/pkg/go/types/resolver_test.go b/src/pkg/go/types/resolver_test.go
deleted file mode 100644
index d4e364451..000000000
--- a/src/pkg/go/types/resolver_test.go
+++ /dev/null
@@ -1,167 +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 types
-
-import (
- "go/ast"
- "go/parser"
- "go/token"
- "testing"
-)
-
-var sources = []string{
- `
- package p
- import "fmt"
- import "math"
- const pi = math.Pi
- func sin(x float64) float64 {
- return math.Sin(x)
- }
- var Println = fmt.Println
- `,
- `
- package p
- import "fmt"
- func f() string {
- _ = "foo"
- return fmt.Sprintf("%d", g())
- }
- func g() (x int) { return }
- `,
- `
- package p
- import . "go/parser"
- import "sync"
- func g() Mode { return ImportsOnly }
- var _, x int = 1, 2
- func init() {}
- type T struct{ sync.Mutex; a, b, c int}
- type I interface{ m() }
- var _ = T{a: 1, b: 2, c: 3}
- func (_ T) m() {}
- `,
-}
-
-var pkgnames = []string{
- "fmt",
- "math",
-}
-
-func TestResolveQualifiedIdents(t *testing.T) {
- // parse package files
- fset := token.NewFileSet()
- var files []*ast.File
- for _, src := range sources {
- f, err := parser.ParseFile(fset, "", src, parser.DeclarationErrors)
- if err != nil {
- t.Fatal(err)
- }
- files = append(files, f)
- }
-
- // resolve and type-check package AST
- idents := make(map[*ast.Ident]Object)
- var ctxt Context
- ctxt.Ident = func(id *ast.Ident, obj Object) { idents[id] = obj }
- pkg, err := ctxt.Check(fset, files)
- if err != nil {
- t.Fatal(err)
- }
-
- // check that all packages were imported
- for _, name := range pkgnames {
- if pkg.Imports[name] == nil {
- t.Errorf("package %s not imported", name)
- }
- }
-
- // check that there are no top-level unresolved identifiers
- for _, f := range files {
- for _, x := range f.Unresolved {
- t.Errorf("%s: unresolved global identifier %s", fset.Position(x.Pos()), x.Name)
- }
- }
-
- // check that qualified identifiers are resolved
- for _, f := range files {
- ast.Inspect(f, func(n ast.Node) bool {
- if s, ok := n.(*ast.SelectorExpr); ok {
- if x, ok := s.X.(*ast.Ident); ok {
- obj := idents[x]
- if obj == nil {
- t.Errorf("%s: unresolved qualified identifier %s", fset.Position(x.Pos()), x.Name)
- return false
- }
- if _, ok := obj.(*Package); ok && idents[s.Sel] == nil {
- t.Errorf("%s: unresolved selector %s", fset.Position(s.Sel.Pos()), s.Sel.Name)
- return false
- }
- return false
- }
- return false
- }
- return true
- })
- }
-
- // Currently, the Check API doesn't call Ident for fields, methods, and composite literal keys.
- // Introduce them artifically so that we can run the check below.
- for _, f := range files {
- ast.Inspect(f, func(n ast.Node) bool {
- switch x := n.(type) {
- case *ast.StructType:
- for _, list := range x.Fields.List {
- for _, f := range list.Names {
- assert(idents[f] == nil)
- idents[f] = &Var{Pkg: pkg, Name: f.Name}
- }
- }
- case *ast.InterfaceType:
- for _, list := range x.Methods.List {
- for _, f := range list.Names {
- assert(idents[f] == nil)
- idents[f] = &Func{Pkg: pkg, Name: f.Name}
- }
- }
- case *ast.CompositeLit:
- for _, e := range x.Elts {
- if kv, ok := e.(*ast.KeyValueExpr); ok {
- if k, ok := kv.Key.(*ast.Ident); ok {
- assert(idents[k] == nil)
- idents[k] = &Var{Pkg: pkg, Name: k.Name}
- }
- }
- }
- }
- return true
- })
- }
-
- // check that each identifier in the source is enumerated by the Context.Ident callback
- for _, f := range files {
- ast.Inspect(f, func(n ast.Node) bool {
- if x, ok := n.(*ast.Ident); ok && x.Name != "_" && x.Name != "." {
- obj := idents[x]
- if obj == nil {
- t.Errorf("%s: unresolved identifier %s", fset.Position(x.Pos()), x.Name)
- } else {
- delete(idents, x)
- }
- return false
- }
- return true
- })
- }
-
- // TODO(gri) enable code below
- // At the moment, the type checker introduces artifical identifiers which are not
- // present in the source. Once it doesn't do that anymore, enable the checks below.
- /*
- for x := range idents {
- t.Errorf("%s: identifier %s not present in source", fset.Position(x.Pos()), x.Name)
- }
- */
-}
diff --git a/src/pkg/go/types/scope.go b/src/pkg/go/types/scope.go
deleted file mode 100644
index 463ee40c5..000000000
--- a/src/pkg/go/types/scope.go
+++ /dev/null
@@ -1,78 +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 types
-
-import (
- "bytes"
- "fmt"
-)
-
-// A Scope maintains the set of named language entities declared
-// in the scope and a link to the immediately surrounding (outer)
-// scope.
-//
-type Scope struct {
- Outer *Scope
- Entries []Object // scope entries in insertion order
- large map[string]Object // for fast lookup - only used for larger scopes
-}
-
-// Lookup returns the object with the given name if it is
-// found in scope s, otherwise it returns nil. Outer scopes
-// are ignored.
-//
-func (s *Scope) Lookup(name string) Object {
- if s.large != nil {
- return s.large[name]
- }
- for _, obj := range s.Entries {
- if obj.GetName() == name {
- return obj
- }
- }
- return nil
-}
-
-// Insert attempts to insert an object obj into scope s.
-// If s already contains an object with the same name,
-// Insert leaves s unchanged and returns that object.
-// Otherwise it inserts obj and returns nil.
-//
-func (s *Scope) Insert(obj Object) Object {
- name := obj.GetName()
- if alt := s.Lookup(name); alt != nil {
- return alt
- }
- s.Entries = append(s.Entries, obj)
-
- // If the scope size reaches a threshold, use a map for faster lookups.
- const threshold = 20
- if len(s.Entries) > threshold {
- if s.large == nil {
- m := make(map[string]Object, len(s.Entries))
- for _, obj := range s.Entries {
- m[obj.GetName()] = obj
- }
- s.large = m
- }
- s.large[name] = obj
- }
-
- return nil
-}
-
-// Debugging support
-func (s *Scope) String() string {
- var buf bytes.Buffer
- fmt.Fprintf(&buf, "scope %p {", s)
- if s != nil && len(s.Entries) > 0 {
- fmt.Fprintln(&buf)
- for _, obj := range s.Entries {
- fmt.Fprintf(&buf, "\t%s\t%T\n", obj.GetName(), obj)
- }
- }
- fmt.Fprintf(&buf, "}\n")
- return buf.String()
-}
diff --git a/src/pkg/go/types/sizes.go b/src/pkg/go/types/sizes.go
deleted file mode 100644
index ef6499ba4..000000000
--- a/src/pkg/go/types/sizes.go
+++ /dev/null
@@ -1,162 +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.
-
-// This file implements support for (unsafe) Alignof, Offsetof, and Sizeof.
-
-package types
-
-func (ctxt *Context) alignof(typ Type) int64 {
- if f := ctxt.Alignof; f != nil {
- if a := f(typ); a >= 1 {
- return a
- }
- panic("Context.Alignof returned an alignment < 1")
- }
- return DefaultAlignof(typ)
-}
-
-func (ctxt *Context) offsetsof(s *Struct) []int64 {
- offsets := s.offsets
- if offsets == nil {
- // compute offsets on demand
- if f := ctxt.Offsetsof; f != nil {
- offsets = f(s.Fields)
- // sanity checks
- if len(offsets) != len(s.Fields) {
- panic("Context.Offsetsof returned the wrong number of offsets")
- }
- for _, o := range offsets {
- if o < 0 {
- panic("Context.Offsetsof returned an offset < 0")
- }
- }
- } else {
- offsets = DefaultOffsetsof(s.Fields)
- }
- s.offsets = offsets
- }
- return offsets
-}
-
-// offsetof returns the offset of the field specified via
-// the index sequence relative to typ. It returns a value
-// < 0 if the field is in an embedded pointer type.
-func (ctxt *Context) offsetof(typ Type, index []int) int64 {
- var o int64
- for _, i := range index {
- s, _ := underlying(typ).(*Struct)
- if s == nil {
- return -1
- }
- o += ctxt.offsetsof(s)[i]
- typ = s.Fields[i].Type
- }
- return o
-}
-
-func (ctxt *Context) sizeof(typ Type) int64 {
- if f := ctxt.Sizeof; f != nil {
- if s := f(typ); s >= 0 {
- return s
- }
- panic("Context.Sizeof returned a size < 0")
- }
- return DefaultSizeof(typ)
-}
-
-// DefaultMaxAlign is the default maximum alignment, in bytes,
-// used by DefaultAlignof.
-const DefaultMaxAlign = 8
-
-// DefaultAlignof implements the default alignment computation
-// for unsafe.Alignof. It is used if Context.Alignof == nil.
-func DefaultAlignof(typ Type) int64 {
- // For arrays and structs, alignment is defined in terms
- // of alignment of the elements and fields, respectively.
- switch t := underlying(typ).(type) {
- case *Array:
- // spec: "For a variable x of array type: unsafe.Alignof(x)
- // is the same as unsafe.Alignof(x[0]), but at least 1."
- return DefaultAlignof(t.Elt)
- case *Struct:
- // spec: "For a variable x of struct type: unsafe.Alignof(x)
- // is the largest of the values unsafe.Alignof(x.f) for each
- // field f of x, but at least 1."
- max := int64(1)
- for _, f := range t.Fields {
- if a := DefaultAlignof(f.Type); a > max {
- max = a
- }
- }
- return max
- }
- a := DefaultSizeof(typ) // may be 0
- // spec: "For a variable x of any type: unsafe.Alignof(x) is at least 1."
- if a < 1 {
- return 1
- }
- if a > DefaultMaxAlign {
- return DefaultMaxAlign
- }
- return a
-}
-
-// align returns the smallest y >= x such that y % a == 0.
-func align(x, a int64) int64 {
- y := x + a - 1
- return y - y%a
-}
-
-// DefaultOffsetsof implements the default field offset computation
-// for unsafe.Offsetof. It is used if Context.Offsetsof == nil.
-func DefaultOffsetsof(fields []*Field) []int64 {
- offsets := make([]int64, len(fields))
- var o int64
- for i, f := range fields {
- a := DefaultAlignof(f.Type)
- o = align(o, a)
- offsets[i] = o
- o += DefaultSizeof(f.Type)
- }
- return offsets
-}
-
-// DefaultPtrSize is the default size of ints, uint, and pointers, in bytes,
-// used by DefaultSizeof.
-const DefaultPtrSize = 8
-
-// DefaultSizeof implements the default size computation
-// for unsafe.Sizeof. It is used if Context.Sizeof == nil.
-func DefaultSizeof(typ Type) int64 {
- switch t := underlying(typ).(type) {
- case *Basic:
- if s := t.size; s > 0 {
- return s
- }
- if t.Kind == String {
- return DefaultPtrSize * 2
- }
- case *Array:
- a := DefaultAlignof(t.Elt)
- s := DefaultSizeof(t.Elt)
- return align(s, a) * t.Len // may be 0
- case *Slice:
- return DefaultPtrSize * 3
- case *Struct:
- n := len(t.Fields)
- if n == 0 {
- return 0
- }
- offsets := t.offsets
- if t.offsets == nil {
- // compute offsets on demand
- offsets = DefaultOffsetsof(t.Fields)
- t.offsets = offsets
- }
- return offsets[n-1] + DefaultSizeof(t.Fields[n-1].Type)
- case *Signature:
- return DefaultPtrSize * 2
- }
- return DefaultPtrSize // catch-all
-}
diff --git a/src/pkg/go/types/stmt.go b/src/pkg/go/types/stmt.go
deleted file mode 100644
index 53c46a167..000000000
--- a/src/pkg/go/types/stmt.go
+++ /dev/null
@@ -1,743 +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.
-
-// This file implements typechecking of statements.
-
-package types
-
-import (
- "go/ast"
- "go/token"
-)
-
-// assigment reports whether x can be assigned to a variable of type 'to',
-// if necessary by attempting to convert untyped values to the appropriate
-// type. If x.mode == invalid upon return, then assignment has already
-// issued an error message and the caller doesn't have to report another.
-// TODO(gri) This latter behavior is for historic reasons and complicates
-// callers. Needs to be cleaned up.
-func (check *checker) assignment(x *operand, to Type) bool {
- if x.mode == invalid {
- return false
- }
-
- if t, ok := x.typ.(*Result); ok {
- // TODO(gri) elsewhere we use "assignment count mismatch" (consolidate)
- check.errorf(x.pos(), "%d-valued expression %s used as single value", len(t.Values), x)
- x.mode = invalid
- return false
- }
-
- check.convertUntyped(x, to)
-
- return x.mode != invalid && x.isAssignable(check.ctxt, to)
-}
-
-// assign1to1 typechecks a single assignment of the form lhs = rhs (if rhs != nil),
-// or lhs = x (if rhs == nil). If decl is set, the lhs operand must be an identifier.
-// If its type is not set, it is deduced from the type or value of x. If lhs has a
-// type it is used as a hint when evaluating rhs, if present.
-//
-func (check *checker) assign1to1(lhs, rhs ast.Expr, x *operand, decl bool, iota int) {
- ident, _ := lhs.(*ast.Ident)
- if x == nil {
- assert(rhs != nil)
- x = new(operand)
- }
-
- if ident != nil && ident.Name == "_" {
- // anything can be assigned to a blank identifier - check rhs only, if present
- if rhs != nil {
- check.expr(x, rhs, nil, iota)
- }
- return
- }
-
- if !decl {
- // regular assignment - start with lhs to obtain a type hint
- // TODO(gri) clean this up - we don't need type hints anymore
- var z operand
- check.expr(&z, lhs, nil, -1)
- if z.mode == invalid {
- z.typ = nil // so we can proceed with rhs
- }
-
- if rhs != nil {
- check.expr(x, rhs, z.typ, -1)
- if x.mode == invalid {
- return
- }
- }
-
- if x.mode == invalid || z.mode == invalid {
- return
- }
-
- if !check.assignment(x, z.typ) {
- if x.mode != invalid {
- check.errorf(x.pos(), "cannot assign %s to %s", x, &z)
- }
- return
- }
- if z.mode == constant {
- check.errorf(x.pos(), "cannot assign %s to %s", x, &z)
- }
- return
- }
-
- // declaration - lhs must be an identifier
- if ident == nil {
- check.errorf(lhs.Pos(), "cannot declare %s", lhs)
- return
- }
-
- // lhs may or may not be typed yet
- obj := check.lookup(ident)
- var typ Type
- if t := obj.GetType(); t != nil {
- typ = t
- }
-
- if rhs != nil {
- check.expr(x, rhs, typ, iota)
- // continue even if x.mode == invalid
- }
-
- if typ == nil {
- // determine lhs type from rhs expression;
- // for variables, convert untyped types to
- // default types
- typ = Typ[Invalid]
- if x.mode != invalid {
- typ = x.typ
- if _, ok := obj.(*Var); ok && isUntyped(typ) {
- if x.isNil() {
- check.errorf(x.pos(), "use of untyped nil")
- x.mode = invalid
- } else {
- typ = defaultType(typ)
- }
- }
- }
- switch obj := obj.(type) {
- case *Const:
- obj.Type = typ
- case *Var:
- obj.Type = typ
- default:
- unreachable()
- }
- }
-
- if x.mode != invalid {
- if !check.assignment(x, typ) {
- if x.mode != invalid {
- switch obj.(type) {
- case *Const:
- check.errorf(x.pos(), "cannot assign %s to variable of type %s", x, typ)
- case *Var:
- check.errorf(x.pos(), "cannot initialize constant of type %s with %s", typ, x)
- default:
- unreachable()
- }
- x.mode = invalid
- }
- }
- }
-
- // for constants, set their value
- if obj, ok := obj.(*Const); ok {
- assert(obj.Val == nil)
- if x.mode != invalid {
- if x.mode == constant {
- if isConstType(x.typ) {
- obj.Val = x.val
- } else {
- check.errorf(x.pos(), "%s has invalid constant type", x)
- }
- } else {
- check.errorf(x.pos(), "%s is not constant", x)
- }
- }
- if obj.Val == nil {
- // set the constant to its type's zero value to reduce spurious errors
- switch typ := underlying(obj.Type); {
- case typ == Typ[Invalid]:
- // ignore
- case isBoolean(typ):
- obj.Val = false
- case isNumeric(typ):
- obj.Val = int64(0)
- case isString(typ):
- obj.Val = ""
- case hasNil(typ):
- obj.Val = nilConst
- default:
- // in all other cases just prevent use of the constant
- // TODO(gri) re-evaluate this code
- obj.Val = nilConst
- }
- }
- }
-}
-
-// assignNtoM typechecks a general assignment. If decl is set, the lhs operands
-// must be identifiers. If their types are not set, they are deduced from the
-// types of the corresponding rhs expressions. iota >= 0 indicates that the
-// "assignment" is part of a constant/variable declaration.
-// Precondition: len(lhs) > 0 .
-//
-func (check *checker) assignNtoM(lhs, rhs []ast.Expr, decl bool, iota int) {
- assert(len(lhs) > 0)
-
- if len(lhs) == len(rhs) {
- for i, e := range rhs {
- check.assign1to1(lhs[i], e, nil, decl, iota)
- }
- return
- }
-
- if len(rhs) == 1 {
- // len(lhs) > 1, therefore a correct rhs expression
- // cannot be a shift and we don't need a type hint;
- // ok to evaluate rhs first
- var x operand
- check.expr(&x, rhs[0], nil, iota)
- if x.mode == invalid {
- // If decl is set, this leaves the lhs identifiers
- // untyped. We catch this when looking up the respective
- // object.
- return
- }
-
- if t, ok := x.typ.(*Result); ok && len(lhs) == len(t.Values) {
- // function result
- x.mode = value
- for i, obj := range t.Values {
- x.expr = nil // TODO(gri) should do better here
- x.typ = obj.Type
- check.assign1to1(lhs[i], nil, &x, decl, iota)
- }
- return
- }
-
- if x.mode == valueok && len(lhs) == 2 {
- // comma-ok expression
- x.mode = value
- check.assign1to1(lhs[0], nil, &x, decl, iota)
-
- x.mode = value
- x.typ = Typ[UntypedBool]
- check.assign1to1(lhs[1], nil, &x, decl, iota)
- return
- }
- }
-
- check.errorf(lhs[0].Pos(), "assignment count mismatch: %d = %d", len(lhs), len(rhs))
-
- // avoid checking the same declaration over and over
- // again for each lhs identifier that has no type yet
- if iota >= 0 {
- // declaration
- for _, e := range lhs {
- if name, ok := e.(*ast.Ident); ok {
- switch obj := check.lookup(name).(type) {
- case *Const:
- obj.Type = Typ[Invalid]
- case *Var:
- obj.Type = Typ[Invalid]
- default:
- unreachable()
- }
- }
- }
- }
-}
-
-func (check *checker) optionalStmt(s ast.Stmt) {
- if s != nil {
- check.stmt(s)
- }
-}
-
-func (check *checker) stmtList(list []ast.Stmt) {
- for _, s := range list {
- check.stmt(s)
- }
-}
-
-func (check *checker) call(call *ast.CallExpr) {
- var x operand
- check.rawExpr(&x, call, nil, -1, false) // don't check if value is used
- // TODO(gri) If a builtin is called, the builtin must be valid in statement context.
-}
-
-func (check *checker) multipleDefaults(list []ast.Stmt) {
- var first ast.Stmt
- for _, s := range list {
- var d ast.Stmt
- switch c := s.(type) {
- case *ast.CaseClause:
- if len(c.List) == 0 {
- d = s
- }
- case *ast.CommClause:
- if c.Comm == nil {
- d = s
- }
- default:
- check.invalidAST(s.Pos(), "case/communication clause expected")
- }
- if d != nil {
- if first != nil {
- check.errorf(d.Pos(), "multiple defaults (first at %s)", first.Pos())
- } else {
- first = d
- }
- }
- }
-}
-
-// stmt typechecks statement s.
-func (check *checker) stmt(s ast.Stmt) {
- switch s := s.(type) {
- case *ast.BadStmt, *ast.EmptyStmt:
- // ignore
-
- case *ast.DeclStmt:
- d, _ := s.Decl.(*ast.GenDecl)
- if d == nil || (d.Tok != token.CONST && d.Tok != token.TYPE && d.Tok != token.VAR) {
- check.invalidAST(token.NoPos, "const, type, or var declaration expected")
- return
- }
- if d.Tok == token.CONST {
- check.assocInitvals(d)
- }
- check.decl(d)
-
- case *ast.LabeledStmt:
- // TODO(gri) anything to do with label itself?
- check.stmt(s.Stmt)
-
- case *ast.ExprStmt:
- var x operand
- used := false
- switch e := unparen(s.X).(type) {
- case *ast.CallExpr:
- // function calls are permitted
- used = true
- // but some builtins are excluded
- // (Caution: This evaluates e.Fun twice, once here and once
- // below as part of s.X. This has consequences for
- // check.register. Perhaps this can be avoided.)
- check.expr(&x, e.Fun, nil, -1)
- if x.mode != invalid {
- if b, ok := x.typ.(*builtin); ok && !b.isStatement {
- used = false
- }
- }
- case *ast.UnaryExpr:
- // receive operations are permitted
- if e.Op == token.ARROW {
- used = true
- }
- }
- if !used {
- check.errorf(s.Pos(), "%s not used", s.X)
- // ok to continue
- }
- check.rawExpr(&x, s.X, nil, -1, false)
- if x.mode == typexpr {
- check.errorf(x.pos(), "%s is not an expression", &x)
- }
-
- case *ast.SendStmt:
- var ch, x operand
- check.expr(&ch, s.Chan, nil, -1)
- check.expr(&x, s.Value, nil, -1)
- if ch.mode == invalid || x.mode == invalid {
- return
- }
- if tch, ok := underlying(ch.typ).(*Chan); !ok || tch.Dir&ast.SEND == 0 || !check.assignment(&x, tch.Elt) {
- if x.mode != invalid {
- check.invalidOp(ch.pos(), "cannot send %s to channel %s", &x, &ch)
- }
- }
-
- case *ast.IncDecStmt:
- var op token.Token
- switch s.Tok {
- case token.INC:
- op = token.ADD
- case token.DEC:
- op = token.SUB
- default:
- check.invalidAST(s.TokPos, "unknown inc/dec operation %s", s.Tok)
- return
- }
- var x operand
- Y := &ast.BasicLit{ValuePos: s.X.Pos(), Kind: token.INT, Value: "1"} // use x's position
- check.binary(&x, s.X, Y, op, -1)
- if x.mode == invalid {
- return
- }
- check.assign1to1(s.X, nil, &x, false, -1)
-
- case *ast.AssignStmt:
- switch s.Tok {
- case token.ASSIGN, token.DEFINE:
- if len(s.Lhs) == 0 {
- check.invalidAST(s.Pos(), "missing lhs in assignment")
- return
- }
- check.assignNtoM(s.Lhs, s.Rhs, s.Tok == token.DEFINE, -1)
- default:
- // assignment operations
- if len(s.Lhs) != 1 || len(s.Rhs) != 1 {
- check.errorf(s.TokPos, "assignment operation %s requires single-valued expressions", s.Tok)
- return
- }
- // TODO(gri) make this conversion more efficient
- var op token.Token
- switch s.Tok {
- case token.ADD_ASSIGN:
- op = token.ADD
- case token.SUB_ASSIGN:
- op = token.SUB
- case token.MUL_ASSIGN:
- op = token.MUL
- case token.QUO_ASSIGN:
- op = token.QUO
- case token.REM_ASSIGN:
- op = token.REM
- case token.AND_ASSIGN:
- op = token.AND
- case token.OR_ASSIGN:
- op = token.OR
- case token.XOR_ASSIGN:
- op = token.XOR
- case token.SHL_ASSIGN:
- op = token.SHL
- case token.SHR_ASSIGN:
- op = token.SHR
- case token.AND_NOT_ASSIGN:
- op = token.AND_NOT
- default:
- check.invalidAST(s.TokPos, "unknown assignment operation %s", s.Tok)
- return
- }
- var x operand
- check.binary(&x, s.Lhs[0], s.Rhs[0], op, -1)
- if x.mode == invalid {
- return
- }
- check.assign1to1(s.Lhs[0], nil, &x, false, -1)
- }
-
- case *ast.GoStmt:
- check.call(s.Call)
-
- case *ast.DeferStmt:
- check.call(s.Call)
-
- case *ast.ReturnStmt:
- sig := check.funcsig
- if n := len(sig.Results); n > 0 {
- // TODO(gri) should not have to compute lhs, named every single time - clean this up
- lhs := make([]ast.Expr, n)
- named := false // if set, function has named results
- for i, res := range sig.Results {
- if len(res.Name) > 0 {
- // a blank (_) result parameter is a named result
- named = true
- }
- name := ast.NewIdent(res.Name)
- name.NamePos = s.Pos()
- check.register(name, &Var{Name: res.Name, Type: res.Type}) // Pkg == nil
- lhs[i] = name
- }
- if len(s.Results) > 0 || !named {
- // TODO(gri) assignNtoM should perhaps not require len(lhs) > 0
- check.assignNtoM(lhs, s.Results, false, -1)
- }
- } else if len(s.Results) > 0 {
- check.errorf(s.Pos(), "no result values expected")
- }
-
- case *ast.BranchStmt:
- // TODO(gri) implement this
-
- case *ast.BlockStmt:
- check.stmtList(s.List)
-
- case *ast.IfStmt:
- check.optionalStmt(s.Init)
- var x operand
- check.expr(&x, s.Cond, nil, -1)
- if x.mode != invalid && !isBoolean(x.typ) {
- check.errorf(s.Cond.Pos(), "non-boolean condition in if statement")
- }
- check.stmt(s.Body)
- check.optionalStmt(s.Else)
-
- case *ast.SwitchStmt:
- check.optionalStmt(s.Init)
- var x operand
- tag := s.Tag
- if tag == nil {
- // use fake true tag value and position it at the opening { of the switch
- ident := &ast.Ident{NamePos: s.Body.Lbrace, Name: "true"}
- check.register(ident, Universe.Lookup("true"))
- tag = ident
- }
- check.expr(&x, tag, nil, -1)
-
- check.multipleDefaults(s.Body.List)
- seen := make(map[interface{}]token.Pos)
- for _, s := range s.Body.List {
- clause, _ := s.(*ast.CaseClause)
- if clause == nil {
- continue // error reported before
- }
- if x.mode != invalid {
- for _, expr := range clause.List {
- x := x // copy of x (don't modify original)
- var y operand
- check.expr(&y, expr, nil, -1)
- if y.mode == invalid {
- continue // error reported before
- }
- // If we have a constant case value, it must appear only
- // once in the switch statement. Determine if there is a
- // duplicate entry, but only report an error if there are
- // no other errors.
- var dupl token.Pos
- var yy operand
- if y.mode == constant {
- // TODO(gri) This code doesn't work correctly for
- // large integer, floating point, or
- // complex values - the respective struct
- // comparisons are shallow. Need to use a
- // hash function to index the map.
- dupl = seen[y.val]
- seen[y.val] = y.pos()
- yy = y // remember y
- }
- // TODO(gri) The convertUntyped call pair below appears in other places. Factor!
- // Order matters: By comparing y against x, error positions are at the case values.
- check.convertUntyped(&y, x.typ)
- if y.mode == invalid {
- continue // error reported before
- }
- check.convertUntyped(&x, y.typ)
- if x.mode == invalid {
- continue // error reported before
- }
- check.comparison(&y, &x, token.EQL)
- if y.mode != invalid && dupl.IsValid() {
- check.errorf(yy.pos(), "%s is duplicate case (previous at %s)",
- &yy, check.fset.Position(dupl))
- }
- }
- }
- check.stmtList(clause.Body)
- }
-
- case *ast.TypeSwitchStmt:
- check.optionalStmt(s.Init)
-
- // A type switch guard must be of the form:
- //
- // TypeSwitchGuard = [ identifier ":=" ] PrimaryExpr "." "(" "type" ")" .
- //
- // The parser is checking syntactic correctness;
- // remaining syntactic errors are considered AST errors here.
- // TODO(gri) better factoring of error handling (invalid ASTs)
- //
- var lhs *Var // lhs variable or nil
- var rhs ast.Expr
- switch guard := s.Assign.(type) {
- case *ast.ExprStmt:
- rhs = guard.X
- case *ast.AssignStmt:
- if len(guard.Lhs) != 1 || guard.Tok != token.DEFINE || len(guard.Rhs) != 1 {
- check.invalidAST(s.Pos(), "incorrect form of type switch guard")
- return
- }
- ident, _ := guard.Lhs[0].(*ast.Ident)
- if ident == nil {
- check.invalidAST(s.Pos(), "incorrect form of type switch guard")
- return
- }
- lhs = check.lookup(ident).(*Var)
- rhs = guard.Rhs[0]
- default:
- check.invalidAST(s.Pos(), "incorrect form of type switch guard")
- return
- }
-
- // rhs must be of the form: expr.(type) and expr must be an interface
- expr, _ := rhs.(*ast.TypeAssertExpr)
- if expr == nil || expr.Type != nil {
- check.invalidAST(s.Pos(), "incorrect form of type switch guard")
- return
- }
- var x operand
- check.expr(&x, expr.X, nil, -1)
- if x.mode == invalid {
- return
- }
- var T *Interface
- if T, _ = underlying(x.typ).(*Interface); T == nil {
- check.errorf(x.pos(), "%s is not an interface", &x)
- return
- }
-
- check.multipleDefaults(s.Body.List)
- for _, s := range s.Body.List {
- clause, _ := s.(*ast.CaseClause)
- if clause == nil {
- continue // error reported before
- }
- // Check each type in this type switch case.
- var typ Type
- for _, expr := range clause.List {
- typ = check.typOrNil(expr, false)
- if typ != nil && typ != Typ[Invalid] {
- if method, wrongType := missingMethod(typ, T); method != nil {
- var msg string
- if wrongType {
- msg = "%s cannot have dynamic type %s (wrong type for method %s)"
- } else {
- msg = "%s cannot have dynamic type %s (missing method %s)"
- }
- check.errorf(expr.Pos(), msg, &x, typ, method.Name)
- // ok to continue
- }
- }
- }
- // If lhs exists, set its type for each clause.
- if lhs != nil {
- // In clauses with a case listing exactly one type, the variable has that type;
- // otherwise, the variable has the type of the expression in the TypeSwitchGuard.
- if len(clause.List) != 1 || typ == nil {
- typ = x.typ
- }
- lhs.Type = typ
- }
- check.stmtList(clause.Body)
- }
-
- // There is only one object (lhs) associated with a lhs identifier, but that object
- // assumes different types for different clauses. Set it back to the type of the
- // TypeSwitchGuard expression so that that variable always has a valid type.
- if lhs != nil {
- lhs.Type = x.typ
- }
-
- case *ast.SelectStmt:
- check.multipleDefaults(s.Body.List)
- for _, s := range s.Body.List {
- clause, _ := s.(*ast.CommClause)
- if clause == nil {
- continue // error reported before
- }
- check.optionalStmt(clause.Comm) // TODO(gri) check correctness of c.Comm (must be Send/RecvStmt)
- check.stmtList(clause.Body)
- }
-
- case *ast.ForStmt:
- check.optionalStmt(s.Init)
- if s.Cond != nil {
- var x operand
- check.expr(&x, s.Cond, nil, -1)
- if x.mode != invalid && !isBoolean(x.typ) {
- check.errorf(s.Cond.Pos(), "non-boolean condition in for statement")
- }
- }
- check.optionalStmt(s.Post)
- check.stmt(s.Body)
-
- case *ast.RangeStmt:
- // check expression to iterate over
- decl := s.Tok == token.DEFINE
- var x operand
- check.expr(&x, s.X, nil, -1)
- if x.mode == invalid {
- // if we don't have a declaration, we can still check the loop's body
- if !decl {
- check.stmt(s.Body)
- }
- return
- }
-
- // determine key/value types
- var key, val Type
- switch typ := underlying(x.typ).(type) {
- case *Basic:
- if isString(typ) {
- key = Typ[UntypedInt]
- val = Typ[UntypedRune]
- }
- case *Array:
- key = Typ[UntypedInt]
- val = typ.Elt
- case *Slice:
- key = Typ[UntypedInt]
- val = typ.Elt
- case *Pointer:
- if typ, _ := underlying(typ.Base).(*Array); typ != nil {
- key = Typ[UntypedInt]
- val = typ.Elt
- }
- case *Map:
- key = typ.Key
- val = typ.Elt
- case *Chan:
- key = typ.Elt
- if typ.Dir&ast.RECV == 0 {
- check.errorf(x.pos(), "cannot range over send-only channel %s", &x)
- // ok to continue
- }
- if s.Value != nil {
- check.errorf(s.Value.Pos(), "iteration over %s permits only one iteration variable", &x)
- // ok to continue
- }
- }
-
- if key == nil {
- check.errorf(x.pos(), "cannot range over %s", &x)
- // if we don't have a declaration, we can still check the loop's body
- if !decl {
- check.stmt(s.Body)
- }
- return
- }
-
- // check assignment to/declaration of iteration variables
- // TODO(gri) The error messages/positions are not great here,
- // they refer to the expression in the range clause.
- // Should give better messages w/o too much code
- // duplication (assignment checking).
- x.mode = value
- if s.Key != nil {
- x.typ = key
- x.expr = s.Key
- check.assign1to1(s.Key, nil, &x, decl, -1)
- } else {
- check.invalidAST(s.Pos(), "range clause requires index iteration variable")
- // ok to continue
- }
- if s.Value != nil {
- x.typ = val
- x.expr = s.Value
- check.assign1to1(s.Value, nil, &x, decl, -1)
- }
-
- check.stmt(s.Body)
-
- default:
- check.errorf(s.Pos(), "invalid statement")
- }
-}
diff --git a/src/pkg/go/types/testdata/builtins.src b/src/pkg/go/types/testdata/builtins.src
deleted file mode 100644
index c08c442ce..000000000
--- a/src/pkg/go/types/testdata/builtins.src
+++ /dev/null
@@ -1,401 +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.
-
-// builtin calls
-
-package builtins
-
-import "unsafe"
-
-func _append() {
- var x int
- var s []byte
- _0 := append /* ERROR "argument" */ ()
- _1 := append("foo" /* ERROR "not a typed slice" */)
- _2 := append(nil /* ERROR "not a typed slice" */, s)
- _3 := append(x /* ERROR "not a typed slice" */, s)
- _4 := append(s)
- append /* ERROR "not used" */ (s)
-}
-
-func _cap() {
- var a [10]bool
- var p *[20]int
- var s []int
- var c chan string
- _0 := cap /* ERROR "argument" */ ()
- _1 := cap /* ERROR "argument" */ (1, 2)
- _2 := cap(42 /* ERROR "invalid" */)
- const _3 = cap(a)
- assert(_3 == 10)
- const _4 = cap(p)
- assert(_4 == 20)
- _5 := cap(c)
- cap /* ERROR "not used" */ (c)
-
- // issue 4744
- type T struct{ a [10]int }
- const _ = cap(((*T)(nil)).a)
-}
-
-func _close() {
- var c chan int
- var r <-chan int
- close /* ERROR "argument" */ ()
- close /* ERROR "argument" */ (1, 2)
- close(42 /* ERROR "not a channel" */)
- close(r /* ERROR "receive-only channel" */)
- close(c)
-}
-
-func _complex() {
- var i32 int32
- var f32 float32
- var f64 float64
- var c64 complex64
- _ = complex /* ERROR "argument" */ ()
- _ = complex /* ERROR "argument" */ (1)
- _ = complex(true /* ERROR "invalid argument" */ , 0)
- _ = complex(i32 /* ERROR "invalid argument" */ , 0)
- _ = complex("foo" /* ERROR "invalid argument" */ , 0)
- _ = complex(c64 /* ERROR "invalid argument" */ , 0)
- _ = complex(0, true /* ERROR "invalid argument" */ )
- _ = complex(0, i32 /* ERROR "invalid argument" */ )
- _ = complex(0, "foo" /* ERROR "invalid argument" */ )
- _ = complex(0, c64 /* ERROR "invalid argument" */ )
- _ = 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)
-}
-
-func _copy() {
- copy /* ERROR "not enough arguments" */ ()
- copy /* ERROR "not enough arguments" */ ("foo")
- 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")
-}
-
-func _delete() {
- var m map[string]int
- var s string
- delete /* ERROR "argument" */ ()
- delete /* ERROR "argument" */ (1)
- delete /* ERROR "argument" */ (1, 2, 3)
- delete(m, 0 /* ERROR "not assignable" */)
- delete(m, s)
-}
-
-func _imag() {
- var f32 float32
- var f64 float64
- var c64 complex64
- var c128 complex128
- _ = imag /* ERROR "argument" */ ()
- _ = imag /* ERROR "argument" */ (1, 2)
- _ = imag(10 /* ERROR "must be a complex number" */)
- _ = imag(2.7182818 /* ERROR "must be a complex number" */)
- _ = imag("foo" /* ERROR "must be a complex number" */)
- 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 assign" */ (c128)
- f64 = imag /* ERROR "cannot assign" */ (c64)
- imag /* ERROR "not used" */ (c64)
-}
-
-func _len() {
- const c = "foobar"
- var a [10]bool
- var p *[20]int
- var s []int
- var m map[string]complex128
- _ = len /* ERROR "argument" */ ()
- _ = len /* ERROR "argument" */ (1, 2)
- _ = 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 /* ERROR "failed" */ (n == 10)
- var ch <-chan int
- const nn = len /* ERROR "not constant" */ (hash[<-ch][len(t)])
- _ = nn // TODO(gri) remove this once unused constants get type-checked
-
- // issue 4744
- type T struct{ a [10]int }
- const _ = len(((*T)(nil)).a)
-}
-
-func _make() {
- n := 0
-
- _ = make /* ERROR "argument" */ ()
- _ = 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 "must be an integer" */)
- _ = make([]int, 10, 2.3 /* ERROR "must be an integer" */)
- _ = make([]int, 5, 10.0)
- _ = make([]int, 0i)
- _ = 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<<100, 1<<100) // run-time panic
- _ = make([]int, 1 /* ERROR "length and capacity swapped" */ <<100 + 1, 1<<100)
- _ = make([]int, 1 /* ERROR "length and capacity swapped" */ <<100, 12345)
-
- // maps
- _ = make /* ERROR "arguments" */ (map[int]string, 10, 20)
- _ = make(map[int]float32, int /* ERROR "not an expression" */)
- _ = make(map[int]float32, "foo" /* ERROR "must be an integer" */)
- _ = make(map[int]float32, 10)
- _ = make(map[int]float32, n)
- _ = make(map[int]float32, int64(n))
-
- // channels
- _ = make /* ERROR "arguments" */ (chan int, 10, 20)
- _ = make(chan int, int /* ERROR "not an expression" */)
- _ = make(chan<- int, "foo" /* ERROR "must be an integer" */)
- _ = make(<-chan float64, 10)
- _ = make(chan chan int, n)
- _ = make(chan string, int64(n))
-
- make /* ERROR "not used" */ ([]int, 10)
-}
-
-func _new() {
- _ = new /* ERROR "argument" */ ()
- _ = new /* ERROR "argument" */ (1, 2)
- _ = new("foo" /* ERROR "not a type" */)
- p := new(float64)
- _ = new(struct{ x, y int })
- q := new(*float64)
- _ = *p == **q
- new /* ERROR "not used" */ (int)
-}
-
-func _panic() {
- panic /* ERROR "arguments" */ ()
- panic /* ERROR "arguments" */ (1, 2)
- panic(0)
- panic("foo")
- panic(false)
-}
-
-func _print() {
- print()
- print(1)
- print(1, 2)
- print("foo")
- print(2.718281828)
- print(false)
-}
-
-func _println() {
- println()
- println(1)
- println(1, 2)
- println("foo")
- println(2.718281828)
- println(false)
-}
-
-func _real() {
- var f32 float32
- var f64 float64
- var c64 complex64
- var c128 complex128
- _ = real /* ERROR "argument" */ ()
- _ = real /* ERROR "argument" */ (1, 2)
- _ = real(10 /* ERROR "must be a complex number" */)
- _ = real(2.7182818 /* ERROR "must be a complex number" */)
- _ = real("foo" /* ERROR "must be a complex number" */)
- 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 assign" */ (c128)
- f64 = real /* ERROR "cannot assign" */ (c64)
- real /* ERROR "not used" */ (c64)
-}
-
-func _recover() {
- _ = recover()
- _ = recover /* ERROR "argument" */ (10)
- recover()
-}
-
-// 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
-
-func _Alignof() {
- var x int
- _ = unsafe /* ERROR "argument" */ .Alignof()
- _ = unsafe /* ERROR "argument" */ .Alignof(1, 2)
- _ = unsafe.Alignof(int /* ERROR "not an expression" */)
- _ = unsafe.Alignof(42)
- _ = unsafe.Alignof(new(struct{}))
- 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)
-}
-
-func _Offsetof() {
- var x struct{ f int }
- _ = unsafe /* ERROR "argument" */ .Offsetof()
- _ = unsafe /* ERROR "argument" */ .Offsetof(1, 2)
- _ = unsafe.Offsetof(int /* ERROR "not an expression" */)
- _ = unsafe.Offsetof(x /* ERROR "not a selector" */)
- _ = 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 y2 S2
- assert(unsafe.Offsetof(y2.S1) == 0)
- _ = unsafe.Offsetof(y2 /* ERROR "embedded via pointer" */ .x)
-}
-
-func _Sizeof() {
- var x int
- _ = unsafe /* ERROR "argument" */ .Sizeof()
- _ = unsafe /* ERROR "argument" */ .Sizeof(1, 2)
- _ = unsafe.Sizeof(int /* ERROR "not an expression" */)
- _ = unsafe.Sizeof(42)
- _ = unsafe.Sizeof(new(complex128))
- 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)
-}
-
-// self-testing only
-func _assert() {
- var x int
- assert /* ERROR "argument" */ ()
- assert /* ERROR "argument" */ (1, 2)
- assert("foo" /* ERROR "boolean constant" */ )
- assert(x /* ERROR "boolean constant" */)
- assert(true)
- assert /* ERROR "failed" */ (false)
-}
-
-// self-testing only
-func _trace() {
- // 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")
-}
diff --git a/src/pkg/go/types/testdata/const0.src b/src/pkg/go/types/testdata/const0.src
deleted file mode 100644
index a2ca344c7..000000000
--- a/src/pkg/go/types/testdata/const0.src
+++ /dev/null
@@ -1,215 +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.
-
-// constant declarations
-
-package const0
-
-// constants declarations must be initialized by constants
-var x = 0
-const c0 = x /* ERROR "not constant" */
-
-// 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
-
- // 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 "cannot compare" */ == 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 // TODO(gri) enable this
- //ti9 = ti3 % ti3 // TODO(gri) enable this
-
- 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 // TODO(gri) enable this
- 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 "cycle" */ = a
- b /* ERROR "cycle" */ , c /* ERROR "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
- _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)
-)
-
-// special cases
-const (
- _n0 = nil /* ERROR "invalid constant type" */
- _n1 = [ /* ERROR "not constant" */ ]int{}
-) \ No newline at end of file
diff --git a/src/pkg/go/types/testdata/conversions.src b/src/pkg/go/types/testdata/conversions.src
deleted file mode 100644
index 1b1518366..000000000
--- a/src/pkg/go/types/testdata/conversions.src
+++ /dev/null
@@ -1,18 +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.
-
-// conversions
-
-package conversions
-
-// argument count
-var (
- _v0 = int /* ERROR "one argument" */ ()
- _v1 = int /* ERROR "one argument" */ (1, 2)
-)
-
-//
-var (
- _v2 = int8(0)
-) \ No newline at end of file
diff --git a/src/pkg/go/types/testdata/decls0.src b/src/pkg/go/types/testdata/decls0.src
deleted file mode 100644
index f0115bd9d..000000000
--- a/src/pkg/go/types/testdata/decls0.src
+++ /dev/null
@@ -1,187 +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.
-
-// type declarations
-
-package decls0
-
-import (
- "unsafe"
- // we can have multiple blank imports (was bug)
- _ "math"
- _ "net/rpc"
- // reflect defines a type "flag" which shows up in the gc export data
- "reflect"
- . "reflect"
-)
-
-// reflect.flag must not be visible in this package
-type flag int
-type _ reflect /* ERROR "cannot refer to unexported" */ .flag
-
-// dot-imported exported objects may conflict with local objects
-type Value /* ERROR "redeclared in this block by dot-import" */ struct{}
-
-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" */ }
-)
-
-
-// invalid array types
-type (
- iA0 [... /* ERROR "invalid use of '...'" */ ]byte
- iA1 [1 /* ERROR "invalid array length" */ <<100]int
- iA2 [- /* ERROR "invalid array length" */ 1]complex128
- iA3 ["foo" /* ERROR "invalid array length" */ ]string
-)
-
-
-type (
- p1 pi /* ERROR "no single 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 {
- U // anonymous field
- // TODO(gri) recognize double-declaration below
- // U /* 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 { /* ERROR "multiple methods named m1" */
- 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
- }
- // Use I09 (rather than I9) because it appears lexically before
- // I10 so that we get the illegal cycle here rather then in the
- // declaration of I10. If the implementation sorts by position
- // rather than name, the error message will still be here.
- I09 /* ERROR "illegal cycle" */ interface {
- I10
- }
- I10 interface {
- I11
- }
- I11 interface {
- I09
- }
-
- 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
-)
diff --git a/src/pkg/go/types/testdata/decls1.src b/src/pkg/go/types/testdata/decls1.src
deleted file mode 100644
index 2251f457f..000000000
--- a/src/pkg/go/types/testdata/decls1.src
+++ /dev/null
@@ -1,132 +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.
-
-// 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 "index" */]
- 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 assign" */ )
-
- t1 int = i + j
- t2 int = i /* ERROR "mismatched types" */ + x
- t3 int = c /* ERROR "cannot assign" */ + d
- t4 string = s + t
- t5 string = s /* ERROR "invalid operation" */ / t
- t6 byte = array[t1]
- t7 byte = array[x /* ERROR "index" */]
- t8 *int = & /* ERROR "cannot assign" */ 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 "unexported" */ .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" */ ()
-)
-
-// 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 /* ERROR "assignment count mismatch" */ , ok2, ok3 = iface.(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 /* ERROR "assignment count mismatch" */ , m2b, m2c = 1, 2
- m3a /* ERROR "assignment count mismatch" */ , m3b = 1, 2, 3
-)
-
-// 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 {}
-func f4() a /* ERROR "not a type" */ {}
-func f5() (a, b, c d /* ERROR "not a type" */) {}
-
-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 {}
-func (T) init(int) int { return 0 }
diff --git a/src/pkg/go/types/testdata/decls2a.src b/src/pkg/go/types/testdata/decls2a.src
deleted file mode 100644
index 3867be737..000000000
--- a/src/pkg/go/types/testdata/decls2a.src
+++ /dev/null
@@ -1,67 +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.
-
-// method declarations
-
-package decls2
-
-import "time"
-
-// T1 declared before its methods.
-type T1 struct{
- f int
-}
-
-func (T1) m() {}
-func (T1) m /* ERROR "redeclared" */ () {}
-func (x *T1) f /* ERROR "field and method" */ () {}
-
-// 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() {}
-
-// TODO(gri) try to get rid of double error reporting here
-func (pi /* ERROR "not a type" */) m1() {}
-func (x pi /* ERROR "not a type" */) m2() {}
-func (x *pi /* ERROR "not a type" */ ) m3() {} // TODO(gri) not closing the last /* comment crashes the system
-
-// Blank types.
-type _ struct { m int }
-type _ struct { m int }
-
-// TODO(gri) blank idents not fully checked - disabled for now
-// func (_ /* ERROR "cannot use _" */) m() {}
-// func (_ /* ERROR "cannot use _" */) m() {}
-
-// 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 non-local or unnamed types.
-func (int /* ERROR "non-local type" */ ) m() {}
-func ([ /* ERROR "expected" */ ]int) m() {}
-func (time /* ERROR "expected" */ .Time) m() {}
-func (x interface /* ERROR "expected" */ {}) m() {}
diff --git a/src/pkg/go/types/testdata/decls2b.src b/src/pkg/go/types/testdata/decls2b.src
deleted file mode 100644
index c7f9ddf01..000000000
--- a/src/pkg/go/types/testdata/decls2b.src
+++ /dev/null
@@ -1,28 +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.
-
-// method declarations
-
-package decls2
-
-const pi = 3.1415
-
-func (T1) m /* ERROR "redeclared" */ () {}
-
-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()
-} \ No newline at end of file
diff --git a/src/pkg/go/types/testdata/decls3.src b/src/pkg/go/types/testdata/decls3.src
deleted file mode 100644
index 6aa9f90e9..000000000
--- a/src/pkg/go/types/testdata/decls3.src
+++ /dev/null
@@ -1,253 +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.
-
-// embedded types
-
-package decls3
-
-// 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 "no single field or method" */ .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 "no single field or method" */ .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 "no single field or method" */ .X
-}
-
-// 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
-}
-
-// 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 single field or method" */ {}{}.Foo
- _ = S0{}.A
- _ = S0 /* ERROR "no single field or method" */ {}.D
- _ = S1{}.A
- _ = S1{}.B
- _ = S1{}.S0
- _ = S1{}.C
- _ = S2{}.A
- _ = S2{}.S1
- _ = S2{}.B
- _ = S2{}.C
- _ = S2 /* ERROR "no single field or method" */ {}.D
- _ = S3 /* ERROR "no single field or method" */ {}.S1
- _ = S3{}.A
- _ = S3 /* ERROR "no single field or method" */ {}.B
- _ = S3{}.D
- _ = S3{}.E
- _ = S4{}.A
- _ = S4 /* ERROR "no single field or method" */ {}.B
- _ = S5 /* ERROR "no single field or method" */ {}.X
- _ = S5{}.Y
- _ = S10 /* ERROR "no single field or method" */ {}.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 "no single field or method" */ {}.X \ No newline at end of file
diff --git a/src/pkg/go/types/testdata/exports.go b/src/pkg/go/types/testdata/exports.go
deleted file mode 100644
index 8ee28b094..000000000
--- a/src/pkg/go/types/testdata/exports.go
+++ /dev/null
@@ -1,89 +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.
-
-// This file is used to generate an object file which
-// serves as test file for gcimporter_test.go.
-
-package exports
-
-import (
- "go/ast"
-)
-
-// Issue 3682: Correctly read dotted identifiers from export data.
-const init1 = 0
-
-func init() {}
-
-const (
- C0 int = 0
- C1 = 3.14159265
- C2 = 2.718281828i
- C3 = -123.456e-789
- C4 = +123.456E+789
- C5 = 1234i
- C6 = "foo\n"
- C7 = `bar\n`
-)
-
-type (
- T1 int
- T2 [10]int
- T3 []int
- T4 *int
- T5 chan int
- T6a chan<- int
- T6b chan (<-chan int)
- T6c chan<- (chan int)
- T7 <-chan *ast.File
- T8 struct{}
- T9 struct {
- a int
- b, c float32
- d []string `go:"tag"`
- }
- T10 struct {
- T8
- T9
- _ *T10
- }
- T11 map[int]string
- T12 interface{}
- T13 interface {
- m1()
- m2(int) float32
- }
- T14 interface {
- T12
- T13
- m3(x ...struct{}) []T9
- }
- T15 func()
- T16 func(int)
- T17 func(x int)
- T18 func() float32
- T19 func() (x float32)
- T20 func(...interface{})
- T21 struct{ next *T21 }
- T22 struct{ link *T23 }
- T23 struct{ link *T22 }
- T24 *T24
- T25 *T26
- T26 *T27
- T27 *T25
- T28 func(T28) T28
-)
-
-var (
- V0 int
- V1 = -991.0
-)
-
-func F1() {}
-func F2(x int) {}
-func F3() int { return 0 }
-func F4() float32 { return 0 }
-func F5(a, b, c int, u, v, w struct{ x, y T1 }, more ...interface{}) (p, q, r chan<- T10)
-
-func (p *T1) M1()
diff --git a/src/pkg/go/types/testdata/expr0.src b/src/pkg/go/types/testdata/expr0.src
deleted file mode 100644
index 8d057f63c..000000000
--- a/src/pkg/go/types/testdata/expr0.src
+++ /dev/null
@@ -1,161 +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.
-
-// unary expressions
-
-package expr0
-
-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" */
-
- // 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 /* ERROR not defined */
- 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 /* ERROR not defined */
- 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 /* ERROR "cannot indirect" */
- s6 = &s4
- s7 = *s6
- s8 = <-s7 /* ERROR "cannot receive" */
-
- // 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" */
-)
-
-// 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
-)
-
diff --git a/src/pkg/go/types/testdata/expr1.src b/src/pkg/go/types/testdata/expr1.src
deleted file mode 100644
index 8ef0aed6d..000000000
--- a/src/pkg/go/types/testdata/expr1.src
+++ /dev/null
@@ -1,7 +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.
-
-// binary expressions
-
-package expr1
diff --git a/src/pkg/go/types/testdata/expr2.src b/src/pkg/go/types/testdata/expr2.src
deleted file mode 100644
index 674be4005..000000000
--- a/src/pkg/go/types/testdata/expr2.src
+++ /dev/null
@@ -1,23 +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.
-
-// 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
- _ = struct{b bool}{x < y}
-}
-
-// corner cases
-var (
- v0 = nil /* ERROR "cannot compare" */ == nil
-) \ No newline at end of file
diff --git a/src/pkg/go/types/testdata/expr3.src b/src/pkg/go/types/testdata/expr3.src
deleted file mode 100644
index ff17f2eee..000000000
--- a/src/pkg/go/types/testdata/expr3.src
+++ /dev/null
@@ -1,463 +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.
-
-// various expressions
-
-package expr3
-
-func shifts1() {
- var (
- i0 int
- u0 uint
- )
-
- var (
- v0 = 1<<0
- v1 = 1<<i0 /* ERROR "must be unsigned" */
- v2 = 1<<u0
- v3 = 1<<"foo" /* ERROR "must be unsigned" */
- v4 = 1<<- /* ERROR "stupid shift" */ 1
- v5 = 1<<1025 /* ERROR "stupid shift" */
- v6 = 1 /* ERROR "overflows" */ <<100
-
- v10 uint = 1 << 0
- v11 uint = 1 << u0
- v12 float32 = 1 /* ERROR "must be integer" */ << u0
- )
-}
-
-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 != 0 // 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
- 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
- )
-}
-
-func shifts3(a int16, b float32) {
- 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)
- // TODO(gri) add more tests (systematically)
-}
-
-func shifts4() {
- // from src/pkg/compress/lzw/reader.go:90
- {
- var d struct {
- bits uint32
- width uint
- }
- _ = uint16(d.bits & (1<<d.width - 1))
- }
-
- // from src/pkg/debug/dwarf/buf.go:116
- {
- var ux uint64
- var bits uint
- x := int64(ux)
- if x&(1<<(bits-1)) != 0 {}
- }
-
- // from src/pkg/encoding/asn1/asn1.go:160
- {
- var bytes []byte
- if bytes[len(bytes)-1]&((1<<bytes[0])-1) != 0 {}
- }
-
- // from src/pkg/math/big/rat.go:140
- {
- var exp int
- var mantissa uint64
- shift := uint64(-1022 - (exp - 1)) // [1..53)
- _ = mantissa & (1<<shift - 1)
- }
-
- // from src/pkg/net/interface.go:51
- {
- type Flags uint
- var f Flags
- var i int
- if f&(1<<uint(i)) != 0 {}
- }
-
- // from src/pkg/runtime/softfloat64.go:234
- {
- var gm uint64
- var shift uint
- _ = gm & (1<<shift - 1)
- }
-
- // from src/pkg/strconv/atof.go:326
- {
- var mant uint64
- var mantbits uint
- if mant == 2<<mantbits {}
- }
-
- // from src/pkg/syscall/route_bsd.go:82
- {
- var Addrs int32
- const rtaRtMask = 1
- var i uint
- if Addrs&rtaRtMask&(1<<i) == 0 {}
- }
-
- // from src/pkg/text/scanner/scanner.go:540
- {
- var s struct { Whitespace uint64 }
- var ch rune
- for s.Whitespace&(1<<uint(ch)) != 0 {}
- }
-}
-
-// TODO(gri) The error messages below depond on adjusting the spec
-// to reflect what gc is doing at the moment (the spec
-// asks for run-time errors at the moment - see issue 4231).
-//
-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 "must be integer" */ ]
- _ = a["foo" /* ERROR "must be integer" */ ]
- _ = a[1.1 /* ERROR "must be integer" */ ]
- _ = a[1.0]
- _ = a[- /* ERROR "index .* negative" */ 1]
- _ = a[- /* ERROR "index .* negative" */ 1 :]
- _ = a[: - /* ERROR "index .* negative" */ 1]
- var a0 int
- a0 = a[0]
- var a1 int32
- a1 = a /* ERROR "cannot assign" */ [1]
- _ = a[9]
- _ = a[10 /* ERROR "index .* out of bounds" */ ]
- _ = a[1 /* ERROR "stupid index" */ <<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 "stupid index" */ <<100]
-
- pa := &a
- _ = pa[9]
- _ = pa[10 /* ERROR "index .* out of bounds" */ ]
- _ = pa[1 /* ERROR "stupid index" */ <<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 "stupid index" */ <<100]
-
- var b [0]int
- _ = b[0 /* ERROR "index .* out of bounds" */ ]
- _ = b[:]
- _ = b[0:]
- _ = b[:0]
- _ = b[0:0]
-
- var s []int
- _ = s[- /* ERROR "index .* negative" */ 1]
- _ = s[- /* ERROR "index .* negative" */ 1 :]
- _ = s[: - /* ERROR "index .* negative" */ 1]
- _ = s[0]
- _ = s[1 : 2]
- _ = s[2 /* ERROR "inverted slice range" */ : 1]
- _ = s[2 :]
- _ = s[: 1 /* ERROR "stupid index" */ <<100]
- _ = s[1 /* ERROR "stupid index" */ <<100 :]
- _ = s[1 /* ERROR "stupid index" */ <<100 : 1 /* ERROR "stupid index" */ <<100]
-
- var t string
- _ = t[- /* ERROR "index .* negative" */ 1]
- _ = t[- /* ERROR "index .* negative" */ 1 :]
- _ = t[: - /* ERROR "index .* negative" */ 1]
- var t0 byte
- t0 = t[0]
- var t1 rune
- t1 = t /* ERROR "cannot assign" */ [2]
- _ = ("foo" + "bar")[5]
- _ = ("foo" + "bar")[6 /* ERROR "index .* out of bounds" */ ]
-
- const c = "foo"
- _ = c[- /* ERROR "index .* negative" */ 1]
- _ = c[- /* ERROR "index .* negative" */ 1 :]
- _ = c[: - /* ERROR "index .* negative" */ 1]
- var c0 byte
- c0 = c[0]
- var c2 float32
- c2 = c /* ERROR "cannot assign" */ [2]
- _ = c[3 /* ERROR "index .* out of bounds" */ ]
- _ = ""[0 /* ERROR "index .* out of bounds" */ ]
-
- _ = 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 assign" */ [1:2]
- ms = "foo" /* ERROR "cannot assign" */ [i:j]
-}
-
-type T struct {
- x int
-}
-
-func (*T) m() {}
-
-func method_expressions() {
- _ = T /* ERROR "no single field or method" */ .a
- _ = T /* ERROR "has no method" */ .x
- _ = T.m
- var f func(*T) = (*T).m
- var g func(*T) = ( /* ERROR "cannot assign" */ T).m
-}
-
-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 use" */ }
- _ = T1{c /* ERROR "unknown field" */ : 0}
- _ = T1{T0: { /* ERROR "missing type" */ }}
- _ = 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 use" */, 3.4 /* ERROR "cannot use" */}
-}
-
-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 "index .* 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 "stupid index" */ <<100: 4, 5 /* ERROR "duplicate index" */ }
- _ = A1{5: 5, 6, 7, 4: 4, 1 /* ERROR "stupid index" */ <<100: 4}
- _ = A1{2.0}
- _ = A1{2.1 /* ERROR "cannot use" */ }
- _ = A1{"foo" /* ERROR "cannot use" */ }
-
- 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 assign" */
-
- a2 := [...]int{- /* ERROR "index .* negative" */ 1: 0}
-
- 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)
-
- // 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 "index .* 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 "stupid index" */ <<100: 4, 5 /* ERROR "duplicate index" */ }
- _ = S0{5: 5, 6, 7, 4: 4, 1 /* ERROR "stupid index" */ <<100: 4}
- _ = S0{2.0}
- _ = S0{2.1 /* ERROR "cannot use" */ }
- _ = S0{"foo" /* ERROR "cannot use" */ }
-
- // indices must be resolved correctly
- // (for details, see comment in go/parser/parser.go, method parseElement)
- index1 := 1
- _ = S0{index1: 1}
- _ = S0{index2: 2}
- _ = S0{index3 /* ERROR "undeclared name" */ : 3}
-}
-
-var index2 int = 2
-
-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 use .* as string key" */ : 2}
- _ = M0{"foo": "bar" /* ERROR "cannot use .* as int value" */ }
- _ = M0{"foo": 1, "bar": 2, "foo" /* ERROR "duplicate key" */ : 3 }
-
- // map keys must be resolved correctly
- // (for details, see comment in go/parser/parser.go, method parseElement)
- key1 := "foo"
- _ = M0{key1: 1}
- _ = M0{key2: 2}
- _ = M0{key3 /* ERROR "undeclared name" */ : 2}
-
- _ = M1{true: 1, false: 0}
- _ = M2{nil: 0, &index2: 1}
-}
-
-var key2 string = "bar"
-
-type I interface {
- m()
-}
-
-type I2 interface {
- m(int)
-}
-
-type T1 struct{}
-type T2 struct{}
-
-func (T2) m(int) {}
-
-func type_asserts() {
- var x int
- _ = x /* ERROR "not an interface" */ .(int)
-
- var e interface{}
- var ok bool
- x, ok = e.(int)
-
- var t I
- _ = t /* ERROR "use of .* outside type switch" */ .(type)
- _ = t.(T)
- _ = t.(T1 /* ERROR "missing method m" */ )
- _ = t.(T2 /* ERROR "wrong type for method m" */ )
- _ = t.(I2 /* ERROR "wrong type for method m" */ )
-}
-
-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 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 assign" */ )
- 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 /* ERROR "too few arguments" */ (3.14)
- f2(3.14, "foo")
- f2(x /* ERROR "cannot assign" */ , "foo")
- f2(g0 /* ERROR "used as value" */ ())
- f2 /* ERROR "too few arguments" */ (g1 /* ERROR "cannot assign" */ ())
- f2(g2())
-
- fs /* ERROR "too few arguments" */ ()
- fs(g0 /* ERROR "used as value" */ ())
- fs(g1 /* ERROR "cannot assign" */ ())
- // fs(g2()) // TODO(gri) missing position in error message
- fs(gs())
-
- fv()
- fv(1, 2.0, x)
- fv(s /* ERROR "cannot assign" */ )
- fv(s...)
- fv(1, s /* ERROR "can only use ... with matching parameter" */ ...)
- fv(gs /* ERROR "cannot assign" */ ())
- fv(gs /* ERROR "cannot assign" */ ()...)
-
- fi()
- fi(1, 2.0, x, 3.14, "foo")
- fi(g2())
- fi(0, g2)
- fi(0, g2 /* ERROR "2-valued expression" */ ())
-}
diff --git a/src/pkg/go/types/testdata/stmt0.src b/src/pkg/go/types/testdata/stmt0.src
deleted file mode 100644
index 9d85de3bb..000000000
--- a/src/pkg/go/types/testdata/stmt0.src
+++ /dev/null
@@ -1,288 +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.
-
-// statements
-
-package stmt0
-
-func _() {
- b, i, f, c, s := false, 1, 1.0, 1i, "foo"
- b = i /* ERROR "cannot assign" */
- i = f /* ERROR "cannot assign" */
- f = c /* ERROR "cannot assign" */
- c = s /* ERROR "cannot assign" */
- s = b /* ERROR "cannot assign" */
-
- v0 /* ERROR "mismatch" */, v1, v2 := 1, 2, 3, 4
-
- b = true
-
- i += 1
- i += "foo" /* ERROR "cannot convert.*int" */
-
- f -= 1
- f -= "foo" /* ERROR "cannot convert.*float64" */
-
- c *= 1
- c /= 0 /* ERROR "division by zero" */
-
- s += "bar"
- s += 1 /* ERROR "cannot convert.*string" */
-
- var u64 uint64
- u64 += 1<<u64
-
- undeclared /* ERROR "undeclared" */ = 991
-}
-
-func incdecs() {
- const c = 3.14
- c /* ERROR "cannot assign" */ ++
- s := "foo"
- s /* ERROR "cannot convert" */ --
- 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
- x int
- )
- select {
- case <-ch:
- ch <- x
- case t, ok := <-ch:
- x = t
- case <-sc /* ERROR "cannot receive from send-only channel" */ :
- }
- select {
- default:
- default /* ERROR "multiple defaults" */ :
- }
-}
-
-func gos() {
- go 1 /* ERROR "expected function/method call" */
- go gos()
- var c chan int
- go close(c)
- go len(c) // TODO(gri) this should not be legal
-}
-
-func defers() {
- defer 1 /* ERROR "expected function/method call" */
- defer defers()
- var c chan int
- defer close(c)
- defer len(c) // TODO(gri) this should not be legal
-}
-
-func switches() {
- var x int
-
- switch x {
- default:
- default /* ERROR "multiple defaults" */ :
- }
-
- switch {
- case 1 /* ERROR "cannot convert" */ :
- }
-
- switch int32(x) {
- case 1, 2:
- case x /* ERROR "cannot compare" */ :
- }
-
- switch x {
- case 1 /* ERROR "overflows int" */ << 100:
- }
-
- switch x {
- case 1:
- case 1 /* ERROR "duplicate case" */ :
- case 2, 3, 4:
- case 1 /* ERROR "duplicate case" */ :
- }
-
- // TODO(gri) duplicate 64bit values that don't fit into an int64 are not yet detected
- switch uint64(x) {
- case 1<<64-1:
- case 1<<64-1:
- }
-}
-
-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 := x.(type) {}
-
- switch x := x.(type) {
- case int:
- var y int = x
- }
-
- switch x := i /* ERROR "not an interface" */ .(type) {}
-
- switch t := x.(type) {
- case nil:
- var v bool = t /* ERROR "cannot assign" */
- case int:
- var v int = t
- case float32, complex64:
- var v float32 = t /* ERROR "cannot assign" */
- default:
- var v float32 = t /* ERROR "cannot assign" */
- }
-
- var t I
- switch t.(type) {
- case T:
- case T1 /* ERROR "missing method m" */ :
- case T2 /* ERROR "wrong type for method m" */ :
- case I2 /* ERROR "wrong type for method m" */ :
- }
-}
-
-func typeswitch0() {
- switch y := interface{}(nil).(type) {
- case int:
- // TODO(gri) y has the wrong type here (type-checking
- // of captured variable is delayed)
- // func() int { return y + 0 }()
- }
-}
-
-func rangeloops() {
- 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 i := range x /* ERROR "cannot range over" */ {}
-
- for i := range a {
- var ii int
- ii = i
- }
- for i, x := range a {
- var ii int
- ii = i
- var xx float64
- xx = x /* ERROR "cannot assign" */
- }
- var ii int
- var xx float32
- for ii, xx := range a {}
-
- for i := range b {
- var ii int
- ii = i
- }
- for i, x := range b {
- var ii int
- ii = i
- var xx string
- xx = x
- }
-
- for i := range s {
- var ii int
- ii = i
- }
- for i, x := range s {
- var ii int
- ii = i
- var xx rune
- xx = x
- }
-
- for _, x := range p {
- var xx complex128
- xx = x
- }
-
- for _, x := range pp /* ERROR "cannot range over" */ {}
-
- for k := range m {
- var kk int32
- kk = k /* ERROR "cannot assign" */
- }
- for k, v := range m {
- var kk int
- kk = k
- if v {}
- }
-
- for _, _ /* ERROR "only one iteration variable" */ = range c {}
- for e := range c {
- var ee int
- ee = e
- }
- for _ = range sc /* ERROR "cannot range over send-only channel" */ {}
- for _ = range rc {}
-
- // constant strings
- const cs = "foo"
- for i, x := range cs {}
- for i, x := range "" {
- var ii int
- ii = i
- var xx rune
- xx = x
- }
-}
diff --git a/src/pkg/go/types/types.go b/src/pkg/go/types/types.go
deleted file mode 100644
index 2f2e579bd..000000000
--- a/src/pkg/go/types/types.go
+++ /dev/null
@@ -1,236 +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 types
-
-import "go/ast"
-
-// All types implement the Type interface.
-type Type interface {
- String() string
- aType()
-}
-
-// BasicKind describes the kind of basic type.
-type BasicKind int
-
-const (
- Invalid BasicKind = iota // type is invalid
-
- // predeclared types
- Bool
- Int
- Int8
- Int16
- Int32
- Int64
- Uint
- Uint8
- Uint16
- Uint32
- Uint64
- Uintptr
- Float32
- Float64
- Complex64
- Complex128
- String
- UnsafePointer
-
- // types for untyped values
- UntypedBool
- UntypedInt
- UntypedRune
- UntypedFloat
- UntypedComplex
- UntypedString
- UntypedNil
-
- // aliases
- Byte = Uint8
- Rune = Int32
-)
-
-// BasicInfo is a set of flags describing properties of a basic type.
-type BasicInfo int
-
-// Properties of basic types.
-const (
- IsBoolean BasicInfo = 1 << iota
- IsInteger
- IsUnsigned
- IsFloat
- IsComplex
- IsString
- IsUntyped
-
- IsOrdered = IsInteger | IsFloat | IsString
- IsNumeric = IsInteger | IsFloat | IsComplex
- IsConstType = IsBoolean | IsNumeric | IsString
-)
-
-// A Basic represents a basic type.
-type Basic struct {
- Kind BasicKind
- Info BasicInfo
- size int64 // use DefaultSizeof to get size
- Name string
-}
-
-// An Array represents an array type [Len]Elt.
-type Array struct {
- Len int64
- Elt Type
-}
-
-// A Slice represents a slice type []Elt.
-type Slice struct {
- Elt Type
-}
-
-// A QualifiedName is a name qualified with the package that declared the name.
-// Note: Pkg may be a fake package (no name, no scope) because the GC compiler's
-// export information doesn't provide full information in some cases.
-// TODO(gri): Should change Pkg to PkgPath since it's the only thing we care about.
-type QualifiedName struct {
- Pkg *Package // nil only for predeclared error.Error (exported)
- Name string // unqualified type name for anonymous fields
-}
-
-// IsSame reports whether p and q are the same.
-func (p QualifiedName) IsSame(q QualifiedName) bool {
- // spec:
- // "Two identifiers are different if they are spelled differently,
- // or if they appear in different packages and are not exported.
- // Otherwise, they are the same."
- if p.Name != q.Name {
- return false
- }
- // p.Name == q.Name
- return ast.IsExported(p.Name) || p.Pkg.Path == q.Pkg.Path
-}
-
-// A Field represents a field of a struct.
-type Field struct {
- QualifiedName
- Type Type
- Tag string
- IsAnonymous bool
-}
-
-// A Struct represents a struct type struct{...}.
-type Struct struct {
- Fields []*Field
- offsets []int64 // field offsets in bytes, lazily computed
-}
-
-func (typ *Struct) fieldIndex(name QualifiedName) int {
- for i, f := range typ.Fields {
- if f.QualifiedName.IsSame(name) {
- return i
- }
- }
- return -1
-}
-
-// A Pointer represents a pointer type *Base.
-type Pointer struct {
- Base Type
-}
-
-// A Result represents a (multi-value) function call result.
-type Result struct {
- Values []*Var // Signature.Results of the function called
-}
-
-// A Signature represents a user-defined function type func(...) (...).
-type Signature struct {
- Recv *Var // nil if not a method
- Params []*Var // (incoming) parameters from left to right; or nil
- Results []*Var // (outgoing) results from left to right; or nil
- IsVariadic bool // true if the last parameter's type is of the form ...T
-}
-
-// builtinId is an id of a builtin function.
-type builtinId int
-
-// Predeclared builtin functions.
-const (
- // Universe scope
- _Append builtinId = iota
- _Cap
- _Close
- _Complex
- _Copy
- _Delete
- _Imag
- _Len
- _Make
- _New
- _Panic
- _Print
- _Println
- _Real
- _Recover
-
- // Unsafe package
- _Alignof
- _Offsetof
- _Sizeof
-
- // Testing support
- _Assert
- _Trace
-)
-
-// A builtin represents the type of a built-in function.
-type builtin struct {
- id builtinId
- name string
- nargs int // number of arguments (minimum if variadic)
- isVariadic bool
- isStatement bool // true if the built-in is valid as an expression statement
-}
-
-// A Method represents a method.
-type Method struct {
- QualifiedName
- Type *Signature
-}
-
-// An Interface represents an interface type interface{...}.
-type Interface struct {
- Methods []*Method // TODO(gri) consider keeping them in sorted order
-}
-
-// A Map represents a map type map[Key]Elt.
-type Map struct {
- Key, Elt Type
-}
-
-// A Chan represents a channel type chan Elt, <-chan Elt, or chan<-Elt.
-type Chan struct {
- Dir ast.ChanDir
- Elt Type
-}
-
-// A NamedType represents a named type as declared in a type declaration.
-type NamedType struct {
- Obj *TypeName // corresponding declared object
- Underlying Type // nil if not fully declared yet; never a *NamedType
- Methods []*Method // TODO(gri) consider keeping them in sorted order
-}
-
-func (*Basic) aType() {}
-func (*Array) aType() {}
-func (*Slice) aType() {}
-func (*Struct) aType() {}
-func (*Pointer) aType() {}
-func (*Result) aType() {}
-func (*Signature) aType() {}
-func (*builtin) aType() {}
-func (*Interface) aType() {}
-func (*Map) aType() {}
-func (*Chan) aType() {}
-func (*NamedType) aType() {}
diff --git a/src/pkg/go/types/types_test.go b/src/pkg/go/types/types_test.go
deleted file mode 100644
index 8e228fa67..000000000
--- a/src/pkg/go/types/types_test.go
+++ /dev/null
@@ -1,171 +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.
-
-// This file contains tests verifying the types associated with an AST after
-// type checking.
-
-package types
-
-import (
- "go/ast"
- "go/parser"
- "testing"
-)
-
-const filename = "<src>"
-
-func makePkg(t *testing.T, src string) (*Package, error) {
- file, err := parser.ParseFile(fset, filename, src, parser.DeclarationErrors)
- if err != nil {
- return nil, err
- }
- pkg, err := Check(fset, []*ast.File{file})
- return pkg, err
-}
-
-type testEntry struct {
- src, str string
-}
-
-// dup returns a testEntry where both src and str are the same.
-func dup(s string) testEntry {
- return testEntry{s, s}
-}
-
-var testTypes = []testEntry{
- // basic types
- dup("int"),
- dup("float32"),
- dup("string"),
-
- // arrays
- dup("[10]int"),
-
- // slices
- dup("[]int"),
- dup("[][]int"),
-
- // structs
- dup("struct{}"),
- dup("struct{x int}"),
- {`struct {
- x, y int
- z float32 "foo"
- }`, `struct{x int; y int; z float32 "foo"}`},
- {`struct {
- string
- elems []T
- }`, `struct{string; elems []T}`},
-
- // pointers
- dup("*int"),
- dup("***struct{}"),
- dup("*struct{a int; b float32}"),
-
- // functions
- dup("func()"),
- dup("func(x int)"),
- {"func(x, y int)", "func(x int, y int)"},
- {"func(x, y int, z string)", "func(x int, y int, z string)"},
- dup("func(int)"),
- {"func(int, string, byte)", "func(int, string, byte)"},
-
- dup("func() int"),
- {"func() (string)", "func() string"},
- dup("func() (u int)"),
- {"func() (u, v int, w string)", "func() (u int, v int, w string)"},
-
- dup("func(int) string"),
- dup("func(x int) string"),
- dup("func(x int) (u string)"),
- {"func(x, y int) (u string)", "func(x int, y int) (u string)"},
-
- dup("func(...int) string"),
- dup("func(x ...int) string"),
- dup("func(x ...int) (u string)"),
- {"func(x, y ...int) (u string)", "func(x int, y ...int) (u string)"},
-
- // interfaces
- dup("interface{}"),
- dup("interface{m()}"),
- dup(`interface{m(int) float32; String() string}`),
- // TODO(gri) add test for interface w/ anonymous field
-
- // maps
- dup("map[string]int"),
- {"map[struct{x, y int}][]byte", "map[struct{x int; y int}][]byte"},
-
- // channels
- dup("chan int"),
- dup("chan<- func()"),
- dup("<-chan []func() int"),
-}
-
-func TestTypes(t *testing.T) {
- for _, test := range testTypes {
- src := "package p; type T " + test.src
- pkg, err := makePkg(t, src)
- if err != nil {
- t.Errorf("%s: %s", src, err)
- continue
- }
- typ := underlying(pkg.Scope.Lookup("T").GetType())
- str := typeString(typ)
- if str != test.str {
- t.Errorf("%s: got %s, want %s", test.src, str, test.str)
- }
- }
-}
-
-var testExprs = []testEntry{
- // basic type literals
- dup("x"),
- dup("true"),
- dup("42"),
- dup("3.1415"),
- dup("2.71828i"),
- dup(`'a'`),
- dup(`"foo"`),
- dup("`bar`"),
-
- // arbitrary expressions
- dup("&x"),
- dup("*&x"),
- dup("(x)"),
- dup("x + y"),
- dup("x + y * 10"),
- dup("t.foo"),
- dup("s[0]"),
- dup("s[x:y]"),
- dup("s[:y]"),
- dup("s[x:]"),
- dup("s[:]"),
- dup("f(1, 2.3)"),
- dup("-f(10, 20)"),
- dup("f(x + y, +3.1415)"),
- {"func(a, b int) {}", "(func literal)"},
- {"func(a, b int) []int {}(1, 2)[x]", "(func literal)(1, 2)[x]"},
- {"[]int{1, 2, 3}", "(composite literal)"},
- {"[]int{1, 2, 3}[x:]", "(composite literal)[x:]"},
- {"i.([]string)", "i.(...)"},
-}
-
-func TestExprs(t *testing.T) {
- for _, test := range testExprs {
- src := "package p; var _ = " + test.src + "; var (x, y int; s []string; f func(int, float32) int; i interface{}; t interface { foo() })"
- file, err := parser.ParseFile(fset, filename, src, parser.DeclarationErrors)
- if err != nil {
- t.Errorf("%s: %s", src, err)
- continue
- }
- // TODO(gri) writing the code below w/o the decl variable will
- // cause a 386 compiler error (out of fixed registers)
- decl := file.Decls[0].(*ast.GenDecl)
- expr := decl.Specs[0].(*ast.ValueSpec).Values[0]
- str := exprString(expr)
- if str != test.str {
- t.Errorf("%s: got %s, want %s", test.src, str, test.str)
- }
- }
-}
diff --git a/src/pkg/go/types/universe.go b/src/pkg/go/types/universe.go
deleted file mode 100644
index b218525c1..000000000
--- a/src/pkg/go/types/universe.go
+++ /dev/null
@@ -1,146 +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.
-
-// This file implements the universe and unsafe package scopes.
-
-package types
-
-import (
- "go/ast"
- "strings"
-)
-
-var (
- Universe *Scope
- Unsafe *Package
- universeIota *Const
-)
-
-// Predeclared types, indexed by BasicKind.
-var Typ = [...]*Basic{
- Invalid: {Invalid, 0, 0, "invalid type"},
-
- Bool: {Bool, IsBoolean, 1, "bool"},
- Int: {Int, IsInteger, 0, "int"},
- Int8: {Int8, IsInteger, 1, "int8"},
- Int16: {Int16, IsInteger, 2, "int16"},
- Int32: {Int32, IsInteger, 4, "int32"},
- Int64: {Int64, IsInteger, 8, "int64"},
- Uint: {Uint, IsInteger | IsUnsigned, 0, "uint"},
- Uint8: {Uint8, IsInteger | IsUnsigned, 1, "uint8"},
- Uint16: {Uint16, IsInteger | IsUnsigned, 2, "uint16"},
- Uint32: {Uint32, IsInteger | IsUnsigned, 4, "uint32"},
- Uint64: {Uint64, IsInteger | IsUnsigned, 8, "uint64"},
- Uintptr: {Uintptr, IsInteger | IsUnsigned, 0, "uintptr"},
- Float32: {Float32, IsFloat, 4, "float32"},
- Float64: {Float64, IsFloat, 8, "float64"},
- Complex64: {Complex64, IsComplex, 8, "complex64"},
- Complex128: {Complex128, IsComplex, 16, "complex128"},
- String: {String, IsString, 0, "string"},
- UnsafePointer: {UnsafePointer, 0, 0, "Pointer"},
-
- UntypedBool: {UntypedBool, IsBoolean | IsUntyped, 0, "untyped boolean"},
- UntypedInt: {UntypedInt, IsInteger | IsUntyped, 0, "untyped integer"},
- UntypedRune: {UntypedRune, IsInteger | IsUntyped, 0, "untyped rune"},
- UntypedFloat: {UntypedFloat, IsFloat | IsUntyped, 0, "untyped float"},
- UntypedComplex: {UntypedComplex, IsComplex | IsUntyped, 0, "untyped complex"},
- UntypedString: {UntypedString, IsString | IsUntyped, 0, "untyped string"},
- UntypedNil: {UntypedNil, IsUntyped, 0, "untyped nil"},
-}
-
-var aliases = [...]*Basic{
- {Byte, IsInteger | IsUnsigned, 1, "byte"},
- {Rune, IsInteger, 4, "rune"},
-}
-
-var predeclaredConstants = [...]*Const{
- {nil, "true", Typ[UntypedBool], true, nil},
- {nil, "false", Typ[UntypedBool], false, nil},
- {nil, "iota", Typ[UntypedInt], zeroConst, nil},
- {nil, "nil", Typ[UntypedNil], nilConst, nil},
-}
-
-var predeclaredFunctions = [...]*builtin{
- {_Append, "append", 1, true, false},
- {_Cap, "cap", 1, false, false},
- {_Close, "close", 1, false, true},
- {_Complex, "complex", 2, false, false},
- {_Copy, "copy", 2, false, true},
- {_Delete, "delete", 2, false, true},
- {_Imag, "imag", 1, false, false},
- {_Len, "len", 1, false, false},
- {_Make, "make", 1, true, false},
- {_New, "new", 1, false, false},
- {_Panic, "panic", 1, false, true},
- {_Print, "print", 0, true, true},
- {_Println, "println", 0, true, true},
- {_Real, "real", 1, false, false},
- {_Recover, "recover", 0, false, true},
-
- {_Alignof, "Alignof", 1, false, false},
- {_Offsetof, "Offsetof", 1, false, false},
- {_Sizeof, "Sizeof", 1, false, false},
-}
-
-func init() {
- Universe = new(Scope)
- Unsafe = &Package{Name: "unsafe", Scope: new(Scope)}
-
- // predeclared types
- for _, t := range Typ {
- def(&TypeName{Name: t.Name, Type: t})
- }
- for _, t := range aliases {
- def(&TypeName{Name: t.Name, Type: t})
- }
-
- // error type
- {
- // Error has a nil package in its qualified name since it is in no package
- err := &Method{QualifiedName{nil, "Error"}, &Signature{Results: []*Var{{Name: "", Type: Typ[String]}}}}
- def(&TypeName{Name: "error", Type: &NamedType{Underlying: &Interface{Methods: []*Method{err}}}})
- }
-
- for _, c := range predeclaredConstants {
- def(c)
- }
-
- for _, f := range predeclaredFunctions {
- def(&Func{Name: f.name, Type: f})
- }
-
- universeIota = Universe.Lookup("iota").(*Const)
-}
-
-// Objects with names containing blanks are internal and not entered into
-// a scope. Objects with exported names are inserted in the unsafe package
-// scope; other objects are inserted in the universe scope.
-//
-func def(obj Object) {
- name := obj.GetName()
- if strings.Index(name, " ") >= 0 {
- return // nothing to do
- }
- // fix Obj link for named types
- if typ, ok := obj.GetType().(*NamedType); ok {
- typ.Obj = obj.(*TypeName)
- }
- // exported identifiers go into package unsafe
- scope := Universe
- if ast.IsExported(name) {
- scope = Unsafe.Scope
- // set Pkg field
- switch obj := obj.(type) {
- case *TypeName:
- obj.Pkg = Unsafe
- case *Func:
- obj.Pkg = Unsafe
- default:
- unreachable()
- }
- }
- if scope.Insert(obj) != nil {
- panic("internal error: double declaration")
- }
-}
diff --git a/src/pkg/hash/crc32/crc32_amd64.s b/src/pkg/hash/crc32/crc32_amd64.s
index 6e6a364ee..826306a3e 100644
--- a/src/pkg/hash/crc32/crc32_amd64.s
+++ b/src/pkg/hash/crc32/crc32_amd64.s
@@ -6,7 +6,7 @@
TEXT ·castagnoliSSE42(SB),7,$0
MOVL crc+0(FP), AX // CRC value
MOVQ p+8(FP), SI // data pointer
- MOVQ p+16(FP), CX // len(p)
+ MOVQ p_len+16(FP), CX // len(p)
NOTL AX
@@ -47,7 +47,7 @@ cleanup:
done:
NOTL AX
- MOVL AX, r+32(FP)
+ MOVL AX, ret+32(FP)
RET
// func haveSSE42() bool
@@ -57,6 +57,6 @@ TEXT ·haveSSE42(SB),7,$0
CPUID
SHRQ $20, CX
ANDQ $1, CX
- MOVB CX, r+0(FP)
+ MOVB CX, ret+0(FP)
RET
diff --git a/src/pkg/html/template/template.go b/src/pkg/html/template/template.go
index 768cee7d5..e183898d5 100644
--- a/src/pkg/html/template/template.go
+++ b/src/pkg/html/template/template.go
@@ -45,18 +45,24 @@ func (t *Template) Templates() []*Template {
return m
}
-// Execute applies a parsed template to the specified data object,
-// writing the output to wr.
-func (t *Template) Execute(wr io.Writer, data interface{}) (err error) {
+// escape escapes all associated templates.
+func (t *Template) escape() error {
t.nameSpace.mu.Lock()
+ defer t.nameSpace.mu.Unlock()
if !t.escaped {
- if err = escapeTemplates(t, t.Name()); err != nil {
- t.escaped = true
+ if err := escapeTemplates(t, t.Name()); err != nil {
+ return err
}
+ t.escaped = true
}
- t.nameSpace.mu.Unlock()
- if err != nil {
- return
+ return nil
+}
+
+// Execute applies a parsed template to the specified data object,
+// writing the output to wr.
+func (t *Template) Execute(wr io.Writer, data interface{}) error {
+ if err := t.escape(); err != nil {
+ return err
}
return t.text.Execute(wr, data)
}
diff --git a/src/pkg/html/template/transition.go b/src/pkg/html/template/transition.go
index 96a4f6678..564eb2020 100644
--- a/src/pkg/html/template/transition.go
+++ b/src/pkg/html/template/transition.go
@@ -71,7 +71,6 @@ func tText(c context, s []byte) (context, int) {
}
k = j
}
- panic("unreachable")
}
var elementContentType = [...]state{
@@ -430,7 +429,6 @@ func tCSS(c context, s []byte) (context, int) {
}
k = i + 1
}
- panic("unreachable")
}
// tCSSStr is the context transition function for the CSS string and URL states.
@@ -471,7 +469,6 @@ func tCSSStr(c context, s []byte) (context, int) {
c, _ = tURL(c, decodeCSS(s[:i+1]))
k = i + 1
}
- panic("unreachable")
}
// tError is the context transition function for the error state.
diff --git a/src/pkg/image/gif/reader.go b/src/pkg/image/gif/reader.go
index 8b36948d6..8e8531f9b 100644
--- a/src/pkg/image/gif/reader.go
+++ b/src/pkg/image/gif/reader.go
@@ -17,6 +17,11 @@ import (
"io"
)
+var (
+ errNotEnough = errors.New("gif: not enough image data")
+ errTooMuch = errors.New("gif: too much image data")
+)
+
// If the io.Reader does not also have ReadByte, then decode will introduce its own buffering.
type reader interface {
io.Reader
@@ -89,29 +94,35 @@ type decoder struct {
// 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
-// block remaining (0, ()), but under normal execution blockReader
-// doesn't consume it, so it is handled in decode.
+// block remaining (0, ()), which is consumed when checking that the
+// blockReader is exhausted.
type blockReader struct {
r reader
slice []byte
+ err error
tmp [256]byte
}
func (b *blockReader) Read(p []byte) (int, error) {
+ if b.err != nil {
+ return 0, b.err
+ }
if len(p) == 0 {
return 0, nil
}
if len(b.slice) == 0 {
- blockLen, err := b.r.ReadByte()
- if err != nil {
- return 0, err
+ var blockLen uint8
+ blockLen, b.err = b.r.ReadByte()
+ if b.err != nil {
+ return 0, b.err
}
if blockLen == 0 {
- return 0, io.EOF
+ b.err = io.EOF
+ return 0, b.err
}
b.slice = b.tmp[0:blockLen]
- if _, err = io.ReadFull(b.r, b.slice); err != nil {
- return 0, err
+ if _, b.err = io.ReadFull(b.r, b.slice); b.err != nil {
+ return 0, b.err
}
}
n := copy(p, b.slice)
@@ -142,35 +153,33 @@ func (d *decoder) decode(r io.Reader, configOnly bool) error {
}
}
-Loop:
- for err == nil {
- var c byte
- c, err = d.r.ReadByte()
- if err == io.EOF {
- break
+ for {
+ c, err := d.r.ReadByte()
+ if err != nil {
+ return err
}
switch c {
case sExtension:
- err = d.readExtension()
+ if err = d.readExtension(); err != nil {
+ return err
+ }
case sImageDescriptor:
- var m *image.Paletted
- m, err = d.newImageFromDescriptor()
+ m, err := d.newImageFromDescriptor()
if err != nil {
- break
+ return err
}
if d.imageFields&fColorMapFollows != 0 {
m.Palette, err = d.readColorMap()
if err != nil {
- break
+ return err
}
// TODO: do we set transparency in this map too? That would be
// d.setTransparency(m.Palette)
} else {
m.Palette = d.globalColorMap
}
- var litWidth uint8
- litWidth, err = d.r.ReadByte()
+ litWidth, err := d.r.ReadByte()
if err != nil {
return err
}
@@ -178,18 +187,27 @@ Loop:
return fmt.Errorf("gif: pixel size in decode out of range: %d", litWidth)
}
// A wonderfully Go-like piece of magic.
- lzwr := lzw.NewReader(&blockReader{r: d.r}, lzw.LSB, int(litWidth))
+ br := &blockReader{r: d.r}
+ lzwr := lzw.NewReader(br, lzw.LSB, int(litWidth))
if _, err = io.ReadFull(lzwr, m.Pix); err != nil {
- break
+ if err != io.ErrUnexpectedEOF {
+ return err
+ }
+ return errNotEnough
}
-
- // There should be a "0" block remaining; drain that.
- c, err = d.r.ReadByte()
- if err != nil {
- return err
+ // Both lzwr and br should be exhausted. Reading from them
+ // should yield (0, io.EOF).
+ if n, err := lzwr.Read(d.tmp[:1]); n != 0 || err != io.EOF {
+ if err != nil {
+ return err
+ }
+ return errTooMuch
}
- if c != 0 {
- return errors.New("gif: extra data after image")
+ if n, err := br.Read(d.tmp[:1]); n != 0 || err != io.EOF {
+ if err != nil {
+ return err
+ }
+ return errTooMuch
}
// Undo the interlacing if necessary.
@@ -202,19 +220,15 @@ Loop:
d.delayTime = 0 // TODO: is this correct, or should we hold on to the value?
case sTrailer:
- break Loop
+ if len(d.image) == 0 {
+ return io.ErrUnexpectedEOF
+ }
+ return nil
default:
- err = fmt.Errorf("gif: unknown block type: 0x%.2x", c)
+ return fmt.Errorf("gif: unknown block type: 0x%.2x", c)
}
}
- if err != nil {
- return err
- }
- if len(d.image) == 0 {
- return io.ErrUnexpectedEOF
- }
- return nil
}
func (d *decoder) readHeaderAndScreenDescriptor() error {
@@ -304,7 +318,6 @@ func (d *decoder) readExtension() error {
return err
}
}
- panic("unreachable")
}
func (d *decoder) readGraphicControl() error {
@@ -335,7 +348,15 @@ func (d *decoder) newImageFromDescriptor() (*image.Paletted, error) {
width := int(d.tmp[4]) + int(d.tmp[5])<<8
height := int(d.tmp[6]) + int(d.tmp[7])<<8
d.imageFields = d.tmp[8]
- return image.NewPaletted(image.Rect(left, top, left+width, top+height), nil), nil
+
+ // The GIF89a spec, Section 20 (Image Descriptor) says:
+ // "Each image must fit within the boundaries of the Logical
+ // Screen, as defined in the Logical Screen Descriptor."
+ bounds := image.Rect(left, top, left+width, top+height)
+ if bounds != bounds.Intersect(image.Rect(0, 0, d.width, d.height)) {
+ return nil, errors.New("gif: frame bounds larger than image bounds")
+ }
+ return image.NewPaletted(bounds, nil), nil
}
func (d *decoder) readBlock() (int, error) {
diff --git a/src/pkg/image/gif/reader_test.go b/src/pkg/image/gif/reader_test.go
new file mode 100644
index 000000000..dcc6c6dd3
--- /dev/null
+++ b/src/pkg/image/gif/reader_test.go
@@ -0,0 +1,138 @@
+package gif
+
+import (
+ "bytes"
+ "compress/lzw"
+ "image"
+ "image/color"
+ "reflect"
+ "testing"
+)
+
+func TestDecode(t *testing.T) {
+ // header and trailer are parts of a valid 2x1 GIF image.
+ const (
+ header = "GIF89a" +
+ "\x02\x00\x01\x00" + // width=2, height=1
+ "\x80\x00\x00" + // headerFields=(a color map of 2 pixels), backgroundIndex, aspect
+ "\x10\x20\x30\x40\x50\x60" // the color map, also known as a palette
+ trailer = "\x3b"
+ )
+
+ // lzwEncode returns an LZW encoding (with 2-bit literals) of n zeroes.
+ lzwEncode := func(n int) []byte {
+ b := &bytes.Buffer{}
+ w := lzw.NewWriter(b, lzw.LSB, 2)
+ w.Write(make([]byte, n))
+ w.Close()
+ return b.Bytes()
+ }
+
+ testCases := []struct {
+ nPix int // The number of pixels in the image data.
+ extra bool // Whether to write an extra block after the LZW-encoded data.
+ wantErr error
+ }{
+ {0, false, errNotEnough},
+ {1, false, errNotEnough},
+ {2, false, nil},
+ {2, true, errTooMuch},
+ {3, false, errTooMuch},
+ }
+ for _, tc := range testCases {
+ b := &bytes.Buffer{}
+ b.WriteString(header)
+ // Write an image with bounds 2x1 but tc.nPix pixels. If tc.nPix != 2
+ // then this should result in an invalid GIF image. First, write a
+ // magic 0x2c (image descriptor) byte, bounds=(0,0)-(2,1), a flags
+ // 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)
+ if len(enc) > 0xff {
+ t.Errorf("nPix=%d, extra=%t: compressed length %d is too large", tc.nPix, tc.extra, len(enc))
+ continue
+ }
+ b.WriteByte(byte(len(enc)))
+ b.Write(enc)
+ }
+ if tc.extra {
+ b.WriteString("\x01\x02") // A 1-byte payload with an 0x02 byte.
+ }
+ b.WriteByte(0x00) // An empty block signifies the end of the image data.
+ b.WriteString(trailer)
+
+ got, err := Decode(b)
+ if err != tc.wantErr {
+ t.Errorf("nPix=%d, extra=%t\ngot %v\nwant %v", tc.nPix, tc.extra, err, tc.wantErr)
+ }
+
+ if tc.wantErr != nil {
+ continue
+ }
+ want := &image.Paletted{
+ Pix: []uint8{0, 0},
+ Stride: 2,
+ Rect: image.Rect(0, 0, 2, 1),
+ Palette: color.Palette{
+ color.RGBA{0x10, 0x20, 0x30, 0xff},
+ color.RGBA{0x40, 0x50, 0x60, 0xff},
+ },
+ }
+ if !reflect.DeepEqual(got, want) {
+ t.Errorf("nPix=%d, extra=%t\ngot %v\nwant %v", tc.nPix, tc.extra, got, want)
+ }
+ }
+}
+
+// testGIF is a simple GIF that we can modify to test different scenarios.
+var testGIF = []byte{
+ 'G', 'I', 'F', '8', '9', 'a',
+ 1, 0, 1, 0, // w=1, h=1 (6)
+ 128, 0, 0, // headerFields, bg, aspect (10)
+ 0, 0, 0, 1, 1, 1, // color map and graphics control (13)
+ 0x21, 0xf9, 0x04, 0x00, 0x00, 0x00, 0xff, 0x00, // (19)
+ // frame 1 (0,0 - 1,1)
+ 0x2c,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x01, 0x00, 0x01, 0x00, // (32)
+ 0x00,
+ 0x02, 0x02, 0x4c, 0x01, 0x00, // lzw pixels
+ // trailer
+ 0x3b,
+}
+
+func try(t *testing.T, b []byte, want string) {
+ _, err := DecodeAll(bytes.NewReader(b))
+ var got string
+ if err != nil {
+ got = err.Error()
+ }
+ if got != want {
+ t.Fatalf("got %v, want %v", got, want)
+ }
+}
+
+func TestBounds(t *testing.T) {
+ // make a local copy of testGIF
+ gif := make([]byte, len(testGIF))
+ copy(gif, testGIF)
+ // Make the bounds too big, just by one.
+ gif[32] = 2
+ want := "gif: frame bounds larger than image bounds"
+ try(t, gif, want)
+
+ // Make the bounds too small; does not trigger bounds
+ // check, but now there's too much data.
+ gif[32] = 0
+ want = "gif: too much image data"
+ try(t, gif, want)
+ gif[32] = 1
+
+ // Make the bounds really big, expect an error.
+ want = "gif: frame bounds larger than image bounds"
+ for i := 0; i < 4; i++ {
+ gif[32+i] = 0xff
+ }
+ try(t, gif, want)
+}
diff --git a/src/pkg/image/jpeg/reader.go b/src/pkg/image/jpeg/reader.go
index 1ee6bbcd1..862d8dc1b 100644
--- a/src/pkg/image/jpeg/reader.go
+++ b/src/pkg/image/jpeg/reader.go
@@ -245,10 +245,38 @@ func (d *decoder) decode(r io.Reader, configOnly bool) (image.Image, error) {
if err != nil {
return nil, err
}
- if d.tmp[0] != 0xff {
- return nil, FormatError("missing 0xff marker start")
+ for d.tmp[0] != 0xff {
+ // Strictly speaking, this is a format error. However, libjpeg is
+ // liberal in what it accepts. As of version 9, next_marker in
+ // jdmarker.c treats this as a warning (JWRN_EXTRANEOUS_DATA) and
+ // continues to decode the stream. Even before next_marker sees
+ // extraneous data, jpeg_fill_bit_buffer in jdhuff.c reads as many
+ // bytes as it can, possibly past the end of a scan's data. It
+ // effectively puts back any markers that it overscanned (e.g. an
+ // "\xff\xd9" EOI marker), but it does not put back non-marker data,
+ // and thus it can silently ignore a small number of extraneous
+ // non-marker bytes before next_marker has a chance to see them (and
+ // print a warning).
+ //
+ // We are therefore also liberal in what we accept. Extraneous data
+ // is silently ignored.
+ //
+ // This is similar to, but not exactly the same as, the restart
+ // mechanism within a scan (the RST[0-7] markers).
+ //
+ // Note that extraneous 0xff bytes in e.g. SOS data are escaped as
+ // "\xff\x00", and so are detected a little further down below.
+ d.tmp[0] = d.tmp[1]
+ d.tmp[1], err = d.r.ReadByte()
+ if err != nil {
+ return nil, err
+ }
}
marker := d.tmp[1]
+ if marker == 0 {
+ // Treat "\xff\x00" as extraneous data.
+ continue
+ }
for marker == 0xff {
// Section B.1.1.2 says, "Any marker may optionally be preceded by any
// number of fill bytes, which are bytes assigned code X'FF'".
diff --git a/src/pkg/image/jpeg/reader_test.go b/src/pkg/image/jpeg/reader_test.go
index b520a8ab1..e951e038c 100644
--- a/src/pkg/image/jpeg/reader_test.go
+++ b/src/pkg/image/jpeg/reader_test.go
@@ -8,8 +8,11 @@ import (
"bytes"
"fmt"
"image"
+ "image/color"
"io/ioutil"
+ "math/rand"
"os"
+ "strings"
"testing"
)
@@ -131,6 +134,66 @@ func pixString(pix []byte, stride, x, y int) string {
return s.String()
}
+func TestExtraneousData(t *testing.T) {
+ // Encode a 1x1 red image.
+ src := image.NewRGBA(image.Rect(0, 0, 1, 1))
+ src.Set(0, 0, color.RGBA{0xff, 0x00, 0x00, 0xff})
+ buf := new(bytes.Buffer)
+ if err := Encode(buf, src, nil); err != nil {
+ t.Fatalf("encode: %v", err)
+ }
+ enc := buf.String()
+ // Sanity check that the encoded JPEG is long enough, that it ends in a
+ // "\xff\xd9" EOI marker, and that it contains a "\xff\xda" SOS marker
+ // somewhere in the final 64 bytes.
+ if len(enc) < 64 {
+ t.Fatalf("encoded JPEG is too short: %d bytes", len(enc))
+ }
+ if got, want := enc[len(enc)-2:], "\xff\xd9"; got != want {
+ t.Fatalf("encoded JPEG ends with %q, want %q", got, want)
+ }
+ if s := enc[len(enc)-64:]; !strings.Contains(s, "\xff\xda") {
+ t.Fatalf("encoded JPEG does not contain a SOS marker (ff da) near the end: % x", s)
+ }
+ // Test that adding some random junk between the SOS marker and the
+ // EOI marker does not affect the decoding.
+ rnd := rand.New(rand.NewSource(1))
+ for i, nerr := 0, 0; i < 1000 && nerr < 10; i++ {
+ buf.Reset()
+ // Write all but the trailing "\xff\xd9" EOI marker.
+ buf.WriteString(enc[:len(enc)-2])
+ // Write some random extraneous data.
+ for n := rnd.Intn(10); n > 0; n-- {
+ if x := byte(rnd.Intn(256)); x != 0xff {
+ buf.WriteByte(x)
+ } else {
+ // The JPEG format escapes a SOS 0xff data byte as "\xff\x00".
+ buf.WriteString("\xff\x00")
+ }
+ }
+ // Write the "\xff\xd9" EOI marker.
+ buf.WriteString("\xff\xd9")
+
+ // Check that we can still decode the resultant image.
+ got, err := Decode(buf)
+ if err != nil {
+ t.Errorf("could not decode image #%d: %v", i, err)
+ nerr++
+ continue
+ }
+ if got.Bounds() != src.Bounds() {
+ t.Errorf("image #%d, bounds differ: %v and %v", i, got.Bounds(), src.Bounds())
+ nerr++
+ continue
+ }
+ if averageDelta(got, src) > 2<<8 {
+ t.Errorf("image #%d changed too much after a round trip", i)
+ nerr++
+ continue
+ }
+ }
+}
+
func benchmarkDecode(b *testing.B, filename string) {
b.StopTimer()
data, err := ioutil.ReadFile(filename)
diff --git a/src/pkg/image/jpeg/scan.go b/src/pkg/image/jpeg/scan.go
index e3ae8ae44..a69ed1748 100644
--- a/src/pkg/image/jpeg/scan.go
+++ b/src/pkg/image/jpeg/scan.go
@@ -109,9 +109,11 @@ func (d *decoder) processSOS(n int) error {
myy := (d.height + 8*v0 - 1) / (8 * v0)
if d.img1 == nil && d.img3 == nil {
d.makeImg(h0, v0, mxx, myy)
- if d.progressive {
- for i := 0; i < nComp; i++ {
- compIndex := scan[i].compIndex
+ }
+ if d.progressive {
+ for i := 0; i < nComp; i++ {
+ compIndex := scan[i].compIndex
+ if d.progCoeffs[compIndex] == nil {
d.progCoeffs[compIndex] = make([]block, mxx*myy*d.comp[compIndex].h*d.comp[compIndex].v)
}
}
diff --git a/src/pkg/image/jpeg/writer_test.go b/src/pkg/image/jpeg/writer_test.go
index 0b2143f5b..514b455dc 100644
--- a/src/pkg/image/jpeg/writer_test.go
+++ b/src/pkg/image/jpeg/writer_test.go
@@ -148,29 +148,38 @@ func TestWriter(t *testing.T) {
t.Error(tc.filename, err)
continue
}
- // Compute the average delta in RGB space.
- b := m0.Bounds()
- var sum, n int64
- for y := b.Min.Y; y < b.Max.Y; y++ {
- for x := b.Min.X; x < b.Max.X; x++ {
- c0 := m0.At(x, y)
- c1 := m1.At(x, y)
- r0, g0, b0, _ := c0.RGBA()
- r1, g1, b1, _ := c1.RGBA()
- sum += delta(r0, r1)
- sum += delta(g0, g1)
- sum += delta(b0, b1)
- n += 3
- }
+ if m0.Bounds() != m1.Bounds() {
+ t.Errorf("%s, bounds differ: %v and %v", tc.filename, m0.Bounds(), m1.Bounds())
+ continue
}
// Compare the average delta to the tolerance level.
- if sum/n > tc.tolerance {
+ if averageDelta(m0, m1) > tc.tolerance {
t.Errorf("%s, quality=%d: average delta is too high", tc.filename, tc.quality)
continue
}
}
}
+// averageDelta returns the average delta in RGB space. The two images must
+// have the same bounds.
+func averageDelta(m0, m1 image.Image) int64 {
+ b := m0.Bounds()
+ var sum, n int64
+ for y := b.Min.Y; y < b.Max.Y; y++ {
+ for x := b.Min.X; x < b.Max.X; x++ {
+ c0 := m0.At(x, y)
+ c1 := m1.At(x, y)
+ r0, g0, b0, _ := c0.RGBA()
+ r1, g1, b1, _ := c1.RGBA()
+ sum += delta(r0, r1)
+ sum += delta(g0, g1)
+ sum += delta(b0, b1)
+ n += 3
+ }
+ }
+ return sum / n
+}
+
func BenchmarkEncode(b *testing.B) {
b.StopTimer()
img := image.NewRGBA(image.Rect(0, 0, 640, 480))
diff --git a/src/pkg/image/png/writer.go b/src/pkg/image/png/writer.go
index 093d47193..629452cbf 100644
--- a/src/pkg/image/png/writer.go
+++ b/src/pkg/image/png/writer.go
@@ -436,7 +436,7 @@ func Encode(w io.Writer, m image.Image) error {
// also rejected.
mw, mh := int64(m.Bounds().Dx()), int64(m.Bounds().Dy())
if mw <= 0 || mh <= 0 || mw >= 1<<32 || mh >= 1<<32 {
- return FormatError("invalid image size: " + strconv.FormatInt(mw, 10) + "x" + strconv.FormatInt(mw, 10))
+ return FormatError("invalid image size: " + strconv.FormatInt(mw, 10) + "x" + strconv.FormatInt(mh, 10))
}
var e encoder
diff --git a/src/pkg/io/io.go b/src/pkg/io/io.go
index 23d05e575..ec2cd6056 100644
--- a/src/pkg/io/io.go
+++ b/src/pkg/io/io.go
@@ -34,6 +34,11 @@ var EOF = errors.New("EOF")
// middle of reading a fixed-size block or data structure.
var ErrUnexpectedEOF = errors.New("unexpected EOF")
+// ErrNoProgress is returned by some clients of an io.Reader when
+// many calls to Read have failed to return any data or error,
+// usually the sign of a broken io.Reader implementation.
+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
@@ -55,6 +60,10 @@ var ErrUnexpectedEOF = errors.New("unexpected EOF")
// 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.
+//
+// Implementations of Read are discouraged from returning a
+// zero byte count with a nil error, and callers should treat
+// that situation as a no-op.
type Reader interface {
Read(p []byte) (n int, err error)
}
@@ -70,6 +79,9 @@ type Writer interface {
}
// Closer is the interface that wraps the basic Close method.
+//
+// The behavior of Close after the first call is undefined.
+// Specific implementations may document their own behavior.
type Closer interface {
Close() error
}
diff --git a/src/pkg/io/ioutil/ioutil.go b/src/pkg/io/ioutil/ioutil.go
index 0eb146c0a..6b395c69b 100644
--- a/src/pkg/io/ioutil/ioutil.go
+++ b/src/pkg/io/ioutil/ioutil.go
@@ -144,7 +144,6 @@ func (devNull) ReadFrom(r io.Reader) (n int64, err error) {
return
}
}
- panic("unreachable")
}
// Discard is an io.Writer on which all Write calls succeed
diff --git a/src/pkg/math/abs_386.s b/src/pkg/math/abs_386.s
index 889e80181..574676475 100644
--- a/src/pkg/math/abs_386.s
+++ b/src/pkg/math/abs_386.s
@@ -6,5 +6,5 @@
TEXT ·Abs(SB),7,$0
FMOVD x+0(FP), F0 // F0=x
FABS // F0=|x|
- FMOVDP F0, r+8(FP)
+ FMOVDP F0, ret+8(FP)
RET
diff --git a/src/pkg/math/abs_amd64.s b/src/pkg/math/abs_amd64.s
index 32b78539a..119346045 100644
--- a/src/pkg/math/abs_amd64.s
+++ b/src/pkg/math/abs_amd64.s
@@ -8,5 +8,5 @@ TEXT ·Abs(SB),7,$0
MOVQ BX, X0 // movsd $(-0.0), x0
MOVSD x+0(FP), X1
ANDNPD X1, X0
- MOVSD X0, r+8(FP)
+ MOVSD X0, ret+8(FP)
RET
diff --git a/src/pkg/math/abs_arm.s b/src/pkg/math/abs_arm.s
index 37a1459fe..929e1ce67 100644
--- a/src/pkg/math/abs_arm.s
+++ b/src/pkg/math/abs_arm.s
@@ -3,9 +3,9 @@
// license that can be found in the LICENSE file.
TEXT ·Abs(SB),7,$0
- MOVW x+0(FP), R0
- MOVW x+4(FP), R1
+ MOVW x_lo+0(FP), R0
+ MOVW x_hi+4(FP), R1
AND $((1<<31)-1), R1
- MOVW R0, r+8(FP)
- MOVW R1, r+12(FP)
+ MOVW R0, ret_lo+8(FP)
+ MOVW R1, ret_hi+12(FP)
RET
diff --git a/src/pkg/math/asin_386.s b/src/pkg/math/asin_386.s
index 93df552dc..cd3f9cd9b 100644
--- a/src/pkg/math/asin_386.s
+++ b/src/pkg/math/asin_386.s
@@ -11,7 +11,7 @@ TEXT ·Asin(SB),7,$0
FSUBRDP F0, F1 // F0=1-sin(x)*sin(x) (=cos(x)*cos(x)), F1=sin(x)
FSQRT // F0=cos(x), F1=sin(x)
FPATAN // F0=arcsin(sin(x))=x
- FMOVDP F0, r+8(FP)
+ FMOVDP F0, ret+8(FP)
RET
// func Acos(x float64) float64
@@ -24,5 +24,5 @@ TEXT ·Acos(SB),7,$0
FSQRT // F0=sin(x), F1=cos(x)
FXCHD F0, F1 // F0=cos(x), F1=sin(x)
FPATAN // F0=arccos(cos(x))=x
- FMOVDP F0, r+8(FP)
+ FMOVDP F0, ret+8(FP)
RET
diff --git a/src/pkg/math/atan2_386.s b/src/pkg/math/atan2_386.s
index 9a664926a..1bf301c4c 100644
--- a/src/pkg/math/atan2_386.s
+++ b/src/pkg/math/atan2_386.s
@@ -7,5 +7,5 @@ TEXT ·Atan2(SB),7,$0
FMOVD y+0(FP), F0 // F0=y
FMOVD x+8(FP), F0 // F0=x, F1=y
FPATAN // F0=atan(F1/F0)
- FMOVDP F0, r+16(FP)
+ FMOVDP F0, ret+16(FP)
RET
diff --git a/src/pkg/math/atan_386.s b/src/pkg/math/atan_386.s
index 245437a78..c988705be 100644
--- a/src/pkg/math/atan_386.s
+++ b/src/pkg/math/atan_386.s
@@ -7,5 +7,5 @@ TEXT ·Atan(SB),7,$0
FMOVD x+0(FP), F0 // F0=x
FLD1 // F0=1, F1=x
FPATAN // F0=atan(F1/F0)
- FMOVDP F0, r+8(FP)
+ FMOVDP F0, ret+8(FP)
RET
diff --git a/src/pkg/math/big/arith_386.s b/src/pkg/math/big/arith_386.s
index c62483317..f0118ec0d 100644
--- a/src/pkg/math/big/arith_386.s
+++ b/src/pkg/math/big/arith_386.s
@@ -29,7 +29,7 @@ TEXT ·addVV(SB),7,$0
MOVL z+0(FP), DI
MOVL x+12(FP), SI
MOVL y+24(FP), CX
- MOVL z+4(FP), BP
+ MOVL z_len+4(FP), BP
MOVL $0, BX // i = 0
MOVL $0, DX // c = 0
JMP E1
@@ -54,7 +54,7 @@ TEXT ·subVV(SB),7,$0
MOVL z+0(FP), DI
MOVL x+12(FP), SI
MOVL y+24(FP), CX
- MOVL z+4(FP), BP
+ MOVL z_len+4(FP), BP
MOVL $0, BX // i = 0
MOVL $0, DX // c = 0
JMP E2
@@ -78,7 +78,7 @@ TEXT ·addVW(SB),7,$0
MOVL z+0(FP), DI
MOVL x+12(FP), SI
MOVL y+24(FP), AX // c = y
- MOVL z+4(FP), BP
+ MOVL z_len+4(FP), BP
MOVL $0, BX // i = 0
JMP E3
@@ -100,7 +100,7 @@ TEXT ·subVW(SB),7,$0
MOVL z+0(FP), DI
MOVL x+12(FP), SI
MOVL y+24(FP), AX // c = y
- MOVL z+4(FP), BP
+ MOVL z_len+4(FP), BP
MOVL $0, BX // i = 0
JMP E4
@@ -120,7 +120,7 @@ E4: CMPL BX, BP // i < n
// func shlVU(z, x []Word, s uint) (c Word)
TEXT ·shlVU(SB),7,$0
- MOVL z+4(FP), BX // i = z
+ MOVL z_len+4(FP), BX // i = z
SUBL $1, BX // i--
JL X8b // i < 0 (n <= 0)
@@ -155,7 +155,7 @@ X8b: MOVL $0, c+28(FP)
// func shrVU(z, x []Word, s uint) (c Word)
TEXT ·shrVU(SB),7,$0
- MOVL z+4(FP), BP
+ MOVL z_len+4(FP), BP
SUBL $1, BP // n--
JL X9b // n < 0 (n <= 0)
@@ -196,7 +196,7 @@ TEXT ·mulAddVWW(SB),7,$0
MOVL x+12(FP), SI
MOVL y+24(FP), BP
MOVL r+28(FP), CX // c = r
- MOVL z+4(FP), BX
+ MOVL z_len+4(FP), BX
LEAL (DI)(BX*4), DI
LEAL (SI)(BX*4), SI
NEGL BX // i = -n
@@ -222,7 +222,7 @@ TEXT ·addMulVVW(SB),7,$0
MOVL z+0(FP), DI
MOVL x+12(FP), SI
MOVL y+24(FP), BP
- MOVL z+4(FP), BX
+ MOVL z_len+4(FP), BX
LEAL (DI)(BX*4), DI
LEAL (SI)(BX*4), SI
NEGL BX // i = -n
@@ -251,7 +251,7 @@ TEXT ·divWVW(SB),7,$0
MOVL xn+12(FP), DX // r = xn
MOVL x+16(FP), SI
MOVL y+28(FP), CX
- MOVL z+4(FP), BX // i = z
+ MOVL z_len+4(FP), BX // i = z
JMP E7
L7: MOVL (SI)(BX*4), AX
diff --git a/src/pkg/math/big/arith_amd64.s b/src/pkg/math/big/arith_amd64.s
index d85964502..62da65030 100644
--- a/src/pkg/math/big/arith_amd64.s
+++ b/src/pkg/math/big/arith_amd64.s
@@ -36,7 +36,7 @@ TEXT ·divWW(SB),7,$0
// func addVV(z, x, y []Word) (c Word)
TEXT ·addVV(SB),7,$0
- MOVQ z+8(FP), DI
+ MOVQ z_len+8(FP), DI
MOVQ x+24(FP), R8
MOVQ y+48(FP), R9
MOVQ z+0(FP), R10
@@ -90,7 +90,7 @@ E1: MOVQ CX, c+72(FP) // return c
// func subVV(z, x, y []Word) (c Word)
// (same as addVV except for SBBQ instead of ADCQ and label names)
TEXT ·subVV(SB),7,$0
- MOVQ z+8(FP), DI
+ MOVQ z_len+8(FP), DI
MOVQ x+24(FP), R8
MOVQ y+48(FP), R9
MOVQ z+0(FP), R10
@@ -143,7 +143,7 @@ E2: MOVQ CX, c+72(FP) // return c
// func addVW(z, x []Word, y Word) (c Word)
TEXT ·addVW(SB),7,$0
- MOVQ z+8(FP), DI
+ MOVQ z_len+8(FP), DI
MOVQ x+24(FP), R8
MOVQ y+48(FP), CX // c = y
MOVQ z+0(FP), R10
@@ -195,7 +195,7 @@ E3: MOVQ CX, c+56(FP) // return c
// func subVW(z, x []Word, y Word) (c Word)
// (same as addVW except for SUBQ/SBBQ instead of ADDQ/ADCQ and label names)
TEXT ·subVW(SB),7,$0
- MOVQ z+8(FP), DI
+ MOVQ z_len+8(FP), DI
MOVQ x+24(FP), R8
MOVQ y+48(FP), CX // c = y
MOVQ z+0(FP), R10
@@ -247,7 +247,7 @@ E4: MOVQ CX, c+56(FP) // return c
// func shlVU(z, x []Word, s uint) (c Word)
TEXT ·shlVU(SB),7,$0
- MOVQ z+8(FP), BX // i = z
+ MOVQ z_len+8(FP), BX // i = z
SUBQ $1, BX // i--
JL X8b // i < 0 (n <= 0)
@@ -282,7 +282,7 @@ X8b: MOVQ $0, c+56(FP)
// func shrVU(z, x []Word, s uint) (c Word)
TEXT ·shrVU(SB),7,$0
- MOVQ z+8(FP), R11
+ MOVQ z_len+8(FP), R11
SUBQ $1, R11 // n--
JL X9b // n < 0 (n <= 0)
@@ -323,7 +323,7 @@ TEXT ·mulAddVWW(SB),7,$0
MOVQ x+24(FP), R8
MOVQ y+48(FP), R9
MOVQ r+56(FP), CX // c = r
- MOVQ z+8(FP), R11
+ MOVQ z_len+8(FP), R11
MOVQ $0, BX // i = 0
JMP E5
@@ -347,7 +347,7 @@ TEXT ·addMulVVW(SB),7,$0
MOVQ z+0(FP), R10
MOVQ x+24(FP), R8
MOVQ y+48(FP), R9
- MOVQ z+8(FP), R11
+ MOVQ z_len+8(FP), R11
MOVQ $0, BX // i = 0
MOVQ $0, CX // c = 0
JMP E6
@@ -374,7 +374,7 @@ TEXT ·divWVW(SB),7,$0
MOVQ xn+24(FP), DX // r = xn
MOVQ x+32(FP), R8
MOVQ y+56(FP), R9
- MOVQ z+8(FP), BX // i = z
+ MOVQ z_len+8(FP), BX // i = z
JMP E7
L7: MOVQ (R8)(BX*8), AX
diff --git a/src/pkg/math/big/arith_arm.s b/src/pkg/math/big/arith_arm.s
index 64610f915..6e2d23d33 100644
--- a/src/pkg/math/big/arith_arm.s
+++ b/src/pkg/math/big/arith_arm.s
@@ -13,7 +13,7 @@ TEXT ·addVV(SB),7,$0
MOVW z+0(FP), R1
MOVW x+12(FP), R2
MOVW y+24(FP), R3
- MOVW z+4(FP), R4
+ MOVW z_len+4(FP), R4
MOVW R4<<2, R4
ADD R1, R4
B E1
@@ -41,7 +41,7 @@ TEXT ·subVV(SB),7,$0
MOVW z+0(FP), R1
MOVW x+12(FP), R2
MOVW y+24(FP), R3
- MOVW z+4(FP), R4
+ MOVW z_len+4(FP), R4
MOVW R4<<2, R4
ADD R1, R4
B E2
@@ -68,7 +68,7 @@ TEXT ·addVW(SB),7,$0
MOVW z+0(FP), R1
MOVW x+12(FP), R2
MOVW y+24(FP), R3
- MOVW z+4(FP), R4
+ MOVW z_len+4(FP), R4
MOVW R4<<2, R4
ADD R1, R4
CMP R1, R4
@@ -102,7 +102,7 @@ TEXT ·subVW(SB),7,$0
MOVW z+0(FP), R1
MOVW x+12(FP), R2
MOVW y+24(FP), R3
- MOVW z+4(FP), R4
+ MOVW z_len+4(FP), R4
MOVW R4<<2, R4
ADD R1, R4
CMP R1, R4
@@ -134,7 +134,7 @@ E4:
// func shlVU(z, x []Word, s uint) (c Word)
TEXT ·shlVU(SB),7,$0
- MOVW z+4(FP), R5
+ MOVW z_len+4(FP), R5
CMP $0, R5
BEQ X7
@@ -183,7 +183,7 @@ X7:
// func shrVU(z, x []Word, s uint) (c Word)
TEXT ·shrVU(SB),7,$0
- MOVW z+4(FP), R5
+ MOVW z_len+4(FP), R5
CMP $0, R5
BEQ X6
@@ -238,7 +238,7 @@ TEXT ·mulAddVWW(SB),7,$0
MOVW x+12(FP), R2
MOVW y+24(FP), R3
MOVW r+28(FP), R4
- MOVW z+4(FP), R5
+ MOVW z_len+4(FP), R5
MOVW R5<<2, R5
ADD R1, R5
B E8
@@ -265,7 +265,7 @@ TEXT ·addMulVVW(SB),7,$0
MOVW z+0(FP), R1
MOVW x+12(FP), R2
MOVW y+24(FP), R3
- MOVW z+4(FP), R5
+ MOVW z_len+4(FP), R5
MOVW R5<<2, R5
ADD R1, R5
MOVW $0, R4
diff --git a/src/pkg/math/big/int.go b/src/pkg/math/big/int.go
index bf2fd2009..d1b5602d6 100644
--- a/src/pkg/math/big/int.go
+++ b/src/pkg/math/big/int.go
@@ -53,7 +53,7 @@ func (z *Int) SetInt64(x int64) *Int {
// SetUint64 sets z to x and returns z.
func (z *Int) SetUint64(x uint64) *Int {
- z.abs = z.abs.setUint64(uint64(x))
+ z.abs = z.abs.setUint64(x)
z.neg = false
return z
}
@@ -513,13 +513,7 @@ func (z *Int) Scan(s fmt.ScanState, ch rune) error {
// Int64 returns the int64 representation of x.
// If x cannot be represented in an int64, the result is undefined.
func (x *Int) Int64() int64 {
- if len(x.abs) == 0 {
- return 0
- }
- v := int64(x.abs[0])
- if _W == 32 && len(x.abs) > 1 {
- v |= int64(x.abs[1]) << 32
- }
+ v := int64(x.Uint64())
if x.neg {
v = -v
}
@@ -527,7 +521,7 @@ func (x *Int) Int64() int64 {
}
// Uint64 returns the uint64 representation of x.
-// If x cannot be represented in an uint64, the result is undefined.
+// If x cannot be represented in a uint64, the result is undefined.
func (x *Int) Uint64() uint64 {
if len(x.abs) == 0 {
return 0
@@ -795,8 +789,8 @@ func (x *Int) Bit(i int) uint {
}
// SetBit sets z to x, with x's i'th bit set to b (0 or 1).
-// That is, if bit is 1 SetBit sets z = x | (1 << i);
-// if bit is 0 it sets z = x &^ (1 << i). If bit is not 0 or 1,
+// That is, if b is 1 SetBit sets z = x | (1 << i);
+// if b is 0 SetBit sets z = x &^ (1 << i). If b is not 0 or 1,
// SetBit will panic.
func (z *Int) SetBit(x *Int, i int, b uint) *Int {
if i < 0 {
diff --git a/src/pkg/math/big/nat.go b/src/pkg/math/big/nat.go
index 9d09f97b7..6874900d0 100644
--- a/src/pkg/math/big/nat.go
+++ b/src/pkg/math/big/nat.go
@@ -1021,8 +1021,6 @@ func trailingZeroBits(x Word) uint {
default:
panic("unknown word size")
}
-
- return 0
}
// trailingZeroBits returns the number of consecutive least significant zero
diff --git a/src/pkg/math/big/rat.go b/src/pkg/math/big/rat.go
index 3e6473d92..75d044fe2 100644
--- a/src/pkg/math/big/rat.go
+++ b/src/pkg/math/big/rat.go
@@ -163,16 +163,16 @@ func quotToFloat(a, b nat) (f float64, exact bool) {
return
}
-// Float64 returns the nearest float64 value to z.
-// If z is exactly representable as a float64, Float64 returns exact=true.
-// If z is negative, so too is f, even if f==0.
-func (z *Rat) Float64() (f float64, exact bool) {
- b := z.b.abs
+// Float64 returns the nearest float64 value for x and a bool indicating
+// whether f represents x exactly. The sign of f always matches the sign
+// of x, even if f == 0.
+func (x *Rat) Float64() (f float64, exact bool) {
+ b := x.b.abs
if len(b) == 0 {
b = b.set(natOne) // materialize denominator
}
- f, exact = quotToFloat(z.a.abs, b)
- if z.a.neg {
+ f, exact = quotToFloat(x.a.abs, b)
+ if x.a.neg {
f = -f
}
return
diff --git a/src/pkg/math/big/rat_test.go b/src/pkg/math/big/rat_test.go
index 462dfb723..1c2c64237 100644
--- a/src/pkg/math/big/rat_test.go
+++ b/src/pkg/math/big/rat_test.go
@@ -503,9 +503,7 @@ func TestIssue3521(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.)
var float64inputs = []string{
- //
// Constants plundered from strconv/testfp.txt.
- //
// Table 1: Stress Inputs for Conversion to 53-bit Binary, < 1/2 ULP
"5e+125",
@@ -583,9 +581,7 @@ var float64inputs = []string{
"75224575729e-45",
"459926601011e+15",
- //
// Constants plundered from strconv/atof_test.go.
- //
"0",
"1",
@@ -734,7 +730,7 @@ func TestFloat64SpecialCases(t *testing.T) {
case f == 0 && r.Num().BitLen() == 0:
// Ok: Rat(0) is equivalent to both +/- float64(0).
default:
- t.Errorf("strconv.ParseFloat(%q) = %g (%b), want %g (%b); delta=%g", input, e, e, f, f, f-e)
+ t.Errorf("strconv.ParseFloat(%q) = %g (%b), want %g (%b); delta = %g", input, e, e, f, f, f-e)
}
}
@@ -795,7 +791,7 @@ func TestFloat64Distribution(t *testing.T) {
if !checkIsBestApprox(t, f, r) {
// Append context information.
- t.Errorf("(input was mantissa %#x, exp %d; f=%g (%b); f~%g; r=%v)",
+ t.Errorf("(input was mantissa %#x, exp %d; f = %g (%b); f ~ %g; r = %v)",
b, exp, f, f, math.Ldexp(float64(b), exp), r)
}
@@ -830,7 +826,7 @@ func checkNonLossyRoundtrip(t *testing.T, f float64) {
}
f2, exact := r.Float64()
if f != f2 || !exact {
- t.Errorf("Rat.SetFloat64(%g).Float64() = %g (%b), %v, want %g (%b), %v; delta=%b",
+ t.Errorf("Rat.SetFloat64(%g).Float64() = %g (%b), %v, want %g (%b), %v; delta = %b",
f, f2, f2, exact, f, f, true, f2-f)
}
}
diff --git a/src/pkg/math/dim_amd64.s b/src/pkg/math/dim_amd64.s
index a1505ce44..0ae8ad196 100644
--- a/src/pkg/math/dim_amd64.s
+++ b/src/pkg/math/dim_amd64.s
@@ -36,12 +36,12 @@ dim3: // (NaN, x) or (x, NaN)
SUBSD y+8(FP), X0
MOVSD $(0.0), X1
MAXSD X1, X0
- MOVSD X0, r+16(FP)
+ MOVSD X0, ret+16(FP)
RET
bothInf: // Dim(-Inf, -Inf) or Dim(+Inf, +Inf)
MOVQ $NaN, AX
isDimNaN:
- MOVQ AX, r+16(FP)
+ MOVQ AX, ret+16(FP)
RET
// func ·Max(x, y float64) float64
@@ -72,28 +72,28 @@ TEXT ·Max(SB),7,$0
MOVQ R8, X0
MOVQ R9, X1
MAXSD X1, X0
- MOVSD X0, r+16(FP)
+ MOVSD X0, ret+16(FP)
RET
isMaxNaN: // return NaN
isPosInf: // return +Inf
- MOVQ AX, r+16(FP)
+ MOVQ AX, ret+16(FP)
RET
isMaxZero:
MOVQ $(1<<63), AX // -0.0
CMPQ AX, R8
JEQ +3(PC)
- MOVQ R8, r+16(FP) // return 0
+ MOVQ R8, ret+16(FP) // return 0
RET
- MOVQ R9, r+16(FP) // return other 0
+ MOVQ R9, ret+16(FP) // return other 0
RET
/*
MOVQ $0, AX
CMPQ AX, R8
JNE +3(PC)
- MOVQ R8, r+16(FP) // return 0
+ MOVQ R8, ret+16(FP) // return 0
RET
- MOVQ R9, r+16(FP) // return other 0
+ MOVQ R9, ret+16(FP) // return other 0
RET
*/
@@ -125,18 +125,18 @@ TEXT ·Min(SB),7,$0
MOVQ R8, X0
MOVQ R9, X1
MINSD X1, X0
- MOVSD X0, r+16(FP)
+ MOVSD X0, ret+16(FP)
RET
isMinNaN: // return NaN
isNegInf: // return -Inf
- MOVQ AX, r+16(FP)
+ MOVQ AX, ret+16(FP)
RET
isMinZero:
MOVQ $(1<<63), AX // -0.0
CMPQ AX, R8
JEQ +3(PC)
- MOVQ R9, r+16(FP) // return other 0
+ MOVQ R9, ret+16(FP) // return other 0
RET
- MOVQ R8, r+16(FP) // return -0
+ MOVQ R8, ret+16(FP) // return -0
RET
diff --git a/src/pkg/math/exp2_386.s b/src/pkg/math/exp2_386.s
index ed82a4dd3..153762631 100644
--- a/src/pkg/math/exp2_386.s
+++ b/src/pkg/math/exp2_386.s
@@ -5,7 +5,7 @@
// func Exp2(x float64) float64
TEXT ·Exp2(SB),7,$0
// test bits for not-finite
- MOVL x+4(FP), AX
+ MOVL x_hi+4(FP), AX
ANDL $0x7ff00000, AX
CMPL AX, $0x7ff00000
JEQ not_finite
@@ -19,20 +19,20 @@ TEXT ·Exp2(SB),7,$0
FADDDP F0, F1 // F0=2**(x-int(x)), F1=int(x)
FSCALE // F0=2**x, F1=int(x)
FMOVDP F0, F1 // F0=2**x
- FMOVDP F0, r+8(FP)
+ FMOVDP F0, ret+8(FP)
RET
not_finite:
// test bits for -Inf
- MOVL x+4(FP), BX
- MOVL x+0(FP), CX
+ MOVL x_hi+4(FP), BX
+ MOVL x_lo+0(FP), CX
CMPL BX, $0xfff00000
JNE not_neginf
CMPL CX, $0
JNE not_neginf
- MOVL $0, r+8(FP)
- MOVL $0, r+12(FP)
+ MOVL $0, ret_lo+8(FP)
+ MOVL $0, ret_hi+12(FP)
RET
not_neginf:
- MOVL CX, r+8(FP)
- MOVL BX, r+12(FP)
+ MOVL CX, ret_lo+8(FP)
+ MOVL BX, ret_hi+12(FP)
RET
diff --git a/src/pkg/math/exp_386.s b/src/pkg/math/exp_386.s
index e0743e72a..aeceb3cad 100644
--- a/src/pkg/math/exp_386.s
+++ b/src/pkg/math/exp_386.s
@@ -5,7 +5,7 @@
// func Exp(x float64) float64
TEXT ·Exp(SB),7,$0
// test bits for not-finite
- MOVL x+4(FP), AX
+ MOVL x_hi+4(FP), AX
ANDL $0x7ff00000, AX
CMPL AX, $0x7ff00000
JEQ not_finite
@@ -20,20 +20,20 @@ TEXT ·Exp(SB),7,$0
FADDDP F0, F1 // F0=2**(x*log2(e)-int(x*log2(e))), F1=int(x*log2(e))
FSCALE // F0=e**x, F1=int(x*log2(e))
FMOVDP F0, F1 // F0=e**x
- FMOVDP F0, r+8(FP)
+ FMOVDP F0, ret+8(FP)
RET
not_finite:
// test bits for -Inf
- MOVL x+4(FP), BX
- MOVL x+0(FP), CX
+ MOVL x_hi+4(FP), BX
+ MOVL x_lo+0(FP), CX
CMPL BX, $0xfff00000
JNE not_neginf
CMPL CX, $0
JNE not_neginf
FLDZ // F0=0
- FMOVDP F0, r+8(FP)
+ FMOVDP F0, ret+8(FP)
RET
not_neginf:
- MOVL CX, r+8(FP)
- MOVL BX, r+12(FP)
+ MOVL CX, ret_lo+8(FP)
+ MOVL BX, ret_hi+12(FP)
RET
diff --git a/src/pkg/math/exp_amd64.s b/src/pkg/math/exp_amd64.s
index 74c9c876a..eb6fb0432 100644
--- a/src/pkg/math/exp_amd64.s
+++ b/src/pkg/math/exp_amd64.s
@@ -93,7 +93,7 @@ TEXT ·Exp(SB),7,$0
SHLQ CX, BX
MOVQ BX, X1
MULSD X1, X0
- MOVSD X0, r+8(FP)
+ MOVSD X0, ret+8(FP)
RET
notFinite:
// test bits for -Inf
@@ -103,10 +103,10 @@ notFinite:
// -Inf, return 0
underflow: // return 0
MOVQ $0, AX
- MOVQ AX, r+8(FP)
+ MOVQ AX, ret+8(FP)
RET
overflow: // return +Inf
MOVQ $PosInf, BX
notNegInf: // NaN or +Inf, return x
- MOVQ BX, r+8(FP)
+ MOVQ BX, ret+8(FP)
RET
diff --git a/src/pkg/math/expm1_386.s b/src/pkg/math/expm1_386.s
index 8185f49a4..0ff9c4ab0 100644
--- a/src/pkg/math/expm1_386.s
+++ b/src/pkg/math/expm1_386.s
@@ -14,11 +14,11 @@ TEXT ·Expm1(SB),7,$0
FLDL2E // F0=log2(e)
FMULD x+0(FP), F0 // F0=x*log2(e) (-1<F0<1)
F2XM1 // F0=e**x-1 = 2**(x*log2(e))-1
- FMOVDP F0, r+8(FP)
+ FMOVDP F0, ret+8(FP)
RET
use_exp:
// test bits for not-finite
- MOVL x+4(FP), AX
+ MOVL x_hi+4(FP), AX
ANDL $0x7ff00000, AX
CMPL AX, $0x7ff00000
JEQ not_finite
@@ -35,21 +35,21 @@ use_exp:
FMOVDP F0, F1 // F0=e**x
FLD1 // F0=1, F1=e**x
FSUBDP F0, F1 // F0=e**x-1
- FMOVDP F0, r+8(FP)
+ FMOVDP F0, ret+8(FP)
RET
not_finite:
// test bits for -Inf
- MOVL x+4(FP), BX
- MOVL x+0(FP), CX
+ MOVL x_hi+4(FP), BX
+ MOVL x_lo+0(FP), CX
CMPL BX, $0xfff00000
JNE not_neginf
CMPL CX, $0
JNE not_neginf
FLD1 // F0=1
FCHS // F0=-1
- FMOVDP F0, r+8(FP)
+ FMOVDP F0, ret+8(FP)
RET
not_neginf:
- MOVL CX, r+8(FP)
- MOVL BX, r+12(FP)
+ MOVL CX, ret_lo+8(FP)
+ MOVL BX, ret_hi+12(FP)
RET
diff --git a/src/pkg/math/floor_386.s b/src/pkg/math/floor_386.s
index a4ae9d2eb..9aa71c043 100644
--- a/src/pkg/math/floor_386.s
+++ b/src/pkg/math/floor_386.s
@@ -13,7 +13,7 @@ TEXT ·Ceil(SB),7,$0
FLDCW -4(SP) // load new Control Word
FRNDINT // F0=Ceil(x)
FLDCW -2(SP) // load old Control Word
- FMOVDP F0, r+8(FP)
+ FMOVDP F0, ret+8(FP)
RET
// func Floor(x float64) float64
@@ -27,7 +27,7 @@ TEXT ·Floor(SB),7,$0
FLDCW -4(SP) // load new Control Word
FRNDINT // F0=Floor(x)
FLDCW -2(SP) // load old Control Word
- FMOVDP F0, r+8(FP)
+ FMOVDP F0, ret+8(FP)
RET
// func Trunc(x float64) float64
@@ -40,5 +40,5 @@ TEXT ·Trunc(SB),7,$0
FLDCW -4(SP) // load new Control Word
FRNDINT // F0=Trunc(x)
FLDCW -2(SP) // load old Control Word
- FMOVDP F0, r+8(FP)
+ FMOVDP F0, ret+8(FP)
RET
diff --git a/src/pkg/math/floor_amd64.s b/src/pkg/math/floor_amd64.s
index e72cc3cf9..bb1a2fd22 100644
--- a/src/pkg/math/floor_amd64.s
+++ b/src/pkg/math/floor_amd64.s
@@ -20,10 +20,10 @@ TEXT ·Floor(SB),7,$0
MOVSD $(-1.0), X2
ANDPD X2, X0 // if x < float(int(x)) {X0 = -1} else {X0 = 0}
ADDSD X1, X0
- MOVSD X0, r+8(FP)
+ MOVSD X0, ret+8(FP)
RET
isBig_floor:
- MOVQ AX, r+8(FP) // return x
+ MOVQ AX, ret+8(FP) // return x
RET
// func Ceil(x float64) float64
@@ -46,10 +46,10 @@ TEXT ·Ceil(SB),7,$0
ANDNPD X3, X0
ORPD X2, X0 // if float(int(x)) <= x {X0 = 1} else {X0 = -0}
ADDSD X1, X0
- MOVSD X0, r+8(FP)
+ MOVSD X0, ret+8(FP)
RET
isBig_ceil:
- MOVQ AX, r+8(FP)
+ MOVQ AX, ret+8(FP)
RET
// func Trunc(x float64) float64
@@ -67,8 +67,8 @@ TEXT ·Trunc(SB),7,$0
ANDNPD X0, X2 // X2 = sign
CVTSQ2SD AX, X0 // X0 = float(int(x))
ORPD X2, X0 // if X0 = 0.0, incorporate sign
- MOVSD X0, r+8(FP)
+ MOVSD X0, ret+8(FP)
RET
isBig_trunc:
- MOVQ AX, r+8(FP) // return x
+ MOVQ AX, ret+8(FP) // return x
RET
diff --git a/src/pkg/math/hypot.go b/src/pkg/math/hypot.go
index 3846e6d87..2087cb05b 100644
--- a/src/pkg/math/hypot.go
+++ b/src/pkg/math/hypot.go
@@ -12,8 +12,10 @@ package math
// unnecessary overflow and underflow.
//
// Special cases are:
-// Hypot(p, q) = +Inf if p or q is infinite
-// Hypot(p, q) = NaN if p or q is NaN
+// Hypot(±Inf, q) = +Inf
+// Hypot(p, ±Inf) = +Inf
+// Hypot(NaN, q) = NaN
+// Hypot(p, NaN) = NaN
func Hypot(p, q float64) float64
func hypot(p, q float64) float64 {
diff --git a/src/pkg/math/hypot_386.s b/src/pkg/math/hypot_386.s
index 51cd90419..8edfe064f 100644
--- a/src/pkg/math/hypot_386.s
+++ b/src/pkg/math/hypot_386.s
@@ -5,11 +5,11 @@
// func Hypot(p, q float64) float64
TEXT ·Hypot(SB),7,$0
// test bits for not-finite
- MOVL p+4(FP), AX // high word p
+ MOVL p_hi+4(FP), AX // high word p
ANDL $0x7ff00000, AX
CMPL AX, $0x7ff00000
JEQ not_finite
- MOVL q+12(FP), AX // high word q
+ MOVL q_hi+12(FP), AX // high word q
ANDL $0x7ff00000, AX
CMPL AX, $0x7ff00000
JEQ not_finite
@@ -31,27 +31,27 @@ TEXT ·Hypot(SB),7,$0
FADDDP F0, F1 // F0=1+q*q, F1=p
FSQRT // F0=sqrt(1+q*q), F1=p
FMULDP F0, F1 // F0=p*sqrt(1+q*q)
- FMOVDP F0, r+16(FP)
+ FMOVDP F0, ret+16(FP)
RET
FMOVDP F0, F1 // F0=0
- FMOVDP F0, r+16(FP)
+ FMOVDP F0, ret+16(FP)
RET
not_finite:
// test bits for -Inf or +Inf
- MOVL p+4(FP), AX // high word p
- ORL p+0(FP), AX // low word p
+ MOVL p_hi+4(FP), AX // high word p
+ ORL p_lo+0(FP), AX // low word p
ANDL $0x7fffffff, AX
CMPL AX, $0x7ff00000
JEQ is_inf
- MOVL q+12(FP), AX // high word q
- ORL q+8(FP), AX // low word q
+ MOVL q_hi+12(FP), AX // high word q
+ ORL q_lo+8(FP), AX // low word q
ANDL $0x7fffffff, AX
CMPL AX, $0x7ff00000
JEQ is_inf
- MOVL $0x7ff80000, r+20(FP) // return NaN = 0x7FF8000000000001
- MOVL $0x00000001, r+16(FP)
+ MOVL $0x7ff80000, ret_hi+20(FP) // return NaN = 0x7FF8000000000001
+ MOVL $0x00000001, ret_lo+16(FP)
RET
is_inf:
- MOVL AX, r+20(FP) // return +Inf = 0x7FF0000000000000
- MOVL $0x00000000, r+16(FP)
+ MOVL AX, ret_hi+20(FP) // return +Inf = 0x7FF0000000000000
+ MOVL $0x00000000, ret_lo+16(FP)
RET
diff --git a/src/pkg/math/hypot_amd64.s b/src/pkg/math/hypot_amd64.s
index 02fff5b92..40ba6f41d 100644
--- a/src/pkg/math/hypot_amd64.s
+++ b/src/pkg/math/hypot_amd64.s
@@ -31,7 +31,7 @@ TEXT ·Hypot(SB),7,$0
ADDSD $1.0, X1
SQRTSD X1, X1
MULSD X1, X0
- MOVSD X0, r+16(FP)
+ MOVSD X0, ret+16(FP)
RET
isInfOrNaN:
CMPQ AX, BX
@@ -39,12 +39,12 @@ isInfOrNaN:
CMPQ AX, CX
JEQ isInf
MOVQ $NaN, AX
- MOVQ AX, r+16(FP) // return NaN
+ MOVQ AX, ret+16(FP) // return NaN
RET
isInf:
- MOVQ AX, r+16(FP) // return +Inf
+ MOVQ AX, ret+16(FP) // return +Inf
RET
isZero:
MOVQ $0, AX
- MOVQ AX, r+16(FP) // return 0
+ MOVQ AX, ret+16(FP) // return 0
RET
diff --git a/src/pkg/math/ldexp_386.s b/src/pkg/math/ldexp_386.s
index 3a65629d2..566245dc2 100644
--- a/src/pkg/math/ldexp_386.s
+++ b/src/pkg/math/ldexp_386.s
@@ -8,5 +8,5 @@ TEXT ·Ldexp(SB),7,$0
FMOVD frac+0(FP), F0 // F0=frac, F1=e
FSCALE // F0=x*2**e, F1=e
FMOVDP F0, F1 // F0=x*2**e
- FMOVDP F0, r+12(FP)
+ FMOVDP F0, ret+12(FP)
RET
diff --git a/src/pkg/math/log10_386.s b/src/pkg/math/log10_386.s
index cc473b424..d4f94235e 100644
--- a/src/pkg/math/log10_386.s
+++ b/src/pkg/math/log10_386.s
@@ -7,7 +7,7 @@ TEXT ·Log10(SB),7,$0
FLDLG2 // F0=log10(2)
FMOVD x+0(FP), F0 // F0=x, F1=log10(2)
FYL2X // F0=log10(x)=log2(x)*log10(2)
- FMOVDP F0, r+8(FP)
+ FMOVDP F0, ret+8(FP)
RET
// func Log2(x float64) float64
@@ -15,5 +15,5 @@ TEXT ·Log2(SB),7,$0
FLD1 // F0=1
FMOVD x+0(FP), F0 // F0=x, F1=1
FYL2X // F0=log2(x)
- FMOVDP F0, r+8(FP)
+ FMOVDP F0, ret+8(FP)
RET
diff --git a/src/pkg/math/log1p_386.s b/src/pkg/math/log1p_386.s
index 30df88e1f..30dc8033d 100644
--- a/src/pkg/math/log1p_386.s
+++ b/src/pkg/math/log1p_386.s
@@ -14,12 +14,12 @@ TEXT ·Log1p(SB),7,$0
JEQ use_fyl2x // jump if F0 >= F1
FMOVD x+0(FP), F0 // F0=x, F1=log(2)
FYL2XP1 // F0=log(1+x)=log2(1+x)*log(2)
- FMOVDP F0, r+8(FP)
+ FMOVDP F0, ret+8(FP)
RET
use_fyl2x:
FLD1 // F0=1, F2=log(2)
FADDD x+0(FP), F0 // F0=1+x, F1=log(2)
FYL2X // F0=log(1+x)=log2(1+x)*log(2)
- FMOVDP F0, r+8(FP)
+ FMOVDP F0, ret+8(FP)
RET
diff --git a/src/pkg/math/log_386.s b/src/pkg/math/log_386.s
index 6cfbc7605..7a6f2c052 100644
--- a/src/pkg/math/log_386.s
+++ b/src/pkg/math/log_386.s
@@ -7,5 +7,5 @@ TEXT ·Log(SB),7,$0
FLDLN2 // F0=log(2)
FMOVD x+0(FP), F0 // F0=x, F1=log(2)
FYL2X // F0=log(x)=log2(x)*log(2)
- FMOVDP F0, r+8(FP)
+ FMOVDP F0, ret+8(FP)
RET
diff --git a/src/pkg/math/log_amd64.s b/src/pkg/math/log_amd64.s
index 75bc55764..6ae5fbc95 100644
--- a/src/pkg/math/log_amd64.s
+++ b/src/pkg/math/log_amd64.s
@@ -94,16 +94,16 @@ TEXT ·Log(SB),7,$0
SUBSD X2, X0 // x0= (hfsq-(s*(hfsq+R)+k*Ln2Lo))-f, x1= k
MULSD $Ln2Hi, X1 // x0= (hfsq-(s*(hfsq+R)+k*Ln2Lo))-f, x1= k*Ln2Hi
SUBSD X0, X1 // x1= k*Ln2Hi-((hfsq-(s*(hfsq+R)+k*Ln2Lo))-f)
- MOVSD X1, r+8(FP)
+ MOVSD X1, ret+8(FP)
RET
isInfOrNaN:
- MOVQ BX, r+8(FP) // +Inf or NaN, return x
+ MOVQ BX, ret+8(FP) // +Inf or NaN, return x
RET
isNegative:
MOVQ $NaN, AX
- MOVQ AX, r+8(FP) // return NaN
+ MOVQ AX, ret+8(FP) // return NaN
RET
isZero:
MOVQ $NegInf, AX
- MOVQ AX, r+8(FP) // return -Inf
+ MOVQ AX, ret+8(FP) // return -Inf
RET
diff --git a/src/pkg/math/mod_386.s b/src/pkg/math/mod_386.s
index 6b9c28d4f..bcb451b5d 100644
--- a/src/pkg/math/mod_386.s
+++ b/src/pkg/math/mod_386.s
@@ -11,5 +11,5 @@ TEXT ·Mod(SB),7,$0
ANDW $0x0400, AX
JNE -3(PC) // jump if reduction incomplete
FMOVDP F0, F1 // F0=x-q*y
- FMOVDP F0, r+16(FP)
+ FMOVDP F0, ret+16(FP)
RET
diff --git a/src/pkg/math/rand/exp.go b/src/pkg/math/rand/exp.go
index 85da49521..4bc110f91 100644
--- a/src/pkg/math/rand/exp.go
+++ b/src/pkg/math/rand/exp.go
@@ -43,7 +43,6 @@ func (r *Rand) ExpFloat64() float64 {
return x
}
}
- panic("unreachable")
}
var ke = [256]uint32{
diff --git a/src/pkg/math/rand/normal.go b/src/pkg/math/rand/normal.go
index 9ab46db9f..ba4ea54ca 100644
--- a/src/pkg/math/rand/normal.go
+++ b/src/pkg/math/rand/normal.go
@@ -63,7 +63,6 @@ func (r *Rand) NormFloat64() float64 {
return x
}
}
- panic("unreachable")
}
var kn = [128]uint32{
diff --git a/src/pkg/math/rand/zipf.go b/src/pkg/math/rand/zipf.go
index 38e8ec516..8db2c6f5b 100644
--- a/src/pkg/math/rand/zipf.go
+++ b/src/pkg/math/rand/zipf.go
@@ -34,7 +34,6 @@ func (z *Zipf) hinv(x float64) float64 {
// NewZipf returns a Zipf generating variates p(k) on [0, imax]
// proportional to (v+k)**(-s) where s>1 and k>=0, and v>=1.
-//
func NewZipf(r *Rand, s float64, v float64, imax uint64) *Zipf {
z := new(Zipf)
if s <= 1.0 || v < 1 {
@@ -52,9 +51,12 @@ func NewZipf(r *Rand, s float64, v float64, imax uint64) *Zipf {
return z
}
-// Uint64 returns a value drawn from the Zipf distributed described
+// Uint64 returns a value drawn from the Zipf distribution described
// by the Zipf object.
func (z *Zipf) Uint64() uint64 {
+ if z == nil {
+ panic("rand: nil Zipf")
+ }
k := 0.0
for {
diff --git a/src/pkg/math/remainder_386.s b/src/pkg/math/remainder_386.s
index 4cb98233a..2238aba49 100644
--- a/src/pkg/math/remainder_386.s
+++ b/src/pkg/math/remainder_386.s
@@ -11,5 +11,5 @@ TEXT ·Remainder(SB),7,$0
ANDW $0x0400, AX
JNE -3(PC) // jump if reduction incomplete
FMOVDP F0, F1 // F0=x-q*y
- FMOVDP F0, r+16(FP)
+ FMOVDP F0, ret+16(FP)
RET
diff --git a/src/pkg/math/sin_386.s b/src/pkg/math/sin_386.s
index 9d00bd92b..b2a836eb1 100644
--- a/src/pkg/math/sin_386.s
+++ b/src/pkg/math/sin_386.s
@@ -9,7 +9,7 @@ TEXT ·Cos(SB),7,$0
FSTSW AX // AX=status word
ANDW $0x0400, AX
JNE 3(PC) // jump if x outside range
- FMOVDP F0, r+8(FP)
+ FMOVDP F0, ret+8(FP)
RET
FLDPI // F0=Pi, F1=x
FADDD F0, F0 // F0=2*Pi, F1=x
@@ -20,7 +20,7 @@ TEXT ·Cos(SB),7,$0
JNE -3(PC) // jump if reduction incomplete
FMOVDP F0, F1 // F0=reduced_x
FCOS // F0=cos(reduced_x)
- FMOVDP F0, r+8(FP)
+ FMOVDP F0, ret+8(FP)
RET
// func Sin(x float64) float64
@@ -30,7 +30,7 @@ TEXT ·Sin(SB),7,$0
FSTSW AX // AX=status word
ANDW $0x0400, AX
JNE 3(PC) // jump if x outside range
- FMOVDP F0, r+8(FP)
+ FMOVDP F0, ret+8(FP)
RET
FLDPI // F0=Pi, F1=x
FADDD F0, F0 // F0=2*Pi, F1=x
@@ -41,5 +41,5 @@ TEXT ·Sin(SB),7,$0
JNE -3(PC) // jump if reduction incomplete
FMOVDP F0, F1 // F0=reduced_x
FSIN // F0=sin(reduced_x)
- FMOVDP F0, r+8(FP)
+ FMOVDP F0, ret+8(FP)
RET
diff --git a/src/pkg/math/sqrt.go b/src/pkg/math/sqrt.go
index 21336df2a..1bd4437f1 100644
--- a/src/pkg/math/sqrt.go
+++ b/src/pkg/math/sqrt.go
@@ -4,15 +4,6 @@
package math
-// Sqrt returns the square root of x.
-//
-// Special cases are:
-// Sqrt(+Inf) = +Inf
-// Sqrt(±0) = ±0
-// Sqrt(x < 0) = NaN
-// Sqrt(NaN) = NaN
-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
@@ -98,6 +89,8 @@ func Sqrt(x float64) float64
// Sqrt(±0) = ±0
// Sqrt(x < 0) = NaN
// Sqrt(NaN) = NaN
+func Sqrt(x float64) float64
+
func sqrt(x float64) float64 {
// special cases
switch {
diff --git a/src/pkg/math/sqrt_386.s b/src/pkg/math/sqrt_386.s
index d0a428d52..824fa634c 100644
--- a/src/pkg/math/sqrt_386.s
+++ b/src/pkg/math/sqrt_386.s
@@ -6,5 +6,5 @@
TEXT ·Sqrt(SB),7,$0
FMOVD x+0(FP),F0
FSQRT
- FMOVDP F0,r+8(FP)
+ FMOVDP F0,ret+8(FP)
RET
diff --git a/src/pkg/math/sqrt_amd64.s b/src/pkg/math/sqrt_amd64.s
index f5b329e70..553c4e01b 100644
--- a/src/pkg/math/sqrt_amd64.s
+++ b/src/pkg/math/sqrt_amd64.s
@@ -5,5 +5,5 @@
// func Sqrt(x float64) float64
TEXT ·Sqrt(SB),7,$0
SQRTSD x+0(FP), X0
- MOVSD X0, r+8(FP)
+ MOVSD X0, ret+8(FP)
RET
diff --git a/src/pkg/math/sqrt_arm.s b/src/pkg/math/sqrt_arm.s
index befbb8a89..b965b4845 100644
--- a/src/pkg/math/sqrt_arm.s
+++ b/src/pkg/math/sqrt_arm.s
@@ -6,5 +6,5 @@
TEXT ·Sqrt(SB),7,$0
MOVD x+0(FP),F0
SQRTD F0,F0
- MOVD F0,r+8(FP)
+ MOVD F0,ret+8(FP)
RET
diff --git a/src/pkg/math/tan_386.s b/src/pkg/math/tan_386.s
index ebb9e798b..f3ad33907 100644
--- a/src/pkg/math/tan_386.s
+++ b/src/pkg/math/tan_386.s
@@ -10,7 +10,7 @@ TEXT ·Tan(SB),7,$0
ANDW $0x0400, AX
JNE 4(PC) // jump if x outside range
FMOVDP F0, F0 // F0=tan(x)
- FMOVDP F0, r+8(FP)
+ FMOVDP F0, ret+8(FP)
RET
FLDPI // F0=Pi, F1=x
FADDD F0, F0 // F0=2*Pi, F1=x
@@ -22,5 +22,5 @@ TEXT ·Tan(SB),7,$0
FMOVDP F0, F1 // F0=reduced_x
FPTAN // F0=1, F1=tan(reduced_x)
FMOVDP F0, F0 // F0=tan(reduced_x)
- FMOVDP F0, r+8(FP)
+ FMOVDP F0, ret+8(FP)
RET
diff --git a/src/pkg/math/tanh.go b/src/pkg/math/tanh.go
index 7305be66c..cf0ffa192 100644
--- a/src/pkg/math/tanh.go
+++ b/src/pkg/math/tanh.go
@@ -65,7 +65,7 @@ var tanhQ = [...]float64{
4.84406305325125486048E3,
}
-// Tanh computes the hyperbolic tangent of x.
+// Tanh returns the hyperbolic tangent of x.
//
// Special cases are:
// Tanh(±0) = ±0
diff --git a/src/pkg/mime/multipart/multipart.go b/src/pkg/mime/multipart/multipart.go
index 77e969b41..2c862a647 100644
--- a/src/pkg/mime/multipart/multipart.go
+++ b/src/pkg/mime/multipart/multipart.go
@@ -28,7 +28,12 @@ var emptyParams = make(map[string]string)
type Part struct {
// The headers of the body, if any, with the keys canonicalized
// in the same fashion that the Go http.Request headers are.
- // i.e. "foo-bar" changes case to "Foo-Bar"
+ // For example, "foo-bar" changes case to "Foo-Bar"
+ //
+ // As a special case, if the "Content-Transfer-Encoding" header
+ // has a value of "quoted-printable", that header is instead
+ // hidden from this map and the body is transparently decoded
+ // during Read calls.
Header textproto.MIMEHeader
buffer *bytes.Buffer
@@ -265,11 +270,10 @@ func (r *Reader) NextPart() (*Part, error) {
return nil, fmt.Errorf("multipart: unexpected line in Next(): %q", line)
}
- panic("unreachable")
}
// isFinalBoundary returns whether line is the final boundary line
-// indiciating that all parts are over.
+// indicating that all parts are over.
// It matches `^--boundary--[ \t]*(\r\n)?$`
func (mr *Reader) isFinalBoundary(line []byte) bool {
if !bytes.HasPrefix(line, mr.dashBoundaryDash) {
diff --git a/src/pkg/mime/multipart/quotedprintable.go b/src/pkg/mime/multipart/quotedprintable.go
index 9e18e1ea1..9ff4ee703 100644
--- a/src/pkg/mime/multipart/quotedprintable.go
+++ b/src/pkg/mime/multipart/quotedprintable.go
@@ -18,16 +18,14 @@ import (
)
type qpReader struct {
- br *bufio.Reader
- skipWhite bool
- rerr error // last read error
- line []byte // to be consumed before more of br
+ br *bufio.Reader
+ rerr error // last read error
+ line []byte // to be consumed before more of br
}
func newQuotedPrintableReader(r io.Reader) io.Reader {
return &qpReader{
- br: bufio.NewReader(r),
- skipWhite: true,
+ br: bufio.NewReader(r),
}
}
@@ -55,10 +53,6 @@ func (q *qpReader) readHexByte(v []byte) (b byte, err error) {
return hb<<4 | lb, nil
}
-func isQPSkipWhiteByte(b byte) bool {
- return b == ' ' || b == '\t'
-}
-
func isQPDiscardWhitespace(r rune) bool {
switch r {
case '\n', '\r', ' ', '\t':
@@ -79,7 +73,6 @@ func (q *qpReader) Read(p []byte) (n int, err error) {
if q.rerr != nil {
return n, q.rerr
}
- q.skipWhite = true
q.line, q.rerr = q.br.ReadSlice('\n')
// Does the line end in CRLF instead of just LF?
@@ -103,11 +96,6 @@ func (q *qpReader) Read(p []byte) (n int, err error) {
continue
}
b := q.line[0]
- if q.skipWhite && isQPSkipWhiteByte(b) {
- q.line = q.line[1:]
- continue
- }
- q.skipWhite = false
switch {
case b == '=':
diff --git a/src/pkg/mime/multipart/quotedprintable_test.go b/src/pkg/mime/multipart/quotedprintable_test.go
index 7bcf5767b..8a95f7f03 100644
--- a/src/pkg/mime/multipart/quotedprintable_test.go
+++ b/src/pkg/mime/multipart/quotedprintable_test.go
@@ -32,8 +32,9 @@ func TestQuotedPrintable(t *testing.T) {
{in: "foo bar=0", want: "foo bar", err: io.ErrUnexpectedEOF},
{in: "foo bar=ab", want: "foo bar", err: "multipart: invalid quoted-printable hex byte 0x61"},
{in: "foo bar=0D=0A", want: "foo bar\r\n"},
- {in: " A B =\r\n C ", want: "A B C"},
- {in: " A B =\n C ", want: "A B C"}, // lax. treating LF as CRLF
+ {in: " A B \r\n C ", want: " A B\r\n C"},
+ {in: " A B =\r\n C ", want: " A B C"},
+ {in: " A B =\n C ", want: " A B C"}, // lax. treating LF as CRLF
{in: "foo=\nbar", want: "foobar"},
{in: "foo\x00bar", want: "foo", err: "multipart: invalid unescaped byte 0x00 in quoted-printable body"},
{in: "foo bar\xff", want: "foo bar", err: "multipart: invalid unescaped byte 0xff in quoted-printable body"},
@@ -57,6 +58,10 @@ func TestQuotedPrintable(t *testing.T) {
{in: "foo=\nbar", want: "foobar"},
{in: "foo=\rbar", want: "foo", err: "multipart: invalid quoted-printable hex byte 0x0d"},
{in: "foo=\r\r\r \nbar", want: "foo", err: `multipart: invalid bytes after =: "\r\r\r \n"`},
+
+ // Example from RFC 2045:
+ {in: "Now's the time =\n" + "for all folk to come=\n" + " to the aid of their country.",
+ want: "Now's the time for all folk to come to the aid of their country."},
}
for _, tt := range tests {
var buf bytes.Buffer
diff --git a/src/pkg/net/conn_test.go b/src/pkg/net/conn_test.go
index fdb90862f..98bd69549 100644
--- a/src/pkg/net/conn_test.go
+++ b/src/pkg/net/conn_test.go
@@ -16,11 +16,11 @@ import (
var connTests = []struct {
net string
- addr string
+ addr func() string
}{
- {"tcp", "127.0.0.1:0"},
- {"unix", testUnixAddr()},
- {"unixpacket", testUnixAddr()},
+ {"tcp", func() string { return "127.0.0.1:0" }},
+ {"unix", testUnixAddr},
+ {"unixpacket", testUnixAddr},
}
// someTimeout is used just to test that net.Conn implementations
@@ -41,7 +41,8 @@ func TestConnAndListener(t *testing.T) {
}
}
- ln, err := Listen(tt.net, tt.addr)
+ addr := tt.addr()
+ ln, err := Listen(tt.net, addr)
if err != nil {
t.Fatalf("Listen failed: %v", err)
}
@@ -51,7 +52,7 @@ func TestConnAndListener(t *testing.T) {
case "unix", "unixpacket":
os.Remove(addr)
}
- }(ln, tt.net, tt.addr)
+ }(ln, tt.net, addr)
ln.Addr()
done := make(chan int)
diff --git a/src/pkg/net/dial.go b/src/pkg/net/dial.go
index 22e1e7dd8..b18d28362 100644
--- a/src/pkg/net/dial.go
+++ b/src/pkg/net/dial.go
@@ -9,78 +9,48 @@ import (
"time"
)
-// A DialOption modifies a DialOpt call.
-type DialOption interface {
- dialOption()
-}
-
-var (
- // TCP is a dial option to dial with TCP (over IPv4 or IPv6).
- TCP = Network("tcp")
-
- // UDP is a dial option to dial with UDP (over IPv4 or IPv6).
- UDP = Network("udp")
-)
-
-// Network returns a DialOption to dial using the given network.
-//
-// Known networks are "tcp", "tcp4" (IPv4-only), "tcp6" (IPv6-only),
-// "udp", "udp4" (IPv4-only), "udp6" (IPv6-only), "ip", "ip4"
-// (IPv4-only), "ip6" (IPv6-only), "unix", "unixgram" and
-// "unixpacket".
-//
-// For IP networks, net must be "ip", "ip4" or "ip6" followed
-// by a colon and a protocol number or name, such as
-// "ipv4:1" or "ip6:ospf".
-func Network(net string) DialOption {
- return dialNetwork(net)
-}
-
-type dialNetwork string
-
-func (dialNetwork) dialOption() {}
-
-// Deadline returns a DialOption to fail a dial that doesn't
-// complete before t.
-func Deadline(t time.Time) DialOption {
- return dialDeadline(t)
-}
-
-// Timeout returns a DialOption to fail a dial that doesn't
-// complete within the provided duration.
-func Timeout(d time.Duration) DialOption {
- return dialDeadline(time.Now().Add(d))
-}
-
-type dialDeadline time.Time
-
-func (dialDeadline) dialOption() {}
-
-type tcpFastOpen struct{}
-
-func (tcpFastOpen) dialOption() {}
-
-// TODO(bradfitz): implement this (golang.org/issue/4842) and unexport this.
+// A Dialer contains options for connecting to an address.
//
-// TCPFastTimeout returns an option to use TCP Fast Open (TFO) when
-// doing this dial. It is only valid for use with TCP connections.
-// Data sent over a TFO connection may be processed by the peer
-// multiple times, so should be used with caution.
-func todo_TCPFastTimeout() DialOption {
- return tcpFastOpen{}
-}
-
-type localAddrOption struct {
- la Addr
-}
-
-func (localAddrOption) dialOption() {}
-
-// LocalAddress returns a dial option to perform a dial with the
-// provided local address. The address must be of a compatible type
-// for the network being dialed.
-func LocalAddress(addr Addr) DialOption {
- return localAddrOption{addr}
+// The zero value for each field is equivalent to dialing
+// without that option. Dialing with the zero value of Dialer
+// is therefore equivalent to just calling the Dial function.
+type Dialer struct {
+ // Timeout is the maximum amount of time a dial will wait for
+ // a connect to complete. If Deadline is also set, it may fail
+ // earlier.
+ //
+ // The default is no timeout.
+ //
+ // With or without a timeout, the operating system may impose
+ // its own earlier timeout. For instance, TCP timeouts are
+ // often around 3 minutes.
+ Timeout time.Duration
+
+ // Deadline is the absolute point in time after which dials
+ // will fail. If Timeout is set, it may fail earlier.
+ // Zero means no deadline, or dependent on the operating system
+ // as with the Timeout option.
+ Deadline time.Time
+
+ // LocalAddr is the local address to use when dialing an
+ // address. The address must be of a compatible type for the
+ // network being dialed.
+ // If nil, a local address is automatically chosen.
+ LocalAddr Addr
+}
+
+// Return either now+Timeout or Deadline, whichever comes first.
+// Or zero, if neither is set.
+func (d *Dialer) deadline() time.Time {
+ if d.Timeout == 0 {
+ return d.Deadline
+ }
+ timeoutDeadline := time.Now().Add(d.Timeout)
+ if d.Deadline.IsZero() || timeoutDeadline.Before(d.Deadline) {
+ return timeoutDeadline
+ } else {
+ return d.Deadline
+ }
}
func parseNetwork(net string) (afnet string, proto int, err error) {
@@ -127,7 +97,7 @@ func resolveAddr(op, net, addr string, deadline time.Time) (Addr, error) {
return resolveInternetAddr(afnet, addr, deadline)
}
-// Dial connects to the address addr on the network net.
+// Dial connects to the address on the named network.
//
// Known networks are "tcp", "tcp4" (IPv4-only), "tcp6" (IPv6-only),
// "udp", "udp4" (IPv4-only), "udp6" (IPv6-only), "ip", "ip4"
@@ -135,67 +105,45 @@ func resolveAddr(op, net, addr string, deadline time.Time) (Addr, error) {
// "unixpacket".
//
// For TCP and UDP networks, addresses have the form host:port.
-// If host is a literal IPv6 address, it must be enclosed
-// in square brackets. The functions JoinHostPort and SplitHostPort
-// manipulate addresses in this form.
+// If host is a literal IPv6 address or host name, it must be enclosed
+// in square brackets as in "[::1]:80", "[ipv6-host]:http" or
+// "[ipv6-host%zone]:80".
+// The functions JoinHostPort and SplitHostPort manipulate addresses
+// in this form.
//
// Examples:
// Dial("tcp", "12.34.56.78:80")
-// Dial("tcp", "google.com:80")
-// Dial("tcp", "[de:ad:be:ef::ca:fe]:80")
+// Dial("tcp", "google.com:http")
+// Dial("tcp", "[2001:db8::1]:http")
+// Dial("tcp", "[fe80::1%lo0]:80")
//
-// For IP networks, net must be "ip", "ip4" or "ip6" followed
-// by a colon and a protocol number or name.
+// For IP networks, the network must be "ip", "ip4" or "ip6" followed
+// by a colon and a protocol number or name and the addr must be a
+// literal IP address.
//
// Examples:
// Dial("ip4:1", "127.0.0.1")
// Dial("ip6:ospf", "::1")
//
-func Dial(net, addr string) (Conn, error) {
- return DialOpt(addr, dialNetwork(net))
+// For Unix networks, the address must be a file system path.
+func Dial(network, address string) (Conn, error) {
+ var d Dialer
+ return d.Dial(network, address)
}
-func netFromOptions(opts []DialOption) string {
- for _, opt := range opts {
- if p, ok := opt.(dialNetwork); ok {
- return string(p)
- }
- }
- return "tcp"
-}
-
-func deadlineFromOptions(opts []DialOption) time.Time {
- for _, opt := range opts {
- if d, ok := opt.(dialDeadline); ok {
- return time.Time(d)
- }
- }
- return noDeadline
-}
-
-var noLocalAddr Addr // nil
-
-func localAddrFromOptions(opts []DialOption) Addr {
- for _, opt := range opts {
- if o, ok := opt.(localAddrOption); ok {
- return o.la
- }
- }
- return noLocalAddr
+// DialTimeout acts like Dial but takes a timeout.
+// The timeout includes name resolution, if required.
+func DialTimeout(network, address string, timeout time.Duration) (Conn, error) {
+ d := Dialer{Timeout: timeout}
+ return d.Dial(network, address)
}
-// DialOpt dials addr using the provided options.
-// If no options are provided, DialOpt(addr) is equivalent
-// to Dial("tcp", addr). See Dial for the syntax of addr.
-func DialOpt(addr string, opts ...DialOption) (Conn, error) {
- net := netFromOptions(opts)
- deadline := deadlineFromOptions(opts)
- la := localAddrFromOptions(opts)
- ra, err := resolveAddr("dial", net, addr, deadline)
- if err != nil {
- return nil, err
- }
- return dial(net, addr, la, ra, deadline)
+// Dial connects to the address on the named network.
+//
+// See func Dial for a description of the network and address
+// parameters.
+func (d *Dialer) Dial(network, address string) (Conn, error) {
+ return resolveAndDial(network, address, d.LocalAddr, d.deadline())
}
func dial(net, addr string, la, ra Addr, deadline time.Time) (c Conn, err error) {
@@ -224,59 +172,6 @@ func dial(net, addr string, la, ra Addr, deadline time.Time) (c Conn, err error)
return
}
-// DialTimeout acts like Dial but takes a timeout.
-// The timeout includes name resolution, if required.
-func DialTimeout(net, addr string, timeout time.Duration) (Conn, error) {
- return dialTimeout(net, addr, timeout)
-}
-
-// dialTimeoutRace is the old implementation of DialTimeout, still used
-// on operating systems where the deadline hasn't been pushed down
-// into the pollserver.
-// TODO: fix this on plan9.
-func dialTimeoutRace(net, addr string, timeout time.Duration) (Conn, error) {
- t := time.NewTimer(timeout)
- defer t.Stop()
- type pair struct {
- Conn
- error
- }
- ch := make(chan pair, 1)
- resolvedAddr := make(chan Addr, 1)
- go func() {
- ra, err := resolveAddr("dial", net, addr, noDeadline)
- if err != nil {
- ch <- pair{nil, err}
- return
- }
- resolvedAddr <- ra // in case we need it for OpError
- c, err := dial(net, addr, noLocalAddr, ra, noDeadline)
- ch <- pair{c, err}
- }()
- select {
- case <-t.C:
- // Try to use the real Addr in our OpError, if we resolved it
- // before the timeout. Otherwise we just use stringAddr.
- var ra Addr
- select {
- case a := <-resolvedAddr:
- ra = a
- default:
- ra = &stringAddr{net, addr}
- }
- err := &OpError{
- Op: "dial",
- Net: net,
- Addr: ra,
- Err: &timeoutError{},
- }
- return nil, err
- case p := <-ch:
- return p.Conn, p.error
- }
- panic("unreachable")
-}
-
type stringAddr struct {
net, addr string
}
@@ -285,8 +180,9 @@ func (a stringAddr) Network() string { return a.net }
func (a stringAddr) String() string { return a.addr }
// Listen announces on the local network address laddr.
-// The network string net must be a stream-oriented network:
-// "tcp", "tcp4", "tcp6", "unix" or "unixpacket".
+// The network net must be a stream-oriented network: "tcp", "tcp4",
+// "tcp6", "unix" or "unixpacket".
+// See Dial for the syntax of laddr.
func Listen(net, laddr string) (Listener, error) {
la, err := resolveAddr("listen", net, laddr, noDeadline)
if err != nil {
@@ -302,8 +198,9 @@ func Listen(net, laddr string) (Listener, error) {
}
// ListenPacket announces on the local network address laddr.
-// The network string net must be a packet-oriented network:
-// "udp", "udp4", "udp6", "ip", "ip4", "ip6" or "unixgram".
+// The network net must be a packet-oriented network: "udp", "udp4",
+// "udp6", "ip", "ip4", "ip6" or "unixgram".
+// See Dial for the syntax of laddr.
func ListenPacket(net, laddr string) (PacketConn, error) {
la, err := resolveAddr("listen", net, laddr, noDeadline)
if err != nil {
diff --git a/src/pkg/net/dial_gen.go b/src/pkg/net/dial_gen.go
new file mode 100644
index 000000000..19f868168
--- /dev/null
+++ b/src/pkg/net/dial_gen.go
@@ -0,0 +1,73 @@
+// 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"
+)
+
+var testingIssue5349 bool // used during tests
+
+// resolveAndDialChannel is the simple pure-Go implementation of
+// resolveAndDial, 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 resolveAndDialChannel(net, addr string, localAddr Addr, deadline time.Time) (Conn, error) {
+ var timeout time.Duration
+ if !deadline.IsZero() {
+ timeout = deadline.Sub(time.Now())
+ }
+ if timeout <= 0 {
+ ra, err := resolveAddr("dial", net, addr, noDeadline)
+ if err != nil {
+ return nil, err
+ }
+ return dial(net, addr, localAddr, ra, noDeadline)
+ }
+ t := time.NewTimer(timeout)
+ defer t.Stop()
+ type pair struct {
+ Conn
+ error
+ }
+ ch := make(chan pair, 1)
+ resolvedAddr := make(chan Addr, 1)
+ go func() {
+ if testingIssue5349 {
+ time.Sleep(time.Millisecond)
+ }
+ ra, err := resolveAddr("dial", net, addr, noDeadline)
+ if err != nil {
+ ch <- pair{nil, err}
+ return
+ }
+ resolvedAddr <- ra // in case we need it for OpError
+ c, err := dial(net, addr, localAddr, ra, noDeadline)
+ ch <- pair{c, err}
+ }()
+ select {
+ case <-t.C:
+ // Try to use the real Addr in our OpError, if we resolved it
+ // before the timeout. Otherwise we just use stringAddr.
+ var ra Addr
+ select {
+ case a := <-resolvedAddr:
+ ra = a
+ default:
+ ra = &stringAddr{net, addr}
+ }
+ err := &OpError{
+ Op: "dial",
+ Net: net,
+ Addr: ra,
+ Err: &timeoutError{},
+ }
+ return nil, err
+ case p := <-ch:
+ return p.Conn, p.error
+ }
+}
diff --git a/src/pkg/net/dial_gen_test.go b/src/pkg/net/dial_gen_test.go
new file mode 100644
index 000000000..c857acd06
--- /dev/null
+++ b/src/pkg/net/dial_gen_test.go
@@ -0,0 +1,11 @@
+// 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 windows plan9
+
+package net
+
+func init() {
+ testingIssue5349 = true
+}
diff --git a/src/pkg/net/dial_test.go b/src/pkg/net/dial_test.go
index 2303e8fa4..e24fecc8d 100644
--- a/src/pkg/net/dial_test.go
+++ b/src/pkg/net/dial_test.go
@@ -28,12 +28,18 @@ func newLocalListener(t *testing.T) Listener {
}
func TestDialTimeout(t *testing.T) {
+ origBacklog := listenerBacklog
+ defer func() {
+ listenerBacklog = origBacklog
+ }()
+ listenerBacklog = 1
+
ln := newLocalListener(t)
defer ln.Close()
errc := make(chan error)
- numConns := listenerBacklog + 10
+ numConns := listenerBacklog + 100
// TODO(bradfitz): It's hard to test this in a portable
// way. This is unfortunate, but works for now.
@@ -324,3 +330,80 @@ func numFD() int {
// All tests using this should be skipped anyway, but:
panic("numFDs not implemented on " + runtime.GOOS)
}
+
+var testPoller = flag.Bool("poller", false, "platform supports runtime-integrated poller")
+
+// Assert that a failed Dial attempt does not leak
+// runtime.PollDesc structures
+func TestDialFailPDLeak(t *testing.T) {
+ if !*testPoller {
+ t.Skip("test disabled; use -poller to enable")
+ }
+
+ const loops = 10
+ const count = 20000
+ var old runtime.MemStats // used by sysdelta
+ runtime.ReadMemStats(&old)
+ sysdelta := func() uint64 {
+ var new runtime.MemStats
+ runtime.ReadMemStats(&new)
+ delta := old.Sys - new.Sys
+ old = new
+ return delta
+ }
+ d := &Dialer{Timeout: time.Nanosecond} // don't bother TCP with handshaking
+ failcount := 0
+ for i := 0; i < loops; i++ {
+ for i := 0; i < count; i++ {
+ conn, err := d.Dial("tcp", "127.0.0.1:1")
+ if err == nil {
+ t.Error("dial should not succeed")
+ conn.Close()
+ t.FailNow()
+ }
+ }
+ if delta := sysdelta(); delta > 0 {
+ failcount++
+ }
+ // there are always some allocations on the first loop
+ if failcount > 3 {
+ t.Error("detected possible memory leak in runtime")
+ t.FailNow()
+ }
+ }
+}
+
+func TestDialer(t *testing.T) {
+ ln, err := Listen("tcp4", "127.0.0.1:0")
+ if err != nil {
+ t.Fatalf("Listen failed: %v", err)
+ }
+ defer ln.Close()
+ ch := make(chan error, 1)
+ go func() {
+ var err error
+ c, err := ln.Accept()
+ if err != nil {
+ ch <- fmt.Errorf("Accept failed: %v", err)
+ return
+ }
+ defer c.Close()
+ ch <- nil
+ }()
+
+ laddr, err := ResolveTCPAddr("tcp4", "127.0.0.1:0")
+ if err != nil {
+ t.Fatalf("ResolveTCPAddr failed: %v", err)
+ }
+ d := &Dialer{LocalAddr: laddr}
+ c, err := d.Dial("tcp4", ln.Addr().String())
+ if err != nil {
+ t.Fatalf("Dial failed: %v", err)
+ }
+ defer c.Close()
+ c.Read(make([]byte, 1))
+ err = <-ch
+ if err != nil {
+ t.Error(err)
+ }
+}
diff --git a/src/pkg/net/empty.c b/src/pkg/net/empty.c
new file mode 100644
index 000000000..a515c2fe2
--- /dev/null
+++ b/src/pkg/net/empty.c
@@ -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.
+
+// This file is required to prevent compiler errors
+// when the package built with CGO_ENABLED=0.
+// Otherwise the compiler says:
+// pkg/net/fd_poll_runtime.go:15: missing function body
diff --git a/src/pkg/net/example_test.go b/src/pkg/net/example_test.go
index eefe84fa7..6f2f9074c 100644
--- a/src/pkg/net/example_test.go
+++ b/src/pkg/net/example_test.go
@@ -16,6 +16,7 @@ func ExampleListener() {
if err != nil {
log.Fatal(err)
}
+ defer l.Close()
for {
// Wait for a connection.
conn, err := l.Accept()
diff --git a/src/pkg/net/fd_darwin.go b/src/pkg/net/fd_darwin.go
deleted file mode 100644
index 382465ba6..000000000
--- a/src/pkg/net/fd_darwin.go
+++ /dev/null
@@ -1,126 +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.
-
-// Waiting for FDs via kqueue/kevent.
-
-package net
-
-import (
- "errors"
- "os"
- "syscall"
-)
-
-type pollster struct {
- kq int
- eventbuf [10]syscall.Kevent_t
- events []syscall.Kevent_t
-
- // An event buffer for AddFD/DelFD.
- // Must hold pollServer lock.
- kbuf [1]syscall.Kevent_t
-}
-
-func newpollster() (p *pollster, err error) {
- p = new(pollster)
- if p.kq, err = syscall.Kqueue(); err != nil {
- return nil, os.NewSyscallError("kqueue", err)
- }
- syscall.CloseOnExec(p.kq)
- p.events = p.eventbuf[0:0]
- return p, nil
-}
-
-// First return value is whether the pollServer should be woken up.
-// This version always returns false.
-func (p *pollster) AddFD(fd int, mode int, repeat bool) (bool, error) {
- // pollServer is locked.
-
- var kmode int
- if mode == 'r' {
- kmode = syscall.EVFILT_READ
- } else {
- kmode = syscall.EVFILT_WRITE
- }
- ev := &p.kbuf[0]
- // EV_ADD - add event to kqueue list
- // EV_RECEIPT - generate fake EV_ERROR as result of add,
- // rather than waiting for real event
- // EV_ONESHOT - delete the event the first time it triggers
- flags := syscall.EV_ADD | syscall.EV_RECEIPT
- if !repeat {
- flags |= syscall.EV_ONESHOT
- }
- syscall.SetKevent(ev, fd, kmode, flags)
-
- n, err := syscall.Kevent(p.kq, p.kbuf[:], p.kbuf[:], nil)
- if err != nil {
- return false, os.NewSyscallError("kevent", err)
- }
- if n != 1 || (ev.Flags&syscall.EV_ERROR) == 0 || int(ev.Ident) != fd || int(ev.Filter) != kmode {
- return false, errors.New("kqueue phase error")
- }
- if ev.Data != 0 {
- return false, syscall.Errno(ev.Data)
- }
- return false, nil
-}
-
-// Return value is whether the pollServer should be woken up.
-// This version always returns false.
-func (p *pollster) DelFD(fd int, mode int) bool {
- // pollServer is locked.
-
- var kmode int
- if mode == 'r' {
- kmode = syscall.EVFILT_READ
- } else {
- kmode = syscall.EVFILT_WRITE
- }
- ev := &p.kbuf[0]
- // EV_DELETE - delete event from kqueue list
- // EV_RECEIPT - generate fake EV_ERROR as result of add,
- // rather than waiting for real event
- syscall.SetKevent(ev, fd, kmode, syscall.EV_DELETE|syscall.EV_RECEIPT)
- syscall.Kevent(p.kq, p.kbuf[0:], p.kbuf[0:], nil)
- return false
-}
-
-func (p *pollster) WaitFD(s *pollServer, nsec int64) (fd int, mode int, err error) {
- var t *syscall.Timespec
- for len(p.events) == 0 {
- if nsec > 0 {
- if t == nil {
- t = new(syscall.Timespec)
- }
- *t = syscall.NsecToTimespec(nsec)
- }
-
- s.Unlock()
- n, err := syscall.Kevent(p.kq, nil, p.eventbuf[:], t)
- s.Lock()
-
- if err != nil {
- if err == syscall.EINTR {
- continue
- }
- return -1, 0, os.NewSyscallError("kevent", nil)
- }
- if n == 0 {
- return -1, 0, nil
- }
- p.events = p.eventbuf[:n]
- }
- ev := &p.events[0]
- p.events = p.events[1:]
- fd = int(ev.Ident)
- if ev.Filter == syscall.EVFILT_READ {
- mode = 'r'
- } else {
- mode = 'w'
- }
- return fd, mode, nil
-}
-
-func (p *pollster) Close() error { return os.NewSyscallError("close", syscall.Close(p.kq)) }
diff --git a/src/pkg/net/fd_linux.go b/src/pkg/net/fd_linux.go
deleted file mode 100644
index 03679196d..000000000
--- a/src/pkg/net/fd_linux.go
+++ /dev/null
@@ -1,192 +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.
-
-// Waiting for FDs via epoll(7).
-
-package net
-
-import (
- "os"
- "syscall"
-)
-
-const (
- readFlags = syscall.EPOLLIN | syscall.EPOLLRDHUP
- writeFlags = syscall.EPOLLOUT
-)
-
-type pollster struct {
- epfd int
-
- // Events we're already waiting for
- // Must hold pollServer lock
- events map[int]uint32
-
- // An event buffer for EpollWait.
- // Used without a lock, may only be used by WaitFD.
- waitEventBuf [10]syscall.EpollEvent
- waitEvents []syscall.EpollEvent
-
- // An event buffer for EpollCtl, to avoid a malloc.
- // Must hold pollServer lock.
- ctlEvent syscall.EpollEvent
-}
-
-func newpollster() (p *pollster, err error) {
- p = new(pollster)
- if p.epfd, err = syscall.EpollCreate1(syscall.EPOLL_CLOEXEC); err != nil {
- if err != syscall.ENOSYS {
- return nil, os.NewSyscallError("epoll_create1", err)
- }
- // The arg to epoll_create is a hint to the kernel
- // about the number of FDs we will care about.
- // We don't know, and since 2.6.8 the kernel ignores it anyhow.
- if p.epfd, err = syscall.EpollCreate(16); err != nil {
- return nil, os.NewSyscallError("epoll_create", err)
- }
- syscall.CloseOnExec(p.epfd)
- }
- p.events = make(map[int]uint32)
- return p, nil
-}
-
-// First return value is whether the pollServer should be woken up.
-// This version always returns false.
-func (p *pollster) AddFD(fd int, mode int, repeat bool) (bool, error) {
- // pollServer is locked.
-
- var already bool
- p.ctlEvent.Fd = int32(fd)
- p.ctlEvent.Events, already = p.events[fd]
- if !repeat {
- p.ctlEvent.Events |= syscall.EPOLLONESHOT
- }
- if mode == 'r' {
- p.ctlEvent.Events |= readFlags
- } else {
- p.ctlEvent.Events |= writeFlags
- }
-
- var op int
- if already {
- op = syscall.EPOLL_CTL_MOD
- } else {
- op = syscall.EPOLL_CTL_ADD
- }
- if err := syscall.EpollCtl(p.epfd, op, fd, &p.ctlEvent); err != nil {
- return false, os.NewSyscallError("epoll_ctl", err)
- }
- p.events[fd] = p.ctlEvent.Events
- return false, nil
-}
-
-func (p *pollster) StopWaiting(fd int, bits uint) {
- // pollServer is locked.
-
- events, already := p.events[fd]
- if !already {
- // The fd returned by the kernel may have been
- // cancelled already; return silently.
- return
- }
-
- // If syscall.EPOLLONESHOT is not set, the wait
- // is a repeating wait, so don't change it.
- if events&syscall.EPOLLONESHOT == 0 {
- return
- }
-
- // Disable the given bits.
- // If we're still waiting for other events, modify the fd
- // event in the kernel. Otherwise, delete it.
- events &= ^uint32(bits)
- if int32(events)&^syscall.EPOLLONESHOT != 0 {
- p.ctlEvent.Fd = int32(fd)
- p.ctlEvent.Events = events
- if err := syscall.EpollCtl(p.epfd, syscall.EPOLL_CTL_MOD, fd, &p.ctlEvent); err != nil {
- print("Epoll modify fd=", fd, ": ", err.Error(), "\n")
- }
- p.events[fd] = events
- } else {
- if err := syscall.EpollCtl(p.epfd, syscall.EPOLL_CTL_DEL, fd, nil); err != nil {
- print("Epoll delete fd=", fd, ": ", err.Error(), "\n")
- }
- delete(p.events, fd)
- }
-}
-
-// Return value is whether the pollServer should be woken up.
-// This version always returns false.
-func (p *pollster) DelFD(fd int, mode int) bool {
- // pollServer is locked.
-
- if mode == 'r' {
- p.StopWaiting(fd, readFlags)
- } else {
- p.StopWaiting(fd, writeFlags)
- }
-
- // Discard any queued up events.
- i := 0
- for i < len(p.waitEvents) {
- if fd == int(p.waitEvents[i].Fd) {
- copy(p.waitEvents[i:], p.waitEvents[i+1:])
- p.waitEvents = p.waitEvents[:len(p.waitEvents)-1]
- } else {
- i++
- }
- }
- return false
-}
-
-func (p *pollster) WaitFD(s *pollServer, nsec int64) (fd int, mode int, err error) {
- for len(p.waitEvents) == 0 {
- var msec int = -1
- if nsec > 0 {
- msec = int((nsec + 1e6 - 1) / 1e6)
- }
-
- s.Unlock()
- n, err := syscall.EpollWait(p.epfd, p.waitEventBuf[0:], msec)
- s.Lock()
-
- if err != nil {
- if err == syscall.EAGAIN || err == syscall.EINTR {
- continue
- }
- return -1, 0, os.NewSyscallError("epoll_wait", err)
- }
- if n == 0 {
- return -1, 0, nil
- }
- p.waitEvents = p.waitEventBuf[0:n]
- }
-
- ev := &p.waitEvents[0]
- p.waitEvents = p.waitEvents[1:]
-
- fd = int(ev.Fd)
-
- if ev.Events&writeFlags != 0 {
- p.StopWaiting(fd, writeFlags)
- return fd, 'w', nil
- }
- if ev.Events&readFlags != 0 {
- p.StopWaiting(fd, readFlags)
- return fd, 'r', nil
- }
-
- // Other events are error conditions - wake whoever is waiting.
- events, _ := p.events[fd]
- if events&writeFlags != 0 {
- p.StopWaiting(fd, writeFlags)
- return fd, 'w', nil
- }
- p.StopWaiting(fd, readFlags)
- return fd, 'r', nil
-}
-
-func (p *pollster) Close() error {
- return os.NewSyscallError("close", syscall.Close(p.epfd))
-}
diff --git a/src/pkg/net/fd_plan9.go b/src/pkg/net/fd_plan9.go
index 169087999..e9527a374 100644
--- a/src/pkg/net/fd_plan9.go
+++ b/src/pkg/net/fd_plan9.go
@@ -23,10 +23,10 @@ var canCancelIO = true // used for testing current package
func sysInit() {
}
-func dialTimeout(net, addr string, timeout time.Duration) (Conn, error) {
+func resolveAndDial(net, addr string, localAddr Addr, deadline time.Time) (Conn, error) {
// On plan9, use the relatively inefficient
// goroutine-racing implementation.
- return dialTimeoutRace(net, addr, timeout)
+ return resolveAndDialChannel(net, addr, localAddr, deadline)
}
func newFD(proto, name string, ctl, data *os.File, laddr, raddr Addr) *netFD {
diff --git a/src/pkg/net/fd_poll_runtime.go b/src/pkg/net/fd_poll_runtime.go
new file mode 100644
index 000000000..e3b4f7e46
--- /dev/null
+++ b/src/pkg/net/fd_poll_runtime.go
@@ -0,0 +1,119 @@
+// 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 linux
+
+package net
+
+import (
+ "sync"
+ "syscall"
+ "time"
+)
+
+func runtime_pollServerInit()
+func runtime_pollOpen(fd int) (uintptr, int)
+func runtime_pollClose(ctx uintptr)
+func runtime_pollWait(ctx uintptr, mode int) int
+func runtime_pollReset(ctx uintptr, mode int) int
+func runtime_pollSetDeadline(ctx uintptr, d int64, mode int)
+func runtime_pollUnblock(ctx uintptr)
+
+var canCancelIO = true // used for testing current package
+
+type pollDesc struct {
+ runtimeCtx uintptr
+}
+
+var serverInit sync.Once
+
+func sysInit() {
+}
+
+func (pd *pollDesc) Init(fd *netFD) error {
+ serverInit.Do(runtime_pollServerInit)
+ ctx, errno := runtime_pollOpen(fd.sysfd)
+ if errno != 0 {
+ return syscall.Errno(errno)
+ }
+ pd.runtimeCtx = ctx
+ return nil
+}
+
+func (pd *pollDesc) Close() {
+ runtime_pollClose(pd.runtimeCtx)
+}
+
+func (pd *pollDesc) Lock() {
+}
+
+func (pd *pollDesc) Unlock() {
+}
+
+func (pd *pollDesc) Wakeup() {
+}
+
+// Evict evicts fd from the pending list, unblocking any I/O running on fd.
+// Return value is whether the pollServer should be woken up.
+func (pd *pollDesc) Evict() bool {
+ runtime_pollUnblock(pd.runtimeCtx)
+ return false
+}
+
+func (pd *pollDesc) PrepareRead() error {
+ res := runtime_pollReset(pd.runtimeCtx, 'r')
+ return convertErr(res)
+}
+
+func (pd *pollDesc) PrepareWrite() error {
+ res := runtime_pollReset(pd.runtimeCtx, 'w')
+ return convertErr(res)
+}
+
+func (pd *pollDesc) WaitRead() error {
+ res := runtime_pollWait(pd.runtimeCtx, 'r')
+ return convertErr(res)
+}
+
+func (pd *pollDesc) WaitWrite() error {
+ res := runtime_pollWait(pd.runtimeCtx, 'w')
+ return convertErr(res)
+}
+
+func convertErr(res int) error {
+ switch res {
+ case 0:
+ return nil
+ case 1:
+ return errClosing
+ case 2:
+ return errTimeout
+ }
+ panic("unreachable")
+}
+
+func setReadDeadline(fd *netFD, t time.Time) error {
+ return setDeadlineImpl(fd, t, 'r')
+}
+
+func setWriteDeadline(fd *netFD, t time.Time) error {
+ return setDeadlineImpl(fd, t, 'w')
+}
+
+func setDeadline(fd *netFD, t time.Time) error {
+ return setDeadlineImpl(fd, t, 'r'+'w')
+}
+
+func setDeadlineImpl(fd *netFD, t time.Time, mode int) error {
+ d := t.UnixNano()
+ if t.IsZero() {
+ d = 0
+ }
+ if err := fd.incref(false); err != nil {
+ return err
+ }
+ runtime_pollSetDeadline(fd.pd.runtimeCtx, d, mode)
+ fd.decref()
+ return nil
+}
diff --git a/src/pkg/net/fd_poll_unix.go b/src/pkg/net/fd_poll_unix.go
new file mode 100644
index 000000000..307e577e9
--- /dev/null
+++ b/src/pkg/net/fd_poll_unix.go
@@ -0,0 +1,360 @@
+// 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 freebsd netbsd openbsd
+
+package net
+
+import (
+ "os"
+ "runtime"
+ "sync"
+ "syscall"
+ "time"
+)
+
+// A pollServer helps FDs determine when to retry a non-blocking
+// read or write after they get EAGAIN. When an FD needs to wait,
+// call s.WaitRead() or s.WaitWrite() to pass the request to the poll server.
+// When the pollServer finds that i/o on FD should be possible
+// again, it will send on fd.cr/fd.cw to wake any waiting goroutines.
+//
+// To avoid races in closing, all fd operations are locked and
+// refcounted. when netFD.Close() is called, it calls syscall.Shutdown
+// and sets a closing flag. Only when the last reference is removed
+// will the fd be closed.
+
+type pollServer struct {
+ pr, pw *os.File
+ poll *pollster // low-level OS hooks
+ sync.Mutex // controls pending and deadline
+ pending map[int]*pollDesc
+ deadline int64 // next deadline (nsec since 1970)
+}
+
+// A pollDesc contains netFD state related to pollServer.
+type pollDesc struct {
+ // immutable after Init()
+ pollServer *pollServer
+ sysfd int
+ cr, cw chan error
+
+ // mutable, protected by pollServer mutex
+ closing bool
+ ncr, ncw int
+
+ // mutable, safe for concurrent access
+ rdeadline, wdeadline deadline
+}
+
+func newPollServer() (s *pollServer, err error) {
+ s = new(pollServer)
+ if s.pr, s.pw, err = os.Pipe(); err != nil {
+ return nil, err
+ }
+ if err = syscall.SetNonblock(int(s.pr.Fd()), true); err != nil {
+ goto Errno
+ }
+ if err = syscall.SetNonblock(int(s.pw.Fd()), true); err != nil {
+ goto Errno
+ }
+ if s.poll, err = newpollster(); err != nil {
+ goto Error
+ }
+ if _, err = s.poll.AddFD(int(s.pr.Fd()), 'r', true); err != nil {
+ s.poll.Close()
+ goto Error
+ }
+ s.pending = make(map[int]*pollDesc)
+ go s.Run()
+ return s, nil
+
+Errno:
+ err = &os.PathError{
+ Op: "setnonblock",
+ Path: s.pr.Name(),
+ Err: err,
+ }
+Error:
+ s.pr.Close()
+ s.pw.Close()
+ return nil, err
+}
+
+func (s *pollServer) AddFD(pd *pollDesc, mode int) error {
+ s.Lock()
+ intfd := pd.sysfd
+ if intfd < 0 || pd.closing {
+ // fd closed underfoot
+ s.Unlock()
+ return errClosing
+ }
+
+ var t int64
+ key := intfd << 1
+ if mode == 'r' {
+ pd.ncr++
+ t = pd.rdeadline.value()
+ } else {
+ pd.ncw++
+ key++
+ t = pd.wdeadline.value()
+ }
+ s.pending[key] = pd
+ doWakeup := false
+ if t > 0 && (s.deadline == 0 || t < s.deadline) {
+ s.deadline = t
+ doWakeup = true
+ }
+
+ wake, err := s.poll.AddFD(intfd, mode, false)
+ s.Unlock()
+ if err != nil {
+ return err
+ }
+ if wake || doWakeup {
+ s.Wakeup()
+ }
+ return nil
+}
+
+// Evict evicts pd from the pending list, unblocking
+// any I/O running on pd. The caller must have locked
+// pollserver.
+// Return value is whether the pollServer should be woken up.
+func (s *pollServer) Evict(pd *pollDesc) bool {
+ pd.closing = true
+ doWakeup := false
+ if s.pending[pd.sysfd<<1] == pd {
+ s.WakeFD(pd, 'r', errClosing)
+ if s.poll.DelFD(pd.sysfd, 'r') {
+ doWakeup = true
+ }
+ delete(s.pending, pd.sysfd<<1)
+ }
+ if s.pending[pd.sysfd<<1|1] == pd {
+ s.WakeFD(pd, 'w', errClosing)
+ if s.poll.DelFD(pd.sysfd, 'w') {
+ doWakeup = true
+ }
+ delete(s.pending, pd.sysfd<<1|1)
+ }
+ return doWakeup
+}
+
+var wakeupbuf [1]byte
+
+func (s *pollServer) Wakeup() { s.pw.Write(wakeupbuf[0:]) }
+
+func (s *pollServer) LookupFD(fd int, mode int) *pollDesc {
+ key := fd << 1
+ if mode == 'w' {
+ key++
+ }
+ netfd, ok := s.pending[key]
+ if !ok {
+ return nil
+ }
+ delete(s.pending, key)
+ return netfd
+}
+
+func (s *pollServer) WakeFD(pd *pollDesc, mode int, err error) {
+ if mode == 'r' {
+ for pd.ncr > 0 {
+ pd.ncr--
+ pd.cr <- err
+ }
+ } else {
+ for pd.ncw > 0 {
+ pd.ncw--
+ pd.cw <- err
+ }
+ }
+}
+
+func (s *pollServer) CheckDeadlines() {
+ now := time.Now().UnixNano()
+ // TODO(rsc): This will need to be handled more efficiently,
+ // probably with a heap indexed by wakeup time.
+
+ var nextDeadline int64
+ for key, pd := range s.pending {
+ var t int64
+ var mode int
+ if key&1 == 0 {
+ mode = 'r'
+ } else {
+ mode = 'w'
+ }
+ if mode == 'r' {
+ t = pd.rdeadline.value()
+ } else {
+ t = pd.wdeadline.value()
+ }
+ if t > 0 {
+ if t <= now {
+ delete(s.pending, key)
+ s.poll.DelFD(pd.sysfd, mode)
+ s.WakeFD(pd, mode, errTimeout)
+ } else if nextDeadline == 0 || t < nextDeadline {
+ nextDeadline = t
+ }
+ }
+ }
+ s.deadline = nextDeadline
+}
+
+func (s *pollServer) Run() {
+ var scratch [100]byte
+ s.Lock()
+ defer s.Unlock()
+ for {
+ var timeout int64 // nsec to wait for or 0 for none
+ if s.deadline > 0 {
+ timeout = s.deadline - time.Now().UnixNano()
+ if timeout <= 0 {
+ s.CheckDeadlines()
+ continue
+ }
+ }
+ fd, mode, err := s.poll.WaitFD(s, timeout)
+ if err != nil {
+ print("pollServer WaitFD: ", err.Error(), "\n")
+ return
+ }
+ if fd < 0 {
+ // Timeout happened.
+ s.CheckDeadlines()
+ continue
+ }
+ if fd == int(s.pr.Fd()) {
+ // Drain our wakeup pipe (we could loop here,
+ // but it's unlikely that there are more than
+ // len(scratch) wakeup calls).
+ s.pr.Read(scratch[0:])
+ s.CheckDeadlines()
+ } else {
+ pd := s.LookupFD(fd, mode)
+ if pd == nil {
+ // This can happen because the WaitFD runs without
+ // holding s's lock, so there might be a pending wakeup
+ // for an fd that has been evicted. No harm done.
+ continue
+ }
+ s.WakeFD(pd, mode, nil)
+ }
+ }
+}
+
+func (pd *pollDesc) Close() {
+}
+
+func (pd *pollDesc) Lock() {
+ pd.pollServer.Lock()
+}
+
+func (pd *pollDesc) Unlock() {
+ pd.pollServer.Unlock()
+}
+
+func (pd *pollDesc) Wakeup() {
+ pd.pollServer.Wakeup()
+}
+
+func (pd *pollDesc) PrepareRead() error {
+ if pd.rdeadline.expired() {
+ return errTimeout
+ }
+ return nil
+}
+
+func (pd *pollDesc) PrepareWrite() error {
+ if pd.wdeadline.expired() {
+ return errTimeout
+ }
+ return nil
+}
+
+func (pd *pollDesc) WaitRead() error {
+ err := pd.pollServer.AddFD(pd, 'r')
+ if err == nil {
+ err = <-pd.cr
+ }
+ return err
+}
+
+func (pd *pollDesc) WaitWrite() error {
+ err := pd.pollServer.AddFD(pd, 'w')
+ if err == nil {
+ err = <-pd.cw
+ }
+ return err
+}
+
+func (pd *pollDesc) Evict() bool {
+ return pd.pollServer.Evict(pd)
+}
+
+// Spread network FDs over several pollServers.
+
+var pollMaxN int
+var pollservers []*pollServer
+var startServersOnce []func()
+
+var canCancelIO = true // used for testing current package
+
+func sysInit() {
+ pollMaxN = runtime.NumCPU()
+ if pollMaxN > 8 {
+ pollMaxN = 8 // No improvement then.
+ }
+ pollservers = make([]*pollServer, pollMaxN)
+ startServersOnce = make([]func(), pollMaxN)
+ for i := 0; i < pollMaxN; i++ {
+ k := i
+ once := new(sync.Once)
+ startServersOnce[i] = func() { once.Do(func() { startServer(k) }) }
+ }
+}
+
+func startServer(k int) {
+ p, err := newPollServer()
+ if err != nil {
+ panic(err)
+ }
+ pollservers[k] = p
+}
+
+func (pd *pollDesc) Init(fd *netFD) error {
+ pollN := runtime.GOMAXPROCS(0)
+ if pollN > pollMaxN {
+ pollN = pollMaxN
+ }
+ k := fd.sysfd % pollN
+ startServersOnce[k]()
+ pd.sysfd = fd.sysfd
+ pd.pollServer = pollservers[k]
+ pd.cr = make(chan error, 1)
+ pd.cw = make(chan error, 1)
+ return nil
+}
+
+// TODO(dfc) these unused error returns could be removed
+
+func setReadDeadline(fd *netFD, t time.Time) error {
+ fd.pd.rdeadline.setTime(t)
+ return nil
+}
+
+func setWriteDeadline(fd *netFD, t time.Time) error {
+ fd.pd.wdeadline.setTime(t)
+ return nil
+}
+
+func setDeadline(fd *netFD, t time.Time) error {
+ setReadDeadline(fd, t)
+ setWriteDeadline(fd, t)
+ return nil
+}
diff --git a/src/pkg/net/fd_unix.go b/src/pkg/net/fd_unix.go
index 0540df825..8c59bff98 100644
--- a/src/pkg/net/fd_unix.go
+++ b/src/pkg/net/fd_unix.go
@@ -9,7 +9,6 @@ package net
import (
"io"
"os"
- "runtime"
"sync"
"syscall"
"time"
@@ -21,7 +20,7 @@ type netFD struct {
sysmu sync.Mutex
sysref int
- // must lock both sysmu and pollserver to write
+ // must lock both sysmu and pollDesc to write
// can lock either to read
closing bool
@@ -31,8 +30,6 @@ type netFD struct {
sotype int
isConnected bool
sysfile *os.File
- cr chan error
- cw chan error
net string
laddr Addr
raddr Addr
@@ -40,264 +37,16 @@ type netFD struct {
// serialize access to Read and Write methods
rio, wio sync.Mutex
- // read and write deadlines
- rdeadline, wdeadline deadline
-
- // owned by fd wait server
- ncr, ncw int
-
// wait server
- pollServer *pollServer
-}
-
-// A pollServer helps FDs determine when to retry a non-blocking
-// read or write after they get EAGAIN. When an FD needs to wait,
-// call s.WaitRead() or s.WaitWrite() to pass the request to the poll server.
-// When the pollServer finds that i/o on FD should be possible
-// again, it will send on fd.cr/fd.cw to wake any waiting goroutines.
-//
-// To avoid races in closing, all fd operations are locked and
-// refcounted. when netFD.Close() is called, it calls syscall.Shutdown
-// and sets a closing flag. Only when the last reference is removed
-// will the fd be closed.
-
-type pollServer struct {
- pr, pw *os.File
- poll *pollster // low-level OS hooks
- sync.Mutex // controls pending and deadline
- pending map[int]*netFD
- deadline int64 // next deadline (nsec since 1970)
-}
-
-func (s *pollServer) AddFD(fd *netFD, mode int) error {
- s.Lock()
- intfd := fd.sysfd
- if intfd < 0 || fd.closing {
- // fd closed underfoot
- s.Unlock()
- return errClosing
- }
-
- var t int64
- key := intfd << 1
- if mode == 'r' {
- fd.ncr++
- t = fd.rdeadline.value()
- } else {
- fd.ncw++
- key++
- t = fd.wdeadline.value()
- }
- s.pending[key] = fd
- doWakeup := false
- if t > 0 && (s.deadline == 0 || t < s.deadline) {
- s.deadline = t
- doWakeup = true
- }
-
- wake, err := s.poll.AddFD(intfd, mode, false)
- s.Unlock()
- if err != nil {
- return &OpError{"addfd", fd.net, fd.laddr, err}
- }
- if wake || doWakeup {
- s.Wakeup()
- }
- return nil
-}
-
-// Evict evicts fd from the pending list, unblocking
-// any I/O running on fd. The caller must have locked
-// pollserver.
-// Return value is whether the pollServer should be woken up.
-func (s *pollServer) Evict(fd *netFD) bool {
- doWakeup := false
- if s.pending[fd.sysfd<<1] == fd {
- s.WakeFD(fd, 'r', errClosing)
- if s.poll.DelFD(fd.sysfd, 'r') {
- doWakeup = true
- }
- delete(s.pending, fd.sysfd<<1)
- }
- if s.pending[fd.sysfd<<1|1] == fd {
- s.WakeFD(fd, 'w', errClosing)
- if s.poll.DelFD(fd.sysfd, 'w') {
- doWakeup = true
- }
- delete(s.pending, fd.sysfd<<1|1)
- }
- return doWakeup
-}
-
-var wakeupbuf [1]byte
-
-func (s *pollServer) Wakeup() { s.pw.Write(wakeupbuf[0:]) }
-
-func (s *pollServer) LookupFD(fd int, mode int) *netFD {
- key := fd << 1
- if mode == 'w' {
- key++
- }
- netfd, ok := s.pending[key]
- if !ok {
- return nil
- }
- delete(s.pending, key)
- return netfd
-}
-
-func (s *pollServer) WakeFD(fd *netFD, mode int, err error) {
- if mode == 'r' {
- for fd.ncr > 0 {
- fd.ncr--
- fd.cr <- err
- }
- } else {
- for fd.ncw > 0 {
- fd.ncw--
- fd.cw <- err
- }
- }
-}
-
-func (s *pollServer) CheckDeadlines() {
- now := time.Now().UnixNano()
- // TODO(rsc): This will need to be handled more efficiently,
- // probably with a heap indexed by wakeup time.
-
- var nextDeadline int64
- for key, fd := range s.pending {
- var t int64
- var mode int
- if key&1 == 0 {
- mode = 'r'
- } else {
- mode = 'w'
- }
- if mode == 'r' {
- t = fd.rdeadline.value()
- } else {
- t = fd.wdeadline.value()
- }
- if t > 0 {
- if t <= now {
- delete(s.pending, key)
- s.poll.DelFD(fd.sysfd, mode)
- s.WakeFD(fd, mode, errTimeout)
- } else if nextDeadline == 0 || t < nextDeadline {
- nextDeadline = t
- }
- }
- }
- s.deadline = nextDeadline
-}
-
-func (s *pollServer) Run() {
- var scratch [100]byte
- s.Lock()
- defer s.Unlock()
- for {
- var timeout int64 // nsec to wait for or 0 for none
- if s.deadline > 0 {
- timeout = s.deadline - time.Now().UnixNano()
- if timeout <= 0 {
- s.CheckDeadlines()
- continue
- }
- }
- fd, mode, err := s.poll.WaitFD(s, timeout)
- if err != nil {
- print("pollServer WaitFD: ", err.Error(), "\n")
- return
- }
- if fd < 0 {
- // Timeout happened.
- s.CheckDeadlines()
- continue
- }
- if fd == int(s.pr.Fd()) {
- // Drain our wakeup pipe (we could loop here,
- // but it's unlikely that there are more than
- // len(scratch) wakeup calls).
- s.pr.Read(scratch[0:])
- s.CheckDeadlines()
- } else {
- netfd := s.LookupFD(fd, mode)
- if netfd == nil {
- // This can happen because the WaitFD runs without
- // holding s's lock, so there might be a pending wakeup
- // for an fd that has been evicted. No harm done.
- continue
- }
- s.WakeFD(netfd, mode, nil)
- }
- }
+ pd pollDesc
}
-func (s *pollServer) WaitRead(fd *netFD) error {
- err := s.AddFD(fd, 'r')
- if err == nil {
- err = <-fd.cr
- }
- return err
-}
-
-func (s *pollServer) WaitWrite(fd *netFD) error {
- err := s.AddFD(fd, 'w')
- if err == nil {
- err = <-fd.cw
- }
- return err
-}
-
-// Network FD methods.
-// Spread network FDs over several pollServers.
-
-var pollMaxN int
-var pollservers []*pollServer
-var startServersOnce []func()
-
-var canCancelIO = true // used for testing current package
-
-func sysInit() {
- pollMaxN = runtime.NumCPU()
- if pollMaxN > 8 {
- pollMaxN = 8 // No improvement then.
- }
- pollservers = make([]*pollServer, pollMaxN)
- startServersOnce = make([]func(), pollMaxN)
- for i := 0; i < pollMaxN; i++ {
- k := i
- once := new(sync.Once)
- startServersOnce[i] = func() { once.Do(func() { startServer(k) }) }
- }
-}
-
-func startServer(k int) {
- p, err := newPollServer()
- if err != nil {
- panic(err)
- }
- pollservers[k] = p
-}
-
-func server(fd int) *pollServer {
- pollN := runtime.GOMAXPROCS(0)
- if pollN > pollMaxN {
- pollN = pollMaxN
- }
- k := fd % pollN
- startServersOnce[k]()
- return pollservers[k]
-}
-
-func dialTimeout(net, addr string, timeout time.Duration) (Conn, error) {
- deadline := time.Now().Add(timeout)
+func resolveAndDial(net, addr string, localAddr Addr, deadline time.Time) (Conn, error) {
ra, err := resolveAddr("dial", net, addr, deadline)
if err != nil {
return nil, err
}
- return dial(net, addr, noLocalAddr, ra, deadline)
+ return dial(net, addr, localAddr, ra, deadline)
}
func newFD(fd, family, sotype int, net string) (*netFD, error) {
@@ -307,9 +56,9 @@ func newFD(fd, family, sotype int, net string) (*netFD, error) {
sotype: sotype,
net: net,
}
- netfd.cr = make(chan error, 1)
- netfd.cw = make(chan error, 1)
- netfd.pollServer = server(fd)
+ if err := netfd.pd.Init(netfd); err != nil {
+ return nil, err
+ }
return netfd, nil
}
@@ -330,26 +79,29 @@ func (fd *netFD) name() string {
return fd.net + ":" + ls + "->" + rs
}
-func (fd *netFD) connect(ra syscall.Sockaddr) error {
- err := syscall.Connect(fd.sysfd, ra)
- if err == syscall.EINPROGRESS {
- if err = fd.pollServer.WaitWrite(fd); err != nil {
- return err
+func (fd *netFD) connect(la, ra syscall.Sockaddr) error {
+ fd.wio.Lock()
+ defer fd.wio.Unlock()
+ if err := fd.pd.PrepareWrite(); err != nil {
+ return err
+ }
+ for {
+ err := syscall.Connect(fd.sysfd, ra)
+ if err == nil || err == syscall.EISCONN {
+ break
}
- var e int
- e, err = syscall.GetsockoptInt(fd.sysfd, syscall.SOL_SOCKET, syscall.SO_ERROR)
- if err != nil {
- return os.NewSyscallError("getsockopt", err)
+ if err != syscall.EINPROGRESS && err != syscall.EALREADY && err != syscall.EINTR {
+ return err
}
- if e != 0 {
- err = syscall.Errno(e)
+ if err = fd.pd.WaitWrite(); err != nil {
+ return err
}
}
- return err
+ return nil
}
// Add a reference to this fd.
-// If closing==true, pollserver must be locked; mark the fd as closing.
+// If closing==true, pollDesc must be locked; mark the fd as closing.
// Returns an error if the fd cannot be used.
func (fd *netFD) incref(closing bool) error {
fd.sysmu.Lock()
@@ -370,30 +122,37 @@ func (fd *netFD) incref(closing bool) error {
func (fd *netFD) decref() {
fd.sysmu.Lock()
fd.sysref--
- if fd.closing && fd.sysref == 0 && fd.sysfile != nil {
- fd.sysfile.Close()
- fd.sysfile = nil
+ if fd.closing && fd.sysref == 0 {
+ // Poller may want to unregister fd in readiness notification mechanism,
+ // so this must be executed before sysfile.Close().
+ fd.pd.Close()
+ if fd.sysfile != nil {
+ fd.sysfile.Close()
+ fd.sysfile = nil
+ } else {
+ closesocket(fd.sysfd)
+ }
fd.sysfd = -1
}
fd.sysmu.Unlock()
}
func (fd *netFD) Close() error {
- fd.pollServer.Lock() // needed for both fd.incref(true) and pollserver.Evict
+ fd.pd.Lock() // needed for both fd.incref(true) and pollDesc.Evict
if err := fd.incref(true); err != nil {
- fd.pollServer.Unlock()
+ fd.pd.Unlock()
return err
}
// 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
// fairly quickly, since all the I/O is non-blocking, and any
- // attempts to block in the pollserver will return errClosing.
- doWakeup := fd.pollServer.Evict(fd)
- fd.pollServer.Unlock()
+ // attempts to block in the pollDesc will return errClosing.
+ doWakeup := fd.pd.Evict()
+ fd.pd.Unlock()
fd.decref()
if doWakeup {
- fd.pollServer.Wakeup()
+ fd.pd.Wakeup()
}
return nil
}
@@ -425,16 +184,15 @@ func (fd *netFD) Read(p []byte) (n int, err error) {
return 0, err
}
defer fd.decref()
+ if err := fd.pd.PrepareRead(); err != nil {
+ return 0, &OpError{"read", fd.net, fd.raddr, err}
+ }
for {
- if fd.rdeadline.expired() {
- err = errTimeout
- break
- }
n, err = syscall.Read(int(fd.sysfd), p)
if err != nil {
n = 0
if err == syscall.EAGAIN {
- if err = fd.pollServer.WaitRead(fd); err == nil {
+ if err = fd.pd.WaitRead(); err == nil {
continue
}
}
@@ -455,16 +213,15 @@ func (fd *netFD) ReadFrom(p []byte) (n int, sa syscall.Sockaddr, err error) {
return 0, nil, err
}
defer fd.decref()
+ if err := fd.pd.PrepareRead(); err != nil {
+ return 0, nil, &OpError{"read", fd.net, fd.laddr, err}
+ }
for {
- if fd.rdeadline.expired() {
- err = errTimeout
- break
- }
n, sa, err = syscall.Recvfrom(fd.sysfd, p, 0)
if err != nil {
n = 0
if err == syscall.EAGAIN {
- if err = fd.pollServer.WaitRead(fd); err == nil {
+ if err = fd.pd.WaitRead(); err == nil {
continue
}
}
@@ -485,16 +242,15 @@ func (fd *netFD) ReadMsg(p []byte, oob []byte) (n, oobn, flags int, sa syscall.S
return 0, 0, 0, nil, err
}
defer fd.decref()
+ if err := fd.pd.PrepareRead(); err != nil {
+ return 0, 0, 0, nil, &OpError{"read", fd.net, fd.laddr, err}
+ }
for {
- if fd.rdeadline.expired() {
- err = errTimeout
- break
- }
n, oobn, flags, sa, err = syscall.Recvmsg(fd.sysfd, p, oob, 0)
if err != nil {
// TODO(dfc) should n and oobn be set to 0
if err == syscall.EAGAIN {
- if err = fd.pollServer.WaitRead(fd); err == nil {
+ if err = fd.pd.WaitRead(); err == nil {
continue
}
}
@@ -522,11 +278,10 @@ func (fd *netFD) Write(p []byte) (nn int, err error) {
return 0, err
}
defer fd.decref()
+ if err := fd.pd.PrepareWrite(); err != nil {
+ return 0, &OpError{"write", fd.net, fd.raddr, err}
+ }
for {
- if fd.wdeadline.expired() {
- err = errTimeout
- break
- }
var n int
n, err = syscall.Write(int(fd.sysfd), p[nn:])
if n > 0 {
@@ -536,7 +291,7 @@ func (fd *netFD) Write(p []byte) (nn int, err error) {
break
}
if err == syscall.EAGAIN {
- if err = fd.pollServer.WaitWrite(fd); err == nil {
+ if err = fd.pd.WaitWrite(); err == nil {
continue
}
}
@@ -562,14 +317,13 @@ func (fd *netFD) WriteTo(p []byte, sa syscall.Sockaddr) (n int, err error) {
return 0, err
}
defer fd.decref()
+ if err := fd.pd.PrepareWrite(); err != nil {
+ return 0, &OpError{"write", fd.net, fd.raddr, err}
+ }
for {
- if fd.wdeadline.expired() {
- err = errTimeout
- break
- }
err = syscall.Sendto(fd.sysfd, p, 0, sa)
if err == syscall.EAGAIN {
- if err = fd.pollServer.WaitWrite(fd); err == nil {
+ if err = fd.pd.WaitWrite(); err == nil {
continue
}
}
@@ -590,14 +344,13 @@ func (fd *netFD) WriteMsg(p []byte, oob []byte, sa syscall.Sockaddr) (n int, oob
return 0, 0, err
}
defer fd.decref()
+ if err := fd.pd.PrepareWrite(); err != nil {
+ return 0, 0, &OpError{"write", fd.net, fd.raddr, err}
+ }
for {
- if fd.wdeadline.expired() {
- err = errTimeout
- break
- }
err = syscall.Sendmsg(fd.sysfd, p, oob, sa, 0)
if err == syscall.EAGAIN {
- if err = fd.pollServer.WaitWrite(fd); err == nil {
+ if err = fd.pd.WaitWrite(); err == nil {
continue
}
}
@@ -613,6 +366,8 @@ func (fd *netFD) WriteMsg(p []byte, oob []byte, sa syscall.Sockaddr) (n int, oob
}
func (fd *netFD) accept(toAddr func(syscall.Sockaddr) Addr) (netfd *netFD, err error) {
+ fd.rio.Lock()
+ defer fd.rio.Unlock()
if err := fd.incref(false); err != nil {
return nil, err
}
@@ -620,11 +375,14 @@ func (fd *netFD) accept(toAddr func(syscall.Sockaddr) Addr) (netfd *netFD, err e
var s int
var rsa syscall.Sockaddr
+ if err = fd.pd.PrepareRead(); err != nil {
+ return nil, &OpError{"accept", fd.net, fd.laddr, err}
+ }
for {
s, rsa, err = accept(fd.sysfd)
if err != nil {
if err == syscall.EAGAIN {
- if err = fd.pollServer.WaitRead(fd); err == nil {
+ if err = fd.pd.WaitRead(); err == nil {
continue
}
} else if err == syscall.ECONNABORTED {
diff --git a/src/pkg/net/fd_windows.go b/src/pkg/net/fd_windows.go
index 0e331b44d..fefd174ba 100644
--- a/src/pkg/net/fd_windows.go
+++ b/src/pkg/net/fd_windows.go
@@ -54,18 +54,17 @@ func canUseConnectEx(net string) bool {
return syscall.LoadConnectEx() == nil
}
-func dialTimeout(net, addr string, timeout time.Duration) (Conn, error) {
+func resolveAndDial(net, addr string, localAddr Addr, deadline time.Time) (Conn, error) {
if !canUseConnectEx(net) {
// Use the relatively inefficient goroutine-racing
// implementation of DialTimeout.
- return dialTimeoutRace(net, addr, timeout)
+ return resolveAndDialChannel(net, addr, localAddr, deadline)
}
- deadline := time.Now().Add(timeout)
ra, err := resolveAddr("dial", net, addr, deadline)
if err != nil {
return nil, err
}
- return dial(net, addr, noLocalAddr, ra, deadline)
+ return dial(net, addr, localAddr, ra, deadline)
}
// Interface for all IO operations.
@@ -138,12 +137,18 @@ type resultSrv struct {
iocp syscall.Handle
}
+func runtime_blockingSyscallHint()
+
func (s *resultSrv) Run() {
var o *syscall.Overlapped
var key uint32
var r ioResult
for {
- r.err = syscall.GetQueuedCompletionStatus(s.iocp, &(r.qty), &key, &o, syscall.INFINITE)
+ r.err = syscall.GetQueuedCompletionStatus(s.iocp, &(r.qty), &key, &o, 0)
+ if r.err == syscall.Errno(syscall.WAIT_TIMEOUT) && o == nil {
+ runtime_blockingSyscallHint()
+ r.err = syscall.GetQueuedCompletionStatus(s.iocp, &(r.qty), &key, &o, syscall.INFINITE)
+ }
switch {
case r.err == nil:
// Dequeued successfully completed IO packet.
@@ -359,22 +364,23 @@ func (o *connectOp) Name() string {
return "ConnectEx"
}
-func (fd *netFD) connect(ra syscall.Sockaddr) error {
+func (fd *netFD) connect(la, ra syscall.Sockaddr) error {
if !canUseConnectEx(fd.net) {
return syscall.Connect(fd.sysfd, ra)
}
// ConnectEx windows API requires an unconnected, previously bound socket.
- var la syscall.Sockaddr
- switch ra.(type) {
- case *syscall.SockaddrInet4:
- la = &syscall.SockaddrInet4{}
- case *syscall.SockaddrInet6:
- la = &syscall.SockaddrInet6{}
- default:
- panic("unexpected type in connect")
- }
- if err := syscall.Bind(fd.sysfd, la); err != nil {
- return err
+ if la == nil {
+ switch ra.(type) {
+ case *syscall.SockaddrInet4:
+ la = &syscall.SockaddrInet4{}
+ case *syscall.SockaddrInet6:
+ la = &syscall.SockaddrInet6{}
+ default:
+ panic("unexpected type in connect")
+ }
+ if err := syscall.Bind(fd.sysfd, la); err != nil {
+ return err
+ }
}
// Call ConnectEx API.
var o connectOp
diff --git a/src/pkg/net/file_windows.go b/src/pkg/net/file_windows.go
index c50c32e21..ca2b9b226 100644
--- a/src/pkg/net/file_windows.go
+++ b/src/pkg/net/file_windows.go
@@ -9,16 +9,28 @@ import (
"syscall"
)
+// FileConn returns a copy of the network connection corresponding to
+// the open file f. It is the caller's responsibility to close f when
+// finished. Closing c does not affect f, and closing f does not
+// affect c.
func FileConn(f *os.File) (c Conn, err error) {
// TODO: Implement this
return nil, os.NewSyscallError("FileConn", syscall.EWINDOWS)
}
+// FileListener returns a copy of the network listener corresponding
+// to the open file f. It is the caller's responsibility to close l
+// when finished. Closing l does not affect f, and closing f does not
+// affect l.
func FileListener(f *os.File) (l Listener, err error) {
// TODO: Implement this
return nil, os.NewSyscallError("FileListener", syscall.EWINDOWS)
}
+// FilePacketConn returns a copy of the packet network connection
+// corresponding to the open file f. It is the caller's
+// responsibility to close f when finished. Closing c does not affect
+// f, and closing f does not affect c.
func FilePacketConn(f *os.File) (c PacketConn, err error) {
// TODO: Implement this
return nil, os.NewSyscallError("FilePacketConn", syscall.EWINDOWS)
diff --git a/src/pkg/net/http/client.go b/src/pkg/net/http/client.go
index 5ee0804c7..a34d47be1 100644
--- a/src/pkg/net/http/client.go
+++ b/src/pkg/net/http/client.go
@@ -19,12 +19,16 @@ import (
"strings"
)
-// A Client is an HTTP client. Its zero value (DefaultClient) is a usable client
-// that uses DefaultTransport.
+// A Client is an HTTP client. Its zero value (DefaultClient) is a
+// usable client that uses DefaultTransport.
//
-// The Client's Transport typically has internal state (cached
-// TCP connections), so Clients should be reused instead of created as
+// The Client's Transport typically has internal state (cached TCP
+// connections), so Clients should be reused instead of created as
// needed. Clients are safe for concurrent use by multiple goroutines.
+//
+// A Client is higher-level than a RoundTripper (such as Transport)
+// and additionally handles HTTP details such as cookies and
+// redirects.
type Client struct {
// Transport specifies the mechanism by which individual
// HTTP requests are made.
diff --git a/src/pkg/net/http/client_test.go b/src/pkg/net/http/client_test.go
index 88649bb16..73f1fe3c1 100644
--- a/src/pkg/net/http/client_test.go
+++ b/src/pkg/net/http/client_test.go
@@ -51,11 +51,10 @@ func pedanticReadAll(r io.Reader) (b []byte, err error) {
return b, err
}
}
- panic("unreachable")
}
func TestClient(t *testing.T) {
- defer checkLeakedTransports(t)
+ defer afterTest(t)
ts := httptest.NewServer(robotsTxtHandler)
defer ts.Close()
@@ -73,7 +72,7 @@ func TestClient(t *testing.T) {
}
func TestClientHead(t *testing.T) {
- defer checkLeakedTransports(t)
+ defer afterTest(t)
ts := httptest.NewServer(robotsTxtHandler)
defer ts.Close()
@@ -96,7 +95,7 @@ func (t *recordingTransport) RoundTrip(req *Request) (resp *Response, err error)
}
func TestGetRequestFormat(t *testing.T) {
- defer checkLeakedTransports(t)
+ defer afterTest(t)
tr := &recordingTransport{}
client := &Client{Transport: tr}
url := "http://dummy.faketld/"
@@ -113,7 +112,7 @@ func TestGetRequestFormat(t *testing.T) {
}
func TestPostRequestFormat(t *testing.T) {
- defer checkLeakedTransports(t)
+ defer afterTest(t)
tr := &recordingTransport{}
client := &Client{Transport: tr}
@@ -140,7 +139,7 @@ func TestPostRequestFormat(t *testing.T) {
}
func TestPostFormRequestFormat(t *testing.T) {
- defer checkLeakedTransports(t)
+ defer afterTest(t)
tr := &recordingTransport{}
client := &Client{Transport: tr}
@@ -181,8 +180,8 @@ func TestPostFormRequestFormat(t *testing.T) {
}
}
-func TestRedirects(t *testing.T) {
- defer checkLeakedTransports(t)
+func TestClientRedirects(t *testing.T) {
+ defer afterTest(t)
var ts *httptest.Server
ts = httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) {
n, _ := strconv.Atoi(r.FormValue("n"))
@@ -256,7 +255,7 @@ func TestRedirects(t *testing.T) {
}
func TestPostRedirects(t *testing.T) {
- defer checkLeakedTransports(t)
+ defer afterTest(t)
var log struct {
sync.Mutex
bytes.Buffer
@@ -374,7 +373,7 @@ func (j *TestJar) Cookies(u *url.URL) []*Cookie {
}
func TestRedirectCookiesOnRequest(t *testing.T) {
- defer checkLeakedTransports(t)
+ defer afterTest(t)
var ts *httptest.Server
ts = httptest.NewServer(echoCookiesRedirectHandler)
defer ts.Close()
@@ -392,7 +391,7 @@ func TestRedirectCookiesOnRequest(t *testing.T) {
}
func TestRedirectCookiesJar(t *testing.T) {
- defer checkLeakedTransports(t)
+ defer afterTest(t)
var ts *httptest.Server
ts = httptest.NewServer(echoCookiesRedirectHandler)
defer ts.Close()
@@ -429,7 +428,7 @@ func matchReturnedCookies(t *testing.T, expected, given []*Cookie) {
}
func TestJarCalls(t *testing.T) {
- defer checkLeakedTransports(t)
+ defer afterTest(t)
ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) {
pathSuffix := r.RequestURI[1:]
if r.RequestURI == "/nosetcookie" {
@@ -493,7 +492,7 @@ func (j *RecordingJar) logf(format string, args ...interface{}) {
}
func TestStreamingGet(t *testing.T) {
- defer checkLeakedTransports(t)
+ defer afterTest(t)
say := make(chan string)
ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) {
w.(Flusher).Flush()
@@ -544,7 +543,7 @@ func (c *writeCountingConn) Write(p []byte) (int, error) {
// TestClientWrites verifies that client requests are buffered and we
// don't send a TCP packet per line of the http request + body.
func TestClientWrites(t *testing.T) {
- defer checkLeakedTransports(t)
+ defer afterTest(t)
ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) {
}))
defer ts.Close()
@@ -578,7 +577,7 @@ func TestClientWrites(t *testing.T) {
}
func TestClientInsecureTransport(t *testing.T) {
- defer checkLeakedTransports(t)
+ defer afterTest(t)
ts := httptest.NewTLSServer(HandlerFunc(func(w ResponseWriter, r *Request) {
w.Write([]byte("Hello"))
}))
@@ -606,7 +605,7 @@ func TestClientInsecureTransport(t *testing.T) {
}
func TestClientErrorWithRequestURI(t *testing.T) {
- defer checkLeakedTransports(t)
+ defer afterTest(t)
req, _ := NewRequest("GET", "http://localhost:1234/", nil)
req.RequestURI = "/this/field/is/illegal/and/should/error/"
_, err := DefaultClient.Do(req)
@@ -635,7 +634,7 @@ func newTLSTransport(t *testing.T, ts *httptest.Server) *Transport {
}
func TestClientWithCorrectTLSServerName(t *testing.T) {
- defer checkLeakedTransports(t)
+ defer afterTest(t)
ts := httptest.NewTLSServer(HandlerFunc(func(w ResponseWriter, r *Request) {
if r.TLS.ServerName != "127.0.0.1" {
t.Errorf("expected client to set ServerName 127.0.0.1, got: %q", r.TLS.ServerName)
@@ -650,7 +649,7 @@ func TestClientWithCorrectTLSServerName(t *testing.T) {
}
func TestClientWithIncorrectTLSServerName(t *testing.T) {
- defer checkLeakedTransports(t)
+ defer afterTest(t)
ts := httptest.NewTLSServer(HandlerFunc(func(w ResponseWriter, r *Request) {}))
defer ts.Close()
@@ -668,7 +667,7 @@ func TestClientWithIncorrectTLSServerName(t *testing.T) {
// Verify Response.ContentLength is populated. http://golang.org/issue/4126
func TestClientHeadContentLength(t *testing.T) {
- defer checkLeakedTransports(t)
+ defer afterTest(t)
ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) {
if v := r.FormValue("cl"); v != "" {
w.Header().Set("Content-Length", v)
diff --git a/src/pkg/net/http/cookiejar/jar.go b/src/pkg/net/http/cookiejar/jar.go
index 5d1aeb87f..5977d48b6 100644
--- a/src/pkg/net/http/cookiejar/jar.go
+++ b/src/pkg/net/http/cookiejar/jar.go
@@ -28,6 +28,9 @@ import (
// An implementation that always returns "" is valid and may be useful for
// testing but it is not secure: it means that the HTTP server for foo.com can
// set a cookie for bar.com.
+//
+// A public suffix list implementation is in the package
+// code.google.com/p/go.net/publicsuffix.
type PublicSuffixList interface {
// PublicSuffix returns the public suffix of domain.
//
diff --git a/src/pkg/net/http/example_test.go b/src/pkg/net/http/example_test.go
index 22073eaf7..bc60df7f2 100644
--- a/src/pkg/net/http/example_test.go
+++ b/src/pkg/net/http/example_test.go
@@ -51,6 +51,20 @@ func ExampleGet() {
}
func ExampleFileServer() {
- // we use StripPrefix so that /tmpfiles/somefile will access /tmp/somefile
+ // Simple static webserver:
+ log.Fatal(http.ListenAndServe(":8080", http.FileServer(http.Dir("/usr/share/doc"))))
+}
+
+func ExampleFileServer_stripPrefix() {
+ // To serve a directory on disk (/tmp) under an alternate URL
+ // path (/tmpfiles/), use StripPrefix to modify the request
+ // URL's path before the FileServer sees it:
+ http.Handle("/tmpfiles/", http.StripPrefix("/tmpfiles/", http.FileServer(http.Dir("/tmp"))))
+}
+
+func ExampleStripPrefix() {
+ // To serve a directory on disk (/tmp) under an alternate URL
+ // path (/tmpfiles/), use StripPrefix to modify the request
+ // URL's path before the FileServer sees it:
http.Handle("/tmpfiles/", http.StripPrefix("/tmpfiles/", http.FileServer(http.Dir("/tmp"))))
}
diff --git a/src/pkg/net/http/export_test.go b/src/pkg/net/http/export_test.go
index a7bca20a0..3fc245326 100644
--- a/src/pkg/net/http/export_test.go
+++ b/src/pkg/net/http/export_test.go
@@ -54,3 +54,5 @@ func NewTestTimeoutHandler(handler Handler, ch <-chan time.Time) Handler {
}
return &timeoutHandler{handler, f, ""}
}
+
+var DefaultUserAgent = defaultUserAgent
diff --git a/src/pkg/net/http/fcgi/child.go b/src/pkg/net/http/fcgi/child.go
index c8b9a33c8..60b794e07 100644
--- a/src/pkg/net/http/fcgi/child.go
+++ b/src/pkg/net/http/fcgi/child.go
@@ -10,10 +10,12 @@ import (
"errors"
"fmt"
"io"
+ "io/ioutil"
"net"
"net/http"
"net/http/cgi"
"os"
+ "strings"
"time"
)
@@ -152,20 +154,23 @@ func (c *child) serve() {
var errCloseConn = errors.New("fcgi: connection should be closed")
+var emptyBody = ioutil.NopCloser(strings.NewReader(""))
+
func (c *child) handleRecord(rec *record) error {
req, ok := c.requests[rec.h.Id]
if !ok && rec.h.Type != typeBeginRequest && rec.h.Type != typeGetValues {
// The spec says to ignore unknown request IDs.
return nil
}
- if ok && rec.h.Type == typeBeginRequest {
- // The server is trying to begin a request with the same ID
- // as an in-progress request. This is an error.
- return errors.New("fcgi: received ID that is already in-flight")
- }
switch rec.h.Type {
case typeBeginRequest:
+ if req != nil {
+ // The server is trying to begin a request with the same ID
+ // as an in-progress request. This is an error.
+ return errors.New("fcgi: received ID that is already in-flight")
+ }
+
var br beginRequest
if err := br.read(rec.content()); err != nil {
return err
@@ -175,6 +180,7 @@ func (c *child) handleRecord(rec *record) error {
return nil
}
c.requests[rec.h.Id] = newRequest(rec.h.Id, br.flags)
+ return nil
case typeParams:
// NOTE(eds): Technically a key-value pair can straddle the boundary
// between two packets. We buffer until we've received all parameters.
@@ -183,6 +189,7 @@ func (c *child) handleRecord(rec *record) error {
return nil
}
req.parseParams()
+ return nil
case typeStdin:
content := rec.content()
if req.pw == nil {
@@ -191,6 +198,8 @@ func (c *child) handleRecord(rec *record) error {
// body could be an io.LimitReader, but it shouldn't matter
// as long as both sides are behaving.
body, req.pw = io.Pipe()
+ } else {
+ body = emptyBody
}
go c.serveRequest(req, body)
}
@@ -201,24 +210,29 @@ func (c *child) handleRecord(rec *record) error {
} else if req.pw != nil {
req.pw.Close()
}
+ return nil
case typeGetValues:
values := map[string]string{"FCGI_MPXS_CONNS": "1"}
c.conn.writePairs(typeGetValuesResult, 0, values)
+ return nil
case typeData:
// If the filter role is implemented, read the data stream here.
+ return nil
case typeAbortRequest:
+ println("abort")
delete(c.requests, rec.h.Id)
c.conn.writeEndRequest(rec.h.Id, 0, statusRequestComplete)
if !req.keepConn {
// connection will close upon return
return errCloseConn
}
+ return nil
default:
b := make([]byte, 8)
b[0] = byte(rec.h.Type)
c.conn.writeRecord(typeUnknownType, 0, b)
+ return nil
}
- return nil
}
func (c *child) serveRequest(req *request, body io.ReadCloser) {
@@ -232,11 +246,19 @@ func (c *child) serveRequest(req *request, body io.ReadCloser) {
httpReq.Body = body
c.handler.ServeHTTP(r, httpReq)
}
- if body != nil {
- body.Close()
- }
r.Close()
c.conn.writeEndRequest(req.reqId, 0, statusRequestComplete)
+
+ // Consume the entire body, so the host isn't still writing to
+ // us when we close the socket below in the !keepConn case,
+ // otherwise we'd send a RST. (golang.org/issue/4183)
+ // TODO(bradfitz): also bound this copy in time. Or send
+ // some sort of abort request to the host, so the host
+ // can properly cut off the client sending all the data.
+ // For now just bound it a little and
+ io.CopyN(ioutil.Discard, body, 100<<20)
+ body.Close()
+
if !req.keepConn {
c.conn.Close()
}
@@ -267,5 +289,4 @@ func Serve(l net.Listener, handler http.Handler) error {
c := newChild(rw, handler)
go c.serve()
}
- panic("unreachable")
}
diff --git a/src/pkg/net/http/fs_test.go b/src/pkg/net/http/fs_test.go
index 0dd6d0df9..2c3737653 100644
--- a/src/pkg/net/http/fs_test.go
+++ b/src/pkg/net/http/fs_test.go
@@ -54,7 +54,7 @@ var ServeFileRangeTests = []struct {
}
func TestServeFile(t *testing.T) {
- defer checkLeakedTransports(t)
+ defer afterTest(t)
ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) {
ServeFile(w, r, "testdata/file")
}))
@@ -170,7 +170,7 @@ var fsRedirectTestData = []struct {
}
func TestFSRedirect(t *testing.T) {
- defer checkLeakedTransports(t)
+ defer afterTest(t)
ts := httptest.NewServer(StripPrefix("/test", FileServer(Dir("."))))
defer ts.Close()
@@ -195,7 +195,7 @@ func (fs *testFileSystem) Open(name string) (File, error) {
}
func TestFileServerCleans(t *testing.T) {
- defer checkLeakedTransports(t)
+ defer afterTest(t)
ch := make(chan string, 1)
fs := FileServer(&testFileSystem{func(name string) (File, error) {
ch <- name
@@ -227,7 +227,7 @@ func mustRemoveAll(dir string) {
}
func TestFileServerImplicitLeadingSlash(t *testing.T) {
- defer checkLeakedTransports(t)
+ defer afterTest(t)
tempDir, err := ioutil.TempDir("", "")
if err != nil {
t.Fatalf("TempDir: %v", err)
@@ -306,7 +306,7 @@ func TestEmptyDirOpenCWD(t *testing.T) {
}
func TestServeFileContentType(t *testing.T) {
- defer checkLeakedTransports(t)
+ defer afterTest(t)
const ctype = "icecream/chocolate"
ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) {
if r.FormValue("override") == "1" {
@@ -330,7 +330,7 @@ func TestServeFileContentType(t *testing.T) {
}
func TestServeFileMimeType(t *testing.T) {
- defer checkLeakedTransports(t)
+ defer afterTest(t)
ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) {
ServeFile(w, r, "testdata/style.css")
}))
@@ -347,7 +347,7 @@ func TestServeFileMimeType(t *testing.T) {
}
func TestServeFileFromCWD(t *testing.T) {
- defer checkLeakedTransports(t)
+ defer afterTest(t)
ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) {
ServeFile(w, r, "fs_test.go")
}))
@@ -363,7 +363,7 @@ func TestServeFileFromCWD(t *testing.T) {
}
func TestServeFileWithContentEncoding(t *testing.T) {
- defer checkLeakedTransports(t)
+ defer afterTest(t)
ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) {
w.Header().Set("Content-Encoding", "foo")
ServeFile(w, r, "testdata/file")
@@ -380,7 +380,7 @@ func TestServeFileWithContentEncoding(t *testing.T) {
}
func TestServeIndexHtml(t *testing.T) {
- defer checkLeakedTransports(t)
+ defer afterTest(t)
const want = "index.html says hello\n"
ts := httptest.NewServer(FileServer(Dir(".")))
defer ts.Close()
@@ -402,7 +402,7 @@ func TestServeIndexHtml(t *testing.T) {
}
func TestFileServerZeroByte(t *testing.T) {
- defer checkLeakedTransports(t)
+ defer afterTest(t)
ts := httptest.NewServer(FileServer(Dir(".")))
defer ts.Close()
@@ -471,7 +471,7 @@ func (fs fakeFS) Open(name string) (File, error) {
}
func TestDirectoryIfNotModified(t *testing.T) {
- defer checkLeakedTransports(t)
+ defer afterTest(t)
const indexContents = "I am a fake index.html file"
fileMod := time.Unix(1000000000, 0).UTC()
fileModStr := fileMod.Format(TimeFormat)
@@ -545,7 +545,7 @@ func mustStat(t *testing.T, fileName string) os.FileInfo {
}
func TestServeContent(t *testing.T) {
- defer checkLeakedTransports(t)
+ defer afterTest(t)
type serveParam struct {
name string
modtime time.Time
@@ -678,7 +678,7 @@ func TestServeContent(t *testing.T) {
// verifies that sendfile is being used on Linux
func TestLinuxSendfile(t *testing.T) {
- defer checkLeakedTransports(t)
+ defer afterTest(t)
if runtime.GOOS != "linux" {
t.Skip("skipping; linux-only test")
}
@@ -697,7 +697,7 @@ func TestLinuxSendfile(t *testing.T) {
defer ln.Close()
var buf bytes.Buffer
- child := exec.Command("strace", "-f", os.Args[0], "-test.run=TestLinuxSendfileChild")
+ child := exec.Command("strace", "-f", "-q", "-e", "trace=sendfile,sendfile64", os.Args[0], "-test.run=TestLinuxSendfileChild")
child.ExtraFiles = append(child.ExtraFiles, lnf)
child.Env = append([]string{"GO_WANT_HELPER_PROCESS=1"}, os.Environ()...)
child.Stdout = &buf
diff --git a/src/pkg/net/http/header.go b/src/pkg/net/http/header.go
index f479b7b4e..6374237fb 100644
--- a/src/pkg/net/http/header.go
+++ b/src/pkg/net/http/header.go
@@ -103,21 +103,41 @@ type keyValues struct {
values []string
}
-type byKey []keyValues
-
-func (s byKey) Len() int { return len(s) }
-func (s byKey) Swap(i, j int) { s[i], s[j] = s[j], s[i] }
-func (s byKey) Less(i, j int) bool { return s[i].key < s[j].key }
-
-func (h Header) sortedKeyValues(exclude map[string]bool) []keyValues {
- kvs := make([]keyValues, 0, len(h))
+// A headerSorter implements sort.Interface by sorting a []keyValues
+// by key. It's used as a pointer, so it can fit in a sort.Interface
+// interface value without allocation.
+type headerSorter struct {
+ kvs []keyValues
+}
+
+func (s *headerSorter) Len() int { return len(s.kvs) }
+func (s *headerSorter) Swap(i, j int) { s.kvs[i], s.kvs[j] = s.kvs[j], s.kvs[i] }
+func (s *headerSorter) Less(i, j int) bool { return s.kvs[i].key < s.kvs[j].key }
+
+// TODO: convert this to a sync.Cache (issue 4720)
+var headerSorterCache = make(chan *headerSorter, 8)
+
+// sortedKeyValues returns h's keys sorted in the returned kvs
+// slice. The headerSorter used to sort is also returned, for possible
+// return to headerSorterCache.
+func (h Header) sortedKeyValues(exclude map[string]bool) (kvs []keyValues, hs *headerSorter) {
+ select {
+ case hs = <-headerSorterCache:
+ default:
+ hs = new(headerSorter)
+ }
+ if cap(hs.kvs) < len(h) {
+ hs.kvs = make([]keyValues, 0, len(h))
+ }
+ kvs = hs.kvs[:0]
for k, vv := range h {
if !exclude[k] {
kvs = append(kvs, keyValues{k, vv})
}
}
- sort.Sort(byKey(kvs))
- return kvs
+ hs.kvs = kvs
+ sort.Sort(hs)
+ return kvs, hs
}
// WriteSubset writes a header in wire format.
@@ -127,7 +147,8 @@ func (h Header) WriteSubset(w io.Writer, exclude map[string]bool) error {
if !ok {
ws = stringWriter{w}
}
- for _, kv := range h.sortedKeyValues(exclude) {
+ kvs, sorter := h.sortedKeyValues(exclude)
+ for _, kv := range kvs {
for _, v := range kv.values {
v = headerNewlineToSpace.Replace(v)
v = textproto.TrimString(v)
@@ -138,6 +159,10 @@ func (h Header) WriteSubset(w io.Writer, exclude map[string]bool) error {
}
}
}
+ select {
+ case headerSorterCache <- sorter:
+ default:
+ }
return nil
}
diff --git a/src/pkg/net/http/header_test.go b/src/pkg/net/http/header_test.go
index 2313b5549..a2b82a701 100644
--- a/src/pkg/net/http/header_test.go
+++ b/src/pkg/net/http/header_test.go
@@ -6,6 +6,7 @@ package http
import (
"bytes"
+ "runtime"
"testing"
"time"
)
@@ -178,7 +179,7 @@ var testHeader = Header{
"Content-Length": {"123"},
"Content-Type": {"text/plain"},
"Date": {"some date at some time Z"},
- "Server": {"Go http package"},
+ "Server": {DefaultUserAgent},
}
var buf bytes.Buffer
@@ -192,13 +193,14 @@ func BenchmarkHeaderWriteSubset(b *testing.B) {
}
func TestHeaderWriteSubsetMallocs(t *testing.T) {
+ if runtime.GOMAXPROCS(0) > 1 {
+ t.Skip("skipping; GOMAXPROCS>1")
+ }
n := testing.AllocsPerRun(100, func() {
buf.Reset()
testHeader.WriteSubset(&buf, nil)
})
- if n > 1 {
- // TODO(bradfitz,rsc): once we can sort without allocating,
- // make this an error. See http://golang.org/issue/3761
- // t.Errorf("got %v allocs, want <= %v", n, 1)
+ if n > 0 {
+ t.Errorf("mallocs = %d; want 0", n)
}
}
diff --git a/src/pkg/net/http/httptest/example_test.go b/src/pkg/net/http/httptest/example_test.go
index 239470d97..42a0ec953 100644
--- a/src/pkg/net/http/httptest/example_test.go
+++ b/src/pkg/net/http/httptest/example_test.go
@@ -12,7 +12,7 @@ import (
"net/http/httptest"
)
-func ExampleRecorder() {
+func ExampleResponseRecorder() {
handler := func(w http.ResponseWriter, r *http.Request) {
http.Error(w, "something failed", http.StatusInternalServerError)
}
diff --git a/src/pkg/net/http/httputil/dump_test.go b/src/pkg/net/http/httputil/dump_test.go
index 5afe9ba74..3e87c27bc 100644
--- a/src/pkg/net/http/httputil/dump_test.go
+++ b/src/pkg/net/http/httputil/dump_test.go
@@ -68,7 +68,7 @@ var dumpTests = []dumpTest{
WantDumpOut: "GET /foo HTTP/1.1\r\n" +
"Host: example.com\r\n" +
- "User-Agent: Go http package\r\n" +
+ "User-Agent: Go 1.1 package http\r\n" +
"Accept-Encoding: gzip\r\n\r\n",
},
@@ -80,7 +80,7 @@ var dumpTests = []dumpTest{
WantDumpOut: "GET /foo HTTP/1.1\r\n" +
"Host: example.com\r\n" +
- "User-Agent: Go http package\r\n" +
+ "User-Agent: Go 1.1 package http\r\n" +
"Accept-Encoding: gzip\r\n\r\n",
},
}
diff --git a/src/pkg/net/http/httputil/reverseproxy.go b/src/pkg/net/http/httputil/reverseproxy.go
index 134c45299..1990f64db 100644
--- a/src/pkg/net/http/httputil/reverseproxy.go
+++ b/src/pkg/net/http/httputil/reverseproxy.go
@@ -81,6 +81,19 @@ func copyHeader(dst, src http.Header) {
}
}
+// Hop-by-hop headers. These are removed when sent to the backend.
+// http://www.w3.org/Protocols/rfc2616/rfc2616-sec13.html
+var hopHeaders = []string{
+ "Connection",
+ "Keep-Alive",
+ "Proxy-Authenticate",
+ "Proxy-Authorization",
+ "Te", // canonicalized version of "TE"
+ "Trailers",
+ "Transfer-Encoding",
+ "Upgrade",
+}
+
func (p *ReverseProxy) ServeHTTP(rw http.ResponseWriter, req *http.Request) {
transport := p.Transport
if transport == nil {
@@ -96,14 +109,21 @@ func (p *ReverseProxy) ServeHTTP(rw http.ResponseWriter, req *http.Request) {
outreq.ProtoMinor = 1
outreq.Close = false
- // Remove the connection header to the backend. We want a
- // persistent connection, regardless of what the client sent
- // to us. This is modifying the same underlying map from req
- // (shallow copied above) so we only copy it if necessary.
- if outreq.Header.Get("Connection") != "" {
- outreq.Header = make(http.Header)
- copyHeader(outreq.Header, req.Header)
- outreq.Header.Del("Connection")
+ // 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
+ // copied above) so we only copy it if necessary.
+ copiedHeaders := false
+ for _, h := range hopHeaders {
+ if outreq.Header.Get(h) != "" {
+ if !copiedHeaders {
+ outreq.Header = make(http.Header)
+ copyHeader(outreq.Header, req.Header)
+ copiedHeaders = true
+ }
+ outreq.Header.Del(h)
+ }
}
if clientIP, _, err := net.SplitHostPort(req.RemoteAddr); err == nil {
@@ -182,7 +202,6 @@ func (m *maxLatencyWriter) flushLoop() {
m.lk.Unlock()
}
}
- panic("unreached")
}
func (m *maxLatencyWriter) stop() { m.done <- true }
diff --git a/src/pkg/net/http/httputil/reverseproxy_test.go b/src/pkg/net/http/httputil/reverseproxy_test.go
index 863927162..1c0444ec4 100644
--- a/src/pkg/net/http/httputil/reverseproxy_test.go
+++ b/src/pkg/net/http/httputil/reverseproxy_test.go
@@ -29,6 +29,9 @@ func TestReverseProxy(t *testing.T) {
if c := r.Header.Get("Connection"); c != "" {
t.Errorf("handler got Connection header value %q", c)
}
+ if c := r.Header.Get("Upgrade"); c != "" {
+ t.Errorf("handler got Upgrade header value %q", c)
+ }
if g, e := r.Host, "some-name"; g != e {
t.Errorf("backend got Host header %q, want %q", g, e)
}
@@ -49,6 +52,7 @@ func TestReverseProxy(t *testing.T) {
getReq, _ := http.NewRequest("GET", frontend.URL, nil)
getReq.Host = "some-name"
getReq.Header.Set("Connection", "close")
+ getReq.Header.Set("Upgrade", "foo")
getReq.Close = true
res, err := http.DefaultClient.Do(getReq)
if err != nil {
diff --git a/src/pkg/net/http/request.go b/src/pkg/net/http/request.go
index 217f35b48..6d4569146 100644
--- a/src/pkg/net/http/request.go
+++ b/src/pkg/net/http/request.go
@@ -48,7 +48,7 @@ var (
ErrUnexpectedTrailer = &ProtocolError{"trailer header without chunked transfer encoding"}
ErrMissingContentLength = &ProtocolError{"missing ContentLength in HEAD response"}
ErrNotMultipart = &ProtocolError{"request Content-Type isn't multipart/form-data"}
- ErrMissingBoundary = &ProtocolError{"no multipart boundary param Content-Type"}
+ ErrMissingBoundary = &ProtocolError{"no multipart boundary param in Content-Type"}
)
type badStringError struct {
@@ -283,7 +283,7 @@ func valueOrDefault(value, def string) string {
return def
}
-const defaultUserAgent = "Go http package"
+const defaultUserAgent = "Go 1.1 package http"
// Write writes an HTTP/1.1 request -- header and body -- in wire format.
// This method consults the following fields of the request:
@@ -467,10 +467,42 @@ func (r *Request) SetBasicAuth(username, password string) {
r.Header.Set("Authorization", "Basic "+base64.StdEncoding.EncodeToString([]byte(s)))
}
+// parseRequestLine parses "GET /foo HTTP/1.1" into its three parts.
+func parseRequestLine(line string) (method, requestURI, proto string, ok bool) {
+ s1 := strings.Index(line, " ")
+ s2 := strings.Index(line[s1+1:], " ")
+ if s1 < 0 || s2 < 0 {
+ return
+ }
+ s2 += s1 + 1
+ return line[:s1], line[s1+1 : s2], line[s2+1:], true
+}
+
+// TODO(bradfitz): use a sync.Cache when available
+var textprotoReaderCache = make(chan *textproto.Reader, 4)
+
+func newTextprotoReader(br *bufio.Reader) *textproto.Reader {
+ select {
+ case r := <-textprotoReaderCache:
+ r.R = br
+ return r
+ default:
+ return textproto.NewReader(br)
+ }
+}
+
+func putTextprotoReader(r *textproto.Reader) {
+ r.R = nil
+ select {
+ case textprotoReaderCache <- r:
+ default:
+ }
+}
+
// ReadRequest reads and parses a request from b.
func ReadRequest(b *bufio.Reader) (req *Request, err error) {
- tp := textproto.NewReader(b)
+ tp := newTextprotoReader(b)
req = new(Request)
// First line: GET /index.html HTTP/1.0
@@ -479,18 +511,18 @@ func ReadRequest(b *bufio.Reader) (req *Request, err error) {
return nil, err
}
defer func() {
+ putTextprotoReader(tp)
if err == io.EOF {
err = io.ErrUnexpectedEOF
}
}()
- var f []string
- if f = strings.SplitN(s, " ", 3); len(f) < 3 {
+ var ok bool
+ req.Method, req.RequestURI, req.Proto, ok = parseRequestLine(s)
+ if !ok {
return nil, &badStringError{"malformed HTTP request", s}
}
- req.Method, req.RequestURI, req.Proto = f[0], f[1], f[2]
rawurl := req.RequestURI
- var ok bool
if req.ProtoMajor, req.ProtoMinor, ok = ParseHTTPVersion(req.Proto); !ok {
return nil, &badStringError{"malformed HTTP version", req.Proto}
}
diff --git a/src/pkg/net/http/request_test.go b/src/pkg/net/http/request_test.go
index 00ad791de..692485c49 100644
--- a/src/pkg/net/http/request_test.go
+++ b/src/pkg/net/http/request_test.go
@@ -267,6 +267,38 @@ func TestNewRequestContentLength(t *testing.T) {
}
}
+var parseHTTPVersionTests = []struct {
+ vers string
+ major, minor int
+ ok bool
+}{
+ {"HTTP/0.9", 0, 9, true},
+ {"HTTP/1.0", 1, 0, true},
+ {"HTTP/1.1", 1, 1, true},
+ {"HTTP/3.14", 3, 14, true},
+
+ {"HTTP", 0, 0, false},
+ {"HTTP/one.one", 0, 0, false},
+ {"HTTP/1.1/", 0, 0, false},
+ {"HTTP/-1,0", 0, 0, false},
+ {"HTTP/0,-1", 0, 0, false},
+ {"HTTP/", 0, 0, false},
+ {"HTTP/1,1", 0, 0, false},
+}
+
+func TestParseHTTPVersion(t *testing.T) {
+ for _, tt := range parseHTTPVersionTests {
+ major, minor, ok := ParseHTTPVersion(tt.vers)
+ if ok != tt.ok || major != tt.major || minor != tt.minor {
+ type version struct {
+ major, minor int
+ ok bool
+ }
+ t.Errorf("failed to parse %q, expected: %#v, got %#v", tt.vers, version{tt.major, tt.minor, tt.ok}, version{major, minor, ok})
+ }
+ }
+}
+
type logWrites struct {
t *testing.T
dst *[]string
@@ -289,7 +321,7 @@ func TestRequestWriteBufferedWriter(t *testing.T) {
want := []string{
"GET / HTTP/1.1\r\n",
"Host: foo.com\r\n",
- "User-Agent: Go http package\r\n",
+ "User-Agent: " + DefaultUserAgent + "\r\n",
"\r\n",
}
if !reflect.DeepEqual(got, want) {
diff --git a/src/pkg/net/http/requestwrite_test.go b/src/pkg/net/http/requestwrite_test.go
index bc637f18b..b27b1f7ce 100644
--- a/src/pkg/net/http/requestwrite_test.go
+++ b/src/pkg/net/http/requestwrite_test.go
@@ -93,13 +93,13 @@ var reqWriteTests = []reqWriteTest{
WantWrite: "GET /search HTTP/1.1\r\n" +
"Host: www.google.com\r\n" +
- "User-Agent: Go http package\r\n" +
+ "User-Agent: Go 1.1 package http\r\n" +
"Transfer-Encoding: chunked\r\n\r\n" +
chunk("abcdef") + chunk(""),
WantProxy: "GET http://www.google.com/search HTTP/1.1\r\n" +
"Host: www.google.com\r\n" +
- "User-Agent: Go http package\r\n" +
+ "User-Agent: Go 1.1 package http\r\n" +
"Transfer-Encoding: chunked\r\n\r\n" +
chunk("abcdef") + chunk(""),
},
@@ -123,14 +123,14 @@ var reqWriteTests = []reqWriteTest{
WantWrite: "POST /search HTTP/1.1\r\n" +
"Host: www.google.com\r\n" +
- "User-Agent: Go http package\r\n" +
+ "User-Agent: Go 1.1 package http\r\n" +
"Connection: close\r\n" +
"Transfer-Encoding: chunked\r\n\r\n" +
chunk("abcdef") + chunk(""),
WantProxy: "POST http://www.google.com/search HTTP/1.1\r\n" +
"Host: www.google.com\r\n" +
- "User-Agent: Go http package\r\n" +
+ "User-Agent: Go 1.1 package http\r\n" +
"Connection: close\r\n" +
"Transfer-Encoding: chunked\r\n\r\n" +
chunk("abcdef") + chunk(""),
@@ -156,7 +156,7 @@ var reqWriteTests = []reqWriteTest{
WantWrite: "POST /search HTTP/1.1\r\n" +
"Host: www.google.com\r\n" +
- "User-Agent: Go http package\r\n" +
+ "User-Agent: Go 1.1 package http\r\n" +
"Connection: close\r\n" +
"Content-Length: 6\r\n" +
"\r\n" +
@@ -164,7 +164,7 @@ var reqWriteTests = []reqWriteTest{
WantProxy: "POST http://www.google.com/search HTTP/1.1\r\n" +
"Host: www.google.com\r\n" +
- "User-Agent: Go http package\r\n" +
+ "User-Agent: Go 1.1 package http\r\n" +
"Connection: close\r\n" +
"Content-Length: 6\r\n" +
"\r\n" +
@@ -187,14 +187,14 @@ var reqWriteTests = []reqWriteTest{
WantWrite: "POST / HTTP/1.1\r\n" +
"Host: example.com\r\n" +
- "User-Agent: Go http package\r\n" +
+ "User-Agent: Go 1.1 package http\r\n" +
"Content-Length: 6\r\n" +
"\r\n" +
"abcdef",
WantProxy: "POST http://example.com/ HTTP/1.1\r\n" +
"Host: example.com\r\n" +
- "User-Agent: Go http package\r\n" +
+ "User-Agent: Go 1.1 package http\r\n" +
"Content-Length: 6\r\n" +
"\r\n" +
"abcdef",
@@ -210,7 +210,7 @@ var reqWriteTests = []reqWriteTest{
WantWrite: "GET /search HTTP/1.1\r\n" +
"Host: www.google.com\r\n" +
- "User-Agent: Go http package\r\n" +
+ "User-Agent: Go 1.1 package http\r\n" +
"\r\n",
},
@@ -232,13 +232,13 @@ var reqWriteTests = []reqWriteTest{
// Also, nginx expects it for POST and PUT.
WantWrite: "POST / HTTP/1.1\r\n" +
"Host: example.com\r\n" +
- "User-Agent: Go http package\r\n" +
+ "User-Agent: Go 1.1 package http\r\n" +
"Content-Length: 0\r\n" +
"\r\n",
WantProxy: "POST / HTTP/1.1\r\n" +
"Host: example.com\r\n" +
- "User-Agent: Go http package\r\n" +
+ "User-Agent: Go 1.1 package http\r\n" +
"Content-Length: 0\r\n" +
"\r\n",
},
@@ -258,13 +258,13 @@ var reqWriteTests = []reqWriteTest{
WantWrite: "POST / HTTP/1.1\r\n" +
"Host: example.com\r\n" +
- "User-Agent: Go http package\r\n" +
+ "User-Agent: Go 1.1 package http\r\n" +
"Transfer-Encoding: chunked\r\n\r\n" +
chunk("x") + chunk(""),
WantProxy: "POST / HTTP/1.1\r\n" +
"Host: example.com\r\n" +
- "User-Agent: Go http package\r\n" +
+ "User-Agent: Go 1.1 package http\r\n" +
"Transfer-Encoding: chunked\r\n\r\n" +
chunk("x") + chunk(""),
},
@@ -325,7 +325,7 @@ var reqWriteTests = []reqWriteTest{
WantWrite: "GET /foo HTTP/1.1\r\n" +
"Host: \r\n" +
- "User-Agent: Go http package\r\n" +
+ "User-Agent: Go 1.1 package http\r\n" +
"X-Foo: X-Bar\r\n\r\n",
},
@@ -351,7 +351,7 @@ var reqWriteTests = []reqWriteTest{
WantWrite: "GET /search HTTP/1.1\r\n" +
"Host: \r\n" +
- "User-Agent: Go http package\r\n\r\n",
+ "User-Agent: Go 1.1 package http\r\n\r\n",
},
// Opaque test #1 from golang.org/issue/4860
@@ -370,7 +370,7 @@ var reqWriteTests = []reqWriteTest{
WantWrite: "GET /%2F/%2F/ HTTP/1.1\r\n" +
"Host: www.google.com\r\n" +
- "User-Agent: Go http package\r\n\r\n",
+ "User-Agent: Go 1.1 package http\r\n\r\n",
},
// Opaque test #2 from golang.org/issue/4860
@@ -389,7 +389,31 @@ var reqWriteTests = []reqWriteTest{
WantWrite: "GET http://y.google.com/%2F/%2F/ HTTP/1.1\r\n" +
"Host: x.google.com\r\n" +
- "User-Agent: Go http package\r\n\r\n",
+ "User-Agent: Go 1.1 package http\r\n\r\n",
+ },
+
+ // Testing custom case in header keys. Issue 5022.
+ {
+ Req: Request{
+ Method: "GET",
+ URL: &url.URL{
+ Scheme: "http",
+ Host: "www.google.com",
+ Path: "/",
+ },
+ Proto: "HTTP/1.1",
+ ProtoMajor: 1,
+ ProtoMinor: 1,
+ Header: Header{
+ "ALL-CAPS": {"x"},
+ },
+ },
+
+ WantWrite: "GET / HTTP/1.1\r\n" +
+ "Host: www.google.com\r\n" +
+ "User-Agent: Go 1.1 package http\r\n" +
+ "ALL-CAPS: x\r\n" +
+ "\r\n",
},
}
@@ -474,7 +498,7 @@ func TestRequestWriteClosesBody(t *testing.T) {
}
expected := "POST / HTTP/1.1\r\n" +
"Host: foo.com\r\n" +
- "User-Agent: Go http package\r\n" +
+ "User-Agent: Go 1.1 package http\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
diff --git a/src/pkg/net/http/response.go b/src/pkg/net/http/response.go
index 391ebbf6d..9a7e4e319 100644
--- a/src/pkg/net/http/response.go
+++ b/src/pkg/net/http/response.go
@@ -46,6 +46,9 @@ type Response struct {
// The http Client and Transport guarantee that Body is always
// non-nil, even on responses without a body or responses with
// a zero-lengthed body.
+ //
+ // The Body is automatically dechunked if the server replied
+ // with a "chunked" Transfer-Encoding.
Body io.ReadCloser
// ContentLength records the length of the associated content. The
diff --git a/src/pkg/net/http/response_test.go b/src/pkg/net/http/response_test.go
index 2f5f77369..02796e88b 100644
--- a/src/pkg/net/http/response_test.go
+++ b/src/pkg/net/http/response_test.go
@@ -112,8 +112,8 @@ var respTests = []respTest{
ProtoMinor: 0,
Request: dummyReq("GET"),
Header: Header{
- "Connection": {"close"}, // TODO(rsc): Delete?
- "Content-Length": {"10"}, // TODO(rsc): Delete?
+ "Connection": {"close"},
+ "Content-Length": {"10"},
},
Close: true,
ContentLength: 10,
@@ -170,7 +170,7 @@ var respTests = []respTest{
Request: dummyReq("GET"),
Header: Header{},
Close: false,
- ContentLength: -1, // TODO(rsc): Fix?
+ ContentLength: -1,
TransferEncoding: []string{"chunked"},
},
@@ -466,7 +466,7 @@ func TestReadResponseCloseInMiddle(t *testing.T) {
if test.compressed {
gzReader, err := gzip.NewReader(resp.Body)
checkErr(err, "gzip.NewReader")
- resp.Body = &readFirstCloseBoth{gzReader, resp.Body}
+ resp.Body = &readerAndCloser{gzReader, resp.Body}
}
rbuf := make([]byte, 2500)
diff --git a/src/pkg/net/http/serve_test.go b/src/pkg/net/http/serve_test.go
index 3300fef59..d7b321597 100644
--- a/src/pkg/net/http/serve_test.go
+++ b/src/pkg/net/http/serve_test.go
@@ -10,6 +10,7 @@ import (
"bufio"
"bytes"
"crypto/tls"
+ "errors"
"fmt"
"io"
"io/ioutil"
@@ -64,10 +65,39 @@ func (a dummyAddr) String() string {
return string(a)
}
+type noopConn struct{}
+
+func (noopConn) LocalAddr() net.Addr { return dummyAddr("local-addr") }
+func (noopConn) RemoteAddr() net.Addr { return dummyAddr("remote-addr") }
+func (noopConn) SetDeadline(t time.Time) error { return nil }
+func (noopConn) SetReadDeadline(t time.Time) error { return nil }
+func (noopConn) SetWriteDeadline(t time.Time) error { return nil }
+
+type rwTestConn struct {
+ io.Reader
+ io.Writer
+ noopConn
+
+ closeFunc func() error // called if non-nil
+ closec chan bool // else, if non-nil, send value to it on close
+}
+
+func (c *rwTestConn) Close() error {
+ if c.closeFunc != nil {
+ return c.closeFunc()
+ }
+ select {
+ case c.closec <- true:
+ default:
+ }
+ return nil
+}
+
type testConn struct {
readBuf bytes.Buffer
writeBuf bytes.Buffer
closec chan bool // if non-nil, send value to it on close
+ noopConn
}
func (c *testConn) Read(b []byte) (int, error) {
@@ -86,26 +116,6 @@ func (c *testConn) Close() error {
return nil
}
-func (c *testConn) LocalAddr() net.Addr {
- return dummyAddr("local-addr")
-}
-
-func (c *testConn) RemoteAddr() net.Addr {
- return dummyAddr("remote-addr")
-}
-
-func (c *testConn) SetDeadline(t time.Time) error {
- return nil
-}
-
-func (c *testConn) SetReadDeadline(t time.Time) error {
- return nil
-}
-
-func (c *testConn) SetWriteDeadline(t time.Time) error {
- return nil
-}
-
func TestConsumingBodyOnNextConn(t *testing.T) {
conn := new(testConn)
for i := 0; i < 2; i++ {
@@ -184,7 +194,7 @@ var vtests = []struct {
}
func TestHostHandlers(t *testing.T) {
- defer checkLeakedTransports(t)
+ defer afterTest(t)
mux := NewServeMux()
for _, h := range handlers {
mux.Handle(h.pattern, stringHandler(h.msg))
@@ -257,7 +267,7 @@ func TestMuxRedirectLeadingSlashes(t *testing.T) {
}
func TestServerTimeouts(t *testing.T) {
- defer checkLeakedTransports(t)
+ defer afterTest(t)
reqNum := 0
ts := httptest.NewUnstartedServer(HandlerFunc(func(res ResponseWriter, req *Request) {
reqNum++
@@ -333,7 +343,7 @@ func TestServerTimeouts(t *testing.T) {
// shouldn't cause a handler to block forever on reads (next HTTP
// request) that will never happen.
func TestOnlyWriteTimeout(t *testing.T) {
- defer checkLeakedTransports(t)
+ defer afterTest(t)
var conn net.Conn
var afterTimeoutErrc = make(chan error, 1)
ts := httptest.NewUnstartedServer(HandlerFunc(func(w ResponseWriter, req *Request) {
@@ -392,7 +402,7 @@ func (l trackLastConnListener) Accept() (c net.Conn, err error) {
// TestIdentityResponse verifies that a handler can unset
func TestIdentityResponse(t *testing.T) {
- defer checkLeakedTransports(t)
+ defer afterTest(t)
handler := HandlerFunc(func(rw ResponseWriter, req *Request) {
rw.Header().Set("Content-Length", "3")
rw.Header().Set("Transfer-Encoding", req.FormValue("te"))
@@ -468,7 +478,7 @@ func TestIdentityResponse(t *testing.T) {
}
func testTCPConnectionCloses(t *testing.T, req string, h Handler) {
- defer checkLeakedTransports(t)
+ defer afterTest(t)
s := httptest.NewServer(h)
defer s.Close()
@@ -539,7 +549,7 @@ func TestHandlersCanSetConnectionClose10(t *testing.T) {
}
func TestSetsRemoteAddr(t *testing.T) {
- defer checkLeakedTransports(t)
+ defer afterTest(t)
ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) {
fmt.Fprintf(w, "%s", r.RemoteAddr)
}))
@@ -560,7 +570,7 @@ func TestSetsRemoteAddr(t *testing.T) {
}
func TestChunkedResponseHeaders(t *testing.T) {
- defer checkLeakedTransports(t)
+ defer afterTest(t)
log.SetOutput(ioutil.Discard) // is noisy otherwise
defer log.SetOutput(os.Stderr)
@@ -591,7 +601,7 @@ func TestChunkedResponseHeaders(t *testing.T) {
// chunking in their response headers and aren't allowed to produce
// output.
func Test304Responses(t *testing.T) {
- defer checkLeakedTransports(t)
+ defer afterTest(t)
ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) {
w.WriteHeader(StatusNotModified)
_, err := w.Write([]byte("illegal body"))
@@ -621,7 +631,7 @@ func Test304Responses(t *testing.T) {
// allowed to produce output, and don't set a Content-Type since
// the real type of the body data cannot be inferred.
func TestHeadResponses(t *testing.T) {
- defer checkLeakedTransports(t)
+ defer afterTest(t)
ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) {
_, err := w.Write([]byte("Ignored body"))
if err != ErrBodyNotAllowed {
@@ -656,7 +666,7 @@ func TestHeadResponses(t *testing.T) {
}
func TestTLSHandshakeTimeout(t *testing.T) {
- defer checkLeakedTransports(t)
+ defer afterTest(t)
ts := httptest.NewUnstartedServer(HandlerFunc(func(w ResponseWriter, r *Request) {}))
ts.Config.ReadTimeout = 250 * time.Millisecond
ts.StartTLS()
@@ -676,7 +686,7 @@ func TestTLSHandshakeTimeout(t *testing.T) {
}
func TestTLSServer(t *testing.T) {
- defer checkLeakedTransports(t)
+ defer afterTest(t)
ts := httptest.NewTLSServer(HandlerFunc(func(w ResponseWriter, r *Request) {
if r.TLS != nil {
w.Header().Set("X-TLS-Set", "true")
@@ -759,7 +769,7 @@ var serverExpectTests = []serverExpectTest{
// Tests that the server responds to the "Expect" request header
// correctly.
func TestServerExpect(t *testing.T) {
- defer checkLeakedTransports(t)
+ defer afterTest(t)
ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) {
// Note using r.FormValue("readbody") because for POST
// requests that would read from r.Body, which we only
@@ -897,7 +907,7 @@ func TestServerUnreadRequestBodyLarge(t *testing.T) {
}
func TestTimeoutHandler(t *testing.T) {
- defer checkLeakedTransports(t)
+ defer afterTest(t)
sendHi := make(chan bool, 1)
writeErrors := make(chan error, 1)
sayHi := HandlerFunc(func(w ResponseWriter, r *Request) {
@@ -972,7 +982,7 @@ func TestRedirectMunging(t *testing.T) {
// the previous request's body, which is not optimal for zero-lengthed bodies,
// as the client would then see http.ErrBodyReadAfterClose and not 0, io.EOF.
func TestZeroLengthPostAndResponse(t *testing.T) {
- defer checkLeakedTransports(t)
+ defer afterTest(t)
ts := httptest.NewServer(HandlerFunc(func(rw ResponseWriter, r *Request) {
all, err := ioutil.ReadAll(r.Body)
if err != nil {
@@ -1023,7 +1033,7 @@ func TestHandlerPanicWithHijack(t *testing.T) {
}
func testHandlerPanic(t *testing.T, withHijack bool, panicValue interface{}) {
- defer checkLeakedTransports(t)
+ 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
// purposes:
@@ -1089,7 +1099,7 @@ func testHandlerPanic(t *testing.T, withHijack bool, panicValue interface{}) {
}
func TestNoDate(t *testing.T) {
- defer checkLeakedTransports(t)
+ defer afterTest(t)
ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) {
w.Header()["Date"] = nil
}))
@@ -1105,7 +1115,7 @@ func TestNoDate(t *testing.T) {
}
func TestStripPrefix(t *testing.T) {
- defer checkLeakedTransports(t)
+ defer afterTest(t)
h := HandlerFunc(func(w ResponseWriter, r *Request) {
w.Header().Set("X-Path", r.URL.Path)
})
@@ -1132,7 +1142,7 @@ func TestStripPrefix(t *testing.T) {
}
func TestRequestLimit(t *testing.T) {
- defer checkLeakedTransports(t)
+ defer afterTest(t)
ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) {
t.Fatalf("didn't expect to get request in Handler")
}))
@@ -1176,7 +1186,7 @@ func (cr countReader) Read(p []byte) (n int, err error) {
}
func TestRequestBodyLimit(t *testing.T) {
- defer checkLeakedTransports(t)
+ defer afterTest(t)
const limit = 1 << 20
ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) {
r.Body = MaxBytesReader(w, r.Body, limit)
@@ -1213,7 +1223,7 @@ func TestRequestBodyLimit(t *testing.T) {
// TestClientWriteShutdown tests that if the client shuts down the write
// side of their TCP connection, the server doesn't send a 400 Bad Request.
func TestClientWriteShutdown(t *testing.T) {
- defer checkLeakedTransports(t)
+ defer afterTest(t)
ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) {}))
defer ts.Close()
conn, err := net.Dial("tcp", ts.Listener.Addr().String())
@@ -1268,7 +1278,7 @@ func TestServerBufferedChunking(t *testing.T) {
// closing the TCP connection, causing the client to get a RST.
// See http://golang.org/issue/3595
func TestServerGracefulClose(t *testing.T) {
- defer checkLeakedTransports(t)
+ defer afterTest(t)
ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) {
Error(w, "bye", StatusUnauthorized)
}))
@@ -1311,7 +1321,7 @@ func TestServerGracefulClose(t *testing.T) {
}
func TestCaseSensitiveMethod(t *testing.T) {
- defer checkLeakedTransports(t)
+ defer afterTest(t)
ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) {
if r.Method != "get" {
t.Errorf(`Got method %q; want "get"`, r.Method)
@@ -1360,6 +1370,7 @@ func TestContentLengthZero(t *testing.T) {
}
func TestCloseNotifier(t *testing.T) {
+ defer afterTest(t)
gotReq := make(chan bool, 1)
sawClose := make(chan bool, 1)
ts := httptest.NewServer(HandlerFunc(func(rw ResponseWriter, req *Request) {
@@ -1395,6 +1406,31 @@ For:
ts.Close()
}
+func TestCloseNotifierChanLeak(t *testing.T) {
+ defer afterTest(t)
+ req := []byte(strings.Replace(`GET / HTTP/1.0
+Host: golang.org
+
+`, "\n", "\r\n", -1))
+ for i := 0; i < 20; i++ {
+ var output bytes.Buffer
+ conn := &rwTestConn{
+ Reader: bytes.NewReader(req),
+ Writer: &output,
+ closec: make(chan bool, 1),
+ }
+ ln := &oneConnListener{conn: conn}
+ handler := HandlerFunc(func(rw ResponseWriter, r *Request) {
+ // Ignore the return value and never read from
+ // it, testing that we don't leak goroutines
+ // on the sending side:
+ _ = rw.(CloseNotifier).CloseNotify()
+ })
+ go Serve(ln, handler)
+ <-conn.closec
+ }
+}
+
func TestOptions(t *testing.T) {
uric := make(chan string, 2) // only expect 1, but leave space for 2
mux := NewServeMux()
@@ -1447,6 +1483,198 @@ 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
+// (*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
+// compatibility with Go 1, we need to be careful to track which
+// headers were live at the time of WriteHeader, so we write the same
+// ones, even if the handler modifies them (~erroneously) after the
+// first Write.
+func TestHeaderToWire(t *testing.T) {
+ req := []byte(strings.Replace(`GET / HTTP/1.1
+Host: golang.org
+
+`, "\n", "\r\n", -1))
+
+ tests := []struct {
+ name string
+ handler func(ResponseWriter, *Request)
+ check func(output string) error
+ }{
+ {
+ name: "write without Header",
+ handler: func(rw ResponseWriter, r *Request) {
+ rw.Write([]byte("hello world"))
+ },
+ check: func(got string) error {
+ if !strings.Contains(got, "Content-Length:") {
+ return errors.New("no content-length")
+ }
+ if !strings.Contains(got, "Content-Type: text/plain") {
+ return errors.New("no content-length")
+ }
+ return nil
+ },
+ },
+ {
+ name: "Header mutation before write",
+ handler: func(rw ResponseWriter, r *Request) {
+ h := rw.Header()
+ h.Set("Content-Type", "some/type")
+ rw.Write([]byte("hello world"))
+ h.Set("Too-Late", "bogus")
+ },
+ check: func(got string) error {
+ if !strings.Contains(got, "Content-Length:") {
+ return errors.New("no content-length")
+ }
+ if !strings.Contains(got, "Content-Type: some/type") {
+ return errors.New("wrong content-type")
+ }
+ if strings.Contains(got, "Too-Late") {
+ return errors.New("don't want too-late header")
+ }
+ return nil
+ },
+ },
+ {
+ name: "write then useless Header mutation",
+ handler: func(rw ResponseWriter, r *Request) {
+ rw.Write([]byte("hello world"))
+ rw.Header().Set("Too-Late", "Write already wrote headers")
+ },
+ check: func(got string) error {
+ if strings.Contains(got, "Too-Late") {
+ return errors.New("header appeared from after WriteHeader")
+ }
+ return nil
+ },
+ },
+ {
+ name: "flush then write",
+ handler: func(rw ResponseWriter, r *Request) {
+ rw.(Flusher).Flush()
+ rw.Write([]byte("post-flush"))
+ rw.Header().Set("Too-Late", "Write already wrote headers")
+ },
+ check: func(got string) error {
+ if !strings.Contains(got, "Transfer-Encoding: chunked") {
+ return errors.New("not chunked")
+ }
+ if strings.Contains(got, "Too-Late") {
+ return errors.New("header appeared from after WriteHeader")
+ }
+ return nil
+ },
+ },
+ {
+ name: "header then flush",
+ handler: func(rw ResponseWriter, r *Request) {
+ rw.Header().Set("Content-Type", "some/type")
+ rw.(Flusher).Flush()
+ rw.Write([]byte("post-flush"))
+ rw.Header().Set("Too-Late", "Write already wrote headers")
+ },
+ check: func(got string) error {
+ if !strings.Contains(got, "Transfer-Encoding: chunked") {
+ return errors.New("not chunked")
+ }
+ if strings.Contains(got, "Too-Late") {
+ return errors.New("header appeared from after WriteHeader")
+ }
+ if !strings.Contains(got, "Content-Type: some/type") {
+ return errors.New("wrong content-length")
+ }
+ return nil
+ },
+ },
+ {
+ name: "sniff-on-first-write content-type",
+ handler: func(rw ResponseWriter, r *Request) {
+ rw.Write([]byte("<html><head></head><body>some html</body></html>"))
+ rw.Header().Set("Content-Type", "x/wrong")
+ },
+ check: func(got string) error {
+ if !strings.Contains(got, "Content-Type: text/html") {
+ return errors.New("wrong content-length; want html")
+ }
+ return nil
+ },
+ },
+ {
+ name: "explicit content-type wins",
+ handler: func(rw ResponseWriter, r *Request) {
+ rw.Header().Set("Content-Type", "some/type")
+ rw.Write([]byte("<html><head></head><body>some html</body></html>"))
+ },
+ check: func(got string) error {
+ if !strings.Contains(got, "Content-Type: some/type") {
+ return errors.New("wrong content-length; want html")
+ }
+ return nil
+ },
+ },
+ {
+ name: "empty handler",
+ handler: func(rw ResponseWriter, r *Request) {
+ },
+ check: func(got string) error {
+ if !strings.Contains(got, "Content-Type: text/plain") {
+ return errors.New("wrong content-length; want text/plain")
+ }
+ if !strings.Contains(got, "Content-Length: 0") {
+ return errors.New("want 0 content-length")
+ }
+ return nil
+ },
+ },
+ {
+ name: "only Header, no write",
+ handler: func(rw ResponseWriter, r *Request) {
+ rw.Header().Set("Some-Header", "some-value")
+ },
+ check: func(got string) error {
+ if !strings.Contains(got, "Some-Header") {
+ return errors.New("didn't get header")
+ }
+ return nil
+ },
+ },
+ {
+ name: "WriteHeader call",
+ handler: func(rw ResponseWriter, r *Request) {
+ rw.WriteHeader(404)
+ rw.Header().Set("Too-Late", "some-value")
+ },
+ check: func(got string) error {
+ if !strings.Contains(got, "404") {
+ return errors.New("wrong status")
+ }
+ if strings.Contains(got, "Some-Header") {
+ return errors.New("shouldn't have seen Too-Late")
+ }
+ return nil
+ },
+ },
+ }
+ for _, tc := range tests {
+ var output bytes.Buffer
+ conn := &rwTestConn{
+ Reader: bytes.NewReader(req),
+ Writer: &output,
+ closec: make(chan bool, 1),
+ }
+ ln := &oneConnListener{conn: conn}
+ go Serve(ln, HandlerFunc(tc.handler))
+ <-conn.closec
+ if err := tc.check(output.String()); err != nil {
+ t.Errorf("%s: %v\nGot response:\n%s", tc.name, err, output.Bytes())
+ }
+ }
+}
+
// goTimeout runs f, failing t if f takes more than ns to complete.
func goTimeout(t *testing.T, d time.Duration, f func()) {
ch := make(chan bool, 2)
@@ -1620,3 +1848,179 @@ func BenchmarkServer(b *testing.B) {
b.Errorf("Test failure: %v, with output: %s", err, out)
}
}
+
+func BenchmarkServerFakeConnNoKeepAlive(b *testing.B) {
+ b.ReportAllocs()
+ req := []byte(strings.Replace(`GET / HTTP/1.0
+Host: golang.org
+Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
+User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_8_2) AppleWebKit/537.17 (KHTML, like Gecko) Chrome/24.0.1312.52 Safari/537.17
+Accept-Encoding: gzip,deflate,sdch
+Accept-Language: en-US,en;q=0.8
+Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.3
+
+`, "\n", "\r\n", -1))
+ res := []byte("Hello world!\n")
+
+ conn := &testConn{
+ // testConn.Close will not push into the channel
+ // if it's full.
+ closec: make(chan bool, 1),
+ }
+ handler := HandlerFunc(func(rw ResponseWriter, r *Request) {
+ rw.Header().Set("Content-Type", "text/html; charset=utf-8")
+ rw.Write(res)
+ })
+ ln := new(oneConnListener)
+ for i := 0; i < b.N; i++ {
+ conn.readBuf.Reset()
+ conn.writeBuf.Reset()
+ conn.readBuf.Write(req)
+ ln.conn = conn
+ Serve(ln, handler)
+ <-conn.closec
+ }
+}
+
+// repeatReader reads content count times, then EOFs.
+type repeatReader struct {
+ content []byte
+ count int
+ off int
+}
+
+func (r *repeatReader) Read(p []byte) (n int, err error) {
+ if r.count <= 0 {
+ return 0, io.EOF
+ }
+ n = copy(p, r.content[r.off:])
+ r.off += n
+ if r.off == len(r.content) {
+ r.count--
+ r.off = 0
+ }
+ return
+}
+
+func BenchmarkServerFakeConnWithKeepAlive(b *testing.B) {
+ b.ReportAllocs()
+
+ req := []byte(strings.Replace(`GET / HTTP/1.1
+Host: golang.org
+Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
+User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_8_2) AppleWebKit/537.17 (KHTML, like Gecko) Chrome/24.0.1312.52 Safari/537.17
+Accept-Encoding: gzip,deflate,sdch
+Accept-Language: en-US,en;q=0.8
+Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.3
+
+`, "\n", "\r\n", -1))
+ res := []byte("Hello world!\n")
+
+ conn := &rwTestConn{
+ Reader: &repeatReader{content: req, count: b.N},
+ Writer: ioutil.Discard,
+ closec: make(chan bool, 1),
+ }
+ handled := 0
+ handler := HandlerFunc(func(rw ResponseWriter, r *Request) {
+ handled++
+ rw.Header().Set("Content-Type", "text/html; charset=utf-8")
+ rw.Write(res)
+ })
+ ln := &oneConnListener{conn: conn}
+ go Serve(ln, handler)
+ <-conn.closec
+ if b.N != handled {
+ b.Errorf("b.N=%d but handled %d", b.N, handled)
+ }
+}
+
+// same as above, but representing the most simple possible request
+// and handler. Notably: the handler does not call rw.Header().
+func BenchmarkServerFakeConnWithKeepAliveLite(b *testing.B) {
+ b.ReportAllocs()
+
+ req := []byte(strings.Replace(`GET / HTTP/1.1
+Host: golang.org
+
+`, "\n", "\r\n", -1))
+ res := []byte("Hello world!\n")
+
+ conn := &rwTestConn{
+ Reader: &repeatReader{content: req, count: b.N},
+ Writer: ioutil.Discard,
+ closec: make(chan bool, 1),
+ }
+ handled := 0
+ handler := HandlerFunc(func(rw ResponseWriter, r *Request) {
+ handled++
+ rw.Write(res)
+ })
+ ln := &oneConnListener{conn: conn}
+ go Serve(ln, handler)
+ <-conn.closec
+ if b.N != handled {
+ b.Errorf("b.N=%d but handled %d", b.N, handled)
+ }
+}
+
+const someResponse = "<html>some response</html>"
+
+// A Response that's just no bigger than 2KB, the buffer-before-chunking threshold.
+var response = bytes.Repeat([]byte(someResponse), 2<<10/len(someResponse))
+
+// Both Content-Type and Content-Length set. Should be no buffering.
+func BenchmarkServerHandlerTypeLen(b *testing.B) {
+ benchmarkHandler(b, HandlerFunc(func(w ResponseWriter, r *Request) {
+ w.Header().Set("Content-Type", "text/html")
+ w.Header().Set("Content-Length", strconv.Itoa(len(response)))
+ w.Write(response)
+ }))
+}
+
+// A Content-Type is set, but no length. No sniffing, but will count the Content-Length.
+func BenchmarkServerHandlerNoLen(b *testing.B) {
+ benchmarkHandler(b, HandlerFunc(func(w ResponseWriter, r *Request) {
+ w.Header().Set("Content-Type", "text/html")
+ w.Write(response)
+ }))
+}
+
+// A Content-Length is set, but the Content-Type will be sniffed.
+func BenchmarkServerHandlerNoType(b *testing.B) {
+ benchmarkHandler(b, HandlerFunc(func(w ResponseWriter, r *Request) {
+ w.Header().Set("Content-Length", strconv.Itoa(len(response)))
+ w.Write(response)
+ }))
+}
+
+// Neither a Content-Type or Content-Length, so sniffed and counted.
+func BenchmarkServerHandlerNoHeader(b *testing.B) {
+ benchmarkHandler(b, HandlerFunc(func(w ResponseWriter, r *Request) {
+ w.Write(response)
+ }))
+}
+
+func benchmarkHandler(b *testing.B, h Handler) {
+ b.ReportAllocs()
+ req := []byte(strings.Replace(`GET / HTTP/1.1
+Host: golang.org
+
+`, "\n", "\r\n", -1))
+ conn := &rwTestConn{
+ Reader: &repeatReader{content: req, count: b.N},
+ Writer: ioutil.Discard,
+ closec: make(chan bool, 1),
+ }
+ handled := 0
+ handler := HandlerFunc(func(rw ResponseWriter, r *Request) {
+ handled++
+ h.ServeHTTP(rw, r)
+ })
+ ln := &oneConnListener{conn: conn}
+ go Serve(ln, handler)
+ <-conn.closec
+ if b.N != handled {
+ b.Errorf("b.N=%d but handled %d", b.N, handled)
+ }
+}
diff --git a/src/pkg/net/http/server.go b/src/pkg/net/http/server.go
index b6ab78228..b25960705 100644
--- a/src/pkg/net/http/server.go
+++ b/src/pkg/net/http/server.go
@@ -4,9 +4,6 @@
// HTTP server. See RFC 2616.
-// TODO(rsc):
-// logging
-
package http
import (
@@ -109,9 +106,11 @@ type conn struct {
remoteAddr string // network address of remote side
server *Server // the Server on which the connection arrived
rwc net.Conn // i/o connection
- sr switchReader // where the LimitReader reads from; usually the rwc
+ sr liveSwitchReader // where the LimitReader reads from; usually the rwc
lr *io.LimitedReader // io.LimitReader(sr)
buf *bufio.ReadWriter // buffered(lr,rwc), reading from bufio->limitReader->sr->rwc
+ bufswr *switchReader // the *switchReader io.Reader source of buf
+ bufsww *switchWriter // the *switchWriter io.Writer dest of buf
tlsState *tls.ConnectionState // or nil when not using TLS
mu sync.Mutex // guards the following
@@ -147,7 +146,7 @@ func (c *conn) closeNotify() <-chan bool {
c.mu.Lock()
defer c.mu.Unlock()
if c.closeNotifyc == nil {
- c.closeNotifyc = make(chan bool)
+ c.closeNotifyc = make(chan bool, 1)
if c.hijackedv {
// to obey the function signature, even though
// it'll never receive a value.
@@ -180,12 +179,26 @@ func (c *conn) noteClientGone() {
c.clientGone = true
}
+// A switchReader can have its Reader changed at runtime.
+// It's not safe for concurrent Reads and switches.
type switchReader struct {
+ io.Reader
+}
+
+// A switchWriter can have its Writer changed at runtime.
+// It's not safe for concurrent Writes and switches.
+type switchWriter struct {
+ io.Writer
+}
+
+// A liveSwitchReader is a switchReader that's safe for concurrent
+// reads and switches, if its mutex is held.
+type liveSwitchReader struct {
sync.Mutex
r io.Reader
}
-func (sr *switchReader) Read(p []byte) (n int, err error) {
+func (sr *liveSwitchReader) Read(p []byte) (n int, err error) {
sr.Lock()
r := sr.r
sr.Unlock()
@@ -206,15 +219,28 @@ const bufferBeforeChunkingSize = 2048
//
// See the comment above (*response).Write for the entire write flow.
type chunkWriter struct {
- res *response
- header Header // a deep copy of r.Header, once WriteHeader is called
- wroteHeader bool // whether the header's been sent
+ res *response
+
+ // header is either nil or a deep clone of res.handlerHeader
+ // at the time of res.WriteHeader, if res.WriteHeader is
+ // called and extra buffering is being done to calculate
+ // Content-Type and/or Content-Length.
+ header Header
+
+ // wroteHeader tells whether the header's been written to "the
+ // wire" (or rather: w.conn.buf). this is unlike
+ // (*response).wroteHeader, which tells only whether it was
+ // logically written.
+ wroteHeader bool
// set by the writeHeader method:
chunking bool // using chunked transfer encoding for reply body
}
-var crlf = []byte("\r\n")
+var (
+ crlf = []byte("\r\n")
+ colonSpace = []byte(": ")
+)
func (cw *chunkWriter) Write(p []byte) (n int, err error) {
if !cw.wroteHeader {
@@ -264,13 +290,15 @@ type response struct {
wroteContinue bool // 100 Continue response was written
w *bufio.Writer // buffers output in chunks to chunkWriter
- cw *chunkWriter
+ cw chunkWriter
+ sw *switchWriter // of the bufio.Writer, for return to putBufioWriter
// handlerHeader is the Header that Handlers get access to,
// which may be retained and mutated even after WriteHeader.
// handlerHeader is copied into cw.header at WriteHeader
// time, and privately mutated thereafter.
handlerHeader Header
+ calledHeader bool // handler accessed handlerHeader via Header
written int64 // number of bytes written in body
contentLength int64 // explicitly-declared Content-Length; or -1
@@ -362,14 +390,98 @@ func (srv *Server) newConn(rwc net.Conn) (c *conn, err error) {
if debugServerConnections {
c.rwc = newLoggingConn("server", c.rwc)
}
- c.sr = switchReader{r: c.rwc}
+ c.sr = liveSwitchReader{r: c.rwc}
c.lr = io.LimitReader(&c.sr, noLimit).(*io.LimitedReader)
- br := bufio.NewReader(c.lr)
- bw := bufio.NewWriter(c.rwc)
+ br, sr := newBufioReader(c.lr)
+ bw, sw := newBufioWriterSize(c.rwc, 4<<10)
c.buf = bufio.NewReadWriter(br, bw)
+ c.bufswr = sr
+ c.bufsww = sw
return c, nil
}
+// TODO: remove this, if issue 5100 is fixed
+type bufioReaderPair struct {
+ br *bufio.Reader
+ sr *switchReader // from which the bufio.Reader is reading
+}
+
+// TODO: remove this, if issue 5100 is fixed
+type bufioWriterPair struct {
+ bw *bufio.Writer
+ sw *switchWriter // to which the bufio.Writer is writing
+}
+
+// TODO: use a sync.Cache instead
+var (
+ bufioReaderCache = make(chan bufioReaderPair, 4)
+ bufioWriterCache2k = make(chan bufioWriterPair, 4)
+ bufioWriterCache4k = make(chan bufioWriterPair, 4)
+)
+
+func bufioWriterCache(size int) chan bufioWriterPair {
+ switch size {
+ case 2 << 10:
+ return bufioWriterCache2k
+ case 4 << 10:
+ return bufioWriterCache4k
+ }
+ return nil
+}
+
+func newBufioReader(r io.Reader) (*bufio.Reader, *switchReader) {
+ select {
+ case p := <-bufioReaderCache:
+ p.sr.Reader = r
+ return p.br, p.sr
+ default:
+ sr := &switchReader{r}
+ return bufio.NewReader(sr), sr
+ }
+}
+
+func putBufioReader(br *bufio.Reader, sr *switchReader) {
+ if n := br.Buffered(); n > 0 {
+ io.CopyN(ioutil.Discard, br, int64(n))
+ }
+ br.Read(nil) // clears br.err
+ sr.Reader = nil
+ select {
+ case bufioReaderCache <- bufioReaderPair{br, sr}:
+ default:
+ }
+}
+
+func newBufioWriterSize(w io.Writer, size int) (*bufio.Writer, *switchWriter) {
+ select {
+ case p := <-bufioWriterCache(size):
+ p.sw.Writer = w
+ return p.bw, p.sw
+ default:
+ sw := &switchWriter{w}
+ return bufio.NewWriterSize(sw, size), sw
+ }
+}
+
+func putBufioWriter(bw *bufio.Writer, sw *switchWriter) {
+ if bw.Buffered() > 0 {
+ // It must have failed to flush to its target
+ // earlier. We can't reuse this bufio.Writer.
+ return
+ }
+ if err := bw.Flush(); err != nil {
+ // Its sticky error field is set, which is returned by
+ // Flush even when there's no data buffered. This
+ // bufio Writer is dead to us. Don't reuse it.
+ return
+ }
+ sw.Writer = nil
+ select {
+ case bufioWriterCache(bw.Available()) <- bufioWriterPair{bw, sw}:
+ default:
+ }
+}
+
// DefaultMaxHeaderBytes is the maximum permitted size of the headers
// in an HTTP request.
// This can be overridden by setting Server.MaxHeaderBytes.
@@ -448,14 +560,20 @@ func (c *conn) readRequest() (w *response, err error) {
req: req,
handlerHeader: make(Header),
contentLength: -1,
- cw: new(chunkWriter),
}
w.cw.res = w
- w.w = bufio.NewWriterSize(w.cw, bufferBeforeChunkingSize)
+ w.w, w.sw = newBufioWriterSize(&w.cw, bufferBeforeChunkingSize)
return w, nil
}
func (w *response) Header() Header {
+ if w.cw.header == nil && w.wroteHeader && !w.cw.wroteHeader {
+ // Accessing the header between logically writing it
+ // and physically writing it means we need to allocate
+ // a clone to snapshot the logically written state.
+ w.cw.header = w.handlerHeader.clone()
+ }
+ w.calledHeader = true
return w.handlerHeader
}
@@ -482,15 +600,48 @@ func (w *response) WriteHeader(code int) {
w.wroteHeader = true
w.status = code
- w.cw.header = w.handlerHeader.clone()
+ if w.calledHeader && w.cw.header == nil {
+ w.cw.header = w.handlerHeader.clone()
+ }
- if cl := w.cw.header.get("Content-Length"); cl != "" {
+ if cl := w.handlerHeader.get("Content-Length"); cl != "" {
v, err := strconv.ParseInt(cl, 10, 64)
if err == nil && v >= 0 {
w.contentLength = v
} else {
log.Printf("http: invalid Content-Length of %q", cl)
- w.cw.header.Del("Content-Length")
+ w.handlerHeader.Del("Content-Length")
+ }
+ }
+}
+
+// extraHeader is the set of headers sometimes added by chunkWriter.writeHeader.
+// This type is used to avoid extra allocations from cloning and/or populating
+// the response Header map and all its 1-element slices.
+type extraHeader struct {
+ contentType string
+ contentLength string
+ connection string
+ date string
+ transferEncoding string
+}
+
+// Sorted the same as extraHeader.Write's loop.
+var extraHeaderKeys = [][]byte{
+ []byte("Content-Type"), []byte("Content-Length"),
+ []byte("Connection"), []byte("Date"), []byte("Transfer-Encoding"),
+}
+
+// The value receiver, despite copying 5 strings to the stack,
+// prevents an extra allocation. The escape analysis isn't smart
+// enough to realize this doesn't mutate h.
+func (h extraHeader) Write(w io.Writer) {
+ for i, v := range []string{h.contentType, h.contentLength, h.connection, h.date, h.transferEncoding} {
+ if v != "" {
+ w.Write(extraHeaderKeys[i])
+ w.Write(colonSpace)
+ io.WriteString(w, v)
+ w.Write(crlf)
}
}
}
@@ -510,23 +661,47 @@ func (cw *chunkWriter) writeHeader(p []byte) {
cw.wroteHeader = true
w := cw.res
- code := w.status
- done := w.handlerDone
+
+ // header is written out to w.conn.buf below. Depending on the
+ // state of the handler, we either own the map or not. If we
+ // don't own it, the exclude map is created lazily for
+ // WriteSubset to remove headers. The setHeader struct holds
+ // headers we need to add.
+ header := cw.header
+ owned := header != nil
+ if !owned {
+ header = w.handlerHeader
+ }
+ var excludeHeader map[string]bool
+ delHeader := func(key string) {
+ if owned {
+ header.Del(key)
+ return
+ }
+ if _, ok := header[key]; !ok {
+ return
+ }
+ if excludeHeader == nil {
+ excludeHeader = make(map[string]bool)
+ }
+ excludeHeader[key] = true
+ }
+ var setHeader extraHeader
// If the handler is done but never sent a Content-Length
// response header and this is our first (and last) write, set
// it, even to zero. This helps HTTP/1.0 clients keep their
// "keep-alive" connections alive.
- if done && cw.header.get("Content-Length") == "" && w.req.Method != "HEAD" {
+ if w.handlerDone && header.get("Content-Length") == "" && w.req.Method != "HEAD" {
w.contentLength = int64(len(p))
- cw.header.Set("Content-Length", strconv.Itoa(len(p)))
+ setHeader.contentLength = strconv.Itoa(len(p))
}
// 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() {
- sentLength := cw.header.get("Content-Length") != ""
- if sentLength && cw.header.get("Connection") == "keep-alive" {
+ sentLength := header.get("Content-Length") != ""
+ if sentLength && header.get("Connection") == "keep-alive" {
w.closeAfterReply = false
}
}
@@ -535,15 +710,15 @@ func (cw *chunkWriter) writeHeader(p []byte) {
hasCL := w.contentLength != -1
if w.req.wantsHttp10KeepAlive() && (w.req.Method == "HEAD" || hasCL) {
- _, connectionHeaderSet := cw.header["Connection"]
+ _, connectionHeaderSet := header["Connection"]
if !connectionHeaderSet {
- cw.header.Set("Connection", "keep-alive")
+ setHeader.connection = "keep-alive"
}
} else if !w.req.ProtoAtLeast(1, 1) || w.req.wantsClose() {
w.closeAfterReply = true
}
- if cw.header.get("Connection") == "close" {
+ if header.get("Connection") == "close" {
w.closeAfterReply = true
}
@@ -557,49 +732,49 @@ func (cw *chunkWriter) writeHeader(p []byte) {
n, _ := io.CopyN(ioutil.Discard, w.req.Body, maxPostHandlerReadBytes+1)
if n >= maxPostHandlerReadBytes {
w.requestTooLarge()
- cw.header.Set("Connection", "close")
+ delHeader("Connection")
+ setHeader.connection = "close"
} else {
w.req.Body.Close()
}
}
}
+ code := w.status
if code == StatusNotModified {
// Must not have body.
- for _, header := range []string{"Content-Type", "Content-Length", "Transfer-Encoding"} {
- // RFC 2616 section 10.3.5: "the response MUST NOT include other entity-headers"
- if cw.header.get(header) != "" {
- cw.header.Del(header)
- }
+ // RFC 2616 section 10.3.5: "the response MUST NOT include other entity-headers"
+ for _, k := range []string{"Content-Type", "Content-Length", "Transfer-Encoding"} {
+ delHeader(k)
}
} else {
// If no content type, apply sniffing algorithm to body.
- if cw.header.get("Content-Type") == "" && w.req.Method != "HEAD" {
- cw.header.Set("Content-Type", DetectContentType(p))
+ if header.get("Content-Type") == "" && w.req.Method != "HEAD" {
+ setHeader.contentType = DetectContentType(p)
}
}
- if _, ok := cw.header["Date"]; !ok {
- cw.header.Set("Date", time.Now().UTC().Format(TimeFormat))
+ if _, ok := header["Date"]; !ok {
+ setHeader.date = time.Now().UTC().Format(TimeFormat)
}
- te := cw.header.get("Transfer-Encoding")
+ te := header.get("Transfer-Encoding")
hasTE := te != ""
if hasCL && hasTE && te != "identity" {
// TODO: return an error if WriteHeader gets a return parameter
// For now just ignore the Content-Length.
log.Printf("http: WriteHeader called with both Transfer-Encoding of %q and a Content-Length of %d",
te, w.contentLength)
- cw.header.Del("Content-Length")
+ delHeader("Content-Length")
hasCL = false
}
if w.req.Method == "HEAD" || code == StatusNotModified {
// do nothing
} else if code == StatusNoContent {
- cw.header.Del("Transfer-Encoding")
+ delHeader("Transfer-Encoding")
} else if hasCL {
- cw.header.Del("Transfer-Encoding")
+ delHeader("Transfer-Encoding")
} else if w.req.ProtoAtLeast(1, 1) {
// HTTP/1.1 or greater: use chunked transfer encoding
// to avoid closing the connection at EOF.
@@ -607,29 +782,63 @@ func (cw *chunkWriter) writeHeader(p []byte) {
// might have set. Deal with that as need arises once we have a valid
// use case.
cw.chunking = true
- cw.header.Set("Transfer-Encoding", "chunked")
+ setHeader.transferEncoding = "chunked"
} else {
// HTTP version < 1.1: cannot do chunked transfer
// encoding and we don't know the Content-Length so
// signal EOF by closing connection.
w.closeAfterReply = true
- cw.header.Del("Transfer-Encoding") // in case already set
+ delHeader("Transfer-Encoding") // in case already set
}
// Cannot use Content-Length with non-identity Transfer-Encoding.
if cw.chunking {
- cw.header.Del("Content-Length")
+ delHeader("Content-Length")
}
if !w.req.ProtoAtLeast(1, 0) {
return
}
if w.closeAfterReply && !hasToken(cw.header.get("Connection"), "close") {
- cw.header.Set("Connection", "close")
+ delHeader("Connection")
+ setHeader.connection = "close"
}
+ io.WriteString(w.conn.buf, statusLine(w.req, code))
+ cw.header.WriteSubset(w.conn.buf, excludeHeader)
+ setHeader.Write(w.conn.buf)
+ w.conn.buf.Write(crlf)
+}
+
+// statusLines is a cache of Status-Line strings, keyed by code (for
+// HTTP/1.1) or negative code (for HTTP/1.0). This is faster than a
+// map keyed by struct of two fields. This map's max size is bounded
+// by 2*len(statusText), two protocol types for each known official
+// status code in the statusText map.
+var (
+ statusMu sync.RWMutex
+ statusLines = make(map[int]string)
+)
+
+// statusLine returns a response Status-Line (RFC 2616 Section 6.1)
+// for the given request and response status code.
+func statusLine(req *Request, code int) string {
+ // Fast path:
+ key := code
+ proto11 := req.ProtoAtLeast(1, 1)
+ if !proto11 {
+ key = -key
+ }
+ statusMu.RLock()
+ line, ok := statusLines[key]
+ statusMu.RUnlock()
+ if ok {
+ return line
+ }
+
+ // Slow path:
proto := "HTTP/1.0"
- if w.req.ProtoAtLeast(1, 1) {
+ if proto11 {
proto = "HTTP/1.1"
}
codestring := strconv.Itoa(code)
@@ -637,9 +846,13 @@ func (cw *chunkWriter) writeHeader(p []byte) {
if !ok {
text = "status code " + codestring
}
- io.WriteString(w.conn.buf, proto+" "+codestring+" "+text+"\r\n")
- cw.header.Write(w.conn.buf)
- w.conn.buf.Write(crlf)
+ line = proto + " " + codestring + " " + text + "\r\n"
+ if ok {
+ statusMu.Lock()
+ defer statusMu.Unlock()
+ statusLines[key] = line
+ }
+ return line
}
// bodyAllowed returns true if a Write is allowed for this response type.
@@ -655,7 +868,7 @@ func (w *response) bodyAllowed() bool {
//
// Handler starts. No header has been sent. The handler can either
// write a header, or just start writing. Writing before sending a header
-// sends an implicity empty 200 OK header.
+// sends an implicitly empty 200 OK header.
//
// If the handler didn't declare a Content-Length up front, we either
// go into chunking mode or, if the handler finishes running before
@@ -713,6 +926,7 @@ func (w *response) finishRequest() {
}
w.w.Flush()
+ putBufioWriter(w.w, w.sw)
w.cw.close()
w.conn.buf.Flush()
@@ -742,6 +956,15 @@ func (w *response) Flush() {
func (c *conn) finalFlush() {
if c.buf != nil {
c.buf.Flush()
+
+ // Steal the bufio.Reader (~4KB worth of memory) and its associated
+ // reader for a future connection.
+ putBufioReader(c.buf.Reader, c.bufswr)
+
+ // Steal the bufio.Writer (~4KB worth of memory) and its associated
+ // writer for a future connection.
+ putBufioWriter(c.buf.Writer, c.bufsww)
+
c.buf = nil
}
}
@@ -948,13 +1171,16 @@ func NotFoundHandler() Handler { return HandlerFunc(NotFound) }
// request for a path that doesn't begin with prefix by
// replying with an HTTP 404 not found error.
func StripPrefix(prefix string, h Handler) Handler {
+ if prefix == "" {
+ return h
+ }
return HandlerFunc(func(w ResponseWriter, r *Request) {
- if !strings.HasPrefix(r.URL.Path, prefix) {
+ if p := strings.TrimPrefix(r.URL.Path, prefix); len(p) < len(r.URL.Path) {
+ r.URL.Path = p
+ h.ServeHTTP(w, r)
+ } else {
NotFound(w, r)
- return
}
- r.URL.Path = r.URL.Path[len(prefix):]
- h.ServeHTTP(w, r)
})
}
@@ -996,9 +1222,9 @@ func Redirect(w ResponseWriter, r *Request, urlStr string, code int) {
}
// clean up but preserve trailing slash
- trailing := urlStr[len(urlStr)-1] == '/'
+ trailing := strings.HasSuffix(urlStr, "/")
urlStr = path.Clean(urlStr)
- if trailing && urlStr[len(urlStr)-1] != '/' {
+ if trailing && !strings.HasSuffix(urlStr, "/") {
urlStr += "/"
}
urlStr += query
@@ -1266,7 +1492,7 @@ type Server struct {
// TLSNextProto optionally specifies a function to take over
// ownership of the provided TLS connection when an NPN
- // protocol upgrade has occured. The map key is the protocol
+ // 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
@@ -1337,7 +1563,6 @@ func (srv *Server) Serve(l net.Listener) error {
}
go c.serve()
}
- panic("not reached")
}
// ListenAndServe listens on the TCP network address addr
diff --git a/src/pkg/net/http/server_test.go b/src/pkg/net/http/server_test.go
index 8b4e8c6d6..e8b69f76c 100644
--- a/src/pkg/net/http/server_test.go
+++ b/src/pkg/net/http/server_test.go
@@ -2,9 +2,11 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-package http
+package http_test
import (
+ . "net/http"
+ "net/http/httptest"
"net/url"
"testing"
)
@@ -76,20 +78,27 @@ func TestServeMuxHandler(t *testing.T) {
},
}
h, pattern := mux.Handler(r)
- cs := &codeSaver{h: Header{}}
- h.ServeHTTP(cs, r)
- if pattern != tt.pattern || cs.code != tt.code {
- t.Errorf("%s %s %s = %d, %q, want %d, %q", tt.method, tt.host, tt.path, cs.code, pattern, tt.code, tt.pattern)
+ rr := httptest.NewRecorder()
+ h.ServeHTTP(rr, r)
+ if pattern != tt.pattern || rr.Code != tt.code {
+ t.Errorf("%s %s %s = %d, %q, want %d, %q", tt.method, tt.host, tt.path, rr.Code, pattern, tt.code, tt.pattern)
}
}
}
-// A codeSaver is a ResponseWriter that saves the code passed to WriteHeader.
-type codeSaver struct {
- h Header
- code int
+func TestServerRedirect(t *testing.T) {
+ // This used to crash. It's not valid input (bad path), but it
+ // shouldn't crash.
+ rr := httptest.NewRecorder()
+ req := &Request{
+ Method: "GET",
+ URL: &url.URL{
+ Scheme: "http",
+ Path: "not-empty-but-no-leading-slash", // bogus
+ },
+ }
+ Redirect(rr, req, "", 304)
+ if rr.Code != 304 {
+ t.Errorf("Code = %d; want 304", rr.Code)
+ }
}
-
-func (cs *codeSaver) Header() Header { return cs.h }
-func (cs *codeSaver) Write(p []byte) (int, error) { return len(p), nil }
-func (cs *codeSaver) WriteHeader(code int) { cs.code = code }
diff --git a/src/pkg/net/http/sniff_test.go b/src/pkg/net/http/sniff_test.go
index 8ab72ac23..106d94ec1 100644
--- a/src/pkg/net/http/sniff_test.go
+++ b/src/pkg/net/http/sniff_test.go
@@ -54,6 +54,7 @@ func TestDetectContentType(t *testing.T) {
}
func TestServerContentType(t *testing.T) {
+ defer afterTest(t)
ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) {
i, _ := strconv.Atoi(r.FormValue("i"))
tt := sniffTests[i]
@@ -84,6 +85,8 @@ func TestServerContentType(t *testing.T) {
}
func TestContentTypeWithCopy(t *testing.T) {
+ defer afterTest(t)
+
const (
input = "\n<html>\n\t<head>\n"
expected = "text/html; charset=utf-8"
@@ -116,6 +119,7 @@ func TestContentTypeWithCopy(t *testing.T) {
}
func TestSniffWriteSize(t *testing.T) {
+ defer afterTest(t)
ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) {
size, _ := strconv.Atoi(r.FormValue("size"))
written, err := io.WriteString(w, strings.Repeat("a", size))
@@ -133,6 +137,11 @@ func TestSniffWriteSize(t *testing.T) {
if err != nil {
t.Fatalf("size %d: %v", size, err)
}
- res.Body.Close()
+ if _, err := io.Copy(ioutil.Discard, res.Body); err != nil {
+ t.Fatalf("size %d: io.Copy of body = %v", size, err)
+ }
+ if err := res.Body.Close(); err != nil {
+ t.Fatalf("size %d: body Close = %v", size, err)
+ }
}
}
diff --git a/src/pkg/net/http/status.go b/src/pkg/net/http/status.go
index 5af0b77c4..d253bd5cb 100644
--- a/src/pkg/net/http/status.go
+++ b/src/pkg/net/http/status.go
@@ -51,6 +51,13 @@ const (
StatusServiceUnavailable = 503
StatusGatewayTimeout = 504
StatusHTTPVersionNotSupported = 505
+
+ // New HTTP status codes from RFC 6585. Not exported yet in Go 1.1.
+ // See discussion at https://codereview.appspot.com/7678043/
+ statusPreconditionRequired = 428
+ statusTooManyRequests = 429
+ statusRequestHeaderFieldsTooLarge = 431
+ statusNetworkAuthenticationRequired = 511
)
var statusText = map[int]string{
@@ -99,6 +106,11 @@ var statusText = map[int]string{
StatusServiceUnavailable: "Service Unavailable",
StatusGatewayTimeout: "Gateway Timeout",
StatusHTTPVersionNotSupported: "HTTP Version Not Supported",
+
+ statusPreconditionRequired: "Precondition Required",
+ statusTooManyRequests: "Too Many Requests",
+ statusRequestHeaderFieldsTooLarge: "Request Header Fields Too Large",
+ statusNetworkAuthenticationRequired: "Network Authentication Required",
}
// StatusText returns a text for the HTTP status code. It returns the empty
diff --git a/src/pkg/net/http/transfer.go b/src/pkg/net/http/transfer.go
index 43c6023a3..53569bcc2 100644
--- a/src/pkg/net/http/transfer.go
+++ b/src/pkg/net/http/transfer.go
@@ -328,12 +328,13 @@ func readTransfer(msg interface{}, r *bufio.Reader) (err error) {
switch {
case chunked(t.TransferEncoding):
if noBodyExpected(t.RequestMethod) {
- t.Body = &body{Reader: io.LimitReader(r, 0), closing: t.Close}
+ t.Body = &body{Reader: eofReader, closing: t.Close}
} else {
t.Body = &body{Reader: newChunkedReader(r), hdr: msg, r: r, closing: t.Close}
}
- case realLength >= 0:
- // TODO: limit the Content-Length. This is an easy DoS vector.
+ case realLength == 0:
+ t.Body = &body{Reader: eofReader, closing: t.Close}
+ case realLength > 0:
t.Body = &body{Reader: io.LimitReader(r, realLength), closing: t.Close}
default:
// realLength < 0, i.e. "Content-Length" not mentioned in header
@@ -342,7 +343,7 @@ func readTransfer(msg interface{}, r *bufio.Reader) (err error) {
t.Body = &body{Reader: r, closing: t.Close}
} else {
// Persistent connection (i.e. HTTP/1.1)
- t.Body = &body{Reader: io.LimitReader(r, 0), closing: t.Close}
+ t.Body = &body{Reader: eofReader, closing: t.Close}
}
}
@@ -612,30 +613,26 @@ func (b *body) Close() error {
if b.closed {
return nil
}
- defer func() {
- b.closed = true
- }()
- if b.hdr == nil && b.closing {
+ var err error
+ switch {
+ case b.hdr == nil && b.closing:
// no trailer and closing the connection next.
// no point in reading to EOF.
- return nil
- }
-
- // In a server request, don't continue reading from the client
- // if we've already hit the maximum body size set by the
- // handler. If this is set, that also means the TCP connection
- // is about to be closed, so getting to the next HTTP request
- // in the stream is not necessary.
- if b.res != nil && b.res.requestBodyLimitHit {
- return nil
- }
-
- // Fully consume the body, which will also lead to us reading
- // the trailer headers after the body, if present.
- if _, err := io.Copy(ioutil.Discard, b); err != nil {
- return err
+ case b.res != nil && b.res.requestBodyLimitHit:
+ // In a server request, don't continue reading from the client
+ // if we've already hit the maximum body size set by the
+ // handler. If this is set, that also means the TCP connection
+ // is about to be closed, so getting to the next HTTP request
+ // in the stream is not necessary.
+ case b.Reader == eofReader:
+ // Nothing to read. No need to io.Copy from it.
+ default:
+ // Fully consume the body, which will also lead to us reading
+ // the trailer headers after the body, if present.
+ _, err = io.Copy(ioutil.Discard, b)
}
- return nil
+ b.closed = true
+ return err
}
// parseContentLength trims whitespace from s and returns -1 if no value
diff --git a/src/pkg/net/http/transport.go b/src/pkg/net/http/transport.go
index 685d7d56c..4cd0533ff 100644
--- a/src/pkg/net/http/transport.go
+++ b/src/pkg/net/http/transport.go
@@ -17,7 +17,6 @@ import (
"errors"
"fmt"
"io"
- "io/ioutil"
"log"
"net"
"net/url"
@@ -42,16 +41,13 @@ const DefaultMaxIdleConnsPerHost = 2
// https, and http proxies (for either http or https with CONNECT).
// Transport can also cache connections for future re-use.
type Transport struct {
- idleMu sync.Mutex
- idleConn map[string][]*persistConn
- reqMu sync.Mutex
- reqConn map[*Request]*persistConn
- altMu sync.RWMutex
- altProto map[string]RoundTripper // nil or map of URI scheme => RoundTripper
-
- // TODO: tunable on global max cached connections
- // TODO: tunable on timeout on cached connections
- // TODO: optional pipelining
+ idleMu sync.Mutex
+ idleConn map[string][]*persistConn
+ idleConnCh map[string]chan *persistConn
+ reqMu sync.Mutex
+ reqConn map[*Request]*persistConn
+ altMu sync.RWMutex
+ altProto map[string]RoundTripper // nil or map of URI scheme => RoundTripper
// Proxy specifies a function to return a proxy for a given
// Request. If the function returns a non-nil error, the
@@ -62,13 +58,24 @@ type Transport struct {
// Dial specifies the dial function for creating TCP
// connections.
// If Dial is nil, net.Dial is used.
- Dial func(net, addr string) (c net.Conn, err error)
+ Dial func(network, addr string) (net.Conn, error)
// TLSClientConfig specifies the TLS configuration to use with
// tls.Client. If nil, the default configuration is used.
TLSClientConfig *tls.Config
- DisableKeepAlives bool
+ // DisableKeepAlives, if true, prevents re-use of TCP connections
+ // between different HTTP requests.
+ DisableKeepAlives bool
+
+ // DisableCompression, if true, prevents the Transport from
+ // requesting compression with an "Accept-Encoding: gzip"
+ // request header when the Request contains no existing
+ // Accept-Encoding value. If the Transport requests gzip on
+ // its own and gets a gzipped response, it's transparently
+ // decoded in the Response.Body. However, if the user
+ // explicitly requested gzip it is not automatically
+ // uncompressed.
DisableCompression bool
// MaxIdleConnsPerHost, if non-zero, controls the maximum idle
@@ -81,6 +88,9 @@ type Transport struct {
// writing the request (including its body, if any). This
// time does not include the time to read the response body.
ResponseHeaderTimeout time.Duration
+
+ // TODO: tunable on global max cached connections
+ // TODO: tunable on timeout on cached connections
}
// ProxyFromEnvironment returns the URL of the proxy to use for a
@@ -133,6 +143,9 @@ func (tr *transportRequest) extraHeaders() Header {
}
// RoundTrip implements the RoundTripper interface.
+//
+// For higher-level HTTP client support (such as handling of cookies
+// and redirects), see Get, Post, and the Client type.
func (t *Transport) RoundTrip(req *Request) (resp *Response, err error) {
if req.URL == nil {
return nil, errors.New("http: nil Request.URL")
@@ -280,6 +293,17 @@ func (t *Transport) putIdleConn(pconn *persistConn) bool {
max = DefaultMaxIdleConnsPerHost
}
t.idleMu.Lock()
+ select {
+ case t.idleConnCh[key] <- pconn:
+ // 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
+ // https://insouciant.org/tech/connection-management-in-chromium/
+ t.idleMu.Unlock()
+ return true
+ default:
+ }
if t.idleConn == nil {
t.idleConn = make(map[string][]*persistConn)
}
@@ -298,8 +322,23 @@ func (t *Transport) putIdleConn(pconn *persistConn) bool {
return true
}
+func (t *Transport) getIdleConnCh(cm *connectMethod) chan *persistConn {
+ key := cm.key()
+ t.idleMu.Lock()
+ defer t.idleMu.Unlock()
+ if t.idleConnCh == nil {
+ t.idleConnCh = make(map[string]chan *persistConn)
+ }
+ ch, ok := t.idleConnCh[key]
+ if !ok {
+ ch = make(chan *persistConn)
+ t.idleConnCh[key] = ch
+ }
+ return ch
+}
+
func (t *Transport) getIdleConn(cm *connectMethod) (pconn *persistConn) {
- key := cm.String()
+ key := cm.key()
t.idleMu.Lock()
defer t.idleMu.Unlock()
if t.idleConn == nil {
@@ -323,7 +362,6 @@ func (t *Transport) getIdleConn(cm *connectMethod) (pconn *persistConn) {
return
}
}
- panic("unreachable")
}
func (t *Transport) setReqConn(r *Request, pc *persistConn) {
@@ -355,6 +393,37 @@ func (t *Transport) getConn(cm *connectMethod) (*persistConn, error) {
return pc, nil
}
+ type dialRes struct {
+ pc *persistConn
+ err error
+ }
+ dialc := make(chan dialRes)
+ go func() {
+ pc, err := t.dialConn(cm)
+ dialc <- dialRes{pc, err}
+ }()
+
+ idleConnCh := t.getIdleConnCh(cm)
+ select {
+ case v := <-dialc:
+ // Our dial finished.
+ return v.pc, v.err
+ case pc := <-idleConnCh:
+ // Another request finished first and its net.Conn
+ // became available before our dial. Or somebody
+ // else's dial that they didn't use.
+ // But our dial is still going, so give it away
+ // when it finishes:
+ go func() {
+ if v := <-dialc; v.err == nil {
+ t.putIdleConn(v.pc)
+ }
+ }()
+ return pc, nil
+ }
+}
+
+func (t *Transport) dialConn(cm *connectMethod) (*persistConn, error) {
conn, err := t.dial("tcp", cm.addr())
if err != nil {
if cm.proxyURL != nil {
@@ -367,7 +436,7 @@ func (t *Transport) getConn(cm *connectMethod) (*persistConn, error) {
pconn := &persistConn{
t: t,
- cacheKey: cm.String(),
+ cacheKey: cm.key(),
conn: conn,
reqch: make(chan requestAndChan, 50),
writech: make(chan writeRequest, 50),
@@ -517,6 +586,10 @@ type connectMethod struct {
targetAddr string // Not used if proxy + http targetScheme (4th example in table)
}
+func (ck *connectMethod) key() string {
+ return ck.String() // TODO: use a struct type instead
+}
+
func (ck *connectMethod) String() string {
proxyStr := ""
targetAddr := ck.targetAddr
@@ -592,7 +665,6 @@ func remoteSideClosed(err error) bool {
func (pc *persistConn) readLoop() {
defer close(pc.closech)
alive := true
- var lastbody io.ReadCloser // last response body, if any, read on this connection
for alive {
pb, err := pc.br.Peek(1)
@@ -611,16 +683,17 @@ func (pc *persistConn) readLoop() {
rc := <-pc.reqch
- // Advance past the previous response's body, if the
- // caller hasn't done so.
- if lastbody != nil {
- lastbody.Close() // assumed idempotent
- lastbody = nil
- }
-
var resp *Response
if err == nil {
resp, err = ReadResponse(pc.br, rc.req)
+ if err == nil && resp.StatusCode == 100 {
+ // Skip any 100-continue for now.
+ // TODO(bradfitz): if rc.req had "Expect: 100-continue",
+ // actually block the request body write and signal the
+ // writeLoop now to begin sending it. (Issue 2184) For now we
+ // eat it, since we're never expecting one.
+ resp, err = ReadResponse(pc.br, rc.req)
+ }
}
hasBody := resp != nil && rc.req.Method != "HEAD" && resp.ContentLength != 0
@@ -636,20 +709,29 @@ func (pc *persistConn) readLoop() {
pc.close()
err = zerr
} else {
- resp.Body = &readFirstCloseBoth{&discardOnCloseReadCloser{gzReader}, resp.Body}
+ resp.Body = &readerAndCloser{gzReader, resp.Body}
}
}
resp.Body = &bodyEOFSignal{body: resp.Body}
}
- if err != nil || resp.Close || rc.req.Close {
+ if err != nil || resp.Close || rc.req.Close || resp.StatusCode <= 199 {
+ // Don't do keep-alive on error if either party requested a close
+ // or we get an unexpected informational (1xx) response.
+ // StatusCode 100 is already handled above.
alive = false
}
var waitForBodyRead chan bool
if hasBody {
- lastbody = resp.Body
- waitForBodyRead = make(chan bool, 1)
+ waitForBodyRead = make(chan bool, 2)
+ resp.Body.(*bodyEOFSignal).earlyCloseFn = func() error {
+ // Sending false here sets alive to
+ // false and closes the connection
+ // below.
+ waitForBodyRead <- false
+ return nil
+ }
resp.Body.(*bodyEOFSignal).fn = func(err error) {
alive1 := alive
if err != nil {
@@ -666,15 +748,6 @@ func (pc *persistConn) readLoop() {
}
if alive && !hasBody {
- // When there's no response body, we immediately
- // reuse the TCP connection (putIdleConn), but
- // we need to prevent ClientConn.Read from
- // closing the Response.Body on the next
- // loop, otherwise it might close the body
- // before the client code has had a chance to
- // read it (even though it'll just be 0, EOF).
- lastbody = nil
-
if !pc.t.putIdleConn(pc) {
alive = false
}
@@ -868,13 +941,16 @@ func canonicalAddr(url *url.URL) string {
// bodyEOFSignal wraps a ReadCloser but runs fn (if non-nil) at most
// once, right before its final (error-producing) Read or Close call
-// returns.
+// returns. If earlyCloseFn is non-nil and Close is called before
+// io.EOF is seen, earlyCloseFn is called instead of fn, and its
+// return value is the return value from Close.
type bodyEOFSignal struct {
- body io.ReadCloser
- mu sync.Mutex // guards closed, rerr and fn
- closed bool // whether Close has been called
- rerr error // sticky Read error
- fn func(error) // error will be nil on Read io.EOF
+ body io.ReadCloser
+ mu sync.Mutex // guards following 4 fields
+ closed bool // whether Close has been called
+ rerr error // sticky Read error
+ fn func(error) // error will be nil on Read io.EOF
+ earlyCloseFn func() error // optional alt Close func used if io.EOF not seen
}
func (es *bodyEOFSignal) Read(p []byte) (n int, err error) {
@@ -907,6 +983,9 @@ func (es *bodyEOFSignal) Close() error {
return nil
}
es.closed = true
+ if es.earlyCloseFn != nil && es.rerr != io.EOF {
+ return es.earlyCloseFn()
+ }
err := es.body.Close()
es.condfn(err)
return err
@@ -924,28 +1003,7 @@ func (es *bodyEOFSignal) condfn(err error) {
es.fn = nil
}
-type readFirstCloseBoth struct {
- io.ReadCloser
+type readerAndCloser struct {
+ io.Reader
io.Closer
}
-
-func (r *readFirstCloseBoth) Close() error {
- if err := r.ReadCloser.Close(); err != nil {
- r.Closer.Close()
- return err
- }
- if err := r.Closer.Close(); err != nil {
- return err
- }
- return nil
-}
-
-// discardOnCloseReadCloser consumes all its input on Close.
-type discardOnCloseReadCloser struct {
- io.ReadCloser
-}
-
-func (d *discardOnCloseReadCloser) Close() error {
- io.Copy(ioutil.Discard, d.ReadCloser) // ignore errors; likely invalid or already closed
- return d.ReadCloser.Close()
-}
diff --git a/src/pkg/net/http/transport_test.go b/src/pkg/net/http/transport_test.go
index 68010e68b..9f64a6e4b 100644
--- a/src/pkg/net/http/transport_test.go
+++ b/src/pkg/net/http/transport_test.go
@@ -7,6 +7,7 @@
package http_test
import (
+ "bufio"
"bytes"
"compress/gzip"
"crypto/rand"
@@ -102,7 +103,7 @@ func (tcs *testConnSet) check(t *testing.T) {
// Two subsequent requests and verify their response is the same.
// The response from the server is our own IP:port
func TestTransportKeepAlives(t *testing.T) {
- defer checkLeakedTransports(t)
+ defer afterTest(t)
ts := httptest.NewServer(hostPortHandler)
defer ts.Close()
@@ -135,7 +136,7 @@ func TestTransportKeepAlives(t *testing.T) {
}
func TestTransportConnectionCloseOnResponse(t *testing.T) {
- defer checkLeakedTransports(t)
+ defer afterTest(t)
ts := httptest.NewServer(hostPortHandler)
defer ts.Close()
@@ -186,7 +187,7 @@ func TestTransportConnectionCloseOnResponse(t *testing.T) {
}
func TestTransportConnectionCloseOnRequest(t *testing.T) {
- defer checkLeakedTransports(t)
+ defer afterTest(t)
ts := httptest.NewServer(hostPortHandler)
defer ts.Close()
@@ -237,7 +238,7 @@ func TestTransportConnectionCloseOnRequest(t *testing.T) {
}
func TestTransportIdleCacheKeys(t *testing.T) {
- defer checkLeakedTransports(t)
+ defer afterTest(t)
ts := httptest.NewServer(hostPortHandler)
defer ts.Close()
@@ -270,7 +271,7 @@ func TestTransportIdleCacheKeys(t *testing.T) {
}
func TestTransportMaxPerHostIdleConns(t *testing.T) {
- defer checkLeakedTransports(t)
+ defer afterTest(t)
resch := make(chan string)
gotReq := make(chan bool)
ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) {
@@ -339,7 +340,7 @@ func TestTransportMaxPerHostIdleConns(t *testing.T) {
}
func TestTransportServerClosingUnexpectedly(t *testing.T) {
- defer checkLeakedTransports(t)
+ defer afterTest(t)
ts := httptest.NewServer(hostPortHandler)
defer ts.Close()
@@ -396,7 +397,7 @@ func TestTransportServerClosingUnexpectedly(t *testing.T) {
// Test for http://golang.org/issue/2616 (appropriate issue number)
// This fails pretty reliably with GOMAXPROCS=100 or something high.
func TestStressSurpriseServerCloses(t *testing.T) {
- defer checkLeakedTransports(t)
+ defer afterTest(t)
if testing.Short() {
t.Skip("skipping test in short mode")
}
@@ -452,7 +453,7 @@ func TestStressSurpriseServerCloses(t *testing.T) {
// TestTransportHeadResponses verifies that we deal with Content-Lengths
// with no bodies properly
func TestTransportHeadResponses(t *testing.T) {
- defer checkLeakedTransports(t)
+ defer afterTest(t)
ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) {
if r.Method != "HEAD" {
panic("expected HEAD; got " + r.Method)
@@ -481,7 +482,7 @@ func TestTransportHeadResponses(t *testing.T) {
// TestTransportHeadChunkedResponse verifies that we ignore chunked transfer-encoding
// on responses to HEAD requests.
func TestTransportHeadChunkedResponse(t *testing.T) {
- defer checkLeakedTransports(t)
+ defer afterTest(t)
ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) {
if r.Method != "HEAD" {
panic("expected HEAD; got " + r.Method)
@@ -523,7 +524,7 @@ var roundTripTests = []struct {
// Test that the modification made to the Request by the RoundTripper is cleaned up
func TestRoundTripGzip(t *testing.T) {
- defer checkLeakedTransports(t)
+ defer afterTest(t)
const responseBody = "test response body"
ts := httptest.NewServer(HandlerFunc(func(rw ResponseWriter, req *Request) {
accept := req.Header.Get("Accept-Encoding")
@@ -580,7 +581,7 @@ func TestRoundTripGzip(t *testing.T) {
}
func TestTransportGzip(t *testing.T) {
- defer checkLeakedTransports(t)
+ defer afterTest(t)
const testString = "The test string aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
const nRandBytes = 1024 * 1024
ts := httptest.NewServer(HandlerFunc(func(rw ResponseWriter, req *Request) {
@@ -673,7 +674,7 @@ func TestTransportGzip(t *testing.T) {
}
func TestTransportProxy(t *testing.T) {
- defer checkLeakedTransports(t)
+ defer afterTest(t)
ch := make(chan string, 1)
ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) {
ch <- "real server"
@@ -702,7 +703,7 @@ func TestTransportProxy(t *testing.T) {
// but checks that we don't recurse forever, and checks that
// Content-Encoding is removed.
func TestTransportGzipRecursive(t *testing.T) {
- defer checkLeakedTransports(t)
+ defer afterTest(t)
ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) {
w.Header().Set("Content-Encoding", "gzip")
w.Write(rgz)
@@ -729,7 +730,7 @@ func TestTransportGzipRecursive(t *testing.T) {
// tests that persistent goroutine connections shut down when no longer desired.
func TestTransportPersistConnLeak(t *testing.T) {
- defer checkLeakedTransports(t)
+ defer afterTest(t)
gotReqCh := make(chan bool)
unblockCh := make(chan bool)
ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) {
@@ -795,7 +796,7 @@ func TestTransportPersistConnLeak(t *testing.T) {
// golang.org/issue/4531: Transport leaks goroutines when
// request.ContentLength is explicitly short
func TestTransportPersistConnLeakShortBody(t *testing.T) {
- defer checkLeakedTransports(t)
+ defer afterTest(t)
ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) {
}))
defer ts.Close()
@@ -834,7 +835,7 @@ func TestTransportPersistConnLeakShortBody(t *testing.T) {
// This used to crash; http://golang.org/issue/3266
func TestTransportIdleConnCrash(t *testing.T) {
- defer checkLeakedTransports(t)
+ defer afterTest(t)
tr := &Transport{}
c := &Client{Transport: tr}
@@ -864,7 +865,7 @@ func TestTransportIdleConnCrash(t *testing.T) {
// which sadly lacked a triggering test. The large response body made
// the old race easier to trigger.
func TestIssue3644(t *testing.T) {
- defer checkLeakedTransports(t)
+ defer afterTest(t)
const numFoos = 5000
ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) {
w.Header().Set("Connection", "close")
@@ -892,7 +893,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) {
- defer checkLeakedTransports(t)
+ defer afterTest(t)
const deniedMsg = "sorry, denied."
ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) {
Error(w, deniedMsg, StatusUnauthorized)
@@ -917,7 +918,7 @@ func TestIssue3595(t *testing.T) {
// From http://golang.org/issue/4454 ,
// "client fails to handle requests with no body and chunked encoding"
func TestChunkedNoContent(t *testing.T) {
- defer checkLeakedTransports(t)
+ defer afterTest(t)
ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) {
w.WriteHeader(StatusNoContent)
}))
@@ -940,21 +941,38 @@ func TestChunkedNoContent(t *testing.T) {
}
func TestTransportConcurrency(t *testing.T) {
- defer checkLeakedTransports(t)
- const maxProcs = 16
- const numReqs = 500
+ defer afterTest(t)
+ maxProcs, numReqs := 16, 500
+ if testing.Short() {
+ maxProcs, numReqs = 4, 50
+ }
defer runtime.GOMAXPROCS(runtime.GOMAXPROCS(maxProcs))
ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) {
fmt.Fprintf(w, "%v", r.FormValue("echo"))
}))
defer ts.Close()
- tr := &Transport{}
+
+ var wg sync.WaitGroup
+ wg.Add(numReqs)
+
+ tr := &Transport{
+ Dial: func(netw, addr string) (c net.Conn, err error) {
+ // 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. So count
+ // our dials as work too so the leak checker
+ // doesn't complain at us.
+ wg.Add(1)
+ defer wg.Done()
+ return net.Dial(netw, addr)
+ },
+ }
+ defer tr.CloseIdleConnections()
c := &Client{Transport: tr}
reqs := make(chan string)
defer close(reqs)
- var wg sync.WaitGroup
- wg.Add(numReqs)
for i := 0; i < maxProcs*2; i++ {
go func() {
for req := range reqs {
@@ -973,8 +991,8 @@ func TestTransportConcurrency(t *testing.T) {
if string(all) != req {
t.Errorf("body of req %s = %q; want %q", req, all, req)
}
- wg.Done()
res.Body.Close()
+ wg.Done()
}
}()
}
@@ -985,7 +1003,7 @@ func TestTransportConcurrency(t *testing.T) {
}
func TestIssue4191_InfiniteGetTimeout(t *testing.T) {
- defer checkLeakedTransports(t)
+ defer afterTest(t)
const debug = false
mux := NewServeMux()
mux.HandleFunc("/get", func(w ResponseWriter, r *Request) {
@@ -1046,7 +1064,7 @@ func TestIssue4191_InfiniteGetTimeout(t *testing.T) {
}
func TestIssue4191_InfiniteGetToPutTimeout(t *testing.T) {
- defer checkLeakedTransports(t)
+ defer afterTest(t)
const debug = false
mux := NewServeMux()
mux.HandleFunc("/get", func(w ResponseWriter, r *Request) {
@@ -1114,7 +1132,7 @@ func TestIssue4191_InfiniteGetToPutTimeout(t *testing.T) {
}
func TestTransportResponseHeaderTimeout(t *testing.T) {
- defer checkLeakedTransports(t)
+ defer afterTest(t)
if testing.Short() {
t.Skip("skipping timeout test in -short mode")
}
@@ -1161,7 +1179,7 @@ func TestTransportResponseHeaderTimeout(t *testing.T) {
}
func TestTransportCancelRequest(t *testing.T) {
- defer checkLeakedTransports(t)
+ defer afterTest(t)
if testing.Short() {
t.Skip("skipping test in -short mode")
}
@@ -1214,6 +1232,70 @@ func TestTransportCancelRequest(t *testing.T) {
}
}
+// golang.org/issue/3672 -- Client can't close HTTP stream
+// Calling Close on a Response.Body used to just read until EOF.
+// Now it actually closes the TCP connection.
+func TestTransportCloseResponseBody(t *testing.T) {
+ defer afterTest(t)
+ writeErr := make(chan error, 1)
+ msg := []byte("young\n")
+ ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) {
+ for {
+ _, err := w.Write(msg)
+ if err != nil {
+ writeErr <- err
+ return
+ }
+ w.(Flusher).Flush()
+ }
+ }))
+ defer ts.Close()
+
+ tr := &Transport{}
+ defer tr.CloseIdleConnections()
+ c := &Client{Transport: tr}
+
+ req, _ := NewRequest("GET", ts.URL, nil)
+ defer tr.CancelRequest(req)
+
+ res, err := c.Do(req)
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ const repeats = 3
+ buf := make([]byte, len(msg)*repeats)
+ want := bytes.Repeat(msg, repeats)
+
+ _, err = io.ReadFull(res.Body, buf)
+ if err != nil {
+ t.Fatal(err)
+ }
+ if !bytes.Equal(buf, want) {
+ t.Errorf("read %q; want %q", buf, want)
+ }
+ didClose := make(chan error, 1)
+ go func() {
+ didClose <- res.Body.Close()
+ }()
+ select {
+ case err := <-didClose:
+ if err != nil {
+ t.Errorf("Close = %v", err)
+ }
+ case <-time.After(10 * time.Second):
+ t.Fatal("too long waiting for close")
+ }
+ select {
+ case err := <-writeErr:
+ if err == nil {
+ t.Errorf("expected non-nil write error")
+ }
+ case <-time.After(10 * time.Second):
+ t.Fatal("too long waiting for write error")
+ }
+}
+
type fooProto struct{}
func (fooProto) RoundTrip(req *Request) (*Response, error) {
@@ -1227,7 +1309,7 @@ func (fooProto) RoundTrip(req *Request) (*Response, error) {
}
func TestTransportAltProto(t *testing.T) {
- defer checkLeakedTransports(t)
+ defer afterTest(t)
tr := &Transport{}
c := &Client{Transport: tr}
tr.RegisterProtocol("foo", fooProto{})
@@ -1246,7 +1328,7 @@ func TestTransportAltProto(t *testing.T) {
}
func TestTransportNoHost(t *testing.T) {
- defer checkLeakedTransports(t)
+ defer afterTest(t)
tr := &Transport{}
_, err := tr.RoundTrip(&Request{
Header: make(Header),
@@ -1260,6 +1342,172 @@ func TestTransportNoHost(t *testing.T) {
}
}
+func TestTransportSocketLateBinding(t *testing.T) {
+ defer afterTest(t)
+
+ mux := NewServeMux()
+ fooGate := make(chan bool, 1)
+ mux.HandleFunc("/foo", func(w ResponseWriter, r *Request) {
+ w.Header().Set("foo-ipport", r.RemoteAddr)
+ w.(Flusher).Flush()
+ <-fooGate
+ })
+ mux.HandleFunc("/bar", func(w ResponseWriter, r *Request) {
+ w.Header().Set("bar-ipport", r.RemoteAddr)
+ })
+ ts := httptest.NewServer(mux)
+ defer ts.Close()
+
+ dialGate := make(chan bool, 1)
+ tr := &Transport{
+ Dial: func(n, addr string) (net.Conn, error) {
+ <-dialGate
+ return net.Dial(n, addr)
+ },
+ DisableKeepAlives: false,
+ }
+ defer tr.CloseIdleConnections()
+ c := &Client{
+ Transport: tr,
+ }
+
+ dialGate <- true // only allow one dial
+ fooRes, err := c.Get(ts.URL + "/foo")
+ if err != nil {
+ t.Fatal(err)
+ }
+ fooAddr := fooRes.Header.Get("foo-ipport")
+ if fooAddr == "" {
+ t.Fatal("No addr on /foo request")
+ }
+ time.AfterFunc(200*time.Millisecond, func() {
+ // let the foo response finish so we can use its
+ // connection for /bar
+ fooGate <- true
+ io.Copy(ioutil.Discard, fooRes.Body)
+ fooRes.Body.Close()
+ })
+
+ barRes, err := c.Get(ts.URL + "/bar")
+ if err != nil {
+ t.Fatal(err)
+ }
+ barAddr := barRes.Header.Get("bar-ipport")
+ if barAddr != fooAddr {
+ t.Fatalf("/foo came from conn %q; /bar came from %q instead", fooAddr, barAddr)
+ }
+ barRes.Body.Close()
+ dialGate <- true
+}
+
+// Issue 2184
+func TestTransportReading100Continue(t *testing.T) {
+ defer afterTest(t)
+
+ const numReqs = 5
+ reqBody := func(n int) string { return fmt.Sprintf("request body %d", n) }
+ reqID := func(n int) string { return fmt.Sprintf("REQ-ID-%d", n) }
+
+ send100Response := func(w *io.PipeWriter, r *io.PipeReader) {
+ defer w.Close()
+ defer r.Close()
+ br := bufio.NewReader(r)
+ n := 0
+ for {
+ n++
+ req, err := ReadRequest(br)
+ if err == io.EOF {
+ return
+ }
+ if err != nil {
+ t.Error(err)
+ return
+ }
+ slurp, err := ioutil.ReadAll(req.Body)
+ if err != nil {
+ t.Errorf("Server request body slurp: %v", err)
+ return
+ }
+ id := req.Header.Get("Request-Id")
+ resCode := req.Header.Get("X-Want-Response-Code")
+ if resCode == "" {
+ resCode = "100 Continue"
+ if string(slurp) != reqBody(n) {
+ t.Errorf("Server got %q, %v; want %q", slurp, err, reqBody(n))
+ }
+ }
+ body := fmt.Sprintf("Response number %d", n)
+ v := []byte(strings.Replace(fmt.Sprintf(`HTTP/1.1 %s
+Date: Thu, 28 Feb 2013 17:55:41 GMT
+
+HTTP/1.1 200 OK
+Content-Type: text/html
+Echo-Request-Id: %s
+Content-Length: %d
+
+%s`, resCode, id, len(body), body), "\n", "\r\n", -1))
+ w.Write(v)
+ if id == reqID(numReqs) {
+ return
+ }
+ }
+
+ }
+
+ tr := &Transport{
+ Dial: func(n, addr string) (net.Conn, error) {
+ sr, sw := io.Pipe() // server read/write
+ cr, cw := io.Pipe() // client read/write
+ conn := &rwTestConn{
+ Reader: cr,
+ Writer: sw,
+ closeFunc: func() error {
+ sw.Close()
+ cw.Close()
+ return nil
+ },
+ }
+ go send100Response(cw, sr)
+ return conn, nil
+ },
+ DisableKeepAlives: false,
+ }
+ defer tr.CloseIdleConnections()
+ c := &Client{Transport: tr}
+
+ testResponse := func(req *Request, name string, wantCode int) {
+ res, err := c.Do(req)
+ if err != nil {
+ t.Fatalf("%s: Do: %v", name, err)
+ }
+ if res.StatusCode != wantCode {
+ t.Fatalf("%s: Response Statuscode=%d; want %d", name, res.StatusCode, wantCode)
+ }
+ if id, idBack := req.Header.Get("Request-Id"), res.Header.Get("Echo-Request-Id"); id != "" && id != idBack {
+ t.Errorf("%s: response id %q != request id %q", name, idBack, id)
+ }
+ _, err = ioutil.ReadAll(res.Body)
+ if err != nil {
+ t.Fatalf("%s: Slurp error: %v", name, err)
+ }
+ }
+
+ // Few 100 responses, making sure we're not off-by-one.
+ for i := 1; i <= numReqs; i++ {
+ req, _ := NewRequest("POST", "http://dummy.tld/", strings.NewReader(reqBody(i)))
+ req.Header.Set("Request-Id", reqID(i))
+ testResponse(req, fmt.Sprintf("100, %d/%d", i, numReqs), 200)
+ }
+
+ // And some other informational 1xx but non-100 responses, to test
+ // we return them but don't re-use the connection.
+ for i := 1; i <= numReqs; i++ {
+ req, _ := NewRequest("POST", "http://other.tld/", strings.NewReader(reqBody(i)))
+ req.Header.Set("X-Want-Response-Code", "123 Sesame Street")
+ testResponse(req, fmt.Sprintf("123, %d/%d", i, numReqs), 123)
+ }
+}
+
type proxyFromEnvTest struct {
req string // URL to fetch; blank means "http://example.com"
env string
diff --git a/src/pkg/net/http/z_last_test.go b/src/pkg/net/http/z_last_test.go
index 44095a8d9..2161db736 100644
--- a/src/pkg/net/http/z_last_test.go
+++ b/src/pkg/net/http/z_last_test.go
@@ -7,43 +7,81 @@ package http_test
import (
"net/http"
"runtime"
+ "sort"
"strings"
"testing"
"time"
)
+func interestingGoroutines() (gs []string) {
+ buf := make([]byte, 2<<20)
+ buf = buf[:runtime.Stack(buf, true)]
+ for _, g := range strings.Split(string(buf), "\n\n") {
+ sl := strings.SplitN(g, "\n", 2)
+ if len(sl) != 2 {
+ continue
+ }
+ stack := strings.TrimSpace(sl[1])
+ if stack == "" ||
+ strings.Contains(stack, "created by net.newPollServer") ||
+ strings.Contains(stack, "created by net.startServer") ||
+ strings.Contains(stack, "created by testing.RunTests") ||
+ strings.Contains(stack, "closeWriteAndWait") ||
+ strings.Contains(stack, "testing.Main(") ||
+ // These only show up with GOTRACEBACK=2; Issue 5005 (comment 28)
+ strings.Contains(stack, "runtime.goexit") ||
+ strings.Contains(stack, "created by runtime.gc") ||
+ strings.Contains(stack, "runtime.MHeap_Scavenger") {
+ continue
+ }
+ gs = append(gs, stack)
+ }
+ sort.Strings(gs)
+ return
+}
+
// Verify the other tests didn't leave any goroutines running.
// This is in a file named z_last_test.go so it sorts at the end.
func TestGoroutinesRunning(t *testing.T) {
- n := runtime.NumGoroutine()
+ if testing.Short() {
+ t.Skip("not counting goroutines for leakage in -short mode")
+ }
+ gs := interestingGoroutines()
+
+ n := 0
+ stackCount := make(map[string]int)
+ for _, g := range gs {
+ stackCount[g]++
+ n++
+ }
+
t.Logf("num goroutines = %d", n)
- if n > 20 {
- // Currently 14 on Linux (blocked in epoll_wait,
- // waiting for on fds that are closed?), but give some
- // slop for now.
- buf := make([]byte, 1<<20)
- buf = buf[:runtime.Stack(buf, true)]
- t.Errorf("Too many goroutines:\n%s", buf)
+ if n > 0 {
+ t.Error("Too many goroutines.")
+ for stack, count := range stackCount {
+ t.Logf("%d instances of:\n%s", count, stack)
+ }
}
}
-func checkLeakedTransports(t *testing.T) {
+func afterTest(t *testing.T) {
http.DefaultTransport.(*http.Transport).CloseIdleConnections()
if testing.Short() {
return
}
- buf := make([]byte, 1<<20)
- var stacks string
var bad string
badSubstring := map[string]string{
").readLoop(": "a Transport",
").writeLoop(": "a Transport",
"created by net/http/httptest.(*Server).Start": "an httptest.Server",
"timeoutHandler": "a TimeoutHandler",
+ "net.(*netFD).connect(": "a timing out dial",
+ ").noteClientGone(": "a closenotifier sender",
}
+ var stacks string
for i := 0; i < 4; i++ {
bad = ""
- stacks = string(buf[:runtime.Stack(buf, true)])
+ stacks = strings.Join(interestingGoroutines(), "\n\n")
for substr, what := range badSubstring {
if strings.Contains(stacks, substr) {
bad = what
diff --git a/src/pkg/net/interface_bsd.go b/src/pkg/net/interface_bsd.go
index f58065a85..716b60a97 100644
--- a/src/pkg/net/interface_bsd.go
+++ b/src/pkg/net/interface_bsd.go
@@ -171,7 +171,6 @@ func newAddr(ifi *Interface, m *syscall.InterfaceAddrMessage) (Addr, error) {
// the interface index in the interface-local or link-
// local address as the kernel-internal form.
if ifa.IP.IsLinkLocalUnicast() {
- ifa.Zone = ifi.Name
ifa.IP[2], ifa.IP[3] = 0, 0
}
}
diff --git a/src/pkg/net/interface_darwin.go b/src/pkg/net/interface_darwin.go
index 83e483ba2..ad0937db0 100644
--- a/src/pkg/net/interface_darwin.go
+++ b/src/pkg/net/interface_darwin.go
@@ -50,11 +50,10 @@ func newMulticastAddr(ifi *Interface, m *syscall.InterfaceMulticastAddrMessage)
case *syscall.SockaddrInet6:
ifma := &IPAddr{IP: make(IP, IPv6len)}
copy(ifma.IP, sa.Addr[:])
- // NOTE: KAME based IPv6 protcol stack usually embeds
+ // NOTE: KAME based IPv6 protocol stack usually embeds
// the interface index in the interface-local or link-
// local address as the kernel-internal form.
if ifma.IP.IsInterfaceLocalMulticast() || ifma.IP.IsLinkLocalMulticast() {
- ifma.Zone = ifi.Name
ifma.IP[2], ifma.IP[3] = 0, 0
}
ifmat = append(ifmat, ifma.toAddr())
diff --git a/src/pkg/net/interface_freebsd.go b/src/pkg/net/interface_freebsd.go
index 1bf5ae72b..5df767910 100644
--- a/src/pkg/net/interface_freebsd.go
+++ b/src/pkg/net/interface_freebsd.go
@@ -50,11 +50,10 @@ func newMulticastAddr(ifi *Interface, m *syscall.InterfaceMulticastAddrMessage)
case *syscall.SockaddrInet6:
ifma := &IPAddr{IP: make(IP, IPv6len)}
copy(ifma.IP, sa.Addr[:])
- // NOTE: KAME based IPv6 protcol stack usually embeds
+ // NOTE: KAME based IPv6 protocol stack usually embeds
// the interface index in the interface-local or link-
// local address as the kernel-internal form.
if ifma.IP.IsInterfaceLocalMulticast() || ifma.IP.IsLinkLocalMulticast() {
- ifma.Zone = ifi.Name
ifma.IP[2], ifma.IP[3] = 0, 0
}
ifmat = append(ifmat, ifma.toAddr())
diff --git a/src/pkg/net/interface_linux.go b/src/pkg/net/interface_linux.go
index e66daef06..1207c0f26 100644
--- a/src/pkg/net/interface_linux.go
+++ b/src/pkg/net/interface_linux.go
@@ -156,9 +156,6 @@ func newAddr(ifi *Interface, ifam *syscall.IfAddrmsg, attrs []syscall.NetlinkRou
case syscall.AF_INET6:
ifa := &IPNet{IP: make(IP, IPv6len), Mask: CIDRMask(int(ifam.Prefixlen), 8*IPv6len)}
copy(ifa.IP, a.Value[:])
- if ifam.Scope == syscall.RT_SCOPE_HOST || ifam.Scope == syscall.RT_SCOPE_LINK {
- ifa.Zone = ifi.Name
- }
return ifa
}
}
@@ -229,9 +226,6 @@ func parseProcNetIGMP6(path string, ifi *Interface) []Addr {
b[i/2], _ = xtoi2(f[2][i:i+2], 0)
}
ifma := IPAddr{IP: IP{b[0], b[1], b[2], b[3], b[4], b[5], b[6], b[7], b[8], b[9], b[10], b[11], b[12], b[13], b[14], b[15]}}
- if ifma.IP.IsInterfaceLocalMulticast() || ifma.IP.IsLinkLocalMulticast() {
- ifma.Zone = ifi.Name
- }
ifmat = append(ifmat, ifma.toAddr())
}
}
diff --git a/src/pkg/net/interface_test.go b/src/pkg/net/interface_test.go
index 7fb342818..e31894abf 100644
--- a/src/pkg/net/interface_test.go
+++ b/src/pkg/net/interface_test.go
@@ -25,6 +25,32 @@ func loopbackInterface() *Interface {
return nil
}
+// ipv6LinkLocalUnicastAddr returns an IPv6 link-local unicast address
+// on the given network interface for tests. It returns "" if no
+// suitable address is found.
+func ipv6LinkLocalUnicastAddr(ifi *Interface) string {
+ if ifi == nil {
+ return ""
+ }
+ ifat, err := ifi.Addrs()
+ if err != nil {
+ return ""
+ }
+ for _, ifa := range ifat {
+ switch ifa := ifa.(type) {
+ case *IPAddr:
+ if ifa.IP.To4() == nil && ifa.IP.IsLinkLocalUnicast() {
+ return ifa.IP.String()
+ }
+ case *IPNet:
+ if ifa.IP.To4() == nil && ifa.IP.IsLinkLocalUnicast() {
+ return ifa.IP.String()
+ }
+ }
+ }
+ return ""
+}
+
func TestInterfaces(t *testing.T) {
ift, err := Interfaces()
if err != nil {
@@ -81,9 +107,9 @@ func testInterfaceMulticastAddrs(t *testing.T, ifi *Interface) {
func testAddrs(t *testing.T, ifat []Addr) {
for _, ifa := range ifat {
- switch v := ifa.(type) {
+ switch ifa := ifa.(type) {
case *IPAddr, *IPNet:
- if v == nil {
+ if ifa == nil {
t.Errorf("\tunexpected value: %v", ifa)
} else {
t.Logf("\tinterface address %q", ifa.String())
@@ -96,9 +122,9 @@ func testAddrs(t *testing.T, ifat []Addr) {
func testMulticastAddrs(t *testing.T, ifmat []Addr) {
for _, ifma := range ifmat {
- switch v := ifma.(type) {
+ switch ifma := ifma.(type) {
case *IPAddr:
- if v == nil {
+ if ifma == nil {
t.Errorf("\tunexpected value: %v", ifma)
} else {
t.Logf("\tjoined group address %q", ifma.String())
diff --git a/src/pkg/net/interface_unix_test.go b/src/pkg/net/interface_unix_test.go
index 6dbd6e6e7..0a453c095 100644
--- a/src/pkg/net/interface_unix_test.go
+++ b/src/pkg/net/interface_unix_test.go
@@ -41,8 +41,11 @@ func (ti *testInterface) teardown() error {
}
func TestPointToPointInterface(t *testing.T) {
- switch runtime.GOOS {
- case "darwin":
+ if testing.Short() {
+ t.Skip("skipping test in short mode")
+ }
+ switch {
+ case runtime.GOOS == "darwin":
t.Skipf("skipping read test on %q", runtime.GOOS)
}
if os.Getuid() != 0 {
@@ -90,6 +93,9 @@ func TestPointToPointInterface(t *testing.T) {
}
func TestInterfaceArrivalAndDeparture(t *testing.T) {
+ if testing.Short() {
+ t.Skip("skipping test in short mode")
+ }
if os.Getuid() != 0 {
t.Skip("skipping test; must be root")
}
diff --git a/src/pkg/net/ip.go b/src/pkg/net/ip.go
index d588e3a42..0e42da216 100644
--- a/src/pkg/net/ip.go
+++ b/src/pkg/net/ip.go
@@ -36,7 +36,6 @@ type IPMask []byte
type IPNet struct {
IP IP // network number
Mask IPMask // network mask
- Zone string // IPv6 scoped addressing zone
}
// IPv4 returns the IP address (in 16-byte form) of the
@@ -223,7 +222,6 @@ func (ip IP) DefaultMask() IPMask {
default:
return classCMask
}
- return nil // not reached
}
func allFF(b []byte) bool {
@@ -433,6 +431,9 @@ func (n *IPNet) Contains(ip IP) bool {
return true
}
+// 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.
// If the mask is not in the canonical form, it returns the
@@ -451,9 +452,6 @@ func (n *IPNet) String() string {
return nn.String() + "/" + itod(uint(l))
}
-// Network returns the address's network name, "ip+net".
-func (n *IPNet) Network() string { return "ip+net" }
-
// Parse IPv4 address (d.d.d.d).
func parseIPv4(s string) IP {
var p [IPv4len]byte
@@ -485,26 +483,26 @@ func parseIPv4(s string) IP {
return IPv4(p[0], p[1], p[2], p[3])
}
-// Parse IPv6 address. Many forms.
-// The basic form is a sequence of eight colon-separated
-// 16-bit hex numbers separated by colons,
-// as in 0123:4567:89ab:cdef:0123:4567:89ab:cdef.
-// Two exceptions:
-// * A run of zeros can be replaced with "::".
-// * The last 32 bits can be in IPv4 form.
-// Thus, ::ffff:1.2.3.4 is the IPv4 address 1.2.3.4.
-func parseIPv6(s string) IP {
- p := make(IP, IPv6len)
+// parseIPv6 parses s as a literal IPv6 address described in RFC 4291
+// and RFC 5952. It can also parse a literal scoped IPv6 address with
+// zone identifier which is described in RFC 4007 when zoneAllowed is
+// 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
+ if zoneAllowed {
+ s, zone = splitHostZone(s)
+ }
+
// Might have leading ellipsis
if len(s) >= 2 && s[0] == ':' && s[1] == ':' {
ellipsis = 0
i = 2
// Might be only ellipsis
if i == len(s) {
- return p
+ return ip, zone
}
}
@@ -514,35 +512,35 @@ func parseIPv6(s string) IP {
// Hex number.
n, i1, ok := xtoi(s, i)
if !ok || n > 0xFFFF {
- return nil
+ return nil, zone
}
// If followed by dot, might be in trailing IPv4.
if i1 < len(s) && s[i1] == '.' {
if ellipsis < 0 && j != IPv6len-IPv4len {
// Not the right place.
- return nil
+ return nil, zone
}
if j+IPv4len > IPv6len {
// Not enough room.
- return nil
+ return nil, zone
}
- p4 := parseIPv4(s[i:])
- if p4 == nil {
- return nil
+ ip4 := parseIPv4(s[i:])
+ if ip4 == nil {
+ return nil, zone
}
- p[j] = p4[12]
- p[j+1] = p4[13]
- p[j+2] = p4[14]
- p[j+3] = p4[15]
+ ip[j] = ip4[12]
+ ip[j+1] = ip4[13]
+ ip[j+2] = ip4[14]
+ ip[j+3] = ip4[15]
i = len(s)
j += IPv4len
break
}
// Save this 16-bit chunk.
- p[j] = byte(n >> 8)
- p[j+1] = byte(n)
+ ip[j] = byte(n >> 8)
+ ip[j+1] = byte(n)
j += 2
// Stop at end of string.
@@ -553,14 +551,14 @@ func parseIPv6(s string) IP {
// Otherwise must be followed by colon and more.
if s[i] != ':' || i+1 == len(s) {
- return nil
+ return nil, zone
}
i++
// Look for ellipsis.
if s[i] == ':' {
if ellipsis >= 0 { // already have one
- return nil
+ return nil, zone
}
ellipsis = j
if i++; i == len(s) { // can be at end
@@ -571,23 +569,23 @@ func parseIPv6(s string) IP {
// Must have used entire string.
if i != len(s) {
- return nil
+ return nil, zone
}
// If didn't parse enough, expand ellipsis.
if j < IPv6len {
if ellipsis < 0 {
- return nil
+ return nil, zone
}
n := IPv6len - j
for k := j - 1; k >= ellipsis; k-- {
- p[k+n] = p[k]
+ ip[k+n] = ip[k]
}
for k := ellipsis + n - 1; k >= ellipsis; k-- {
- p[k] = 0
+ ip[k] = 0
}
}
- return p
+ return ip, zone
}
// A ParseError represents a malformed text string and the type of string that was expected.
@@ -600,26 +598,17 @@ func (e *ParseError) Error() string {
return "invalid " + e.Type + ": " + e.Text
}
-func parseIP(s string) IP {
- if p := parseIPv4(s); p != nil {
- return p
- }
- if p := parseIPv6(s); p != nil {
- return p
- }
- return nil
-}
-
// 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.
// If s is not a valid textual representation of an IP address,
// ParseIP returns nil.
func ParseIP(s string) IP {
- if p := parseIPv4(s); p != nil {
- return p
+ if ip := parseIPv4(s); ip != nil {
+ return ip
}
- return parseIPv6(s)
+ ip, _ := parseIPv6(s, false)
+ return ip
}
// ParseCIDR parses s as a CIDR notation IP address and mask,
@@ -634,15 +623,15 @@ func ParseCIDR(s string) (IP, *IPNet, error) {
if i < 0 {
return nil, nil, &ParseError{"CIDR address", s}
}
- ipstr, maskstr := s[:i], s[i+1:]
+ addr, mask := s[:i], s[i+1:]
iplen := IPv4len
- ip := parseIPv4(ipstr)
+ ip := parseIPv4(addr)
if ip == nil {
iplen = IPv6len
- ip = parseIPv6(ipstr)
+ ip, _ = parseIPv6(addr, false)
}
- n, i, ok := dtoi(maskstr, 0)
- if ip == nil || !ok || i != len(maskstr) || n < 0 || n > 8*iplen {
+ n, i, ok := dtoi(mask, 0)
+ if ip == nil || !ok || i != len(mask) || n < 0 || n > 8*iplen {
return nil, nil, &ParseError{"CIDR address", s}
}
m := CIDRMask(n, 8*iplen)
diff --git a/src/pkg/net/ip_test.go b/src/pkg/net/ip_test.go
index f8b7f067f..16f30d446 100644
--- a/src/pkg/net/ip_test.go
+++ b/src/pkg/net/ip_test.go
@@ -5,23 +5,12 @@
package net
import (
- "bytes"
"reflect"
"runtime"
"testing"
)
-func isEqual(a, b []byte) bool {
- if a == nil && b == nil {
- return true
- }
- if a == nil || b == nil {
- return false
- }
- return bytes.Equal(a, b)
-}
-
-var parseiptests = []struct {
+var parseIPTests = []struct {
in string
out IP
}{
@@ -33,22 +22,23 @@ var parseiptests = []struct {
{"::ffff:127.0.0.1", IPv4(127, 0, 0, 1)},
{"2001:4860:0:2001::68", IP{0x20, 0x01, 0x48, 0x60, 0, 0, 0x20, 0x01, 0, 0, 0, 0, 0, 0, 0x00, 0x68}},
{"::ffff:4a7d:1363", IPv4(74, 125, 19, 99)},
+ {"fe80::1%lo0", nil},
+ {"fe80::1%911", nil},
{"", nil},
}
func TestParseIP(t *testing.T) {
- for _, tt := range parseiptests {
- if out := ParseIP(tt.in); !isEqual(out, tt.out) {
+ for _, tt := range parseIPTests {
+ if out := ParseIP(tt.in); !reflect.DeepEqual(out, tt.out) {
t.Errorf("ParseIP(%q) = %v, want %v", tt.in, out, tt.out)
}
}
}
-var ipstringtests = []struct {
+var ipStringTests = []struct {
in IP
- out string
+ out string // see RFC 5952
}{
- // cf. RFC 5952 (A Recommendation for IPv6 Address Text Representation)
{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"},
@@ -61,14 +51,14 @@ var ipstringtests = []struct {
}
func TestIPString(t *testing.T) {
- for _, tt := range ipstringtests {
+ for _, tt := range ipStringTests {
if out := tt.in.String(); out != tt.out {
t.Errorf("IP.String(%v) = %q, want %q", tt.in, out, tt.out)
}
}
}
-var ipmasktests = []struct {
+var ipMaskTests = []struct {
in IP
mask IPMask
out IP
@@ -82,14 +72,14 @@ var ipmasktests = []struct {
}
func TestIPMask(t *testing.T) {
- for _, tt := range ipmasktests {
+ for _, tt := range ipMaskTests {
if out := tt.in.Mask(tt.mask); out == nil || !tt.out.Equal(out) {
t.Errorf("IP(%v).Mask(%v) = %v, want %v", tt.in, tt.mask, out, tt.out)
}
}
}
-var ipmaskstringtests = []struct {
+var ipMaskStringTests = []struct {
in IPMask
out string
}{
@@ -101,14 +91,14 @@ var ipmaskstringtests = []struct {
}
func TestIPMaskString(t *testing.T) {
- for _, tt := range ipmaskstringtests {
+ for _, tt := range ipMaskStringTests {
if out := tt.in.String(); out != tt.out {
t.Errorf("IPMask.String(%v) = %q, want %q", tt.in, out, tt.out)
}
}
}
-var parsecidrtests = []struct {
+var parseCIDRTests = []struct {
in string
ip IP
net *IPNet
@@ -138,18 +128,18 @@ var parsecidrtests = []struct {
}
func TestParseCIDR(t *testing.T) {
- for _, tt := range parsecidrtests {
+ for _, tt := range parseCIDRTests {
ip, net, err := ParseCIDR(tt.in)
if !reflect.DeepEqual(err, tt.err) {
t.Errorf("ParseCIDR(%q) = %v, %v; want %v, %v", tt.in, ip, net, tt.ip, tt.net)
}
- if err == nil && (!tt.ip.Equal(ip) || !tt.net.IP.Equal(net.IP) || !isEqual(net.Mask, tt.net.Mask)) {
- t.Errorf("ParseCIDR(%q) = %v, {%v, %v}; want %v {%v, %v}", tt.in, ip, net.IP, net.Mask, tt.ip, tt.net.IP, tt.net.Mask)
+ if err == nil && (!tt.ip.Equal(ip) || !tt.net.IP.Equal(net.IP) || !reflect.DeepEqual(net.Mask, tt.net.Mask)) {
+ t.Errorf("ParseCIDR(%q) = %v, {%v, %v}; want %v, {%v, %v}", tt.in, ip, net.IP, net.Mask, tt.ip, tt.net.IP, tt.net.Mask)
}
}
}
-var ipnetcontainstests = []struct {
+var ipNetContainsTests = []struct {
ip IP
net *IPNet
ok bool
@@ -165,14 +155,14 @@ var ipnetcontainstests = []struct {
}
func TestIPNetContains(t *testing.T) {
- for _, tt := range ipnetcontainstests {
+ for _, tt := range ipNetContainsTests {
if ok := tt.net.Contains(tt.ip); ok != tt.ok {
t.Errorf("IPNet(%v).Contains(%v) = %v, want %v", tt.net, tt.ip, ok, tt.ok)
}
}
}
-var ipnetstringtests = []struct {
+var ipNetStringTests = []struct {
in *IPNet
out string
}{
@@ -183,14 +173,14 @@ var ipnetstringtests = []struct {
}
func TestIPNetString(t *testing.T) {
- for _, tt := range ipnetstringtests {
+ for _, tt := range ipNetStringTests {
if out := tt.in.String(); out != tt.out {
t.Errorf("IPNet.String(%v) = %q, want %q", tt.in, out, tt.out)
}
}
}
-var cidrmasktests = []struct {
+var cidrMaskTests = []struct {
ones int
bits int
out IPMask
@@ -210,8 +200,8 @@ var cidrmasktests = []struct {
}
func TestCIDRMask(t *testing.T) {
- for _, tt := range cidrmasktests {
- if out := CIDRMask(tt.ones, tt.bits); !isEqual(out, tt.out) {
+ for _, tt := range cidrMaskTests {
+ if out := CIDRMask(tt.ones, tt.bits); !reflect.DeepEqual(out, tt.out) {
t.Errorf("CIDRMask(%v, %v) = %v, want %v", tt.ones, tt.bits, out, tt.out)
}
}
@@ -229,7 +219,7 @@ var (
v4maskzero = IPMask{0, 0, 0, 0}
)
-var networknumberandmasktests = []struct {
+var networkNumberAndMaskTests = []struct {
in IPNet
out IPNet
}{
@@ -251,75 +241,90 @@ var networknumberandmasktests = []struct {
}
func TestNetworkNumberAndMask(t *testing.T) {
- for _, tt := range networknumberandmasktests {
+ for _, tt := range networkNumberAndMaskTests {
ip, m := networkNumberAndMask(&tt.in)
out := &IPNet{IP: ip, Mask: m}
if !reflect.DeepEqual(&tt.out, out) {
- t.Errorf("networkNumberAndMask(%v) = %v; want %v", tt.in, out, &tt.out)
+ t.Errorf("networkNumberAndMask(%v) = %v, want %v", tt.in, out, &tt.out)
}
}
}
-var splitjointests = []struct {
- Host string
- Port string
- Join string
+var splitJoinTests = []struct {
+ host string
+ port string
+ join string
}{
{"www.google.com", "80", "www.google.com:80"},
{"127.0.0.1", "1234", "127.0.0.1:1234"},
{"::1", "80", "[::1]:80"},
- {"google.com", "https%foo", "google.com:https%foo"}, // Go 1.0 behavior
+ {"fe80::1%lo0", "80", "[fe80::1%lo0]:80"},
+ {"localhost%lo0", "80", "[localhost%lo0]:80"},
{"", "0", ":0"},
- {"127.0.0.1", "", "127.0.0.1:"}, // Go 1.0 behaviour
- {"www.google.com", "", "www.google.com:"}, // Go 1.0 behaviour
+
+ {"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
}
-var splitfailuretests = []struct {
- HostPort string
- Err string
+var splitFailureTests = []struct {
+ hostPort string
+ err string
}{
{"www.google.com", "missing port in address"},
{"127.0.0.1", "missing port in address"},
{"[::1]", "missing port in address"},
+ {"[fe80::1%lo0]", "missing port in address"},
+ {"[localhost%lo0]", "missing port in address"},
+ {"localhost%lo0", "missing port in address"},
+
{"::1", "too many colons in address"},
+ {"fe80::1%lo0", "too many colons in address"},
+ {"fe80::1%lo0:80", "too many colons in address"},
+
+ {"localhost%lo0:80", "missing brackets in address"},
// Test cases that didn't fail in Go 1.0
+
{"[foo:bar]", "missing port in address"},
{"[foo:bar]baz", "missing port in address"},
- {"[foo]:[bar]:baz", "too many colons in address"},
{"[foo]bar:baz", "missing port in address"},
+
+ {"[foo]:[bar]:baz", "too many colons in address"},
+
{"[foo]:[bar]baz", "unexpected '[' in address"},
{"foo[bar]:baz", "unexpected '[' in address"},
+
{"foo]bar:baz", "unexpected ']' in address"},
}
func TestSplitHostPort(t *testing.T) {
- for _, tt := range splitjointests {
- if host, port, err := SplitHostPort(tt.Join); host != tt.Host || port != tt.Port || err != nil {
- t.Errorf("SplitHostPort(%q) = %q, %q, %v; want %q, %q, nil", tt.Join, host, port, err, tt.Host, tt.Port)
+ for _, tt := range splitJoinTests {
+ if host, port, err := SplitHostPort(tt.join); host != tt.host || port != tt.port || err != nil {
+ t.Errorf("SplitHostPort(%q) = %q, %q, %v; want %q, %q, nil", tt.join, host, port, err, tt.host, tt.port)
}
}
- for _, tt := range splitfailuretests {
- if _, _, err := SplitHostPort(tt.HostPort); err == nil {
- t.Errorf("SplitHostPort(%q) should have failed", tt.HostPort)
+ for _, tt := range splitFailureTests {
+ if _, _, 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 e.Err != tt.err {
+ t.Errorf("SplitHostPort(%q) = _, _, %q; want %q", tt.hostPort, e.Err, tt.err)
}
}
}
}
func TestJoinHostPort(t *testing.T) {
- for _, tt := range splitjointests {
- if join := JoinHostPort(tt.Host, tt.Port); join != tt.Join {
- t.Errorf("JoinHostPort(%q, %q) = %q; want %q", tt.Host, tt.Port, join, tt.Join)
+ for _, tt := range splitJoinTests {
+ if join := JoinHostPort(tt.host, tt.port); join != tt.join {
+ t.Errorf("JoinHostPort(%q, %q) = %q; want %q", tt.host, tt.port, join, tt.join)
}
}
}
-var ipaftests = []struct {
+var ipAddrFamilyTests = []struct {
in IP
af4 bool
af6 bool
@@ -342,7 +347,7 @@ var ipaftests = []struct {
}
func TestIPAddrFamily(t *testing.T) {
- for _, tt := range ipaftests {
+ for _, tt := range ipAddrFamilyTests {
if af := tt.in.To4() != nil; af != tt.af4 {
t.Errorf("verifying IPv4 address family for %q = %v, want %v", tt.in, af, tt.af4)
}
@@ -352,7 +357,7 @@ func TestIPAddrFamily(t *testing.T) {
}
}
-var ipscopetests = []struct {
+var ipAddrScopeTests = []struct {
scope func(IP) bool
in IP
ok bool
@@ -393,7 +398,7 @@ func name(f interface{}) string {
}
func TestIPAddrScope(t *testing.T) {
- for _, tt := range ipscopetests {
+ for _, tt := range ipAddrScopeTests {
if ok := tt.scope(tt.in); ok != tt.ok {
t.Errorf("%s(%q) = %v, want %v", name(tt.scope), tt.in, ok, tt.ok)
}
diff --git a/src/pkg/net/ipraw_test.go b/src/pkg/net/ipraw_test.go
index 65defc7ea..12c199d1c 100644
--- a/src/pkg/net/ipraw_test.go
+++ b/src/pkg/net/ipraw_test.go
@@ -2,32 +2,36 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// +build !plan9
-
package net
import (
"bytes"
"errors"
+ "fmt"
"os"
"reflect"
"testing"
"time"
)
-var resolveIPAddrTests = []struct {
+type resolveIPAddrTest struct {
net string
litAddr string
addr *IPAddr
err error
-}{
+}
+
+var resolveIPAddrTests = []resolveIPAddrTest{
{"ip", "127.0.0.1", &IPAddr{IP: IPv4(127, 0, 0, 1)}, nil},
{"ip4", "127.0.0.1", &IPAddr{IP: IPv4(127, 0, 0, 1)}, nil},
{"ip4:icmp", "127.0.0.1", &IPAddr{IP: IPv4(127, 0, 0, 1)}, nil},
{"ip", "::1", &IPAddr{IP: ParseIP("::1")}, nil},
{"ip6", "::1", &IPAddr{IP: ParseIP("::1")}, nil},
- {"ip6:icmp", "::1", &IPAddr{IP: ParseIP("::1")}, nil},
+ {"ip6:ipv6-icmp", "::1", &IPAddr{IP: ParseIP("::1")}, nil},
+
+ {"ip", "::1%en0", &IPAddr{IP: ParseIP("::1"), Zone: "en0"}, nil},
+ {"ip6", "::1%911", &IPAddr{IP: ParseIP("::1"), Zone: "911"}, nil},
{"", "127.0.0.1", &IPAddr{IP: IPv4(127, 0, 0, 1)}, nil}, // Go 1.0 behavior
{"", "::1", &IPAddr{IP: ParseIP("::1")}, nil}, // Go 1.0 behavior
@@ -37,13 +41,22 @@ var resolveIPAddrTests = []struct {
{"tcp", "1.2.3.4:123", nil, UnknownNetworkError("tcp")},
}
+func init() {
+ if ifi := loopbackInterface(); ifi != nil {
+ index := fmt.Sprintf("%v", ifi.Index)
+ resolveIPAddrTests = append(resolveIPAddrTests, []resolveIPAddrTest{
+ {"ip6", "fe80::1%" + ifi.Name, &IPAddr{IP: ParseIP("fe80::1"), Zone: zoneToString(ifi.Index)}, nil},
+ {"ip6", "fe80::1%" + index, &IPAddr{IP: ParseIP("fe80::1"), Zone: index}, nil},
+ }...)
+ }
+}
+
func TestResolveIPAddr(t *testing.T) {
for _, tt := range resolveIPAddrTests {
addr, err := ResolveIPAddr(tt.net, tt.litAddr)
if err != tt.err {
- t.Fatalf("ResolveIPAddr(%v, %v) failed: %v", tt.net, tt.litAddr, err)
- }
- if !reflect.DeepEqual(addr, tt.addr) {
+ condFatalf(t, "ResolveIPAddr(%v, %v) failed: %v", tt.net, tt.litAddr, err)
+ } else if !reflect.DeepEqual(addr, tt.addr) {
t.Fatalf("got %#v; expected %#v", addr, tt.addr)
}
}
@@ -339,3 +352,19 @@ func TestIPConnLocalName(t *testing.T) {
}
}
}
+
+func TestIPConnRemoteName(t *testing.T) {
+ if os.Getuid() != 0 {
+ t.Skip("skipping test; must be root")
+ }
+
+ raddr := &IPAddr{IP: IPv4(127, 0, 0, 10).To4()}
+ c, err := DialIP("ip:tcp", &IPAddr{IP: IPv4(127, 0, 0, 1)}, raddr)
+ if err != nil {
+ t.Fatalf("DialIP failed: %v", err)
+ }
+ defer c.Close()
+ if !reflect.DeepEqual(raddr, c.RemoteAddr()) {
+ t.Fatalf("got %#v, expected %#v", c.RemoteAddr(), raddr)
+ }
+}
diff --git a/src/pkg/net/iprawsock.go b/src/pkg/net/iprawsock.go
index daccba366..0be94eb70 100644
--- a/src/pkg/net/iprawsock.go
+++ b/src/pkg/net/iprawsock.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.
-// Raw IP sockets
-
package net
// IPAddr represents the address of an IP end point.
@@ -19,12 +17,15 @@ func (a *IPAddr) String() string {
if a == nil {
return "<nil>"
}
+ if a.Zone != "" {
+ return a.IP.String() + "%" + a.Zone
+ }
return a.IP.String()
}
-// ResolveIPAddr parses addr as an IP address and resolves domain
-// names to numeric addresses on the network net, which must be
-// "ip", "ip4" or "ip6".
+// 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".
func ResolveIPAddr(net, addr string) (*IPAddr, error) {
if net == "" { // a hint wildcard for Go 1.0 undocumented behavior
net = "ip"
diff --git a/src/pkg/net/iprawsock_plan9.go b/src/pkg/net/iprawsock_plan9.go
index 88e3b2c60..e62d116b8 100644
--- a/src/pkg/net/iprawsock_plan9.go
+++ b/src/pkg/net/iprawsock_plan9.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.
-// Raw IP sockets for Plan 9
-
package net
import (
@@ -34,7 +32,7 @@ func (c *IPConn) ReadFrom(b []byte) (int, Addr, error) {
}
// ReadMsgIP reads a packet from c, copying the payload into b and the
-// associdated out-of-band data into oob. It returns the number of
+// 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) {
@@ -76,7 +74,7 @@ func dialIP(netProto string, laddr, raddr *IPAddr, deadline time.Time) (*IPConn,
}
// ListenIP listens for incoming IP packets addressed to the local
-// address laddr. The returned connection c's ReadFrom and WriteTo
+// 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) {
diff --git a/src/pkg/net/iprawsock_posix.go b/src/pkg/net/iprawsock_posix.go
index 2ef4db19c..caeeb4653 100644
--- a/src/pkg/net/iprawsock_posix.go
+++ b/src/pkg/net/iprawsock_posix.go
@@ -4,8 +4,6 @@
// +build darwin freebsd linux netbsd openbsd windows
-// Raw IP sockets for POSIX
-
package net
import (
@@ -51,8 +49,8 @@ func (a *IPAddr) toAddr() sockaddr {
return a
}
-// IPConn is the implementation of the Conn and PacketConn
-// interfaces for IP network connections.
+// IPConn is the implementation of the Conn and PacketConn interfaces
+// for IP network connections.
type IPConn struct {
conn
}
@@ -98,7 +96,7 @@ func (c *IPConn) ReadFrom(b []byte) (int, Addr, error) {
}
// ReadMsgIP reads a packet from c, copying the payload into b and the
-// associdated out-of-band data into oob. It returns the number of
+// 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) {
@@ -116,12 +114,13 @@ func (c *IPConn) ReadMsgIP(b, oob []byte) (n, oobn, flags int, addr *IPAddr, err
return
}
-// WriteToIP writes an IP packet to addr via c, copying the payload from b.
+// 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.
+// 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
@@ -159,8 +158,9 @@ func (c *IPConn) WriteMsgIP(b, oob []byte, addr *IPAddr) (n, oobn int, err error
return c.fd.WriteMsg(b, oob, sa)
}
-// 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.
+// 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)
}
@@ -185,10 +185,10 @@ func dialIP(netProto string, laddr, raddr *IPAddr, deadline time.Time) (*IPConn,
return newIPConn(fd), nil
}
-// ListenIP listens for incoming IP packets addressed to the
-// local address laddr. The returned connection c's ReadFrom
-// and WriteTo methods can be used to receive and send IP
-// packets with per-packet addressing.
+// 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)
if err != nil {
diff --git a/src/pkg/net/ipsock.go b/src/pkg/net/ipsock.go
index 1ef489289..d93059587 100644
--- a/src/pkg/net/ipsock.go
+++ b/src/pkg/net/ipsock.go
@@ -68,15 +68,12 @@ func (e InvalidAddrError) Error() string { return string(e) }
func (e InvalidAddrError) Timeout() bool { return false }
func (e InvalidAddrError) Temporary() bool { return false }
-// SplitHostPort splits a network address of the form
-// "host:port" or "[host]:port" into host and port.
-// The latter form must be used when host contains a colon.
+// 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
+// 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) {
- host, port, _, err = splitHostPort(hostport)
- return
-}
-
-func splitHostPort(hostport string) (host, port, zone string, err error) {
j, k := 0, 0
// The port starts after the last colon.
@@ -110,10 +107,12 @@ func splitHostPort(hostport string) (host, port, zone string, err error) {
j, k = 1, end+1 // there can't be a '[' resp. ']' before these positions
} else {
host = hostport[:i]
-
if byteIndex(host, ':') >= 0 {
goto tooManyColons
}
+ if byteIndex(host, '%') >= 0 {
+ goto missingBrackets
+ }
}
if byteIndex(hostport[j:], '[') >= 0 {
err = &AddrError{"unexpected '[' in address", hostport}
@@ -134,13 +133,29 @@ missingPort:
tooManyColons:
err = &AddrError{"too many colons in address", hostport}
return
+
+missingBrackets:
+ err = &AddrError{"missing brackets in address", hostport}
+ return
+}
+
+func splitHostZone(s string) (host, zone string) {
+ // The IPv6 scoped addressing zone identifer starts after the
+ // last percent sign.
+ if i := last(s, '%'); i > 0 {
+ host, zone = s[:i], s[i+1:]
+ } else {
+ host = s
+ }
+ return
}
-// JoinHostPort combines host and port into a network address
-// of the form "host:port" or, if host contains a colon, "[host]:port".
+// JoinHostPort combines host and port into a network address of the
+// form "host:port" or, if host contains a colon or a percent sign,
+// "[host]:port".
func JoinHostPort(host, port string) string {
- // If host has colons, have to bracket it.
- if byteIndex(host, ':') >= 0 {
+ // If host has colons or a percent sign, have to bracket it.
+ if byteIndex(host, ':') >= 0 || byteIndex(host, '%') >= 0 {
return "[" + host + "]:" + port
}
return host + ":" + port
@@ -155,7 +170,7 @@ func resolveInternetAddr(net, addr string, deadline time.Time) (Addr, error) {
switch net {
case "tcp", "tcp4", "tcp6", "udp", "udp4", "udp6":
if addr != "" {
- if host, port, zone, err = splitHostPort(addr); err != nil {
+ if host, port, err = SplitHostPort(addr); err != nil {
return nil, err
}
if portnum, err = parsePort(net, port); err != nil {
@@ -184,21 +199,25 @@ func resolveInternetAddr(net, addr string, deadline time.Time) (Addr, error) {
return inetaddr(net, nil, portnum, zone), nil
}
// Try as an IP address.
- if ip := ParseIP(host); ip != nil {
+ if ip := parseIPv4(host); ip != nil {
+ return inetaddr(net, ip, portnum, zone), nil
+ }
+ if ip, zone := parseIPv6(host, true); ip != nil {
return inetaddr(net, ip, portnum, zone), nil
}
+ // Try as a domain name.
+ host, zone = splitHostZone(host)
+ addrs, err := lookupHostDeadline(host, deadline)
+ if err != nil {
+ return nil, err
+ }
var filter func(IP) IP
if net != "" && net[len(net)-1] == '4' {
filter = ipv4only
}
- if net != "" && net[len(net)-1] == '6' {
+ if net != "" && net[len(net)-1] == '6' || zone != "" {
filter = ipv6only
}
- // Try as a DNS name.
- addrs, err := lookupHostDeadline(host, deadline)
- if err != nil {
- return nil, err
- }
ip := firstFavoriteAddr(filter, addrs)
if ip == nil {
// should not happen
diff --git a/src/pkg/net/lookup_plan9.go b/src/pkg/net/lookup_plan9.go
index ae7cf7942..94c553328 100644
--- a/src/pkg/net/lookup_plan9.go
+++ b/src/pkg/net/lookup_plan9.go
@@ -7,7 +7,6 @@ package net
import (
"errors"
"os"
- "syscall"
)
func query(filename, query string, bufSize int) (res []string, err error) {
@@ -70,9 +69,26 @@ func queryDNS(addr string, typ string) (res []string, err error) {
return query("/net/dns", addr+" "+typ, 1024)
}
+// lookupProtocol looks up IP protocol name and returns
+// the corresponding protocol number.
func lookupProtocol(name string) (proto int, err error) {
- // TODO: Implement this
- return 0, syscall.EPLAN9
+ lines, err := query("/net/cs", "!protocol="+name, 128)
+ if err != nil {
+ return 0, err
+ }
+ unknownProtoError := errors.New("unknown IP protocol specified: " + name)
+ if len(lines) == 0 {
+ return 0, unknownProtoError
+ }
+ f := getFields(lines[0])
+ if len(f) < 2 {
+ return 0, unknownProtoError
+ }
+ s := f[1]
+ if n, _, ok := dtoi(s, byteIndex(s, '=')+1); ok {
+ return n, nil
+ }
+ return 0, unknownProtoError
}
func lookupHost(host string) (addrs []string, err error) {
diff --git a/src/pkg/net/multicast_posix_test.go b/src/pkg/net/multicast_posix_test.go
deleted file mode 100644
index ff1edaf83..000000000
--- a/src/pkg/net/multicast_posix_test.go
+++ /dev/null
@@ -1,180 +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 !plan9
-
-package net
-
-import (
- "errors"
- "os"
- "runtime"
- "testing"
-)
-
-var multicastListenerTests = []struct {
- net string
- gaddr *UDPAddr
- flags Flags
- ipv6 bool // test with underlying AF_INET6 socket
-}{
- // cf. RFC 4727: Experimental Values in IPv4, IPv6, ICMPv4, ICMPv6, UDP, and TCP Headers
-
- {"udp", &UDPAddr{IP: IPv4(224, 0, 0, 254), Port: 12345}, FlagUp | FlagLoopback, false},
- {"udp", &UDPAddr{IP: IPv4(224, 0, 0, 254), Port: 12345}, 0, false},
- {"udp", &UDPAddr{IP: ParseIP("ff0e::114"), Port: 12345}, FlagUp | FlagLoopback, true},
- {"udp", &UDPAddr{IP: ParseIP("ff0e::114"), Port: 12345}, 0, true},
-
- {"udp4", &UDPAddr{IP: IPv4(224, 0, 0, 254), Port: 12345}, FlagUp | FlagLoopback, false},
- {"udp4", &UDPAddr{IP: IPv4(224, 0, 0, 254), Port: 12345}, 0, false},
-
- {"udp6", &UDPAddr{IP: ParseIP("ff01::114"), Port: 12345}, FlagUp | FlagLoopback, true},
- {"udp6", &UDPAddr{IP: ParseIP("ff01::114"), Port: 12345}, 0, true},
- {"udp6", &UDPAddr{IP: ParseIP("ff02::114"), Port: 12345}, FlagUp | FlagLoopback, true},
- {"udp6", &UDPAddr{IP: ParseIP("ff02::114"), Port: 12345}, 0, true},
- {"udp6", &UDPAddr{IP: ParseIP("ff04::114"), Port: 12345}, FlagUp | FlagLoopback, true},
- {"udp6", &UDPAddr{IP: ParseIP("ff04::114"), Port: 12345}, 0, true},
- {"udp6", &UDPAddr{IP: ParseIP("ff05::114"), Port: 12345}, FlagUp | FlagLoopback, true},
- {"udp6", &UDPAddr{IP: ParseIP("ff05::114"), Port: 12345}, 0, true},
- {"udp6", &UDPAddr{IP: ParseIP("ff08::114"), Port: 12345}, FlagUp | FlagLoopback, true},
- {"udp6", &UDPAddr{IP: ParseIP("ff08::114"), Port: 12345}, 0, true},
- {"udp6", &UDPAddr{IP: ParseIP("ff0e::114"), Port: 12345}, FlagUp | FlagLoopback, true},
- {"udp6", &UDPAddr{IP: ParseIP("ff0e::114"), Port: 12345}, 0, true},
-}
-
-// TestMulticastListener tests both single and double listen to a test
-// listener with same address family, same group address and same port.
-func TestMulticastListener(t *testing.T) {
- switch runtime.GOOS {
- case "netbsd", "openbsd", "plan9", "solaris", "windows":
- t.Skipf("skipping test on %q", runtime.GOOS)
- case "linux":
- if runtime.GOARCH == "arm" || runtime.GOARCH == "alpha" {
- t.Skipf("skipping test on %q/%q", runtime.GOOS, runtime.GOARCH)
- }
- }
-
- for _, tt := range multicastListenerTests {
- if tt.ipv6 && (!*testIPv6 || !supportsIPv6 || os.Getuid() != 0) {
- continue
- }
- ifi, err := availMulticastInterface(t, tt.flags)
- if err != nil {
- continue
- }
- c1, err := ListenMulticastUDP(tt.net, ifi, tt.gaddr)
- if err != nil {
- t.Fatalf("First ListenMulticastUDP failed: %v", err)
- }
- checkMulticastListener(t, err, c1, tt.gaddr)
- c2, err := ListenMulticastUDP(tt.net, ifi, tt.gaddr)
- if err != nil {
- t.Fatalf("Second ListenMulticastUDP failed: %v", err)
- }
- checkMulticastListener(t, err, c2, tt.gaddr)
- c2.Close()
- c1.Close()
- }
-}
-
-func TestSimpleMulticastListener(t *testing.T) {
- switch runtime.GOOS {
- case "plan9":
- t.Skipf("skipping test on %q", runtime.GOOS)
- case "windows":
- if testing.Short() || !*testExternal {
- t.Skip("skipping test on windows to avoid firewall")
- }
- }
-
- for _, tt := range multicastListenerTests {
- if tt.ipv6 {
- continue
- }
- tt.flags = FlagUp | FlagMulticast // for windows testing
- ifi, err := availMulticastInterface(t, tt.flags)
- if err != nil {
- continue
- }
- c1, err := ListenMulticastUDP(tt.net, ifi, tt.gaddr)
- if err != nil {
- t.Fatalf("First ListenMulticastUDP failed: %v", err)
- }
- checkSimpleMulticastListener(t, err, c1, tt.gaddr)
- c2, err := ListenMulticastUDP(tt.net, ifi, tt.gaddr)
- if err != nil {
- t.Fatalf("Second ListenMulticastUDP failed: %v", err)
- }
- checkSimpleMulticastListener(t, err, c2, tt.gaddr)
- c2.Close()
- c1.Close()
- }
-}
-
-func checkMulticastListener(t *testing.T, err error, c *UDPConn, gaddr *UDPAddr) {
- if !multicastRIBContains(t, gaddr.IP) {
- t.Errorf("%q not found in RIB", gaddr.String())
- return
- }
- la := c.LocalAddr()
- if la == nil {
- t.Error("LocalAddr failed")
- return
- }
- if a, ok := la.(*UDPAddr); !ok || a.Port == 0 {
- t.Errorf("got %v; expected a proper address with non-zero port number", la)
- return
- }
-}
-
-func checkSimpleMulticastListener(t *testing.T, err error, c *UDPConn, gaddr *UDPAddr) {
- la := c.LocalAddr()
- if la == nil {
- t.Error("LocalAddr failed")
- return
- }
- if a, ok := la.(*UDPAddr); !ok || a.Port == 0 {
- t.Errorf("got %v; expected a proper address with non-zero port number", la)
- return
- }
-}
-
-func availMulticastInterface(t *testing.T, flags Flags) (*Interface, error) {
- var ifi *Interface
- if flags != Flags(0) {
- ift, err := Interfaces()
- if err != nil {
- t.Fatalf("Interfaces failed: %v", err)
- }
- for _, x := range ift {
- if x.Flags&flags == flags {
- ifi = &x
- break
- }
- }
- if ifi == nil {
- return nil, errors.New("an appropriate multicast interface not found")
- }
- }
- return ifi, nil
-}
-
-func multicastRIBContains(t *testing.T, ip IP) bool {
- ift, err := Interfaces()
- if err != nil {
- t.Fatalf("Interfaces failed: %v", err)
- }
- for _, ifi := range ift {
- ifmat, err := ifi.MulticastAddrs()
- if err != nil {
- t.Fatalf("MulticastAddrs failed: %v", err)
- }
- for _, ifma := range ifmat {
- if ifma.(*IPAddr).IP.Equal(ip) {
- return true
- }
- }
- }
- return false
-}
diff --git a/src/pkg/net/multicast_test.go b/src/pkg/net/multicast_test.go
new file mode 100644
index 000000000..8ff02a3c9
--- /dev/null
+++ b/src/pkg/net/multicast_test.go
@@ -0,0 +1,184 @@
+// 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"
+ "os"
+ "runtime"
+ "testing"
+)
+
+var ipv4MulticastListenerTests = []struct {
+ net string
+ gaddr *UDPAddr // see RFC 4727
+}{
+ {"udp", &UDPAddr{IP: IPv4(224, 0, 0, 254), Port: 12345}},
+
+ {"udp4", &UDPAddr{IP: IPv4(224, 0, 0, 254), Port: 12345}},
+}
+
+// TestIPv4MulticastListener tests both single and double listen to a
+// test listener with same address family, same group address and same
+// port.
+func TestIPv4MulticastListener(t *testing.T) {
+ switch runtime.GOOS {
+ case "plan9":
+ t.Skipf("skipping test on %q", runtime.GOOS)
+ }
+
+ closer := func(cs []*UDPConn) {
+ for _, c := range cs {
+ if c != nil {
+ c.Close()
+ }
+ }
+ }
+
+ for _, ifi := range []*Interface{loopbackInterface(), nil} {
+ // Note that multicast interface assignment by system
+ // is not recommended because it usually relies on
+ // routing stuff for finding out an appropriate
+ // nexthop containing both network and link layer
+ // adjacencies.
+ if ifi == nil && !*testExternal {
+ continue
+ }
+ for _, tt := range ipv4MulticastListenerTests {
+ var err error
+ cs := make([]*UDPConn, 2)
+ if cs[0], err = ListenMulticastUDP(tt.net, ifi, tt.gaddr); err != nil {
+ t.Fatalf("First ListenMulticastUDP on %v failed: %v", ifi, err)
+ }
+ if err := checkMulticastListener(cs[0], tt.gaddr.IP); err != nil {
+ closer(cs)
+ t.Fatal(err)
+ }
+ if cs[1], err = ListenMulticastUDP(tt.net, ifi, tt.gaddr); err != nil {
+ closer(cs)
+ t.Fatalf("Second ListenMulticastUDP on %v failed: %v", ifi, err)
+ }
+ if err := checkMulticastListener(cs[1], tt.gaddr.IP); err != nil {
+ closer(cs)
+ t.Fatal(err)
+ }
+ closer(cs)
+ }
+ }
+}
+
+var ipv6MulticastListenerTests = []struct {
+ net string
+ gaddr *UDPAddr // see RFC 4727
+}{
+ {"udp", &UDPAddr{IP: ParseIP("ff01::114"), Port: 12345}},
+ {"udp", &UDPAddr{IP: ParseIP("ff02::114"), Port: 12345}},
+ {"udp", &UDPAddr{IP: ParseIP("ff04::114"), Port: 12345}},
+ {"udp", &UDPAddr{IP: ParseIP("ff05::114"), Port: 12345}},
+ {"udp", &UDPAddr{IP: ParseIP("ff08::114"), Port: 12345}},
+ {"udp", &UDPAddr{IP: ParseIP("ff0e::114"), Port: 12345}},
+
+ {"udp6", &UDPAddr{IP: ParseIP("ff01::114"), Port: 12345}},
+ {"udp6", &UDPAddr{IP: ParseIP("ff02::114"), Port: 12345}},
+ {"udp6", &UDPAddr{IP: ParseIP("ff04::114"), Port: 12345}},
+ {"udp6", &UDPAddr{IP: ParseIP("ff05::114"), Port: 12345}},
+ {"udp6", &UDPAddr{IP: ParseIP("ff08::114"), Port: 12345}},
+ {"udp6", &UDPAddr{IP: ParseIP("ff0e::114"), Port: 12345}},
+}
+
+// TestIPv6MulticastListener tests both single and double listen to a
+// test listener with same address family, same group address and same
+// port.
+func TestIPv6MulticastListener(t *testing.T) {
+ switch runtime.GOOS {
+ case "plan9", "solaris":
+ t.Skipf("skipping test on %q", runtime.GOOS)
+ }
+ if !supportsIPv6 {
+ t.Skip("ipv6 is not supported")
+ }
+ if os.Getuid() != 0 {
+ t.Skip("skipping test; must be root")
+ }
+
+ closer := func(cs []*UDPConn) {
+ for _, c := range cs {
+ if c != nil {
+ c.Close()
+ }
+ }
+ }
+
+ for _, ifi := range []*Interface{loopbackInterface(), nil} {
+ // Note that multicast interface assignment by system
+ // is not recommended because it usually relies on
+ // routing stuff for finding out an appropriate
+ // nexthop containing both network and link layer
+ // adjacencies.
+ if ifi == nil && (!*testExternal || !*testIPv6) {
+ continue
+ }
+ for _, tt := range ipv6MulticastListenerTests {
+ var err error
+ cs := make([]*UDPConn, 2)
+ if cs[0], err = ListenMulticastUDP(tt.net, ifi, tt.gaddr); err != nil {
+ t.Fatalf("First ListenMulticastUDP on %v failed: %v", ifi, err)
+ }
+ if err := checkMulticastListener(cs[0], tt.gaddr.IP); err != nil {
+ closer(cs)
+ t.Fatal(err)
+ }
+ if cs[1], err = ListenMulticastUDP(tt.net, ifi, tt.gaddr); err != nil {
+ closer(cs)
+ t.Fatalf("Second ListenMulticastUDP on %v failed: %v", ifi, err)
+ }
+ if err := checkMulticastListener(cs[1], tt.gaddr.IP); err != nil {
+ closer(cs)
+ t.Fatal(err)
+ }
+ closer(cs)
+ }
+ }
+}
+
+func checkMulticastListener(c *UDPConn, ip IP) error {
+ if ok, err := multicastRIBContains(ip); err != nil {
+ return err
+ } else if !ok {
+ return fmt.Errorf("%q not found in multicast RIB", ip.String())
+ }
+ la := c.LocalAddr()
+ if la, ok := la.(*UDPAddr); !ok || la.Port == 0 {
+ return fmt.Errorf("got %v; expected a proper address with non-zero port number", la)
+ }
+ return nil
+}
+
+func multicastRIBContains(ip IP) (bool, error) {
+ switch runtime.GOOS {
+ case "netbsd", "openbsd", "plan9", "solaris", "windows":
+ return true, nil // not implemented yet
+ case "linux":
+ if runtime.GOARCH == "arm" || runtime.GOARCH == "alpha" {
+ return true, nil // not implemented yet
+ }
+ }
+ ift, err := Interfaces()
+ if err != nil {
+ return false, err
+ }
+ for _, ifi := range ift {
+ ifmat, err := ifi.MulticastAddrs()
+ if err != nil {
+ return false, err
+ }
+ for _, ifma := range ifmat {
+ if ifma.(*IPAddr).IP.Equal(ip) {
+ return true, nil
+ }
+ }
+ }
+ return false, nil
+}
diff --git a/src/pkg/net/newpollserver_unix.go b/src/pkg/net/newpollserver_unix.go
deleted file mode 100644
index 618b5b10b..000000000
--- a/src/pkg/net/newpollserver_unix.go
+++ /dev/null
@@ -1,46 +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.
-
-// +build darwin freebsd linux netbsd openbsd
-
-package net
-
-import (
- "os"
- "syscall"
-)
-
-func newPollServer() (s *pollServer, err error) {
- s = new(pollServer)
- if s.pr, s.pw, err = os.Pipe(); err != nil {
- return nil, err
- }
- if err = syscall.SetNonblock(int(s.pr.Fd()), true); err != nil {
- goto Errno
- }
- if err = syscall.SetNonblock(int(s.pw.Fd()), true); err != nil {
- goto Errno
- }
- if s.poll, err = newpollster(); err != nil {
- goto Error
- }
- if _, err = s.poll.AddFD(int(s.pr.Fd()), 'r', true); err != nil {
- s.poll.Close()
- goto Error
- }
- s.pending = make(map[int]*netFD)
- go s.Run()
- return s, nil
-
-Errno:
- err = &os.PathError{
- Op: "setnonblock",
- Path: s.pr.Name(),
- Err: err,
- }
-Error:
- s.pr.Close()
- s.pw.Close()
- return nil, err
-}
diff --git a/src/pkg/net/packetconn_test.go b/src/pkg/net/packetconn_test.go
index 93c7a6472..ec5dd710f 100644
--- a/src/pkg/net/packetconn_test.go
+++ b/src/pkg/net/packetconn_test.go
@@ -15,14 +15,20 @@ import (
"time"
)
+func strfunc(s string) func() string {
+ return func() string {
+ return s
+ }
+}
+
var packetConnTests = []struct {
net string
- addr1 string
- addr2 string
+ addr1 func() string
+ addr2 func() string
}{
- {"udp", "127.0.0.1:0", "127.0.0.1:0"},
- {"ip:icmp", "127.0.0.1", "127.0.0.1"},
- {"unixgram", testUnixAddr(), testUnixAddr()},
+ {"udp", strfunc("127.0.0.1:0"), strfunc("127.0.0.1:0")},
+ {"ip:icmp", strfunc("127.0.0.1"), strfunc("127.0.0.1")},
+ {"unixgram", testUnixAddr, testUnixAddr},
}
func TestPacketConn(t *testing.T) {
@@ -70,21 +76,22 @@ func TestPacketConn(t *testing.T) {
continue
}
- c1, err := ListenPacket(tt.net, tt.addr1)
+ addr1, addr2 := tt.addr1(), tt.addr2()
+ c1, err := ListenPacket(tt.net, addr1)
if err != nil {
t.Fatalf("ListenPacket failed: %v", err)
}
- defer closer(c1, netstr[0], tt.addr1, tt.addr2)
+ defer closer(c1, netstr[0], addr1, addr2)
c1.LocalAddr()
c1.SetDeadline(time.Now().Add(100 * time.Millisecond))
c1.SetReadDeadline(time.Now().Add(100 * time.Millisecond))
c1.SetWriteDeadline(time.Now().Add(100 * time.Millisecond))
- c2, err := ListenPacket(tt.net, tt.addr2)
+ c2, err := ListenPacket(tt.net, addr2)
if err != nil {
t.Fatalf("ListenPacket failed: %v", err)
}
- defer closer(c2, netstr[0], tt.addr1, tt.addr2)
+ defer closer(c2, netstr[0], addr1, addr2)
c2.LocalAddr()
c2.SetDeadline(time.Now().Add(100 * time.Millisecond))
c2.SetReadDeadline(time.Now().Add(100 * time.Millisecond))
@@ -152,11 +159,12 @@ func TestConnAndPacketConn(t *testing.T) {
continue
}
- c1, err := ListenPacket(tt.net, tt.addr1)
+ addr1, addr2 := tt.addr1(), tt.addr2()
+ c1, err := ListenPacket(tt.net, addr1)
if err != nil {
t.Fatalf("ListenPacket failed: %v", err)
}
- defer closer(c1, netstr[0], tt.addr1, tt.addr2)
+ defer closer(c1, netstr[0], addr1, addr2)
c1.LocalAddr()
c1.SetDeadline(time.Now().Add(100 * time.Millisecond))
c1.SetReadDeadline(time.Now().Add(100 * time.Millisecond))
diff --git a/src/pkg/net/protoconn_test.go b/src/pkg/net/protoconn_test.go
index 2fe7d1d1f..b59925e01 100644
--- a/src/pkg/net/protoconn_test.go
+++ b/src/pkg/net/protoconn_test.go
@@ -15,9 +15,11 @@ import (
"time"
)
-// testUnixAddr uses ioutil.TempFile to get a name that is unique.
+// testUnixAddr uses ioutil.TempFile to get a name that is unique. It
+// also uses /tmp directory in case it is prohibited to create UNIX
+// sockets in TMPDIR.
func testUnixAddr() string {
- f, err := ioutil.TempFile("", "nettest")
+ f, err := ioutil.TempFile("/tmp", "nettest")
if err != nil {
panic(err)
}
@@ -163,7 +165,7 @@ func TestUDPConnSpecificMethods(t *testing.T) {
func TestIPConnSpecificMethods(t *testing.T) {
switch runtime.GOOS {
case "plan9":
- t.Skipf("skipping read test on %q", runtime.GOOS)
+ t.Skipf("skipping test on %q", runtime.GOOS)
}
if os.Getuid() != 0 {
t.Skipf("skipping test; must be root")
@@ -220,7 +222,7 @@ func TestIPConnSpecificMethods(t *testing.T) {
func TestUnixListenerSpecificMethods(t *testing.T) {
switch runtime.GOOS {
case "plan9", "windows":
- t.Skipf("skipping read test on %q", runtime.GOOS)
+ t.Skipf("skipping test on %q", runtime.GOOS)
}
addr := testUnixAddr()
diff --git a/src/pkg/net/rpc/jsonrpc/all_test.go b/src/pkg/net/rpc/jsonrpc/all_test.go
index 3c7c4d48f..40d4b82d7 100644
--- a/src/pkg/net/rpc/jsonrpc/all_test.go
+++ b/src/pkg/net/rpc/jsonrpc/all_test.go
@@ -9,6 +9,7 @@ import (
"errors"
"fmt"
"io"
+ "io/ioutil"
"net"
"net/rpc"
"testing"
@@ -185,6 +186,22 @@ func TestMalformedInput(t *testing.T) {
ServeConn(srv) // must return, not loop
}
+func TestMalformedOutput(t *testing.T) {
+ cli, srv := net.Pipe()
+ go srv.Write([]byte(`{"id":0,"result":null,"error":null}`))
+ go ioutil.ReadAll(srv)
+
+ client := NewClient(cli)
+ defer client.Close()
+
+ args := &Args{7, 8}
+ reply := new(Reply)
+ err := client.Call("Arith.Add", args, reply)
+ if err == nil {
+ t.Error("expected error")
+ }
+}
+
func TestUnexpectedError(t *testing.T) {
cli, srv := myPipe()
go cli.PipeWriter.CloseWithError(errors.New("unexpected error!")) // reader will get this error
diff --git a/src/pkg/net/rpc/jsonrpc/client.go b/src/pkg/net/rpc/jsonrpc/client.go
index 3fa8cbf08..2194f2125 100644
--- a/src/pkg/net/rpc/jsonrpc/client.go
+++ b/src/pkg/net/rpc/jsonrpc/client.go
@@ -83,7 +83,7 @@ func (c *clientCodec) ReadResponseHeader(r *rpc.Response) error {
r.Error = ""
r.Seq = c.resp.Id
- if c.resp.Error != nil {
+ if c.resp.Error != nil || c.resp.Result == nil {
x, ok := c.resp.Error.(string)
if !ok {
return fmt.Errorf("invalid error %v", c.resp.Error)
diff --git a/src/pkg/net/rpc/server_test.go b/src/pkg/net/rpc/server_test.go
index 8a1530623..eb17210ab 100644
--- a/src/pkg/net/rpc/server_test.go
+++ b/src/pkg/net/rpc/server_test.go
@@ -399,12 +399,10 @@ func (WriteFailCodec) WriteRequest(*Request, interface{}) error {
func (WriteFailCodec) ReadResponseHeader(*Response) error {
select {}
- panic("unreachable")
}
func (WriteFailCodec) ReadResponseBody(interface{}) error {
select {}
- panic("unreachable")
}
func (WriteFailCodec) Close() error {
@@ -465,10 +463,16 @@ func countMallocs(dial func() (*Client, error), t *testing.T) float64 {
}
func TestCountMallocs(t *testing.T) {
+ if runtime.GOMAXPROCS(0) > 1 {
+ t.Skip("skipping; GOMAXPROCS>1")
+ }
fmt.Printf("mallocs per rpc round trip: %v\n", countMallocs(dialDirect, t))
}
func TestCountMallocsOverHTTP(t *testing.T) {
+ if runtime.GOMAXPROCS(0) > 1 {
+ t.Skip("skipping; GOMAXPROCS>1")
+ }
fmt.Printf("mallocs per HTTP rpc round trip: %v\n", countMallocs(dialHTTP, t))
}
diff --git a/src/pkg/net/sendfile_freebsd.go b/src/pkg/net/sendfile_freebsd.go
index 8008bc3b5..dc5b76755 100644
--- a/src/pkg/net/sendfile_freebsd.go
+++ b/src/pkg/net/sendfile_freebsd.go
@@ -83,7 +83,7 @@ func sendFile(c *netFD, r io.Reader) (written int64, err error, handled bool) {
break
}
if err1 == syscall.EAGAIN {
- if err1 = c.pollServer.WaitWrite(c); err1 == nil {
+ if err1 = c.pd.WaitWrite(); err1 == nil {
continue
}
}
diff --git a/src/pkg/net/sendfile_linux.go b/src/pkg/net/sendfile_linux.go
index 3357e6538..6f1323b3d 100644
--- a/src/pkg/net/sendfile_linux.go
+++ b/src/pkg/net/sendfile_linux.go
@@ -59,7 +59,7 @@ func sendFile(c *netFD, r io.Reader) (written int64, err error, handled bool) {
break
}
if err1 == syscall.EAGAIN {
- if err1 = c.pollServer.WaitWrite(c); err1 == nil {
+ if err1 = c.pd.WaitWrite(); err1 == nil {
continue
}
}
diff --git a/src/pkg/net/server_test.go b/src/pkg/net/server_test.go
index 25c2be5a7..9194a8ec2 100644
--- a/src/pkg/net/server_test.go
+++ b/src/pkg/net/server_test.go
@@ -9,6 +9,7 @@ import (
"io"
"os"
"runtime"
+ "strconv"
"testing"
"time"
)
@@ -41,6 +42,12 @@ func skipServerTest(net, unixsotype, addr string, ipv6, ipv4map, linuxonly bool)
return false
}
+func tempfile(filename string) string {
+ // use /tmp in case it is prohibited to create
+ // UNIX sockets in TMPDIR
+ return "/tmp/" + filename + "." + strconv.Itoa(os.Getpid())
+}
+
var streamConnServerTests = []struct {
snet string // server side
saddr string
@@ -86,7 +93,7 @@ var streamConnServerTests = []struct {
{snet: "tcp6", saddr: "[::1]", cnet: "tcp6", caddr: "[::1]", ipv6: true},
- {snet: "unix", saddr: "/tmp/gotest1.net", cnet: "unix", caddr: "/tmp/gotest1.net.local"},
+ {snet: "unix", saddr: tempfile("gotest1.net"), cnet: "unix", caddr: tempfile("gotest1.net.local")},
{snet: "unix", saddr: "@gotest2/net", cnet: "unix", caddr: "@gotest2/net.local", linux: true},
}
@@ -135,7 +142,7 @@ var seqpacketConnServerTests = []struct {
caddr string // client address
empty bool // test with empty data
}{
- {net: "unixpacket", saddr: "/tmp/gotest3.net", caddr: "/tmp/gotest3.net.local"},
+ {net: "unixpacket", saddr: tempfile("/gotest3.net"), caddr: tempfile("gotest3.net.local")},
{net: "unixpacket", saddr: "@gotest4/net", caddr: "@gotest4/net.local"},
}
@@ -294,10 +301,10 @@ var datagramPacketConnServerTests = []struct {
{snet: "udp", saddr: "[::1]", cnet: "udp", caddr: "[::1]", ipv6: true, empty: true},
{snet: "udp", saddr: "[::1]", cnet: "udp", caddr: "[::1]", ipv6: true, dial: true, empty: true},
- {snet: "unixgram", saddr: "/tmp/gotest5.net", cnet: "unixgram", caddr: "/tmp/gotest5.net.local"},
- {snet: "unixgram", saddr: "/tmp/gotest5.net", cnet: "unixgram", caddr: "/tmp/gotest5.net.local", dial: true},
- {snet: "unixgram", saddr: "/tmp/gotest5.net", cnet: "unixgram", caddr: "/tmp/gotest5.net.local", empty: true},
- {snet: "unixgram", saddr: "/tmp/gotest5.net", cnet: "unixgram", caddr: "/tmp/gotest5.net.local", dial: true, empty: true},
+ {snet: "unixgram", saddr: tempfile("gotest5.net"), cnet: "unixgram", caddr: tempfile("gotest5.net.local")},
+ {snet: "unixgram", saddr: tempfile("gotest5.net"), cnet: "unixgram", caddr: tempfile("gotest5.net.local"), dial: true},
+ {snet: "unixgram", saddr: tempfile("gotest5.net"), cnet: "unixgram", caddr: tempfile("gotest5.net.local"), empty: true},
+ {snet: "unixgram", saddr: tempfile("gotest5.net"), cnet: "unixgram", caddr: tempfile("gotest5.net.local"), dial: true, empty: true},
{snet: "unixgram", saddr: "@gotest6/net", cnet: "unixgram", caddr: "@gotest6/net.local", linux: true},
}
@@ -395,7 +402,7 @@ func runDatagramConnClient(t *testing.T, net, laddr, taddr string, isEmpty bool)
t.Fatalf("Dial(%q, %q) failed: %v", net, taddr, err)
}
case "unixgram":
- c, err = DialUnix(net, &UnixAddr{laddr, net}, &UnixAddr{taddr, net})
+ c, err = DialUnix(net, &UnixAddr{Name: laddr, Net: net}, &UnixAddr{Name: taddr, Net: net})
if err != nil {
t.Fatalf("DialUnix(%q, {%q, %q}) failed: %v", net, laddr, taddr, err)
}
diff --git a/src/pkg/net/smtp/auth.go b/src/pkg/net/smtp/auth.go
index d401e3c21..3f1339ebc 100644
--- a/src/pkg/net/smtp/auth.go
+++ b/src/pkg/net/smtp/auth.go
@@ -54,7 +54,16 @@ func PlainAuth(identity, username, password, host string) Auth {
func (a *plainAuth) Start(server *ServerInfo) (string, []byte, error) {
if !server.TLS {
- return "", nil, errors.New("unencrypted connection")
+ advertised := false
+ for _, mechanism := range server.Auth {
+ if mechanism == "PLAIN" {
+ advertised = true
+ break
+ }
+ }
+ if !advertised {
+ return "", nil, errors.New("unencrypted connection")
+ }
}
if server.Name != a.host {
return "", nil, errors.New("wrong host name")
diff --git a/src/pkg/net/smtp/smtp_test.go b/src/pkg/net/smtp/smtp_test.go
index 8317428cb..c190b32c0 100644
--- a/src/pkg/net/smtp/smtp_test.go
+++ b/src/pkg/net/smtp/smtp_test.go
@@ -57,6 +57,41 @@ testLoop:
}
}
+func TestAuthPlain(t *testing.T) {
+ auth := PlainAuth("foo", "bar", "baz", "servername")
+
+ tests := []struct {
+ server *ServerInfo
+ err string
+ }{
+ {
+ server: &ServerInfo{Name: "servername", TLS: true},
+ },
+ {
+ // Okay; explicitly advertised by server.
+ server: &ServerInfo{Name: "servername", Auth: []string{"PLAIN"}},
+ },
+ {
+ server: &ServerInfo{Name: "servername", Auth: []string{"CRAM-MD5"}},
+ err: "unencrypted connection",
+ },
+ {
+ server: &ServerInfo{Name: "attacker", TLS: true},
+ err: "wrong host name",
+ },
+ }
+ for i, tt := range tests {
+ _, _, err := auth.Start(tt.server)
+ got := ""
+ if err != nil {
+ got = err.Error()
+ }
+ if got != tt.err {
+ t.Errorf("%d. got error = %q; want %q", i, got, tt.err)
+ }
+ }
+}
+
type faker struct {
io.ReadWriter
}
diff --git a/src/pkg/net/sock_bsd.go b/src/pkg/net/sock_bsd.go
index 3205f9404..d99349265 100644
--- a/src/pkg/net/sock_bsd.go
+++ b/src/pkg/net/sock_bsd.go
@@ -27,5 +27,11 @@ func maxListenerBacklog() int {
if n == 0 || err != nil {
return syscall.SOMAXCONN
}
+ // FreeBSD stores the backlog in a uint16, as does Linux.
+ // Assume the other BSDs do too. Truncate number to avoid wrapping.
+ // See issue 5030.
+ if n > 1<<16-1 {
+ n = 1<<16 - 1
+ }
return int(n)
}
diff --git a/src/pkg/net/sock_cloexec.go b/src/pkg/net/sock_cloexec.go
index 12d0f3488..3f22cd8f5 100644
--- a/src/pkg/net/sock_cloexec.go
+++ b/src/pkg/net/sock_cloexec.go
@@ -44,8 +44,8 @@ func sysSocket(f, t, p int) (int, error) {
func accept(fd int) (int, syscall.Sockaddr, error) {
nfd, sa, err := syscall.Accept4(fd, syscall.SOCK_NONBLOCK|syscall.SOCK_CLOEXEC)
// The accept4 system call was introduced in Linux 2.6.28. If
- // we get an ENOSYS error, fall back to using accept.
- if err == nil || err != syscall.ENOSYS {
+ // we get an ENOSYS or EINVAL error, fall back to using accept.
+ if err == nil || (err != syscall.ENOSYS && err != syscall.EINVAL) {
return nfd, sa, err
}
diff --git a/src/pkg/net/sock_linux.go b/src/pkg/net/sock_linux.go
index 8bbd74ddc..cc5ce153b 100644
--- a/src/pkg/net/sock_linux.go
+++ b/src/pkg/net/sock_linux.go
@@ -21,5 +21,11 @@ func maxListenerBacklog() int {
if n == 0 || !ok {
return syscall.SOMAXCONN
}
+ // Linux stores the backlog in a uint16.
+ // Truncate number to avoid wrapping.
+ // See issue 5030.
+ if n > 1<<16-1 {
+ n = 1<<16 - 1
+ }
return n
}
diff --git a/src/pkg/net/sock_posix.go b/src/pkg/net/sock_posix.go
index b50a892b1..be89c26db 100644
--- a/src/pkg/net/sock_posix.go
+++ b/src/pkg/net/sock_posix.go
@@ -25,7 +25,8 @@ func socket(net string, f, t, p int, ipv6only bool, ulsa, ursa syscall.Sockaddr,
return nil, err
}
- if ulsa != nil {
+ // This socket is used by a listener.
+ if ulsa != nil && ursa == nil {
// We provide a socket that listens to a wildcard
// address with reusable UDP port when the given ulsa
// is an appropriate UDP multicast address prefix.
@@ -37,6 +38,9 @@ func socket(net string, f, t, p int, ipv6only bool, ulsa, ursa syscall.Sockaddr,
closesocket(s)
return nil, err
}
+ }
+
+ if ulsa != nil {
if err = syscall.Bind(s, ulsa); err != nil {
closesocket(s)
return nil, err
@@ -48,19 +52,27 @@ func socket(net string, f, t, p int, ipv6only bool, ulsa, ursa syscall.Sockaddr,
return nil, err
}
+ // This socket is used by a dialer.
if ursa != nil {
- fd.wdeadline.setTime(deadline)
- if err = fd.connect(ursa); err != nil {
- closesocket(s)
+ if !deadline.IsZero() {
+ setWriteDeadline(fd, deadline)
+ }
+ if err = fd.connect(ulsa, ursa); err != nil {
+ fd.Close()
return nil, err
}
fd.isConnected = true
- fd.wdeadline.set(0)
+ if !deadline.IsZero() {
+ setWriteDeadline(fd, time.Time{})
+ }
}
lsa, _ := syscall.Getsockname(s)
laddr := toAddr(lsa)
rsa, _ := syscall.Getpeername(s)
+ if rsa == nil {
+ rsa = ursa
+ }
raddr := toAddr(rsa)
fd.setAddr(laddr, raddr)
return fd, nil
diff --git a/src/pkg/net/sock_windows.go b/src/pkg/net/sock_windows.go
index a77c48437..41368d39e 100644
--- a/src/pkg/net/sock_windows.go
+++ b/src/pkg/net/sock_windows.go
@@ -8,6 +8,7 @@ import "syscall"
func maxListenerBacklog() int {
// TODO: Implement this
+ // NOTE: Never return a number bigger than 1<<16 - 1. See issue 5030.
return syscall.SOMAXCONN
}
diff --git a/src/pkg/net/sockopt_posix.go b/src/pkg/net/sockopt_posix.go
index fe371fe0c..1590f4e98 100644
--- a/src/pkg/net/sockopt_posix.go
+++ b/src/pkg/net/sockopt_posix.go
@@ -11,7 +11,6 @@ package net
import (
"os"
"syscall"
- "time"
)
// Boolean to int.
@@ -119,24 +118,6 @@ func setWriteBuffer(fd *netFD, bytes int) error {
return os.NewSyscallError("setsockopt", syscall.SetsockoptInt(fd.sysfd, syscall.SOL_SOCKET, syscall.SO_SNDBUF, bytes))
}
-// TODO(dfc) these unused error returns could be removed
-
-func setReadDeadline(fd *netFD, t time.Time) error {
- fd.rdeadline.setTime(t)
- return nil
-}
-
-func setWriteDeadline(fd *netFD, t time.Time) error {
- fd.wdeadline.setTime(t)
- return nil
-}
-
-func setDeadline(fd *netFD, t time.Time) error {
- setReadDeadline(fd, t)
- setWriteDeadline(fd, t)
- return nil
-}
-
func setKeepAlive(fd *netFD, keepalive bool) error {
if err := fd.incref(false); err != nil {
return err
diff --git a/src/pkg/net/sockopt_windows.go b/src/pkg/net/sockopt_windows.go
index 509b5963b..0861fe8f4 100644
--- a/src/pkg/net/sockopt_windows.go
+++ b/src/pkg/net/sockopt_windows.go
@@ -9,6 +9,7 @@ package net
import (
"os"
"syscall"
+ "time"
)
func setDefaultSockopts(s syscall.Handle, f, t int, ipv6only bool) error {
@@ -47,3 +48,21 @@ func setDefaultMulticastSockopts(s syscall.Handle) error {
}
return nil
}
+
+// TODO(dfc) these unused error returns could be removed
+
+func setReadDeadline(fd *netFD, t time.Time) error {
+ fd.rdeadline.setTime(t)
+ return nil
+}
+
+func setWriteDeadline(fd *netFD, t time.Time) error {
+ fd.wdeadline.setTime(t)
+ return nil
+}
+
+func setDeadline(fd *netFD, t time.Time) error {
+ setReadDeadline(fd, t)
+ setWriteDeadline(fd, t)
+ return nil
+}
diff --git a/src/pkg/net/tcp_test.go b/src/pkg/net/tcp_test.go
index 6c4485a94..a71b02b47 100644
--- a/src/pkg/net/tcp_test.go
+++ b/src/pkg/net/tcp_test.go
@@ -5,6 +5,7 @@
package net
import (
+ "fmt"
"reflect"
"runtime"
"testing"
@@ -146,24 +147,39 @@ func benchmarkTCP(b *testing.B, persistent, timeout bool, laddr string) {
}
}
-var resolveTCPAddrTests = []struct {
+type resolveTCPAddrTest struct {
net string
litAddr string
addr *TCPAddr
err error
-}{
+}
+
+var resolveTCPAddrTests = []resolveTCPAddrTest{
{"tcp", "127.0.0.1:0", &TCPAddr{IP: IPv4(127, 0, 0, 1), Port: 0}, nil},
{"tcp4", "127.0.0.1:65535", &TCPAddr{IP: IPv4(127, 0, 0, 1), Port: 65535}, nil},
{"tcp", "[::1]:1", &TCPAddr{IP: ParseIP("::1"), Port: 1}, nil},
{"tcp6", "[::1]:65534", &TCPAddr{IP: ParseIP("::1"), Port: 65534}, nil},
+ {"tcp", "[::1%en0]:1", &TCPAddr{IP: ParseIP("::1"), Port: 1, Zone: "en0"}, nil},
+ {"tcp6", "[::1%911]:2", &TCPAddr{IP: ParseIP("::1"), Port: 2, Zone: "911"}, nil},
+
{"", "127.0.0.1:0", &TCPAddr{IP: IPv4(127, 0, 0, 1), Port: 0}, nil}, // Go 1.0 behavior
{"", "[::1]:0", &TCPAddr{IP: ParseIP("::1"), Port: 0}, nil}, // Go 1.0 behavior
{"http", "127.0.0.1:0", nil, UnknownNetworkError("http")},
}
+func init() {
+ if ifi := loopbackInterface(); ifi != nil {
+ index := fmt.Sprintf("%v", ifi.Index)
+ resolveTCPAddrTests = append(resolveTCPAddrTests, []resolveTCPAddrTest{
+ {"tcp6", "[fe80::1%" + ifi.Name + "]:3", &TCPAddr{IP: ParseIP("fe80::1"), Port: 3, Zone: zoneToString(ifi.Index)}, nil},
+ {"tcp6", "[fe80::1%" + index + "]:4", &TCPAddr{IP: ParseIP("fe80::1"), Port: 4, Zone: index}, nil},
+ }...)
+ }
+}
+
func TestResolveTCPAddr(t *testing.T) {
for _, tt := range resolveTCPAddrTests {
addr, err := ResolveTCPAddr(tt.net, tt.litAddr)
@@ -193,14 +209,88 @@ func TestTCPListenerName(t *testing.T) {
for _, tt := range tcpListenerNameTests {
ln, err := ListenTCP(tt.net, tt.laddr)
if err != nil {
- t.Errorf("ListenTCP failed: %v", err)
- return
+ t.Fatalf("ListenTCP failed: %v", err)
}
defer ln.Close()
la := ln.Addr()
if a, ok := la.(*TCPAddr); !ok || a.Port == 0 {
- t.Errorf("got %v; expected a proper address with non-zero port number", la)
- return
+ t.Fatalf("got %v; expected a proper address with non-zero port number", la)
}
}
}
+
+func TestIPv6LinkLocalUnicastTCP(t *testing.T) {
+ if testing.Short() || !*testExternal {
+ t.Skip("skipping test to avoid external network")
+ }
+ if !supportsIPv6 {
+ t.Skip("ipv6 is not supported")
+ }
+ ifi := loopbackInterface()
+ if ifi == nil {
+ t.Skip("loopback interface not found")
+ }
+ laddr := ipv6LinkLocalUnicastAddr(ifi)
+ if laddr == "" {
+ t.Skip("ipv6 unicast address on loopback not found")
+ }
+
+ type test struct {
+ net, addr string
+ nameLookup bool
+ }
+ var tests = []test{
+ {"tcp", "[" + laddr + "%" + ifi.Name + "]:0", false},
+ {"tcp6", "[" + laddr + "%" + ifi.Name + "]:0", false},
+ }
+ switch runtime.GOOS {
+ case "darwin", "freebsd", "opensbd", "netbsd":
+ tests = append(tests, []test{
+ {"tcp", "[localhost%" + ifi.Name + "]:0", true},
+ {"tcp6", "[localhost%" + ifi.Name + "]:0", true},
+ }...)
+ case "linux":
+ tests = append(tests, []test{
+ {"tcp", "[ip6-localhost%" + ifi.Name + "]:0", true},
+ {"tcp6", "[ip6-localhost%" + ifi.Name + "]:0", true},
+ }...)
+ }
+ for _, tt := range tests {
+ ln, err := Listen(tt.net, tt.addr)
+ if err != nil {
+ // It might return "LookupHost returned no
+ // suitable address" error on some platforms.
+ t.Logf("Listen failed: %v", err)
+ continue
+ }
+ defer ln.Close()
+ if la, ok := ln.Addr().(*TCPAddr); !ok || !tt.nameLookup && la.Zone == "" {
+ t.Fatalf("got %v; expected a proper address with zone identifier", la)
+ }
+
+ done := make(chan int)
+ go transponder(t, ln, done)
+
+ c, err := Dial(tt.net, ln.Addr().String())
+ if err != nil {
+ t.Fatalf("Dial failed: %v", err)
+ }
+ defer c.Close()
+ if la, ok := c.LocalAddr().(*TCPAddr); !ok || !tt.nameLookup && la.Zone == "" {
+ t.Fatalf("got %v; expected a proper address with zone identifier", la)
+ }
+ if ra, ok := c.RemoteAddr().(*TCPAddr); !ok || !tt.nameLookup && ra.Zone == "" {
+ t.Fatalf("got %v; expected a proper address with zone identifier", ra)
+ }
+
+ if _, err := c.Write([]byte("TCP OVER IPV6 LINKLOCAL TEST")); err != nil {
+ t.Fatalf("Conn.Write failed: %v", err)
+ }
+ b := make([]byte, 32)
+ if _, err := c.Read(b); err != nil {
+ t.Fatalf("Conn.Read failed: %v", err)
+ }
+
+ <-done
+ }
+}
diff --git a/src/pkg/net/tcpsock.go b/src/pkg/net/tcpsock.go
index d5158b22d..4d9ebd214 100644
--- a/src/pkg/net/tcpsock.go
+++ b/src/pkg/net/tcpsock.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.
-// TCP sockets
-
package net
// TCPAddr represents the address of a TCP end point.
@@ -20,14 +18,18 @@ func (a *TCPAddr) String() string {
if a == nil {
return "<nil>"
}
+ if a.Zone != "" {
+ return JoinHostPort(a.IP.String()+"%"+a.Zone, itoa(a.Port))
+ }
return JoinHostPort(a.IP.String(), itoa(a.Port))
}
-// ResolveTCPAddr parses addr as a TCP address of the form
-// host:port and resolves domain names or port names to
-// numeric addresses on the network net, which must be "tcp",
-// "tcp4" or "tcp6". A literal IPv6 host address must be
-// enclosed in square brackets, as in "[::]:80".
+// ResolveTCPAddr parses addr as a TCP address of the form "host:port"
+// or "[ipv6-host%zone]:port" and resolves a pair of domain name and
+// port name on the network net, which must be "tcp", "tcp4" or
+// "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".
func ResolveTCPAddr(net, addr string) (*TCPAddr, error) {
switch net {
case "tcp", "tcp4", "tcp6":
diff --git a/src/pkg/net/tcpsock_plan9.go b/src/pkg/net/tcpsock_plan9.go
index ed3664603..48334fed7 100644
--- a/src/pkg/net/tcpsock_plan9.go
+++ b/src/pkg/net/tcpsock_plan9.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.
-// TCP sockets for Plan 9
-
package net
import (
@@ -161,12 +159,16 @@ func (l *TCPListener) SetDeadline(t time.Time) error {
// 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) { return l.dup() }
// 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, it means to listen on some available port. The caller
-// can use l.Addr() to retrieve the chosen address.
+// 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":
diff --git a/src/pkg/net/tcpsock_posix.go b/src/pkg/net/tcpsock_posix.go
index bd5a2a287..876edb101 100644
--- a/src/pkg/net/tcpsock_posix.go
+++ b/src/pkg/net/tcpsock_posix.go
@@ -4,8 +4,6 @@
// +build darwin freebsd linux netbsd openbsd windows
-// TCP sockets
-
package net
import (
@@ -58,8 +56,8 @@ func (a *TCPAddr) toAddr() sockaddr {
return a
}
-// TCPConn is an implementation of the Conn interface
-// for TCP network connections.
+// TCPConn is an implementation of the Conn interface for TCP network
+// connections.
type TCPConn struct {
conn
}
@@ -96,17 +94,17 @@ func (c *TCPConn) CloseWrite() error {
return c.fd.CloseWrite()
}
-// SetLinger sets the behavior of Close() on a connection
-// which still has data waiting to be sent or to be acknowledged.
+// 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), Close returns immediately and
-// the operating system finishes sending the data in the background.
+// If sec < 0 (the default), Close returns immediately and the
+// operating system finishes sending the data in the background.
//
// If sec == 0, Close returns immediately and the operating system
// discards any unsent or unacknowledged data.
//
-// If sec > 0, Close blocks for at most sec seconds waiting for
-// data to be sent and acknowledged.
+// If sec > 0, Close blocks for at most sec seconds waiting for data
+// to be sent and acknowledged.
func (c *TCPConn) SetLinger(sec int) error {
if !c.ok() {
return syscall.EINVAL
@@ -124,9 +122,9 @@ func (c *TCPConn) SetKeepAlive(keepalive bool) error {
}
// 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.
+// 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
@@ -135,8 +133,8 @@ func (c *TCPConn) SetNoDelay(noDelay bool) error {
}
// 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.
+// 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":
@@ -216,16 +214,15 @@ func spuriousENOTAVAIL(err error) bool {
return ok && e.Err == syscall.EADDRNOTAVAIL
}
-// TCPListener is a TCP network listener.
-// Clients should typically use variables of type Listener
-// instead of assuming TCP.
+// 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
-// and the remote address.
-func (l *TCPListener) AcceptTCP() (c *TCPConn, err error) {
+// AcceptTCP accepts the next incoming call and returns the new
+// connection and the remote address.
+func (l *TCPListener) AcceptTCP() (*TCPConn, error) {
if l == nil || l.fd == nil {
return nil, syscall.EINVAL
}
@@ -236,14 +233,14 @@ func (l *TCPListener) AcceptTCP() (c *TCPConn, err error) {
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() (c Conn, err error) {
- c1, err := l.AcceptTCP()
+// 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()
if err != nil {
return nil, err
}
- return c1, nil
+ return c, nil
}
// Close stops listening on the TCP address.
@@ -267,15 +264,19 @@ func (l *TCPListener) SetDeadline(t time.Time) error {
return setDeadline(l.fd, t)
}
-// File returns a copy of the underlying os.File, set to blocking mode.
-// It is the caller's responsibility to close f when finished.
+// 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) { return l.fd.dup() }
-// 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, it means to listen on some available port.
-// The caller can use l.Addr() to retrieve the chosen address.
+// 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":
@@ -291,7 +292,7 @@ func ListenTCP(net string, laddr *TCPAddr) (*TCPListener, error) {
}
err = syscall.Listen(fd.sysfd, listenerBacklog)
if err != nil {
- closesocket(fd.sysfd)
+ fd.Close()
return nil, &OpError{"listen", net, laddr, err}
}
return &TCPListener{fd}, nil
diff --git a/src/pkg/net/textproto/reader.go b/src/pkg/net/textproto/reader.go
index b61bea862..5bd26ac8d 100644
--- a/src/pkg/net/textproto/reader.go
+++ b/src/pkg/net/textproto/reader.go
@@ -489,7 +489,6 @@ func (r *Reader) ReadMIMEHeader() (MIMEHeader, error) {
return m, err
}
}
- panic("unreachable")
}
// CanonicalMIMEHeaderKey returns the canonical format of the
@@ -575,6 +574,7 @@ var commonHeaders = []string{
"Content-Length",
"Content-Transfer-Encoding",
"Content-Type",
+ "Cookie",
"Date",
"Dkim-Signature",
"Etag",
diff --git a/src/pkg/net/textproto/reader_test.go b/src/pkg/net/textproto/reader_test.go
index 26987f611..f27042d4e 100644
--- a/src/pkg/net/textproto/reader_test.go
+++ b/src/pkg/net/textproto/reader_test.go
@@ -290,6 +290,7 @@ Non-Interned: test
`, "\n", "\r\n", -1)
func BenchmarkReadMIMEHeader(b *testing.B) {
+ b.ReportAllocs()
var buf bytes.Buffer
br := bufio.NewReader(&buf)
r := NewReader(br)
@@ -319,6 +320,7 @@ func BenchmarkReadMIMEHeader(b *testing.B) {
}
func BenchmarkUncommon(b *testing.B) {
+ b.ReportAllocs()
var buf bytes.Buffer
br := bufio.NewReader(&buf)
r := NewReader(br)
diff --git a/src/pkg/net/timeout_test.go b/src/pkg/net/timeout_test.go
index 0260efcc0..2e92147b8 100644
--- a/src/pkg/net/timeout_test.go
+++ b/src/pkg/net/timeout_test.go
@@ -532,7 +532,7 @@ func TestReadDeadlineDataAvailable(t *testing.T) {
defer ln.Close()
servec := make(chan copyRes)
- const msg = "data client shouldn't read, even though it it'll be waiting"
+ const msg = "data client shouldn't read, even though it'll be waiting"
go func() {
c, err := ln.Accept()
if err != nil {
@@ -596,6 +596,64 @@ func TestWriteDeadlineBufferAvailable(t *testing.T) {
}
}
+// TestAcceptDeadlineConnectionAvailable tests that accept deadlines work, even
+// if there's incoming connections available.
+func TestAcceptDeadlineConnectionAvailable(t *testing.T) {
+ switch runtime.GOOS {
+ case "plan9":
+ t.Skipf("skipping test on %q", runtime.GOOS)
+ }
+
+ ln := newLocalListener(t).(*TCPListener)
+ defer ln.Close()
+
+ go func() {
+ c, err := Dial("tcp", ln.Addr().String())
+ if err != nil {
+ t.Fatalf("Dial: %v", err)
+ }
+ defer c.Close()
+ var buf [1]byte
+ c.Read(buf[:]) // block until the connection or listener is closed
+ }()
+ time.Sleep(10 * time.Millisecond)
+ ln.SetDeadline(time.Now().Add(-5 * time.Second)) // in the past
+ c, err := ln.Accept()
+ if err == nil {
+ defer c.Close()
+ }
+ if !isTimeout(err) {
+ t.Fatalf("Accept: got %v; want timeout", err)
+ }
+}
+
+// TestConnectDeadlineInThePast tests that connect deadlines work, even
+// if the connection can be established w/o blocking.
+func TestConnectDeadlineInThePast(t *testing.T) {
+ switch runtime.GOOS {
+ case "plan9":
+ t.Skipf("skipping test on %q", runtime.GOOS)
+ }
+
+ ln := newLocalListener(t).(*TCPListener)
+ defer ln.Close()
+
+ go func() {
+ c, err := ln.Accept()
+ if err == nil {
+ defer c.Close()
+ }
+ }()
+ time.Sleep(10 * time.Millisecond)
+ c, err := DialTimeout("tcp", ln.Addr().String(), -5*time.Second) // in the past
+ if err == nil {
+ defer c.Close()
+ }
+ if !isTimeout(err) {
+ t.Fatalf("DialTimeout: got %v; want timeout", err)
+ }
+}
+
// TestProlongTimeout tests concurrent deadline modification.
// Known to cause data races in the past.
func TestProlongTimeout(t *testing.T) {
diff --git a/src/pkg/net/udp_test.go b/src/pkg/net/udp_test.go
index 220422e13..4278f6dd4 100644
--- a/src/pkg/net/udp_test.go
+++ b/src/pkg/net/udp_test.go
@@ -5,29 +5,45 @@
package net
import (
+ "fmt"
"reflect"
"runtime"
"testing"
)
-var resolveUDPAddrTests = []struct {
+type resolveUDPAddrTest struct {
net string
litAddr string
addr *UDPAddr
err error
-}{
+}
+
+var resolveUDPAddrTests = []resolveUDPAddrTest{
{"udp", "127.0.0.1:0", &UDPAddr{IP: IPv4(127, 0, 0, 1), Port: 0}, nil},
{"udp4", "127.0.0.1:65535", &UDPAddr{IP: IPv4(127, 0, 0, 1), Port: 65535}, nil},
{"udp", "[::1]:1", &UDPAddr{IP: ParseIP("::1"), Port: 1}, nil},
{"udp6", "[::1]:65534", &UDPAddr{IP: ParseIP("::1"), Port: 65534}, nil},
+ {"udp", "[::1%en0]:1", &UDPAddr{IP: ParseIP("::1"), Port: 1, Zone: "en0"}, nil},
+ {"udp6", "[::1%911]:2", &UDPAddr{IP: ParseIP("::1"), Port: 2, Zone: "911"}, nil},
+
{"", "127.0.0.1:0", &UDPAddr{IP: IPv4(127, 0, 0, 1), Port: 0}, nil}, // Go 1.0 behavior
{"", "[::1]:0", &UDPAddr{IP: ParseIP("::1"), Port: 0}, nil}, // Go 1.0 behavior
{"sip", "127.0.0.1:0", nil, UnknownNetworkError("sip")},
}
+func init() {
+ if ifi := loopbackInterface(); ifi != nil {
+ index := fmt.Sprintf("%v", ifi.Index)
+ resolveUDPAddrTests = append(resolveUDPAddrTests, []resolveUDPAddrTest{
+ {"udp6", "[fe80::1%" + ifi.Name + "]:3", &UDPAddr{IP: ParseIP("fe80::1"), Port: 3, Zone: zoneToString(ifi.Index)}, nil},
+ {"udp6", "[fe80::1%" + index + "]:4", &UDPAddr{IP: ParseIP("fe80::1"), Port: 4, Zone: index}, nil},
+ }...)
+ }
+}
+
func TestResolveUDPAddr(t *testing.T) {
for _, tt := range resolveUDPAddrTests {
addr, err := ResolveUDPAddr(tt.net, tt.litAddr)
@@ -135,14 +151,125 @@ func TestUDPConnLocalName(t *testing.T) {
for _, tt := range udpConnLocalNameTests {
c, err := ListenUDP(tt.net, tt.laddr)
if err != nil {
- t.Errorf("ListenUDP failed: %v", err)
- return
+ t.Fatalf("ListenUDP failed: %v", err)
}
defer c.Close()
la := c.LocalAddr()
if a, ok := la.(*UDPAddr); !ok || a.Port == 0 {
- t.Errorf("got %v; expected a proper address with non-zero port number", la)
- return
+ t.Fatalf("got %v; expected a proper address with non-zero port number", la)
+ }
+ }
+}
+
+func TestUDPConnLocalAndRemoteNames(t *testing.T) {
+ for _, laddr := range []string{"", "127.0.0.1:0"} {
+ c1, err := ListenPacket("udp", "127.0.0.1:0")
+ if err != nil {
+ t.Fatalf("ListenUDP failed: %v", err)
+ }
+ defer c1.Close()
+
+ var la *UDPAddr
+ if laddr != "" {
+ var err error
+ if la, err = ResolveUDPAddr("udp", laddr); err != nil {
+ t.Fatalf("ResolveUDPAddr failed: %v", err)
+ }
+ }
+ c2, err := DialUDP("udp", la, c1.LocalAddr().(*UDPAddr))
+ if err != nil {
+ t.Fatalf("DialUDP failed: %v", err)
+ }
+ defer c2.Close()
+
+ var connAddrs = [4]struct {
+ got Addr
+ ok bool
+ }{
+ {c1.LocalAddr(), true},
+ {c1.(*UDPConn).RemoteAddr(), false},
+ {c2.LocalAddr(), true},
+ {c2.RemoteAddr(), true},
+ }
+ for _, ca := range connAddrs {
+ if a, ok := ca.got.(*UDPAddr); ok != ca.ok || ok && a.Port == 0 {
+ t.Fatalf("got %v; expected a proper address with non-zero port number", ca.got)
+ }
+ }
+ }
+}
+
+func TestIPv6LinkLocalUnicastUDP(t *testing.T) {
+ if testing.Short() || !*testExternal {
+ t.Skip("skipping test to avoid external network")
+ }
+ if !supportsIPv6 {
+ t.Skip("ipv6 is not supported")
+ }
+ ifi := loopbackInterface()
+ if ifi == nil {
+ t.Skip("loopback interface not found")
+ }
+ laddr := ipv6LinkLocalUnicastAddr(ifi)
+ if laddr == "" {
+ t.Skip("ipv6 unicast address on loopback not found")
+ }
+
+ type test struct {
+ net, addr string
+ nameLookup bool
+ }
+ var tests = []test{
+ {"udp", "[" + laddr + "%" + ifi.Name + "]:0", false},
+ {"udp6", "[" + laddr + "%" + ifi.Name + "]:0", false},
+ }
+ switch runtime.GOOS {
+ case "darwin", "freebsd", "openbsd", "netbsd":
+ tests = append(tests, []test{
+ {"udp", "[localhost%" + ifi.Name + "]:0", true},
+ {"udp6", "[localhost%" + ifi.Name + "]:0", true},
+ }...)
+ case "linux":
+ tests = append(tests, []test{
+ {"udp", "[ip6-localhost%" + ifi.Name + "]:0", true},
+ {"udp6", "[ip6-localhost%" + ifi.Name + "]:0", true},
+ }...)
+ }
+ for _, tt := range tests {
+ c1, err := ListenPacket(tt.net, tt.addr)
+ if err != nil {
+ // It might return "LookupHost returned no
+ // suitable address" error on some platforms.
+ t.Logf("ListenPacket failed: %v", err)
+ continue
+ }
+ defer c1.Close()
+ if la, ok := c1.LocalAddr().(*UDPAddr); !ok || !tt.nameLookup && la.Zone == "" {
+ t.Fatalf("got %v; expected a proper address with zone identifier", la)
+ }
+
+ c2, err := Dial(tt.net, c1.LocalAddr().String())
+ if err != nil {
+ t.Fatalf("Dial failed: %v", err)
+ }
+ defer c2.Close()
+ if la, ok := c2.LocalAddr().(*UDPAddr); !ok || !tt.nameLookup && la.Zone == "" {
+ t.Fatalf("got %v; expected a proper address with zone identifier", la)
+ }
+ if ra, ok := c2.RemoteAddr().(*UDPAddr); !ok || !tt.nameLookup && ra.Zone == "" {
+ t.Fatalf("got %v; expected a proper address with zone identifier", ra)
+ }
+
+ if _, err := c2.Write([]byte("UDP OVER IPV6 LINKLOCAL TEST")); err != nil {
+ t.Fatalf("Conn.Write failed: %v", err)
+ }
+ b := make([]byte, 32)
+ if _, from, err := c1.ReadFrom(b); err != nil {
+ t.Fatalf("PacketConn.ReadFrom failed: %v", err)
+ } else {
+ if ra, ok := from.(*UDPAddr); !ok || !tt.nameLookup && ra.Zone == "" {
+ t.Fatalf("got %v; expected a proper address with zone identifier", ra)
+ }
}
}
}
diff --git a/src/pkg/net/udpsock.go b/src/pkg/net/udpsock.go
index 6e5e90268..5ce7d6bea 100644
--- a/src/pkg/net/udpsock.go
+++ b/src/pkg/net/udpsock.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.
-// UDP sockets
-
package net
import "errors"
@@ -24,14 +22,18 @@ func (a *UDPAddr) String() string {
if a == nil {
return "<nil>"
}
+ if a.Zone != "" {
+ return JoinHostPort(a.IP.String()+"%"+a.Zone, itoa(a.Port))
+ }
return JoinHostPort(a.IP.String(), itoa(a.Port))
}
-// ResolveUDPAddr parses addr as a UDP address of the form
-// host:port and resolves domain names or port names to
-// numeric addresses on the network net, which must be "udp",
-// "udp4" or "udp6". A literal IPv6 host address must be
-// enclosed in square brackets, as in "[::]:80".
+// ResolveUDPAddr parses addr as a UDP address of the form "host:port"
+// or "[ipv6-host%zone]:port" and resolves a pair of domain name and
+// port name on the network net, which must be "udp", "udp4" or
+// "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".
func ResolveUDPAddr(net, addr string) (*UDPAddr, error) {
switch net {
case "udp", "udp4", "udp6":
diff --git a/src/pkg/net/udpsock_plan9.go b/src/pkg/net/udpsock_plan9.go
index 2a7e3d19c..12a348399 100644
--- a/src/pkg/net/udpsock_plan9.go
+++ b/src/pkg/net/udpsock_plan9.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.
-// UDP sockets for Plan 9
-
package net
import (
@@ -13,15 +11,13 @@ import (
"time"
)
-// UDPConn is the implementation of the Conn and PacketConn
-// interfaces for UDP network connections.
+// 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}}
-}
+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
@@ -58,7 +54,7 @@ func (c *UDPConn) ReadFrom(b []byte) (int, Addr, error) {
}
// ReadMsgUDP reads a packet from c, copying the payload into b and
-// the associdated out-of-band data into oob. It returns the number
+// 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.
@@ -164,7 +160,10 @@ func unmarshalUDPHeader(b []byte) (*udpHeader, []byte) {
}
// ListenUDP listens for incoming UDP packets addressed to the local
-// address laddr. The returned connection c's ReadFrom and WriteTo
+// 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) {
diff --git a/src/pkg/net/udpsock_posix.go b/src/pkg/net/udpsock_posix.go
index 385cd902e..b90cb030d 100644
--- a/src/pkg/net/udpsock_posix.go
+++ b/src/pkg/net/udpsock_posix.go
@@ -4,8 +4,6 @@
// +build darwin freebsd linux netbsd openbsd windows
-// UDP sockets for POSIX
-
package net
import (
@@ -51,8 +49,8 @@ func (a *UDPAddr) toAddr() sockaddr {
return a
}
-// UDPConn is the implementation of the Conn and PacketConn
-// interfaces for UDP network connections.
+// UDPConn is the implementation of the Conn and PacketConn interfaces
+// for UDP network connections.
type UDPConn struct {
conn
}
@@ -63,8 +61,9 @@ func newUDPConn(fd *netFD) *UDPConn { return &UDPConn{conn{fd}} }
// 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.
+// 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() {
return 0, nil, syscall.EINVAL
@@ -89,7 +88,7 @@ func (c *UDPConn) ReadFrom(b []byte) (int, Addr, error) {
}
// ReadMsgUDP reads a packet from c, copying the payload into b and
-// the associdated out-of-band data into oob. It returns the number
+// 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.
@@ -108,12 +107,13 @@ func (c *UDPConn) ReadMsgUDP(b, oob []byte) (n, oobn, flags int, addr *UDPAddr,
return
}
-// WriteToUDP writes a UDP packet to addr via c, copying the payload from b.
+// 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.
+// 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
@@ -158,8 +158,8 @@ func (c *UDPConn) WriteMsgUDP(b, oob []byte, addr *UDPAddr) (n, oobn int, err er
}
// 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.
+// 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)
}
@@ -180,10 +180,13 @@ func dialUDP(net string, laddr, raddr *UDPAddr, deadline time.Time) (*UDPConn, e
return newUDPConn(fd), nil
}
-// ListenUDP listens for incoming UDP packets addressed to the
-// local address laddr. The returned connection c's ReadFrom
-// and WriteTo methods can be used to receive and send UDP
-// packets with per-packet addressing.
+// 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":
@@ -201,9 +204,9 @@ func ListenUDP(net string, laddr *UDPAddr) (*UDPConn, error) {
}
// ListenMulticastUDP listens for incoming multicast UDP packets
-// addressed to the group address gaddr on ifi, which specifies
-// the interface to join. ListenMulticastUDP uses default
-// multicast interface if ifi is nil.
+// addressed to the group address gaddr on ifi, which specifies the
+// interface to join. ListenMulticastUDP uses default multicast
+// interface if ifi is nil.
func ListenMulticastUDP(net string, ifi *Interface, gaddr *UDPAddr) (*UDPConn, error) {
switch net {
case "udp", "udp4", "udp6":
diff --git a/src/pkg/net/unicast_posix_test.go b/src/pkg/net/unicast_posix_test.go
index a8855cab7..b0588f4e5 100644
--- a/src/pkg/net/unicast_posix_test.go
+++ b/src/pkg/net/unicast_posix_test.go
@@ -45,7 +45,7 @@ var listenerTests = []struct {
// same port.
func TestTCPListener(t *testing.T) {
switch runtime.GOOS {
- case "plan9", "windows":
+ case "plan9":
t.Skipf("skipping test on %q", runtime.GOOS)
}
@@ -69,65 +69,8 @@ func TestTCPListener(t *testing.T) {
// same port.
func TestUDPListener(t *testing.T) {
switch runtime.GOOS {
- case "plan9", "windows":
- t.Skipf("skipping test on %q", runtime.GOOS)
- }
-
- toudpnet := func(net string) string {
- switch net {
- case "tcp":
- return "udp"
- case "tcp4":
- return "udp4"
- case "tcp6":
- return "udp6"
- }
- return "<nil>"
- }
-
- for _, tt := range listenerTests {
- if tt.wildcard && (testing.Short() || !*testExternal) {
- continue
- }
- if tt.ipv6 && !supportsIPv6 {
- continue
- }
- tt.net = toudpnet(tt.net)
- l1, port := usableListenPacketPort(t, tt.net, tt.laddr)
- checkFirstListener(t, tt.net, tt.laddr+":"+port, l1)
- l2, err := ListenPacket(tt.net, tt.laddr+":"+port)
- checkSecondListener(t, tt.net, tt.laddr+":"+port, err, l2)
- l1.Close()
- }
-}
-
-func TestSimpleTCPListener(t *testing.T) {
- switch runtime.GOOS {
- case "plan9":
- t.Skipf("skipping test on %q", runtime.GOOS)
- return
- }
-
- for _, tt := range listenerTests {
- if tt.wildcard && (testing.Short() || !*testExternal) {
- continue
- }
- if tt.ipv6 {
- continue
- }
- l1, port := usableListenPort(t, tt.net, tt.laddr)
- checkFirstListener(t, tt.net, tt.laddr+":"+port, l1)
- l2, err := Listen(tt.net, tt.laddr+":"+port)
- checkSecondListener(t, tt.net, tt.laddr+":"+port, err, l2)
- l1.Close()
- }
-}
-
-func TestSimpleUDPListener(t *testing.T) {
- switch runtime.GOOS {
case "plan9":
t.Skipf("skipping test on %q", runtime.GOOS)
- return
}
toudpnet := func(net string) string {
@@ -146,7 +89,7 @@ func TestSimpleUDPListener(t *testing.T) {
if tt.wildcard && (testing.Short() || !*testExternal) {
continue
}
- if tt.ipv6 {
+ if tt.ipv6 && !supportsIPv6 {
continue
}
tt.net = toudpnet(tt.net)
@@ -231,7 +174,7 @@ func TestDualStackTCPListener(t *testing.T) {
t.Skipf("skipping test on %q", runtime.GOOS)
}
if !supportsIPv6 {
- return
+ t.Skip("ipv6 is not supported")
}
for _, tt := range dualStackListenerTests {
@@ -263,7 +206,7 @@ func TestDualStackUDPListener(t *testing.T) {
t.Skipf("skipping test on %q", runtime.GOOS)
}
if !supportsIPv6 {
- return
+ t.Skip("ipv6 is not supported")
}
toudpnet := func(net string) string {
diff --git a/src/pkg/net/unix_test.go b/src/pkg/net/unix_test.go
index 2eaabe86e..5e63e9d9d 100644
--- a/src/pkg/net/unix_test.go
+++ b/src/pkg/net/unix_test.go
@@ -33,7 +33,6 @@ func TestReadUnixgramWithUnnamedSocket(t *testing.T) {
off := make(chan bool)
data := [5]byte{1, 2, 3, 4, 5}
-
go func() {
defer func() { off <- true }()
s, err := syscall.Socket(syscall.AF_UNIX, syscall.SOCK_DGRAM, 0)
@@ -54,15 +53,13 @@ func TestReadUnixgramWithUnnamedSocket(t *testing.T) {
c.SetReadDeadline(time.Now().Add(100 * time.Millisecond))
n, from, err := c.ReadFrom(b)
if err != nil {
- t.Errorf("UnixConn.ReadFrom failed: %v", err)
- return
+ t.Fatalf("UnixConn.ReadFrom failed: %v", err)
}
if from != nil {
- t.Errorf("neighbor address is %v", from)
+ t.Fatalf("neighbor address is %v", from)
}
if !bytes.Equal(b[:n], data[:]) {
- t.Errorf("got %v, want %v", b[:n], data[:])
- return
+ t.Fatalf("got %v, want %v", b[:n], data[:])
}
}
@@ -101,13 +98,12 @@ func TestReadUnixgramWithZeroBytesBuffer(t *testing.T) {
<-off
c.SetReadDeadline(time.Now().Add(100 * time.Millisecond))
- var peer Addr
- if _, peer, err = c.ReadFrom(nil); err != nil {
- t.Errorf("UnixConn.ReadFrom failed: %v", err)
- return
+ _, from, err := c.ReadFrom(nil)
+ if err != nil {
+ t.Fatalf("UnixConn.ReadFrom failed: %v", err)
}
- if peer != nil {
- t.Errorf("peer adddress is %v", peer)
+ if from != nil {
+ t.Fatalf("neighbor address is %v", from)
}
}
@@ -126,10 +122,10 @@ func TestUnixAutobind(t *testing.T) {
// retrieve the autobind address
autoAddr := c1.LocalAddr().(*UnixAddr)
if len(autoAddr.Name) <= 1 {
- t.Fatalf("Invalid autobind address: %v", autoAddr)
+ t.Fatalf("invalid autobind address: %v", autoAddr)
}
if autoAddr.Name[0] != '@' {
- t.Fatalf("Invalid autobind address: %v", autoAddr)
+ t.Fatalf("invalid autobind address: %v", autoAddr)
}
c2, err := DialUnix("unixgram", nil, autoAddr)
@@ -139,6 +135,112 @@ func TestUnixAutobind(t *testing.T) {
defer c2.Close()
if !reflect.DeepEqual(c1.LocalAddr(), c2.RemoteAddr()) {
- t.Fatalf("Expected autobind address %v, got %v", c1.LocalAddr(), c2.RemoteAddr())
+ t.Fatalf("expected autobind address %v, got %v", c1.LocalAddr(), c2.RemoteAddr())
+ }
+}
+
+func TestUnixConnLocalAndRemoteNames(t *testing.T) {
+ for _, laddr := range []string{"", testUnixAddr()} {
+ taddr := testUnixAddr()
+ ta, err := ResolveUnixAddr("unix", taddr)
+ if err != nil {
+ t.Fatalf("ResolveUnixAddr failed: %v", err)
+ }
+ ln, err := ListenUnix("unix", ta)
+ if err != nil {
+ t.Fatalf("ListenUnix failed: %v", err)
+ }
+ defer func() {
+ ln.Close()
+ os.Remove(taddr)
+ }()
+
+ done := make(chan int)
+ go transponder(t, ln, done)
+
+ la, err := ResolveUnixAddr("unix", laddr)
+ if err != nil {
+ t.Fatalf("ResolveUnixAddr failed: %v", err)
+ }
+ c, err := DialUnix("unix", la, ta)
+ if err != nil {
+ t.Fatalf("DialUnix failed: %v", err)
+ }
+ defer func() {
+ c.Close()
+ if la != nil {
+ defer os.Remove(laddr)
+ }
+ }()
+ if _, err := c.Write([]byte("UNIXCONN LOCAL AND REMOTE NAME TEST")); err != nil {
+ t.Fatalf("UnixConn.Write failed: %v", err)
+ }
+
+ if runtime.GOOS == "linux" && laddr == "" {
+ laddr = "@" // autobind feature
+ }
+ var connAddrs = [3]struct{ got, want Addr }{
+ {ln.Addr(), ta},
+ {c.LocalAddr(), &UnixAddr{Name: laddr, Net: "unix"}},
+ {c.RemoteAddr(), ta},
+ }
+ for _, ca := range connAddrs {
+ if !reflect.DeepEqual(ca.got, ca.want) {
+ t.Fatalf("got %#v, expected %#v", ca.got, ca.want)
+ }
+ }
+
+ <-done
+ }
+}
+
+func TestUnixgramConnLocalAndRemoteNames(t *testing.T) {
+ for _, laddr := range []string{"", testUnixAddr()} {
+ taddr := testUnixAddr()
+ ta, err := ResolveUnixAddr("unixgram", taddr)
+ if err != nil {
+ t.Fatalf("ResolveUnixAddr failed: %v", err)
+ }
+ c1, err := ListenUnixgram("unixgram", ta)
+ if err != nil {
+ t.Fatalf("ListenUnixgram failed: %v", err)
+ }
+ defer func() {
+ c1.Close()
+ os.Remove(taddr)
+ }()
+
+ var la *UnixAddr
+ if laddr != "" {
+ var err error
+ if la, err = ResolveUnixAddr("unixgram", laddr); err != nil {
+ t.Fatalf("ResolveUnixAddr failed: %v", err)
+ }
+ }
+ c2, err := DialUnix("unixgram", la, ta)
+ if err != nil {
+ t.Fatalf("DialUnix failed: %v", err)
+ }
+ defer func() {
+ c2.Close()
+ if la != nil {
+ defer os.Remove(laddr)
+ }
+ }()
+
+ if runtime.GOOS == "linux" && laddr == "" {
+ laddr = "@" // autobind feature
+ }
+ var connAddrs = [4]struct{ got, want Addr }{
+ {c1.LocalAddr(), ta},
+ {c1.RemoteAddr(), nil},
+ {c2.LocalAddr(), &UnixAddr{Name: laddr, Net: "unixgram"}},
+ {c2.RemoteAddr(), ta},
+ }
+ for _, ca := range connAddrs {
+ if !reflect.DeepEqual(ca.got, ca.want) {
+ t.Fatalf("got %#v, expected %#v", ca.got, ca.want)
+ }
+ }
}
}
diff --git a/src/pkg/net/unixsock.go b/src/pkg/net/unixsock.go
index ae0956958..21a19eca2 100644
--- a/src/pkg/net/unixsock.go
+++ b/src/pkg/net/unixsock.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.
-// Unix domain sockets
-
package net
// UnixAddr represents the address of a Unix domain socket end point.
@@ -12,7 +10,8 @@ type UnixAddr struct {
Net string
}
-// Network returns the address's network name, "unix" or "unixgram".
+// Network returns the address's network name, "unix", "unixgram" or
+// "unixpacket".
func (a *UnixAddr) Network() string {
return a.Net
}
@@ -36,11 +35,9 @@ func (a *UnixAddr) toAddr() Addr {
// "unixpacket".
func ResolveUnixAddr(net, addr string) (*UnixAddr, error) {
switch net {
- case "unix":
- case "unixpacket":
- case "unixgram":
+ case "unix", "unixgram", "unixpacket":
+ return &UnixAddr{Name: addr, Net: net}, nil
default:
return nil, UnknownNetworkError(net)
}
- return &UnixAddr{addr, net}, nil
}
diff --git a/src/pkg/net/unixsock_plan9.go b/src/pkg/net/unixsock_plan9.go
index 00a0be5b0..8a1281fb1 100644
--- a/src/pkg/net/unixsock_plan9.go
+++ b/src/pkg/net/unixsock_plan9.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.
-// Unix domain sockets stubs for Plan 9
-
package net
import (
@@ -128,14 +126,18 @@ func (l *UnixListener) SetDeadline(t time.Time) error {
// 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, syscall.EPLAN9
}
// ListenUnixgram listens for incoming Unix datagram packets addressed
-// to the local address laddr. The returned connection c's ReadFrom
-// and WriteTo methods can be used to receive and send packets with
-// per-packet addressing. The network net must be "unixgram".
+// 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, syscall.EPLAN9
}
diff --git a/src/pkg/net/unixsock_posix.go b/src/pkg/net/unixsock_posix.go
index 6d6ce3f5e..5db30df95 100644
--- a/src/pkg/net/unixsock_posix.go
+++ b/src/pkg/net/unixsock_posix.go
@@ -4,8 +4,6 @@
// +build darwin freebsd linux netbsd openbsd windows
-// Unix domain sockets
-
package net
import (
@@ -15,6 +13,13 @@ import (
"time"
)
+func (a *UnixAddr) isUnnamed() bool {
+ if a == nil || a.Name == "" {
+ return true
+ }
+ return false
+}
+
func unixSocket(net string, laddr, raddr *UnixAddr, mode string, deadline time.Time) (*netFD, error) {
var sotype int
switch net {
@@ -31,12 +36,12 @@ func unixSocket(net string, laddr, raddr *UnixAddr, mode string, deadline time.T
var la, ra syscall.Sockaddr
switch mode {
case "dial":
- if laddr != nil {
+ if !laddr.isUnnamed() {
la = &syscall.SockaddrUnix{Name: laddr.Name}
}
if raddr != nil {
ra = &syscall.SockaddrUnix{Name: raddr.Name}
- } else if sotype != syscall.SOCK_DGRAM || laddr == nil {
+ } else if sotype != syscall.SOCK_DGRAM || laddr.isUnnamed() {
return nil, &OpError{Op: mode, Net: net, Err: errMissingAddress}
}
case "listen":
@@ -69,21 +74,21 @@ error:
func sockaddrToUnix(sa syscall.Sockaddr) Addr {
if s, ok := sa.(*syscall.SockaddrUnix); ok {
- return &UnixAddr{s.Name, "unix"}
+ return &UnixAddr{Name: s.Name, Net: "unix"}
}
return nil
}
func sockaddrToUnixgram(sa syscall.Sockaddr) Addr {
if s, ok := sa.(*syscall.SockaddrUnix); ok {
- return &UnixAddr{s.Name, "unixgram"}
+ return &UnixAddr{Name: s.Name, Net: "unixgram"}
}
return nil
}
func sockaddrToUnixpacket(sa syscall.Sockaddr) Addr {
if s, ok := sa.(*syscall.SockaddrUnix); ok {
- return &UnixAddr{s.Name, "unixpacket"}
+ return &UnixAddr{Name: s.Name, Net: "unixpacket"}
}
return nil
}
@@ -92,14 +97,13 @@ func sotypeToNet(sotype int) string {
switch sotype {
case syscall.SOCK_STREAM:
return "unix"
- case syscall.SOCK_SEQPACKET:
- return "unixpacket"
case syscall.SOCK_DGRAM:
return "unixgram"
+ case syscall.SOCK_SEQPACKET:
+ return "unixpacket"
default:
panic("sotypeToNet unknown socket type")
}
- return ""
}
// UnixConn is an implementation of the Conn interface for connections
@@ -125,7 +129,7 @@ func (c *UnixConn) ReadFromUnix(b []byte) (n int, addr *UnixAddr, err error) {
switch sa := sa.(type) {
case *syscall.SockaddrUnix:
if sa.Name != "" {
- addr = &UnixAddr{sa.Name, sotypeToNet(c.fd.sotype)}
+ addr = &UnixAddr{Name: sa.Name, Net: sotypeToNet(c.fd.sotype)}
}
}
return
@@ -152,7 +156,7 @@ func (c *UnixConn) ReadMsgUnix(b, oob []byte) (n, oobn, flags int, addr *UnixAdd
switch sa := sa.(type) {
case *syscall.SockaddrUnix:
if sa.Name != "" {
- addr = &UnixAddr{sa.Name, sotypeToNet(c.fd.sotype)}
+ addr = &UnixAddr{Name: sa.Name, Net: sotypeToNet(c.fd.sotype)}
}
}
return
@@ -267,7 +271,7 @@ func ListenUnix(net string, laddr *UnixAddr) (*UnixListener, error) {
}
err = syscall.Listen(fd.sysfd, listenerBacklog)
if err != nil {
- closesocket(fd.sysfd)
+ fd.Close()
return nil, &OpError{Op: "listen", Net: net, Addr: laddr, Err: err}
}
return &UnixListener{fd, laddr.Name}, nil
@@ -335,12 +339,16 @@ func (l *UnixListener) SetDeadline(t time.Time) (err error) {
// 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) { return l.fd.dup() }
// ListenUnixgram listens for incoming Unix datagram packets addressed
-// to the local address laddr. The returned connection c's ReadFrom
-// and WriteTo methods can be used to receive and send packets with
-// per-packet addressing. The network net must be "unixgram".
+// 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":
diff --git a/src/pkg/net/url/url.go b/src/pkg/net/url/url.go
index a39964ea1..459dc473c 100644
--- a/src/pkg/net/url/url.go
+++ b/src/pkg/net/url/url.go
@@ -317,23 +317,22 @@ func getscheme(rawurl string) (scheme, path string, err error) {
// Maybe s is of the form t c u.
// If so, return t, c u (or t, u if cutc == true).
// If not, return s, "".
-func split(s string, c byte, cutc bool) (string, string) {
- for i := 0; i < len(s); i++ {
- if s[i] == c {
- if cutc {
- return s[0:i], s[i+1:]
- }
- return s[0:i], s[i:]
- }
+func split(s string, c string, cutc bool) (string, string) {
+ i := strings.Index(s, c)
+ if i < 0 {
+ return s, ""
+ }
+ if cutc {
+ return s[0:i], s[i+len(c):]
}
- return s, ""
+ return s[0:i], s[i:]
}
// Parse parses rawurl into a URL structure.
// The rawurl may be relative or absolute.
func Parse(rawurl string) (url *URL, err error) {
// Cut off #frag
- u, frag := split(rawurl, '#', true)
+ u, frag := split(rawurl, "#", true)
if url, err = parse(u, false); err != nil {
return nil, err
}
@@ -362,7 +361,7 @@ func ParseRequestURI(rawurl string) (url *URL, err error) {
func parse(rawurl string, viaRequest bool) (url *URL, err error) {
var rest string
- if rawurl == "" {
+ if rawurl == "" && viaRequest {
err = errors.New("empty url")
goto Error
}
@@ -380,7 +379,7 @@ func parse(rawurl string, viaRequest bool) (url *URL, err error) {
}
url.Scheme = strings.ToLower(url.Scheme)
- rest, url.RawQuery = split(rest, '?', true)
+ rest, url.RawQuery = split(rest, "?", true)
if !strings.HasPrefix(rest, "/") {
if url.Scheme != "" {
@@ -396,7 +395,7 @@ func parse(rawurl string, viaRequest bool) (url *URL, err error) {
if (url.Scheme != "" || !viaRequest && !strings.HasPrefix(rest, "///")) && strings.HasPrefix(rest, "//") {
var authority string
- authority, rest = split(rest[2:], '/', false)
+ authority, rest = split(rest[2:], "/", false)
url.User, url.Host, err = parseAuthority(authority)
if err != nil {
goto Error
@@ -428,7 +427,7 @@ func parseAuthority(authority string) (user *Userinfo, host string, err error) {
}
user = User(userinfo)
} else {
- username, password := split(userinfo, ':', true)
+ username, password := split(userinfo, ":", true)
if username, err = unescape(username, encodeUserPassword); err != nil {
return
}
@@ -583,43 +582,39 @@ func (v Values) Encode() string {
}
// resolvePath applies special path segments from refs and applies
-// them to base, per RFC 2396.
-func resolvePath(basepath string, refpath string) string {
- base := strings.Split(basepath, "/")
- refs := strings.Split(refpath, "/")
- if len(base) == 0 {
- base = []string{""}
+// them to base, per RFC 3986.
+func resolvePath(base, ref string) string {
+ var full string
+ if ref == "" {
+ full = base
+ } else if ref[0] != '/' {
+ i := strings.LastIndex(base, "/")
+ full = base[:i+1] + ref
+ } else {
+ full = ref
}
-
- rm := true
- for idx, ref := range refs {
- switch {
- case ref == ".":
- if idx == 0 {
- base[len(base)-1] = ""
- rm = true
- } else {
- rm = false
- }
- case ref == "..":
- newLen := len(base) - 1
- if newLen < 1 {
- newLen = 1
- }
- base = base[0:newLen]
- if rm {
- base[len(base)-1] = ""
+ if full == "" {
+ return ""
+ }
+ var dst []string
+ src := strings.Split(full, "/")
+ for _, elem := range src {
+ switch elem {
+ case ".":
+ // drop
+ case "..":
+ if len(dst) > 0 {
+ dst = dst[:len(dst)-1]
}
default:
- if idx == 0 || base[len(base)-1] == "" {
- base[len(base)-1] = ref
- } else {
- base = append(base, ref)
- }
- rm = false
+ dst = append(dst, elem)
}
}
- return strings.Join(base, "/")
+ if last := src[len(src)-1]; last == "." || last == ".." {
+ // Add final slash to the joined path.
+ dst = append(dst, "")
+ }
+ return "/" + strings.TrimLeft(strings.Join(dst, "/"), "/")
}
// IsAbs returns true if the URL is absolute.
@@ -639,43 +634,39 @@ func (u *URL) Parse(ref string) (*URL, error) {
}
// ResolveReference resolves a URI reference to an absolute URI from
-// an absolute base URI, per RFC 2396 Section 5.2. The URI reference
+// an absolute base URI, per RFC 3986 Section 5.2. The URI reference
// 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.
func (u *URL) ResolveReference(ref *URL) *URL {
- if ref.IsAbs() {
- url := *ref
+ url := *ref
+ if ref.Scheme == "" {
+ url.Scheme = u.Scheme
+ }
+ if ref.Scheme != "" || ref.Host != "" || ref.User != nil {
+ // The "absoluteURI" or "net_path" cases.
+ url.Path = resolvePath(ref.Path, "")
return &url
}
- // relativeURI = ( net_path | abs_path | rel_path ) [ "?" query ]
- url := *u
- url.RawQuery = ref.RawQuery
- url.Fragment = ref.Fragment
if ref.Opaque != "" {
- url.Opaque = ref.Opaque
url.User = nil
url.Host = ""
url.Path = ""
return &url
}
- if ref.Host != "" || ref.User != nil {
- // The "net_path" case.
- url.Host = ref.Host
- url.User = ref.User
- }
- if strings.HasPrefix(ref.Path, "/") {
- // The "abs_path" case.
- url.Path = ref.Path
- } else {
- // The "rel_path" case.
- path := resolvePath(u.Path, ref.Path)
- if !strings.HasPrefix(path, "/") {
- path = "/" + path
+ if ref.Path == "" {
+ if ref.RawQuery == "" {
+ url.RawQuery = u.RawQuery
+ if ref.Fragment == "" {
+ url.Fragment = u.Fragment
+ }
}
- url.Path = path
}
+ // The "abs_path" or "rel_path" cases.
+ url.Host = u.Host
+ url.User = u.User
+ url.Path = resolvePath(u.Path, ref.Path)
return &url
}
diff --git a/src/pkg/net/url/url_test.go b/src/pkg/net/url/url_test.go
index 4c4f406c2..9d81289ce 100644
--- a/src/pkg/net/url/url_test.go
+++ b/src/pkg/net/url/url_test.go
@@ -523,18 +523,18 @@ func TestEncodeQuery(t *testing.T) {
var resolvePathTests = []struct {
base, ref, expected string
}{
- {"a/b", ".", "a/"},
- {"a/b", "c", "a/c"},
- {"a/b", "..", ""},
- {"a/", "..", ""},
- {"a/", "../..", ""},
- {"a/b/c", "..", "a/"},
- {"a/b/c", "../d", "a/d"},
- {"a/b/c", ".././d", "a/d"},
- {"a/b", "./..", ""},
- {"a/./b", ".", "a/./"},
- {"a/../", ".", "a/../"},
- {"a/.././b", "c", "a/.././c"},
+ {"a/b", ".", "/a/"},
+ {"a/b", "c", "/a/c"},
+ {"a/b", "..", "/"},
+ {"a/", "..", "/"},
+ {"a/", "../..", "/"},
+ {"a/b/c", "..", "/a/"},
+ {"a/b/c", "../d", "/a/d"},
+ {"a/b/c", ".././d", "/a/d"},
+ {"a/b", "./..", "/"},
+ {"a/./b", ".", "/a/"},
+ {"a/../", ".", "/"},
+ {"a/.././b", "c", "/c"},
}
func TestResolvePath(t *testing.T) {
@@ -587,16 +587,71 @@ var resolveReferenceTests = []struct {
{"http://foo.com/bar/baz", "quux/./dotdot/dotdot/././../../tail", "http://foo.com/bar/quux/tail"},
{"http://foo.com/bar/baz", "quux/./dotdot/dotdot/./.././../tail", "http://foo.com/bar/quux/tail"},
{"http://foo.com/bar/baz", "quux/./dotdot/dotdot/dotdot/./../../.././././tail", "http://foo.com/bar/quux/tail"},
- {"http://foo.com/bar/baz", "quux/./dotdot/../dotdot/../dot/./tail/..", "http://foo.com/bar/quux/dot"},
+ {"http://foo.com/bar/baz", "quux/./dotdot/../dotdot/../dot/./tail/..", "http://foo.com/bar/quux/dot/"},
- // "." and ".." in the base aren't special
- {"http://foo.com/dot/./dotdot/../foo/bar", "../baz", "http://foo.com/dot/./dotdot/../baz"},
+ // Remove any dot-segments prior to forming the target URI.
+ // http://tools.ietf.org/html/rfc3986#section-5.2.4
+ {"http://foo.com/dot/./dotdot/../foo/bar", "../baz", "http://foo.com/dot/baz"},
// Triple dot isn't special
{"http://foo.com/bar", "...", "http://foo.com/..."},
// Fragment
{"http://foo.com/bar", ".#frag", "http://foo.com/#frag"},
+
+ // 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"},
+ {"http://a/b/c/d;p?q", "g", "http://a/b/c/g"},
+ {"http://a/b/c/d;p?q", "./g", "http://a/b/c/g"},
+ {"http://a/b/c/d;p?q", "g/", "http://a/b/c/g/"},
+ {"http://a/b/c/d;p?q", "/g", "http://a/g"},
+ {"http://a/b/c/d;p?q", "//g", "http://g"},
+ {"http://a/b/c/d;p?q", "?y", "http://a/b/c/d;p?y"},
+ {"http://a/b/c/d;p?q", "g?y", "http://a/b/c/g?y"},
+ {"http://a/b/c/d;p?q", "#s", "http://a/b/c/d;p?q#s"},
+ {"http://a/b/c/d;p?q", "g#s", "http://a/b/c/g#s"},
+ {"http://a/b/c/d;p?q", "g?y#s", "http://a/b/c/g?y#s"},
+ {"http://a/b/c/d;p?q", ";x", "http://a/b/c/;x"},
+ {"http://a/b/c/d;p?q", "g;x", "http://a/b/c/g;x"},
+ {"http://a/b/c/d;p?q", "g;x?y#s", "http://a/b/c/g;x?y#s"},
+ {"http://a/b/c/d;p?q", "", "http://a/b/c/d;p?q"},
+ {"http://a/b/c/d;p?q", ".", "http://a/b/c/"},
+ {"http://a/b/c/d;p?q", "./", "http://a/b/c/"},
+ {"http://a/b/c/d;p?q", "..", "http://a/b/"},
+ {"http://a/b/c/d;p?q", "../", "http://a/b/"},
+ {"http://a/b/c/d;p?q", "../g", "http://a/b/g"},
+ {"http://a/b/c/d;p?q", "../..", "http://a/"},
+ {"http://a/b/c/d;p?q", "../../", "http://a/"},
+ {"http://a/b/c/d;p?q", "../../g", "http://a/g"},
+
+ // RFC 3986: Abnormal Examples
+ // http://tools.ietf.org/html/rfc3986#section-5.4.2
+ {"http://a/b/c/d;p?q", "../../../g", "http://a/g"},
+ {"http://a/b/c/d;p?q", "../../../../g", "http://a/g"},
+ {"http://a/b/c/d;p?q", "/./g", "http://a/g"},
+ {"http://a/b/c/d;p?q", "/../g", "http://a/g"},
+ {"http://a/b/c/d;p?q", "g.", "http://a/b/c/g."},
+ {"http://a/b/c/d;p?q", ".g", "http://a/b/c/.g"},
+ {"http://a/b/c/d;p?q", "g..", "http://a/b/c/g.."},
+ {"http://a/b/c/d;p?q", "..g", "http://a/b/c/..g"},
+ {"http://a/b/c/d;p?q", "./../g", "http://a/b/g"},
+ {"http://a/b/c/d;p?q", "./g/.", "http://a/b/c/g/"},
+ {"http://a/b/c/d;p?q", "g/./h", "http://a/b/c/g/h"},
+ {"http://a/b/c/d;p?q", "g/../h", "http://a/b/c/h"},
+ {"http://a/b/c/d;p?q", "g;x=1/./y", "http://a/b/c/g;x=1/y"},
+ {"http://a/b/c/d;p?q", "g;x=1/../y", "http://a/b/c/y"},
+ {"http://a/b/c/d;p?q", "g?y/./x", "http://a/b/c/g?y/./x"},
+ {"http://a/b/c/d;p?q", "g?y/../x", "http://a/b/c/g?y/../x"},
+ {"http://a/b/c/d;p?q", "g#s/./x", "http://a/b/c/g#s/./x"},
+ {"http://a/b/c/d;p?q", "g#s/../x", "http://a/b/c/g#s/../x"},
+
+ // Extras.
+ {"https://a/b/c/d;p?q", "//g?q", "https://g?q"},
+ {"https://a/b/c/d;p?q", "//g#s", "https://g#s"},
+ {"https://a/b/c/d;p?q", "//g/d/e/f?y#s", "https://g/d/e/f?y#s"},
+ {"https://a/b/c/d;p#s", "?y", "https://a/b/c/d;p?y"},
+ {"https://a/b/c/d;p?q#s", "?y", "https://a/b/c/d;p?y"},
}
func TestResolveReference(t *testing.T) {
@@ -607,91 +662,44 @@ func TestResolveReference(t *testing.T) {
}
return u
}
+ opaque := &URL{Scheme: "scheme", Opaque: "opaque"}
for _, test := range resolveReferenceTests {
base := mustParse(test.base)
rel := mustParse(test.rel)
url := base.ResolveReference(rel)
- urlStr := url.String()
- if urlStr != test.expected {
- t.Errorf("Resolving %q + %q != %q; got %q", test.base, test.rel, test.expected, urlStr)
+ if url.String() != test.expected {
+ t.Errorf("URL(%q).ResolveReference(%q) == %q, got %q", test.base, test.rel, test.expected, url.String())
}
- }
-
- // Test that new instances are returned.
- base := mustParse("http://foo.com/")
- abs := base.ResolveReference(mustParse("."))
- if base == abs {
- t.Errorf("Expected no-op reference to return new URL instance.")
- }
- barRef := mustParse("http://bar.com/")
- abs = base.ResolveReference(barRef)
- if abs == barRef {
- t.Errorf("Expected resolution of absolute reference to return new URL instance.")
- }
-
- // Test the convenience wrapper too
- base = mustParse("http://foo.com/path/one/")
- abs, _ = base.Parse("../two")
- expected := "http://foo.com/path/two"
- if abs.String() != expected {
- t.Errorf("Parse wrapper got %q; expected %q", abs.String(), expected)
- }
- _, err := base.Parse("")
- if err == nil {
- t.Errorf("Expected an error from Parse wrapper parsing an empty string.")
- }
-
- // Ensure Opaque resets the URL.
- base = mustParse("scheme://user@foo.com/bar")
- abs = base.ResolveReference(&URL{Opaque: "opaque"})
- want := mustParse("scheme:opaque")
- if *abs != *want {
- t.Errorf("ResolveReference failed to resolve opaque URL: want %#v, got %#v", abs, want)
- }
-}
-
-func TestResolveReferenceOpaque(t *testing.T) {
- mustParse := func(url string) *URL {
- u, err := Parse(url)
+ // Ensure that new instances are returned.
+ if base == url {
+ t.Errorf("Expected URL.ResolveReference to return new URL instance.")
+ }
+ // Test the convenience wrapper too.
+ url, err := base.Parse(test.rel)
if err != nil {
- t.Fatalf("Expected URL to parse: %q, got error: %v", url, err)
+ 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 base == url {
+ // Ensure that new instances are returned for the wrapper too.
+ t.Errorf("Expected URL.Parse to return new URL instance.")
}
- return u
- }
- for _, test := range resolveReferenceTests {
- base := mustParse(test.base)
- rel := mustParse(test.rel)
- url := base.ResolveReference(rel)
- urlStr := url.String()
- if urlStr != test.expected {
- t.Errorf("Resolving %q + %q != %q; got %q", test.base, test.rel, test.expected, urlStr)
+ // 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)
+ }
+ // 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)
+ } else if base == url {
+ // Ensure that new instances are returned, again.
+ t.Errorf("Expected URL.Parse to return new URL instance.")
}
}
-
- // Test that new instances are returned.
- base := mustParse("http://foo.com/")
- abs := base.ResolveReference(mustParse("."))
- if base == abs {
- t.Errorf("Expected no-op reference to return new URL instance.")
- }
- barRef := mustParse("http://bar.com/")
- abs = base.ResolveReference(barRef)
- if abs == barRef {
- t.Errorf("Expected resolution of absolute reference to return new URL instance.")
- }
-
- // Test the convenience wrapper too
- base = mustParse("http://foo.com/path/one/")
- abs, _ = base.Parse("../two")
- expected := "http://foo.com/path/two"
- if abs.String() != expected {
- t.Errorf("Parse wrapper got %q; expected %q", abs.String(), expected)
- }
- _, err := base.Parse("")
- if err == nil {
- t.Errorf("Expected an error from Parse wrapper parsing an empty string.")
- }
-
}
func TestQueryValues(t *testing.T) {
diff --git a/src/pkg/os/exec/exec.go b/src/pkg/os/exec/exec.go
index 8368491b0..a3bbcf300 100644
--- a/src/pkg/os/exec/exec.go
+++ b/src/pkg/os/exec/exec.go
@@ -235,6 +235,8 @@ func (c *Cmd) Run() error {
// Start starts the specified command but does not wait for it to complete.
func (c *Cmd) Start() error {
if c.err != nil {
+ c.closeDescriptors(c.closeAfterStart)
+ c.closeDescriptors(c.closeAfterWait)
return c.err
}
if c.Process != nil {
diff --git a/src/pkg/os/exec/exec_test.go b/src/pkg/os/exec/exec_test.go
index 611ac0267..6f5860e95 100644
--- a/src/pkg/os/exec/exec_test.go
+++ b/src/pkg/os/exec/exec_test.go
@@ -19,13 +19,14 @@ import (
"strconv"
"strings"
"testing"
+ "time"
)
func helperCommand(s ...string) *Cmd {
cs := []string{"-test.run=TestHelperProcess", "--"}
cs = append(cs, s...)
cmd := Command(os.Args[0], cs...)
- cmd.Env = append([]string{"GO_WANT_HELPER_PROCESS=1"}, os.Environ()...)
+ cmd.Env = []string{"GO_WANT_HELPER_PROCESS=1"}
return cmd
}
@@ -151,6 +152,33 @@ func TestPipes(t *testing.T) {
check("Wait", err)
}
+// Issue 5071
+func TestPipeLookPathLeak(t *testing.T) {
+ fd0 := numOpenFDS(t)
+ for i := 0; i < 4; i++ {
+ cmd := Command("something-that-does-not-exist-binary")
+ cmd.StdoutPipe()
+ cmd.StderrPipe()
+ cmd.StdinPipe()
+ if err := cmd.Run(); err == nil {
+ t.Fatal("unexpected success")
+ }
+ }
+ fdGrowth := numOpenFDS(t) - fd0
+ if fdGrowth > 2 {
+ t.Errorf("leaked %d fds; want ~0", fdGrowth)
+ }
+}
+
+func numOpenFDS(t *testing.T) int {
+ lsof, err := Command("lsof", "-n", "-p", strconv.Itoa(os.Getpid())).Output()
+ if err != nil {
+ t.Skip("skipping test; error finding or running lsof")
+ return 0
+ }
+ return bytes.Count(lsof, []byte("\n"))
+}
+
var testedAlreadyLeaked = false
// basefds returns the number of expected file descriptors
@@ -167,6 +195,98 @@ func basefds() uintptr {
return n
}
+func TestExtraFilesFDShuffle(t *testing.T) {
+ t.Skip("TODO: TestExtraFilesFDShuffle is too non-portable; skipping")
+
+ // syscall.StartProcess maps all the FDs passed to it in
+ // ProcAttr.Files (the concatenation of stdin,stdout,stderr and
+ // ExtraFiles) into consecutive FDs in the child, that is:
+ // Files{11, 12, 6, 7, 9, 3} should result in the file
+ // represented by FD 11 in the parent being made available as 0
+ // in the child, 12 as 1, etc.
+ //
+ // 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
+ // 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
+ // must be at an index of 4 or higher in ProcAttr.Files and
+ // the FD of the write end of the Stderr pipe (as obtained by
+ // StderrPipe()) must be the same as the size of ProcAttr.Files;
+ // therefore we test that the read end of this pipe (which is what
+ // is returned to the parent by StderrPipe() being one less than
+ // the size of ProcAttr.Files, i.e. 3+len(cmd.ExtraFiles).
+ //
+ // Moving this test case around within the overall tests may
+ // affect the FDs obtained and hence the checks to catch these cases.
+ npipes := 2
+ c := helperCommand("extraFilesAndPipes", strconv.Itoa(npipes+1))
+ rd, wr, _ := os.Pipe()
+ defer rd.Close()
+ if rd.Fd() != 3 {
+ t.Errorf("bad test value for test pipe: fd %d", rd.Fd())
+ }
+ stderr, _ := c.StderrPipe()
+ wr.WriteString("_LAST")
+ wr.Close()
+
+ pipes := make([]struct {
+ r, w *os.File
+ }, npipes)
+ data := []string{"a", "b"}
+
+ for i := 0; i < npipes; i++ {
+ r, w, err := os.Pipe()
+ if err != nil {
+ t.Fatalf("unexpected error creating pipe: %s", err)
+ }
+ pipes[i].r = r
+ pipes[i].w = w
+ w.WriteString(data[i])
+ c.ExtraFiles = append(c.ExtraFiles, pipes[i].r)
+ defer func() {
+ r.Close()
+ w.Close()
+ }()
+ }
+ // Put fd 3 at the end.
+ c.ExtraFiles = append(c.ExtraFiles, rd)
+
+ stderrFd := int(stderr.(*os.File).Fd())
+ if stderrFd != ((len(c.ExtraFiles) + 3) - 1) {
+ t.Errorf("bad test value for stderr pipe")
+ }
+
+ expected := "child: " + strings.Join(data, "") + "_LAST"
+
+ err := c.Start()
+ if err != nil {
+ t.Fatalf("Run: %v", err)
+ }
+ ch := make(chan string, 1)
+ go func(ch chan string) {
+ buf := make([]byte, 512)
+ n, err := stderr.Read(buf)
+ if err != nil {
+ t.Fatalf("Read: %s", err)
+ ch <- err.Error()
+ } else {
+ ch <- string(buf[:n])
+ }
+ close(ch)
+ }(ch)
+ select {
+ case m := <-ch:
+ if m != expected {
+ t.Errorf("Read: '%s' not '%s'", m, expected)
+ }
+ case <-time.After(5 * time.Second):
+ t.Errorf("Read timedout")
+ }
+ c.Wait()
+}
+
func TestExtraFiles(t *testing.T) {
if runtime.GOOS == "windows" {
t.Skip("no operating system support; skipping")
@@ -289,6 +409,13 @@ func TestExtraFilesRace(t *testing.T) {
}
la.Close()
lb.Close()
+ for _, f := range ca.ExtraFiles {
+ f.Close()
+ }
+ for _, f := range cb.ExtraFiles {
+ f.Close()
+ }
+
}
}
@@ -422,6 +549,35 @@ func TestHelperProcess(*testing.T) {
}
}
os.Exit(0)
+ case "extraFilesAndPipes":
+ n, _ := strconv.Atoi(args[0])
+ pipes := make([]*os.File, n)
+ for i := 0; i < n; i++ {
+ pipes[i] = os.NewFile(uintptr(3+i), strconv.Itoa(i))
+ }
+ response := ""
+ for i, r := range pipes {
+ ch := make(chan string, 1)
+ go func(c chan string) {
+ buf := make([]byte, 10)
+ n, err := r.Read(buf)
+ if err != nil {
+ fmt.Fprintf(os.Stderr, "Child: read error: %v on pipe %d\n", err, i)
+ os.Exit(1)
+ }
+ c <- string(buf[:n])
+ close(c)
+ }(ch)
+ select {
+ case m := <-ch:
+ response = response + m
+ case <-time.After(5 * time.Second):
+ fmt.Fprintf(os.Stderr, "Child: Timeout reading from pipe: %d\n", i)
+ os.Exit(1)
+ }
+ }
+ fmt.Fprintf(os.Stderr, "child: %s", response)
+ os.Exit(0)
default:
fmt.Fprintf(os.Stderr, "Unknown command %q\n", cmd)
os.Exit(2)
diff --git a/src/pkg/os/file_posix.go b/src/pkg/os/file_posix.go
index b979fed97..3df43feaa 100644
--- a/src/pkg/os/file_posix.go
+++ b/src/pkg/os/file_posix.go
@@ -46,8 +46,6 @@ func Readlink(name string) (string, error) {
return string(b[0:n]), nil
}
}
- // Silence 6g.
- return "", nil
}
// Rename renames a file.
diff --git a/src/pkg/os/file_unix.go b/src/pkg/os/file_unix.go
index 4f59c94cb..898e7634a 100644
--- a/src/pkg/os/file_unix.go
+++ b/src/pkg/os/file_unix.go
@@ -198,7 +198,6 @@ func (f *File) write(b []byte) (n int, err error) {
return n, err
}
- panic("not reached")
}
// pwrite writes len(b) bytes to the File starting at byte offset off.
diff --git a/src/pkg/os/file_windows.go b/src/pkg/os/file_windows.go
index 2eba7a475..82af756d8 100644
--- a/src/pkg/os/file_windows.go
+++ b/src/pkg/os/file_windows.go
@@ -243,7 +243,7 @@ func (file *File) readdir(n int) (fi []FileInfo, err error) {
return fi, nil
}
-// readConsole reads utf16 charcters from console File,
+// readConsole reads utf16 characters from console File,
// encodes them into utf8 and stores them in buffer b.
// It returns the number of utf8 bytes read and an error, if any.
func (f *File) readConsole(b []byte) (n int, err error) {
diff --git a/src/pkg/os/getwd.go b/src/pkg/os/getwd.go
index 1b2212306..0235c5d77 100644
--- a/src/pkg/os/getwd.go
+++ b/src/pkg/os/getwd.go
@@ -90,8 +90,6 @@ func Getwd() (pwd string, err error) {
}
}
}
- fd.Close()
- return "", ErrNotExist
Found:
pd, err := fd.Stat()
diff --git a/src/pkg/os/signal/sig.s b/src/pkg/os/signal/sig.s
index d1984cf88..df4855de8 100644
--- a/src/pkg/os/signal/sig.s
+++ b/src/pkg/os/signal/sig.s
@@ -4,10 +4,15 @@
// Assembly to get into package runtime without using exported symbols.
+// +build amd64 arm 386
+
#ifdef GOARCH_arm
#define JMP B
#endif
+TEXT ·signal_disable(SB),7,$0
+ JMP runtime·signal_disable(SB)
+
TEXT ·signal_enable(SB),7,$0
JMP runtime·signal_enable(SB)
diff --git a/src/pkg/os/signal/signal.go b/src/pkg/os/signal/signal.go
index dfdcf4061..300427549 100644
--- a/src/pkg/os/signal/signal.go
+++ b/src/pkg/os/signal/signal.go
@@ -5,7 +5,7 @@
// Package signal implements access to incoming signals.
package signal
-// BUG(rsc): This package is not yet implemented on Plan 9 and Windows.
+// BUG(rsc): This package is not yet implemented on Plan 9.
import (
"os"
@@ -14,13 +14,20 @@ import (
var handlers struct {
sync.Mutex
- list []handler
+ m map[chan<- os.Signal]*handler
+ ref [numSig]int64
}
type handler struct {
- c chan<- os.Signal
- sig os.Signal
- all bool
+ mask [(numSig + 31) / 32]uint32
+}
+
+func (h *handler) want(sig int) bool {
+ return (h.mask[sig/32]>>uint(sig&31))&1 != 0
+}
+
+func (h *handler) set(sig int) {
+ h.mask[sig/32] |= 1 << uint(sig&31)
}
// Notify causes package signal to relay incoming signals to c.
@@ -32,6 +39,13 @@ type handler struct {
// 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:
+// each call expands the set of signals sent to that channel.
+// The only way to remove signals from the set is to call Stop.
+//
+// It is allowed to call Notify multiple times with different channels
+// and the same signals: each channel receives copies of incoming
+// signals independently.
func Notify(c chan<- os.Signal, sig ...os.Signal) {
if c == nil {
panic("os/signal: Notify using nil channel")
@@ -39,32 +53,77 @@ func Notify(c chan<- os.Signal, sig ...os.Signal) {
handlers.Lock()
defer handlers.Unlock()
+
+ h := handlers.m[c]
+ if h == nil {
+ if handlers.m == nil {
+ handlers.m = make(map[chan<- os.Signal]*handler)
+ }
+ h = new(handler)
+ handlers.m[c] = h
+ }
+
+ add := func(n int) {
+ if n < 0 {
+ return
+ }
+ if !h.want(n) {
+ h.set(n)
+ if handlers.ref[n] == 0 {
+ enableSignal(n)
+ }
+ handlers.ref[n]++
+ }
+ }
+
if len(sig) == 0 {
- enableSignal(nil)
- handlers.list = append(handlers.list, handler{c: c, all: true})
+ for n := 0; n < numSig; n++ {
+ add(n)
+ }
} else {
for _, s := range sig {
- // We use nil as a special wildcard value for enableSignal,
- // so filter it out of the list of arguments. This is safe because
- // we will never get an incoming nil signal, so discarding the
- // registration cannot affect the observed behavior.
- if s != nil {
- enableSignal(s)
- handlers.list = append(handlers.list, handler{c: c, sig: s})
+ add(signum(s))
+ }
+ }
+}
+
+// Stop causes package signal to stop relaying incoming signals to c.
+// It undoes the effect of all prior calls to Notify using c.
+// When Stop returns, it is guaranteed that c will receive no more signals.
+func Stop(c chan<- os.Signal) {
+ handlers.Lock()
+ defer handlers.Unlock()
+
+ h := handlers.m[c]
+ if h == nil {
+ return
+ }
+ delete(handlers.m, c)
+
+ for n := 0; n < numSig; n++ {
+ if h.want(n) {
+ handlers.ref[n]--
+ if handlers.ref[n] == 0 {
+ disableSignal(n)
}
}
}
}
func process(sig os.Signal) {
+ n := signum(sig)
+ if n < 0 {
+ return
+ }
+
handlers.Lock()
defer handlers.Unlock()
- for _, h := range handlers.list {
- if h.all || h.sig == sig {
+ for c, h := range handlers.m {
+ if h.want(n) {
// send but do not block for it
select {
- case h.c <- sig:
+ case c <- sig:
default:
}
}
diff --git a/src/pkg/os/signal/signal_stub.go b/src/pkg/os/signal/signal_stub.go
index fc227cf4c..d0a6935ff 100644
--- a/src/pkg/os/signal/signal_stub.go
+++ b/src/pkg/os/signal/signal_stub.go
@@ -8,4 +8,10 @@ package signal
import "os"
-func enableSignal(sig os.Signal) {}
+const numSig = 0
+
+func signum(sig os.Signal) int { return -1 }
+
+func disableSignal(int) {}
+
+func enableSignal(int) {}
diff --git a/src/pkg/os/signal/signal_test.go b/src/pkg/os/signal/signal_test.go
index 509b273aa..d13833306 100644
--- a/src/pkg/os/signal/signal_test.go
+++ b/src/pkg/os/signal/signal_test.go
@@ -7,15 +7,17 @@
package signal
import (
+ "flag"
+ "io/ioutil"
"os"
+ "os/exec"
"runtime"
+ "strconv"
"syscall"
"testing"
"time"
)
-const sighup = syscall.SIGHUP
-
func waitSig(t *testing.T, c <-chan os.Signal, sig os.Signal) {
select {
case s := <-c:
@@ -27,15 +29,17 @@ func waitSig(t *testing.T, c <-chan os.Signal, sig os.Signal) {
}
}
+// Test that basic signal handling works.
func TestSignal(t *testing.T) {
// Ask for SIGHUP
c := make(chan os.Signal, 1)
- Notify(c, sighup)
+ Notify(c, syscall.SIGHUP)
+ defer Stop(c)
t.Logf("sighup...")
// Send this process a SIGHUP
- syscall.Kill(syscall.Getpid(), sighup)
- waitSig(t, c, sighup)
+ syscall.Kill(syscall.Getpid(), syscall.SIGHUP)
+ waitSig(t, c, syscall.SIGHUP)
// Ask for everything we can get.
c1 := make(chan os.Signal, 1)
@@ -71,6 +75,7 @@ func TestStress(t *testing.T) {
go func() {
sig := make(chan os.Signal, 1)
Notify(sig, syscall.SIGUSR1)
+ defer Stop(sig)
Loop:
for {
select {
@@ -98,4 +103,106 @@ func TestStress(t *testing.T) {
close(done)
<-finished
<-finished
+ // When run with 'go test -cpu=1,2,4' SIGUSR1 from this test can slip
+ // into subsequent TestSignal() causing failure.
+ // Sleep for a while to reduce the possibility of the failure.
+ time.Sleep(10 * time.Millisecond)
+}
+
+var sendUncaughtSighup = flag.Int("send_uncaught_sighup", 0, "send uncaught SIGHUP during TestStop")
+
+// Test that Stop cancels the channel's registrations.
+func TestStop(t *testing.T) {
+ sigs := []syscall.Signal{
+ syscall.SIGWINCH,
+ syscall.SIGHUP,
+ }
+
+ for _, sig := range sigs {
+ // Send the signal.
+ // If it's SIGWINCH, we should not see it.
+ // If it's SIGHUP, maybe we'll die. Let the flag tell us what to do.
+ if sig != syscall.SIGHUP || *sendUncaughtSighup == 1 {
+ syscall.Kill(syscall.Getpid(), sig)
+ }
+ time.Sleep(10 * time.Millisecond)
+
+ // Ask for signal
+ c := make(chan os.Signal, 1)
+ Notify(c, sig)
+ defer Stop(c)
+
+ // Send this process that signal
+ syscall.Kill(syscall.Getpid(), sig)
+ waitSig(t, c, sig)
+
+ Stop(c)
+ select {
+ case s := <-c:
+ t.Fatalf("unexpected signal %v", s)
+ case <-time.After(10 * time.Millisecond):
+ // nothing to read - good
+ }
+
+ // Send the signal.
+ // If it's SIGWINCH, we should not see it.
+ // If it's SIGHUP, maybe we'll die. Let the flag tell us what to do.
+ if sig != syscall.SIGHUP || *sendUncaughtSighup == 2 {
+ syscall.Kill(syscall.Getpid(), sig)
+ }
+
+ select {
+ case s := <-c:
+ t.Fatalf("unexpected signal %v", s)
+ case <-time.After(10 * time.Millisecond):
+ // nothing to read - good
+ }
+ }
+}
+
+// Test that when run under nohup, an uncaught SIGHUP does not kill the program,
+// but a
+func TestNohup(t *testing.T) {
+ // Ugly: ask for SIGHUP so that child will not have no-hup set
+ // even if test is running under nohup environment.
+ // We have no intention of reading from c.
+ c := make(chan os.Signal, 1)
+ Notify(c, syscall.SIGHUP)
+
+ // When run without nohup, the test should crash on an uncaught SIGHUP.
+ // When run under nohup, the test should ignore uncaught SIGHUPs,
+ // because the runtime is not supposed to be listening for them.
+ // Either way, TestStop should still be able to catch them when it wants them
+ // and then when it stops wanting them, the original behavior should resume.
+ //
+ // send_uncaught_sighup=1 sends the SIGHUP before starting to listen for SIGHUPs.
+ // send_uncaught_sighup=2 sends the SIGHUP after no longer listening for SIGHUPs.
+ //
+ // Both should fail without nohup and succeed with nohup.
+
+ for i := 1; i <= 2; i++ {
+ out, err := exec.Command(os.Args[0], "-test.run=TestStop", "-send_uncaught_sighup="+strconv.Itoa(i)).CombinedOutput()
+ if err == nil {
+ t.Fatalf("ran test with -send_uncaught_sighup=%d and it succeeded: expected failure.\nOutput:\n%s", i, out)
+ }
+ }
+
+ Stop(c)
+
+ // Again, this time with nohup, assuming we can find it.
+ _, err := os.Stat("/usr/bin/nohup")
+ if err != nil {
+ t.Skip("cannot find nohup; skipping second half of test")
+ }
+
+ for i := 1; i <= 2; i++ {
+ os.Remove("nohup.out")
+ out, err := exec.Command("/usr/bin/nohup", os.Args[0], "-test.run=TestStop", "-send_uncaught_sighup="+strconv.Itoa(i)).CombinedOutput()
+
+ data, _ := ioutil.ReadFile("nohup.out")
+ os.Remove("nohup.out")
+ if err != nil {
+ t.Fatalf("ran test with -send_uncaught_sighup=%d under nohup and it failed: expected success.\nError: %v\nOutput:\n%s%s", i, err, out, data)
+ }
+ }
}
diff --git a/src/pkg/os/signal/signal_unix.go b/src/pkg/os/signal/signal_unix.go
index 20ee5f26a..6b4c8ab66 100644
--- a/src/pkg/os/signal/signal_unix.go
+++ b/src/pkg/os/signal/signal_unix.go
@@ -12,6 +12,7 @@ import (
)
// In assembly.
+func signal_disable(uint32)
func signal_enable(uint32)
func signal_recv() uint32
@@ -26,13 +27,27 @@ func init() {
go loop()
}
-func enableSignal(sig os.Signal) {
+const (
+ numSig = 65 // max across all systems
+)
+
+func signum(sig os.Signal) int {
switch sig := sig.(type) {
- case nil:
- signal_enable(^uint32(0))
case syscall.Signal:
- signal_enable(uint32(sig))
+ i := int(sig)
+ if i < 0 || i >= numSig {
+ return -1
+ }
+ return i
default:
- // Can ignore: this signal (whatever it is) will never come in.
+ return -1
}
}
+
+func enableSignal(sig int) {
+ signal_enable(uint32(sig))
+}
+
+func disableSignal(sig int) {
+ signal_disable(uint32(sig))
+}
diff --git a/src/pkg/path/filepath/path_test.go b/src/pkg/path/filepath/path_test.go
index e768ad32f..c4d73602f 100644
--- a/src/pkg/path/filepath/path_test.go
+++ b/src/pkg/path/filepath/path_test.go
@@ -107,6 +107,11 @@ func TestClean(t *testing.T) {
}
}
+ if runtime.GOMAXPROCS(0) > 1 {
+ t.Log("skipping AllocsPerRun checks; GOMAXPROCS>1")
+ return
+ }
+
for _, test := range tests {
allocs := testing.AllocsPerRun(100, func() { filepath.Clean(test.result) })
if allocs > 0 {
diff --git a/src/pkg/path/path_test.go b/src/pkg/path/path_test.go
index 220ec1a0b..69caa80e4 100644
--- a/src/pkg/path/path_test.go
+++ b/src/pkg/path/path_test.go
@@ -5,6 +5,7 @@
package path
import (
+ "runtime"
"testing"
)
@@ -72,6 +73,11 @@ func TestClean(t *testing.T) {
}
}
+ if runtime.GOMAXPROCS(0) > 1 {
+ t.Log("skipping AllocsPerRun checks; GOMAXPROCS>1")
+ return
+ }
+
for _, test := range cleantests {
allocs := testing.AllocsPerRun(100, func() { Clean(test.result) })
if allocs > 0 {
diff --git a/src/pkg/reflect/all_test.go b/src/pkg/reflect/all_test.go
index 6f006db18..56cb315ad 100644
--- a/src/pkg/reflect/all_test.go
+++ b/src/pkg/reflect/all_test.go
@@ -13,6 +13,8 @@ import (
"math/rand"
"os"
. "reflect"
+ "runtime"
+ "sort"
"sync"
"testing"
"time"
@@ -1457,7 +1459,7 @@ func (p Point) AnotherMethod(scale int) int {
// This will be index 1.
func (p Point) Dist(scale int) int {
- // println("Point.Dist", p.x, p.y, scale)
+ //println("Point.Dist", p.x, p.y, scale)
return p.x*p.x*scale + p.y*p.y*scale
}
@@ -1473,23 +1475,23 @@ func TestMethod(t *testing.T) {
if !ok {
t.Fatalf("method by name failed")
}
- m.Func.Call([]Value{ValueOf(p), ValueOf(10)})[0].Int()
- if i != 250 {
- t.Errorf("Type MethodByName returned %d; want 250", i)
+ i = m.Func.Call([]Value{ValueOf(p), ValueOf(11)})[0].Int()
+ if i != 275 {
+ t.Errorf("Type MethodByName returned %d; want 275", i)
}
- i = TypeOf(&p).Method(1).Func.Call([]Value{ValueOf(&p), ValueOf(10)})[0].Int()
- if i != 250 {
- t.Errorf("Pointer Type Method returned %d; want 250", i)
+ 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)
}
m, ok = TypeOf(&p).MethodByName("Dist")
if !ok {
t.Fatalf("ptr method by name failed")
}
- i = m.Func.Call([]Value{ValueOf(&p), ValueOf(10)})[0].Int()
- if i != 250 {
- t.Errorf("Pointer Type MethodByName returned %d; want 250", i)
+ i = m.Func.Call([]Value{ValueOf(&p), ValueOf(13)})[0].Int()
+ if i != 325 {
+ t.Errorf("Pointer Type MethodByName returned %d; want 325", i)
}
// Curried method of value.
@@ -1498,7 +1500,74 @@ func TestMethod(t *testing.T) {
if tt := v.Type(); tt != tfunc {
t.Errorf("Value Method Type is %s; want %s", tt, tfunc)
}
- i = v.Call([]Value{ValueOf(10)})[0].Int()
+ i = v.Call([]Value{ValueOf(14)})[0].Int()
+ if i != 350 {
+ t.Errorf("Value Method returned %d; want 350", i)
+ }
+ v = ValueOf(p).MethodByName("Dist")
+ if tt := v.Type(); tt != tfunc {
+ t.Errorf("Value MethodByName Type is %s; want %s", tt, tfunc)
+ }
+ i = v.Call([]Value{ValueOf(15)})[0].Int()
+ if i != 375 {
+ t.Errorf("Value MethodByName returned %d; want 375", i)
+ }
+
+ // Curried method of pointer.
+ v = ValueOf(&p).Method(1)
+ if tt := v.Type(); tt != tfunc {
+ t.Errorf("Pointer Value Method Type is %s; want %s", tt, tfunc)
+ }
+ i = v.Call([]Value{ValueOf(16)})[0].Int()
+ if i != 400 {
+ t.Errorf("Pointer Value Method returned %d; want 400", i)
+ }
+ v = ValueOf(&p).MethodByName("Dist")
+ if tt := v.Type(); tt != tfunc {
+ t.Errorf("Pointer Value MethodByName Type is %s; want %s", tt, tfunc)
+ }
+ i = v.Call([]Value{ValueOf(17)})[0].Int()
+ if i != 425 {
+ t.Errorf("Pointer Value MethodByName returned %d; want 425", i)
+ }
+
+ // Curried method of interface value.
+ // Have to wrap interface value in a struct to get at it.
+ // Passing it to ValueOf directly would
+ // access the underlying Point, not the interface.
+ var x interface {
+ Dist(int) int
+ } = p
+ pv := ValueOf(&x).Elem()
+ v = pv.Method(0)
+ if tt := v.Type(); tt != tfunc {
+ t.Errorf("Interface Method Type is %s; want %s", tt, tfunc)
+ }
+ i = v.Call([]Value{ValueOf(18)})[0].Int()
+ if i != 450 {
+ t.Errorf("Interface Method returned %d; want 450", i)
+ }
+ v = pv.MethodByName("Dist")
+ if tt := v.Type(); tt != tfunc {
+ t.Errorf("Interface MethodByName Type is %s; want %s", tt, tfunc)
+ }
+ i = v.Call([]Value{ValueOf(19)})[0].Int()
+ if i != 475 {
+ t.Errorf("Interface MethodByName returned %d; want 475", i)
+ }
+}
+
+func TestMethodValue(t *testing.T) {
+ p := Point{3, 4}
+ var i int64
+
+ // Curried method of value.
+ tfunc := TypeOf((func(int) int)(nil))
+ v := ValueOf(p).Method(1)
+ if tt := v.Type(); tt != tfunc {
+ t.Errorf("Value Method Type is %s; want %s", tt, tfunc)
+ }
+ i = ValueOf(v.Interface()).Call([]Value{ValueOf(10)})[0].Int()
if i != 250 {
t.Errorf("Value Method returned %d; want 250", i)
}
@@ -1506,9 +1575,9 @@ func TestMethod(t *testing.T) {
if tt := v.Type(); tt != tfunc {
t.Errorf("Value MethodByName Type is %s; want %s", tt, tfunc)
}
- i = v.Call([]Value{ValueOf(10)})[0].Int()
- if i != 250 {
- t.Errorf("Value MethodByName returned %d; want 250", i)
+ i = ValueOf(v.Interface()).Call([]Value{ValueOf(11)})[0].Int()
+ if i != 275 {
+ t.Errorf("Value MethodByName returned %d; want 275", i)
}
// Curried method of pointer.
@@ -1516,17 +1585,17 @@ func TestMethod(t *testing.T) {
if tt := v.Type(); tt != tfunc {
t.Errorf("Pointer Value Method Type is %s; want %s", tt, tfunc)
}
- i = v.Call([]Value{ValueOf(10)})[0].Int()
- if i != 250 {
- t.Errorf("Pointer Value Method returned %d; want 250", i)
+ i = ValueOf(v.Interface()).Call([]Value{ValueOf(12)})[0].Int()
+ if i != 300 {
+ t.Errorf("Pointer Value Method returned %d; want 300", i)
}
v = ValueOf(&p).MethodByName("Dist")
if tt := v.Type(); tt != tfunc {
t.Errorf("Pointer Value MethodByName Type is %s; want %s", tt, tfunc)
}
- i = v.Call([]Value{ValueOf(10)})[0].Int()
- if i != 250 {
- t.Errorf("Pointer Value MethodByName returned %d; want 250", i)
+ i = ValueOf(v.Interface()).Call([]Value{ValueOf(13)})[0].Int()
+ if i != 325 {
+ t.Errorf("Pointer Value MethodByName returned %d; want 325", i)
}
// Curried method of interface value.
@@ -1543,20 +1612,203 @@ func TestMethod(t *testing.T) {
if tt := v.Type(); tt != tfunc {
t.Errorf("Interface Method Type is %s; want %s", tt, tfunc)
}
- i = v.Call([]Value{ValueOf(10)})[0].Int()
- if i != 250 {
- t.Errorf("Interface Method returned %d; want 250", i)
+ i = ValueOf(v.Interface()).Call([]Value{ValueOf(14)})[0].Int()
+ if i != 350 {
+ t.Errorf("Interface Method returned %d; want 350", i)
}
v = pv.MethodByName("Dist")
if tt := v.Type(); tt != tfunc {
t.Errorf("Interface MethodByName Type is %s; want %s", tt, tfunc)
}
- i = v.Call([]Value{ValueOf(10)})[0].Int()
- if i != 250 {
- t.Errorf("Interface MethodByName returned %d; want 250", i)
+ i = ValueOf(v.Interface()).Call([]Value{ValueOf(15)})[0].Int()
+ if i != 375 {
+ t.Errorf("Interface MethodByName returned %d; want 375", i)
}
}
+// Reflect version of $GOROOT/test/method5.go
+
+// Concrete types implementing M method.
+// Smaller than a word, word-sized, larger than a word.
+// Value and pointer receivers.
+
+type Tinter interface {
+ M(int, byte) (byte, int)
+}
+
+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]) }
+
+// 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)
+}
+
+// Embedding via pointer.
+
+type Tm1 struct {
+ Tm2
+}
+
+type Tm2 struct {
+ *Tm3
+}
+
+type Tm3 struct {
+ *Tm4
+}
+
+type Tm4 struct {
+}
+
+func (t4 Tm4) M(x int, b byte) (byte, int) { return b, x + 40 }
+
+func TestMethod5(t *testing.T) {
+ CheckF := func(name string, f func(int, byte) (byte, int), inc int) {
+ b, x := f(1000, 99)
+ if b != 99 || x != 1000+inc {
+ t.Errorf("%s(1000, 99) = %v, %v, want 99, %v", name, b, x, 1000+inc)
+ }
+ }
+
+ CheckV := func(name string, i Value, inc int) {
+ bx := i.Method(0).Call([]Value{ValueOf(1000), ValueOf(byte(99))})
+ b := bx[0].Interface()
+ x := bx[1].Interface()
+ if b != byte(99) || x != 1000+inc {
+ t.Errorf("direct %s.M(1000, 99) = %v, %v, want 99, %v", name, b, x, 1000+inc)
+ }
+
+ CheckF(name+".M", i.Method(0).Interface().(func(int, byte) (byte, int)), inc)
+ }
+
+ var TinterType = TypeOf(new(Tinter)).Elem()
+ var tinterType = TypeOf(new(tinter)).Elem()
+
+ CheckI := func(name string, i interface{}, inc int) {
+ v := ValueOf(i)
+ CheckV(name, v, inc)
+ CheckV("(i="+name+")", v.Convert(TinterType), inc)
+ }
+
+ sv := Tsmallv(1)
+ CheckI("sv", sv, 1)
+ CheckI("&sv", &sv, 1)
+
+ sp := Tsmallp(2)
+ CheckI("&sp", &sp, 2)
+
+ wv := Twordv(3)
+ CheckI("wv", wv, 3)
+ CheckI("&wv", &wv, 3)
+
+ wp := Twordp(4)
+ CheckI("&wp", &wp, 4)
+
+ bv := Tbigv([2]uintptr{5, 6})
+ CheckI("bv", bv, 11)
+ CheckI("&bv", &bv, 11)
+
+ bp := Tbigp([2]uintptr{7, 8})
+ CheckI("&bp", &bp, 15)
+
+ t4 := Tm4{}
+ t3 := Tm3{&t4}
+ t2 := Tm2{&t3}
+ t1 := Tm1{t2}
+ CheckI("t4", t4, 40)
+ CheckI("&t4", &t4, 40)
+ CheckI("t3", t3, 40)
+ CheckI("&t3", &t3, 40)
+ CheckI("t2", t2, 40)
+ CheckI("&t2", &t2, 40)
+ 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) })
+}
+
func TestInterfaceSet(t *testing.T) {
p := &Point{3, 4}
@@ -1948,6 +2200,30 @@ func TestPtrTo(t *testing.T) {
}
}
+func TestPtrToGC(t *testing.T) {
+ type T *uintptr
+ tt := TypeOf(T(nil))
+ pt := PtrTo(tt)
+ const n = 100
+ var x []interface{}
+ for i := 0; i < n; i++ {
+ v := New(pt)
+ p := new(*uintptr)
+ *p = new(uintptr)
+ **p = uintptr(i)
+ v.Elem().Set(ValueOf(p).Convert(pt))
+ x = append(x, v.Interface())
+ }
+ runtime.GC()
+
+ for i, xi := range x {
+ k := ValueOf(xi).Elem().Elem().Elem().Interface().(uintptr)
+ if k != uintptr(i) {
+ t.Errorf("lost x[%d] = %d, want %d", i, k, i)
+ }
+ }
+}
+
func TestAddr(t *testing.T) {
var p struct {
X, Y int
@@ -2011,6 +2287,9 @@ func TestAddr(t *testing.T) {
}
func noAlloc(t *testing.T, n int, f func(int)) {
+ if runtime.GOMAXPROCS(0) > 1 {
+ t.Skip("skipping; GOMAXPROCS>1")
+ }
i := -1
allocs := testing.AllocsPerRun(n, func() {
f(i)
@@ -2737,8 +3016,10 @@ func TestSliceOf(t *testing.T) {
type T int
st := SliceOf(TypeOf(T(1)))
v := MakeSlice(st, 10, 10)
+ runtime.GC()
for i := 0; i < v.Len(); i++ {
v.Index(i).Set(ValueOf(T(i)))
+ runtime.GC()
}
s := fmt.Sprint(v.Interface())
want := "[0 1 2 3 4 5 6 7 8 9]"
@@ -2751,13 +3032,44 @@ func TestSliceOf(t *testing.T) {
checkSameType(t, Zero(SliceOf(TypeOf(T1(1)))).Interface(), []T1{})
}
+func TestSliceOfGC(t *testing.T) {
+ type T *uintptr
+ tt := TypeOf(T(nil))
+ st := SliceOf(tt)
+ const n = 100
+ var x []interface{}
+ for i := 0; i < n; i++ {
+ v := MakeSlice(st, n, n)
+ for j := 0; j < v.Len(); j++ {
+ p := new(uintptr)
+ *p = uintptr(i*n + j)
+ v.Index(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.Len(); j++ {
+ k := v.Index(j).Elem().Interface()
+ if k != uintptr(i*n+j) {
+ t.Errorf("lost x[%d][%d] = %d, want %d", i, j, k, i*n+j)
+ }
+ }
+ }
+}
+
func TestChanOf(t *testing.T) {
// check construction and use of type not in binary
type T string
ct := ChanOf(BothDir, TypeOf(T("")))
v := MakeChan(ct, 2)
+ runtime.GC()
v.Send(ValueOf(T("hello")))
+ runtime.GC()
v.Send(ValueOf(T("world")))
+ runtime.GC()
sv1, _ := v.Recv()
sv2, _ := v.Recv()
@@ -2772,13 +3084,63 @@ func TestChanOf(t *testing.T) {
checkSameType(t, Zero(ChanOf(BothDir, TypeOf(T1(1)))).Interface(), (chan T1)(nil))
}
+func TestChanOfGC(t *testing.T) {
+ done := make(chan bool, 1)
+ go func() {
+ select {
+ case <-done:
+ case <-time.After(5 * time.Second):
+ panic("deadlock in TestChanOfGC")
+ }
+ }()
+
+ defer func() {
+ done <- true
+ }()
+
+ type T *uintptr
+ tt := TypeOf(T(nil))
+ ct := ChanOf(BothDir, tt)
+
+ // NOTE: The garbage collector handles allocated channels specially,
+ // so we have to save pointers to channels in x; the pointer code will
+ // use the gc info in the newly constructed chan type.
+ const n = 100
+ var x []interface{}
+ for i := 0; i < n; i++ {
+ v := MakeChan(ct, n)
+ for j := 0; j < n; j++ {
+ p := new(uintptr)
+ *p = uintptr(i*n + j)
+ v.Send(ValueOf(p).Convert(tt))
+ }
+ pv := New(ct)
+ pv.Elem().Set(v)
+ x = append(x, pv.Interface())
+ }
+ runtime.GC()
+
+ for i, xi := range x {
+ v := ValueOf(xi).Elem()
+ for j := 0; j < n; j++ {
+ pv, _ := v.Recv()
+ k := pv.Elem().Interface()
+ if k != uintptr(i*n+j) {
+ t.Errorf("lost x[%d][%d] = %d, want %d", i, j, k, i*n+j)
+ }
+ }
+ }
+}
+
func TestMapOf(t *testing.T) {
// check construction and use of type not in binary
type K string
type V float64
v := MakeMap(MapOf(TypeOf(K("")), TypeOf(V(0))))
+ runtime.GC()
v.SetMapIndex(ValueOf(K("a")), ValueOf(V(1)))
+ runtime.GC()
s := fmt.Sprint(v.Interface())
want := "map[a:1]"
@@ -2788,6 +3150,81 @@ func TestMapOf(t *testing.T) {
// check that type already in binary is found
checkSameType(t, Zero(MapOf(TypeOf(V(0)), TypeOf(K("")))).Interface(), map[V]K(nil))
+
+ // check that invalid key type panics
+ shouldPanic(func() { MapOf(TypeOf((func())(nil)), TypeOf(false)) })
+}
+
+func TestMapOfGCKeys(t *testing.T) {
+ type T *uintptr
+ tt := TypeOf(T(nil))
+ mt := MapOf(tt, TypeOf(false))
+
+ // NOTE: The garbage collector handles allocated maps specially,
+ // so we have to save pointers to maps in x; the pointer code will
+ // use the gc info in the newly constructed map type.
+ const n = 100
+ var x []interface{}
+ for i := 0; i < n; i++ {
+ v := MakeMap(mt)
+ for j := 0; j < n; j++ {
+ p := new(uintptr)
+ *p = uintptr(i*n + j)
+ v.SetMapIndex(ValueOf(p).Convert(tt), ValueOf(true))
+ }
+ pv := New(mt)
+ pv.Elem().Set(v)
+ x = append(x, pv.Interface())
+ }
+ runtime.GC()
+
+ for i, xi := range x {
+ v := ValueOf(xi).Elem()
+ var out []int
+ for _, kv := range v.MapKeys() {
+ out = append(out, int(kv.Elem().Interface().(uintptr)))
+ }
+ sort.Ints(out)
+ for j, k := range out {
+ if k != i*n+j {
+ t.Errorf("lost x[%d][%d] = %d, want %d", i, j, k, i*n+j)
+ }
+ }
+ }
+}
+
+func TestMapOfGCValues(t *testing.T) {
+ type T *uintptr
+ tt := TypeOf(T(nil))
+ mt := MapOf(TypeOf(1), tt)
+
+ // NOTE: The garbage collector handles allocated maps specially,
+ // so we have to save pointers to maps in x; the pointer code will
+ // use the gc info in the newly constructed map type.
+ const n = 100
+ var x []interface{}
+ for i := 0; i < n; i++ {
+ v := MakeMap(mt)
+ for j := 0; j < n; j++ {
+ p := new(uintptr)
+ *p = uintptr(i*n + j)
+ v.SetMapIndex(ValueOf(j), ValueOf(p).Convert(tt))
+ }
+ pv := New(mt)
+ pv.Elem().Set(v)
+ x = append(x, pv.Interface())
+ }
+ runtime.GC()
+
+ for i, xi := range x {
+ v := ValueOf(xi).Elem()
+ for j := 0; j < n; j++ {
+ k := v.MapIndex(ValueOf(j)).Elem().Interface().(uintptr)
+ if k != uintptr(i*n+j) {
+ t.Errorf("lost x[%d][%d] = %d, want %d", i, j, k, i*n+j)
+ }
+ }
+ }
}
type B1 struct {
diff --git a/src/pkg/reflect/asm_386.s b/src/pkg/reflect/asm_386.s
index 27d3fa21d..bbd068d98 100644
--- a/src/pkg/reflect/asm_386.s
+++ b/src/pkg/reflect/asm_386.s
@@ -3,11 +3,21 @@
// license that can be found in the LICENSE file.
// makeFuncStub is the code half of the function returned by MakeFunc.
-// See the comment on the declaration of makeFuncStub in value.go
+// See the comment on the declaration of makeFuncStub in makefunc.go
// for more details.
TEXT ·makeFuncStub(SB),7,$8
MOVL DX, 0(SP)
- LEAL arg+0(FP), CX
+ LEAL argframe+0(FP), CX
MOVL CX, 4(SP)
CALL ·callReflect(SB)
RET
+
+// methodValueCall is the code half of the function returned by makeMethodValue.
+// See the comment on the declaration of methodValueCall in makefunc.go
+// for more details.
+TEXT ·methodValueCall(SB),7,$8
+ MOVL DX, 0(SP)
+ LEAL argframe+0(FP), CX
+ MOVL CX, 4(SP)
+ CALL ·callMethod(SB)
+ RET
diff --git a/src/pkg/reflect/asm_amd64.s b/src/pkg/reflect/asm_amd64.s
index d51d982a9..2e7fce55d 100644
--- a/src/pkg/reflect/asm_amd64.s
+++ b/src/pkg/reflect/asm_amd64.s
@@ -3,11 +3,21 @@
// license that can be found in the LICENSE file.
// makeFuncStub is the code half of the function returned by MakeFunc.
-// See the comment on the declaration of makeFuncStub in value.go
+// See the comment on the declaration of makeFuncStub in makefunc.go
// for more details.
TEXT ·makeFuncStub(SB),7,$16
MOVQ DX, 0(SP)
- LEAQ arg+0(FP), CX
+ LEAQ argframe+0(FP), CX
MOVQ CX, 8(SP)
CALL ·callReflect(SB)
RET
+
+// methodValueCall is the code half of the function returned by makeMethodValue.
+// See the comment on the declaration of methodValueCall in makefunc.go
+// for more details.
+TEXT ·methodValueCall(SB),7,$16
+ MOVQ DX, 0(SP)
+ LEAQ argframe+0(FP), CX
+ MOVQ CX, 8(SP)
+ CALL ·callMethod(SB)
+ RET
diff --git a/src/pkg/reflect/asm_arm.s b/src/pkg/reflect/asm_arm.s
index db487f8a5..fb1dddebe 100644
--- a/src/pkg/reflect/asm_arm.s
+++ b/src/pkg/reflect/asm_arm.s
@@ -3,11 +3,21 @@
// license that can be found in the LICENSE file.
// makeFuncStub is jumped to by the code generated by MakeFunc.
-// See the comment on the declaration of makeFuncStub in value.go
+// See the comment on the declaration of makeFuncStub in makefunc.go
// for more details.
TEXT ·makeFuncStub(SB),7,$8
MOVW R7, 4(R13)
- MOVW $arg+0(FP), R1
+ MOVW $argframe+0(FP), R1
MOVW R1, 8(R13)
BL ·callReflect(SB)
RET
+
+// methodValueCall is the code half of the function returned by makeMethodValue.
+// See the comment on the declaration of methodValueCall in makefunc.go
+// for more details.
+TEXT ·methodValueCall(SB),7,$8
+ MOVW R7, 4(R13)
+ MOVW $argframe+0(FP), R1
+ MOVW R1, 8(R13)
+ BL ·callMethod(SB)
+ RET
diff --git a/src/pkg/reflect/deepequal.go b/src/pkg/reflect/deepequal.go
index db047963e..915afed4c 100644
--- a/src/pkg/reflect/deepequal.go
+++ b/src/pkg/reflect/deepequal.go
@@ -118,8 +118,6 @@ func deepValueEqual(v1, v2 Value, visited map[uintptr]*visit, depth int) (b bool
// Normal equality suffices
return valueInterface(v1, false) == valueInterface(v2, false)
}
-
- panic("Not reached")
}
// DeepEqual tests for deep equality. It uses normal == equality where
diff --git a/src/pkg/reflect/makefunc.go b/src/pkg/reflect/makefunc.go
index 024f938f1..ccdd683a0 100644
--- a/src/pkg/reflect/makefunc.go
+++ b/src/pkg/reflect/makefunc.go
@@ -48,8 +48,8 @@ func MakeFunc(typ Type, fn func(args []Value) (results []Value)) Value {
t := typ.common()
ftyp := (*funcType)(unsafe.Pointer(t))
- // indirect Go func value (dummy) to obtain
- // actual code address. (A Go func is a pointer
+ // Indirect Go func value (dummy) to obtain
+ // actual code address. (A Go func value is a pointer
// to a C function pointer. http://golang.org/s/go11func.)
dummy := makeFuncStub
code := **(**uintptr)(unsafe.Pointer(&dummy))
@@ -65,3 +65,56 @@ func MakeFunc(typ Type, fn func(args []Value) (results []Value)) Value {
// where ctxt is the context register and frame is a pointer to the first
// word in the passed-in argument frame.
func makeFuncStub()
+
+type methodValue struct {
+ fn uintptr
+ method int
+ rcvr Value
+}
+
+// makeMethodValue converts v from the rcvr+method index representation
+// of a method value to an actual method func value, which is
+// basically the receiver value with a special bit set, into a true
+// func value - a value holding an actual func. The output is
+// semantically equivalent to the input as far as the user of package
+// reflect can tell, but the true func representation can be handled
+// by code like Convert and Interface and Assign.
+func makeMethodValue(op string, v Value) Value {
+ if v.flag&flagMethod == 0 {
+ panic("reflect: internal error: invalid use of makePartialFunc")
+ }
+
+ // Ignoring the flagMethod bit, v describes the receiver, not the method type.
+ fl := v.flag & (flagRO | flagAddr | flagIndir)
+ fl |= flag(v.typ.Kind()) << flagKindShift
+ rcvr := Value{v.typ, v.val, fl}
+
+ // v.Type returns the actual type of the method value.
+ funcType := v.Type().(*rtype)
+
+ // Indirect Go func value (dummy) to obtain
+ // actual code address. (A Go func value is a pointer
+ // to a C function pointer. http://golang.org/s/go11func.)
+ dummy := methodValueCall
+ code := **(**uintptr)(unsafe.Pointer(&dummy))
+
+ fv := &methodValue{
+ fn: code,
+ method: int(v.flag) >> flagMethodShift,
+ rcvr: rcvr,
+ }
+
+ // Cause panic if method is not appropriate.
+ // The panic would still happen during the call if we omit this,
+ // but we want Interface() and other operations to fail early.
+ methodReceiver(op, fv.rcvr, fv.method)
+
+ return Value{funcType, unsafe.Pointer(fv), v.flag&flagRO | flag(Func)<<flagKindShift}
+}
+
+// methodValueCall is an assembly function that is the code half of
+// the function returned from makeMethodValue. It expects a *methodValue
+// as its context register, and its job is to invoke callMethod(ctxt, frame)
+// where ctxt is the context register and frame is a pointer to the first
+// word in the passed-in argument frame.
+func methodValueCall()
diff --git a/src/pkg/reflect/tostring_test.go b/src/pkg/reflect/tostring_test.go
index 7486a9bfc..e416fd84d 100644
--- a/src/pkg/reflect/tostring_test.go
+++ b/src/pkg/reflect/tostring_test.go
@@ -92,5 +92,4 @@ func valueToString(val Value) string {
default:
panic("valueToString: can't print type " + typ.String())
}
- return "valueToString: can't happen"
}
diff --git a/src/pkg/reflect/type.go b/src/pkg/reflect/type.go
index 94a7521a7..b513fee90 100644
--- a/src/pkg/reflect/type.go
+++ b/src/pkg/reflect/type.go
@@ -233,17 +233,17 @@ const (
// with a unique tag like `reflect:"array"` or `reflect:"ptr"`
// so that code cannot convert from, say, *arrayType to *ptrType.
type rtype struct {
- size uintptr // size in bytes
- hash uint32 // hash of type; avoids computation in hash tables
- _ uint8 // unused/padding
- align uint8 // alignment of variable with this type
- fieldAlign uint8 // alignment of struct field with this type
- kind uint8 // enumeration for C
- alg *uintptr // algorithm table (../runtime/runtime.h:/Alg)
- gc uintptr // garbage collection data
- string *string // string form; unnecessary but undeniably useful
- *uncommonType // (relatively) uncommon fields
- ptrToThis *rtype // type for pointer to this type, if used in binary or has methods
+ size uintptr // size in bytes
+ hash uint32 // hash of type; avoids computation in hash tables
+ _ uint8 // unused/padding
+ align uint8 // alignment of variable with this type
+ fieldAlign uint8 // alignment of struct field with this type
+ kind uint8 // enumeration for C
+ alg *uintptr // algorithm table (../runtime/runtime.h:/Alg)
+ gc unsafe.Pointer // garbage collection data
+ string *string // string form; unnecessary but undeniably useful
+ *uncommonType // (relatively) uncommon fields
+ ptrToThis *rtype // type for pointer to this type, if used in binary or has methods
}
// Method on non-interface type
@@ -345,6 +345,25 @@ type structType struct {
fields []structField // sorted by offset
}
+// NOTE: These are copied from ../runtime/mgc0.h.
+// They must be kept in sync.
+const (
+ _GC_END = iota
+ _GC_PTR
+ _GC_APTR
+ _GC_ARRAY_START
+ _GC_ARRAY_NEXT
+ _GC_CALL
+ _GC_MAP_PTR
+ _GC_CHAN_PTR
+ _GC_STRING
+ _GC_EFACE
+ _GC_IFACE
+ _GC_SLICE
+ _GC_REGION
+ _GC_NUM_INSTR
+)
+
/*
* The compiler knows the exact layout of all the data structures above.
* The compiler does not know about the data structures and methods below.
@@ -368,7 +387,10 @@ type Method struct {
// High bit says whether type has
// embedded pointers,to help garbage collector.
-const kindMask = 0x7f
+const (
+ kindMask = 0x7f
+ kindNoPointers = 0x80
+)
func (k Kind) String() string {
if int(k) < len(kindNames) {
@@ -978,6 +1000,32 @@ var ptrMap struct {
m map[*rtype]*ptrType
}
+// garbage collection bytecode program for pointer to memory without pointers.
+// See ../../cmd/gc/reflect.c:/^dgcsym1 and :/^dgcsym.
+type ptrDataGC struct {
+ width uintptr // sizeof(ptr)
+ op uintptr // _GC_APTR
+ off uintptr // 0
+ end uintptr // _GC_END
+}
+
+var ptrDataGCProg = ptrDataGC{
+ width: unsafe.Sizeof((*byte)(nil)),
+ op: _GC_APTR,
+ off: 0,
+ end: _GC_END,
+}
+
+// garbage collection bytecode program for pointer to memory with pointers.
+// See ../../cmd/gc/reflect.c:/^dgcsym1 and :/^dgcsym.
+type ptrGC struct {
+ width uintptr // sizeof(ptr)
+ op uintptr // _GC_PTR
+ off uintptr // 0
+ elemgc unsafe.Pointer // element gc type
+ end uintptr // _GC_END
+}
+
// PtrTo returns the pointer type with element t.
// For example, if t represents type Foo, PtrTo(t) represents *Foo.
func PtrTo(t Type) Type {
@@ -1034,6 +1082,20 @@ func (t *rtype) ptrTo() *rtype {
p.ptrToThis = nil
p.elem = t
+ if t.kind&kindNoPointers != 0 {
+ p.gc = unsafe.Pointer(&ptrDataGCProg)
+ } else {
+ p.gc = unsafe.Pointer(&ptrGC{
+ width: p.size,
+ op: _GC_PTR,
+ off: 0,
+ elemgc: t.gc,
+ end: _GC_END,
+ })
+ }
+ // INCORRECT. Uncomment to check that TestPtrToGC fails when p.gc is wrong.
+ //p.gc = unsafe.Pointer(&badGC{width: p.size, end: _GC_END})
+
ptrMap.m[t] = p
ptrMap.Unlock()
return &p.rtype
@@ -1246,7 +1308,7 @@ func haveIdenticalUnderlyingType(T, V *rtype) bool {
}
// typelinks is implemented in package runtime.
-// It retuns a slice of all the 'typelink' information in the binary,
+// It returns a slice of all the 'typelink' information in the binary,
// which is to say a slice of known types, sorted by string.
// Note that strings are not unique identifiers for types:
// there can be more than one with a given string.
@@ -1338,6 +1400,21 @@ func cachePut(k cacheKey, t *rtype) Type {
return t
}
+// garbage collection bytecode program for chan or map.
+// See ../../cmd/gc/reflect.c:/^dgcsym1 and :/^dgcsym.
+type chanMapGC struct {
+ width uintptr // sizeof(map)
+ op uintptr // _GC_MAP_PTR or _GC_CHAN_PTR
+ off uintptr // 0
+ typ *rtype // map type
+ end uintptr // _GC_END
+}
+
+type badGC struct {
+ width uintptr
+ end uintptr
+}
+
// ChanOf returns the channel type with the given direction and element type.
// For example, if t represents int, ChanOf(RecvDir, t) represents <-chan int.
//
@@ -1390,20 +1467,35 @@ func ChanOf(dir ChanDir, t Type) Type {
ch.uncommonType = nil
ch.ptrToThis = nil
+ ch.gc = unsafe.Pointer(&chanMapGC{
+ width: ch.size,
+ op: _GC_CHAN_PTR,
+ off: 0,
+ typ: &ch.rtype,
+ end: _GC_END,
+ })
+
+ // INCORRECT. Uncomment to check that TestChanOfGC fails when ch.gc is wrong.
+ //ch.gc = unsafe.Pointer(&badGC{width: ch.size, end: _GC_END})
+
return cachePut(ckey, &ch.rtype)
}
+func ismapkey(*rtype) bool // implemented in runtime
+
// MapOf returns the map type with the given key and element types.
// For example, if k represents int and e represents string,
// MapOf(k, e) represents map[int]string.
//
// If the key type is not a valid map key type (that is, if it does
-// not implement Go's == operator), MapOf panics. TODO(rsc).
+// not implement Go's == operator), MapOf panics.
func MapOf(key, elem Type) Type {
ktyp := key.(*rtype)
etyp := elem.(*rtype)
- // TODO: Check for invalid key types.
+ if !ismapkey(ktyp) {
+ panic("reflect.MapOf: invalid key type " + ktyp.String())
+ }
// Look in cache.
ckey := cacheKey{Map, ktyp, etyp, 0}
@@ -1432,9 +1524,47 @@ func MapOf(key, elem Type) Type {
mt.uncommonType = nil
mt.ptrToThis = nil
+ mt.gc = unsafe.Pointer(&chanMapGC{
+ width: mt.size,
+ op: _GC_MAP_PTR,
+ off: 0,
+ typ: &mt.rtype,
+ end: _GC_END,
+ })
+
+ // 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})
+
return cachePut(ckey, &mt.rtype)
}
+// garbage collection bytecode program for slice of non-zero-length values.
+// See ../../cmd/gc/reflect.c:/^dgcsym1 and :/^dgcsym.
+type sliceGC struct {
+ width uintptr // sizeof(slice)
+ op uintptr // _GC_SLICE
+ off uintptr // 0
+ elemgc unsafe.Pointer // element gc program
+ end uintptr // _GC_END
+}
+
+// garbage collection bytecode program for slice of zero-length values.
+// See ../../cmd/gc/reflect.c:/^dgcsym1 and :/^dgcsym.
+type sliceEmptyGC struct {
+ width uintptr // sizeof(slice)
+ op uintptr // _GC_APTR
+ off uintptr // 0
+ end uintptr // _GC_END
+}
+
+var sliceEmptyGCProg = sliceEmptyGC{
+ width: unsafe.Sizeof([]byte(nil)),
+ op: _GC_APTR,
+ off: 0,
+ end: _GC_END,
+}
+
// SliceOf returns the slice type with element type t.
// For example, if t represents int, SliceOf(t) represents []int.
func SliceOf(t Type) Type {
@@ -1466,6 +1596,21 @@ func SliceOf(t Type) Type {
slice.uncommonType = nil
slice.ptrToThis = nil
+ if typ.size == 0 {
+ slice.gc = unsafe.Pointer(&sliceEmptyGCProg)
+ } else {
+ slice.gc = unsafe.Pointer(&sliceGC{
+ width: slice.size,
+ op: _GC_SLICE,
+ off: 0,
+ elemgc: typ.gc,
+ end: _GC_END,
+ })
+ }
+
+ // INCORRECT. Uncomment to check that TestSliceOfOfGC fails when slice.gc is wrong.
+ //slice.gc = unsafe.Pointer(&badGC{width: slice.size, end: _GC_END})
+
return cachePut(ckey, &slice.rtype)
}
diff --git a/src/pkg/reflect/value.go b/src/pkg/reflect/value.go
index c87812c46..80aa85723 100644
--- a/src/pkg/reflect/value.go
+++ b/src/pkg/reflect/value.go
@@ -249,7 +249,7 @@ func (f flag) mustBeExported() {
panic(&ValueError{methodName(), 0})
}
if f&flagRO != 0 {
- panic(methodName() + " using value obtained using unexported field")
+ panic("reflect: " + methodName() + " using value obtained using unexported field")
}
}
@@ -262,10 +262,10 @@ func (f flag) mustBeAssignable() {
}
// Assignable if addressable and not read-only.
if f&flagRO != 0 {
- panic(methodName() + " using value obtained using unexported field")
+ panic("reflect: " + methodName() + " using value obtained using unexported field")
}
if f&flagAddr == 0 {
- panic(methodName() + " using unaddressable value")
+ panic("reflect: " + methodName() + " using unaddressable value")
}
}
@@ -358,7 +358,7 @@ func (v Value) CallSlice(in []Value) []Value {
return v.call("CallSlice", in)
}
-func (v Value) call(method string, in []Value) []Value {
+func (v Value) call(op string, in []Value) []Value {
// Get function pointer, type.
t := v.typ
var (
@@ -366,36 +366,7 @@ func (v Value) call(method string, in []Value) []Value {
rcvr iword
)
if v.flag&flagMethod != 0 {
- i := int(v.flag) >> flagMethodShift
- if v.typ.Kind() == Interface {
- tt := (*interfaceType)(unsafe.Pointer(v.typ))
- if i < 0 || i >= len(tt.methods) {
- panic("reflect: broken Value")
- }
- m := &tt.methods[i]
- if m.pkgPath != nil {
- panic(method + " of unexported method")
- }
- t = m.typ
- iface := (*nonEmptyInterface)(v.val)
- if iface.itab == nil {
- panic(method + " of method on nil interface value")
- }
- fn = unsafe.Pointer(&iface.itab.fun[i])
- rcvr = iface.word
- } else {
- ut := v.typ.uncommon()
- if ut == nil || i < 0 || i >= len(ut.methods) {
- panic("reflect: broken Value")
- }
- m := &ut.methods[i]
- if m.pkgPath != nil {
- panic(method + " of unexported method")
- }
- fn = unsafe.Pointer(&m.ifn)
- t = m.mtyp
- rcvr = v.iword()
- }
+ t, fn, rcvr = methodReceiver(op, v, int(v.flag)>>flagMethodShift)
} else if v.flag&flagIndir != 0 {
fn = *(*unsafe.Pointer)(v.val)
} else {
@@ -406,7 +377,7 @@ func (v Value) call(method string, in []Value) []Value {
panic("reflect.Value.Call: call of nil function")
}
- isSlice := method == "CallSlice"
+ isSlice := op == "CallSlice"
n := t.NumIn()
if isSlice {
if !t.IsVariadic() {
@@ -431,12 +402,12 @@ func (v Value) call(method string, in []Value) []Value {
}
for _, x := range in {
if x.Kind() == Invalid {
- panic("reflect: " + method + " using zero Value argument")
+ panic("reflect: " + op + " using zero Value argument")
}
}
for i := 0; i < n; i++ {
if xt, targ := in[i].Type(), t.In(i); !xt.AssignableTo(targ) {
- panic("reflect: " + method + " using " + xt.String() + " as type " + targ.String())
+ panic("reflect: " + op + " using " + xt.String() + " as type " + targ.String())
}
}
if !isSlice && t.IsVariadic() {
@@ -447,7 +418,7 @@ func (v Value) call(method string, in []Value) []Value {
for i := 0; i < m; i++ {
x := in[n+i]
if xt := x.Type(); !xt.AssignableTo(elem) {
- panic("reflect: cannot use " + xt.String() + " as type " + elem.String() + " in " + method)
+ panic("reflect: cannot use " + xt.String() + " as type " + elem.String() + " in " + op)
}
slice.Index(i).Set(x)
}
@@ -467,40 +438,11 @@ func (v Value) call(method string, in []Value) []Value {
// This computation is 5g/6g/8g-dependent
// and probably wrong for gccgo, but so
// is most of this function.
- size := uintptr(0)
- if v.flag&flagMethod != 0 {
- // extra word for receiver interface word
- size += ptrSize
- }
- for i := 0; i < nin; i++ {
- tv := t.In(i)
- a := uintptr(tv.Align())
- size = (size + a - 1) &^ (a - 1)
- size += tv.Size()
- }
- size = (size + ptrSize - 1) &^ (ptrSize - 1)
- for i := 0; i < nout; i++ {
- tv := t.Out(i)
- a := uintptr(tv.Align())
- size = (size + a - 1) &^ (a - 1)
- size += tv.Size()
- }
-
- // size must be > 0 in order for &args[0] to be valid.
- // the argument copying is going to round it up to
- // a multiple of ptrSize anyway, so make it ptrSize to begin with.
- if size < ptrSize {
- size = ptrSize
- }
-
- // round to pointer size
- size = (size + ptrSize - 1) &^ (ptrSize - 1)
+ size, _, _, _ := frameSize(t, v.flag&flagMethod != 0)
// Copy into args.
//
- // TODO(rsc): revisit when reference counting happens.
- // The values are holding up the in references for us,
- // but something must be done for the out references.
+ // TODO(rsc): This will need to be updated for any new garbage collector.
// For now make everything look like a pointer by allocating
// a []unsafe.Pointer.
args := make([]unsafe.Pointer, size/ptrSize)
@@ -616,6 +558,119 @@ func callReflect(ctxt *makeFuncImpl, frame unsafe.Pointer) {
}
}
+// methodReceiver returns information about the receiver
+// described by v. The Value v may or may not have the
+// flagMethod bit set, so the kind cached in v.flag should
+// not be used.
+func methodReceiver(op string, v Value, methodIndex int) (t *rtype, fn unsafe.Pointer, rcvr iword) {
+ i := methodIndex
+ if v.typ.Kind() == Interface {
+ tt := (*interfaceType)(unsafe.Pointer(v.typ))
+ if i < 0 || i >= len(tt.methods) {
+ panic("reflect: internal error: invalid method index")
+ }
+ m := &tt.methods[i]
+ if m.pkgPath != nil {
+ panic("reflect: " + op + " of unexported method")
+ }
+ t = m.typ
+ iface := (*nonEmptyInterface)(v.val)
+ if iface.itab == nil {
+ panic("reflect: " + op + " of method on nil interface value")
+ }
+ fn = unsafe.Pointer(&iface.itab.fun[i])
+ rcvr = iface.word
+ } else {
+ ut := v.typ.uncommon()
+ if ut == nil || i < 0 || i >= len(ut.methods) {
+ panic("reflect: internal error: invalid method index")
+ }
+ m := &ut.methods[i]
+ if m.pkgPath != nil {
+ panic("reflect: " + op + " of unexported method")
+ }
+ fn = unsafe.Pointer(&m.ifn)
+ t = m.mtyp
+ rcvr = v.iword()
+ }
+ return
+}
+
+// align returns the result of rounding x up to a multiple of n.
+// n must be a power of two.
+func align(x, n uintptr) uintptr {
+ return (x + n - 1) &^ (n - 1)
+}
+
+// frameSize returns the sizes of the argument and result frame
+// for a function of the given type. The rcvr bool specifies whether
+// a one-word receiver should be included in the total.
+func frameSize(t *rtype, rcvr bool) (total, in, outOffset, out uintptr) {
+ if rcvr {
+ // extra word for receiver interface word
+ total += ptrSize
+ }
+
+ nin := t.NumIn()
+ in = -total
+ for i := 0; i < nin; i++ {
+ tv := t.In(i)
+ total = align(total, uintptr(tv.Align()))
+ total += tv.Size()
+ }
+ in += total
+ total = align(total, ptrSize)
+ nout := t.NumOut()
+ outOffset = total
+ out = -total
+ for i := 0; i < nout; i++ {
+ tv := t.Out(i)
+ total = align(total, uintptr(tv.Align()))
+ total += tv.Size()
+ }
+ out += total
+
+ // total must be > 0 in order for &args[0] to be valid.
+ // the argument copying is going to round it up to
+ // a multiple of ptrSize anyway, so make it ptrSize to begin with.
+ if total < ptrSize {
+ total = ptrSize
+ }
+
+ // round to pointer
+ total = align(total, ptrSize)
+
+ return
+}
+
+// callMethod is the call implementation used by a function returned
+// by makeMethodValue (used by v.Method(i).Interface()).
+// It is a streamlined version of the usual reflect call: the caller has
+// already laid out the argument frame for us, so we don't have
+// to deal with individual Values for each argument.
+// It is in this file so that it can be next to the two similar functions above.
+// The remainder of the makeMethodValue implementation is in makefunc.go.
+func callMethod(ctxt *methodValue, frame unsafe.Pointer) {
+ t, fn, rcvr := methodReceiver("call", ctxt.rcvr, ctxt.method)
+ total, in, outOffset, out := frameSize(t, true)
+
+ // Copy into args.
+ //
+ // TODO(rsc): This will need to be updated for any new garbage collector.
+ // For now make everything look like a pointer by allocating
+ // a []unsafe.Pointer.
+ args := make([]unsafe.Pointer, total/ptrSize)
+ args[0] = unsafe.Pointer(rcvr)
+ base := unsafe.Pointer(&args[0])
+ memmove(unsafe.Pointer(uintptr(base)+ptrSize), frame, in)
+
+ // Call.
+ call(fn, unsafe.Pointer(&args[0]), uint32(total))
+
+ // Copy return values.
+ memmove(unsafe.Pointer(uintptr(frame)+outOffset-ptrSize), unsafe.Pointer(uintptr(base)+outOffset), out)
+}
+
// funcName returns the name of f, for use in error messages.
func funcName(f func([]Value) []Value) string {
pc := *(*uintptr)(unsafe.Pointer(&f))
@@ -902,7 +957,7 @@ func (v Value) CanInterface() bool {
if v.flag == 0 {
panic(&ValueError{"reflect.Value.CanInterface", Invalid})
}
- return v.flag&(flagMethod|flagRO) == 0
+ return v.flag&flagRO == 0
}
// Interface returns v's current value as an interface{}.
@@ -921,16 +976,15 @@ func valueInterface(v Value, safe bool) interface{} {
if v.flag == 0 {
panic(&ValueError{"reflect.Value.Interface", 0})
}
- if v.flag&flagMethod != 0 {
- panic("reflect.Value.Interface: cannot create interface value for method with bound receiver")
- }
-
if safe && v.flag&flagRO != 0 {
// Do not allow access to unexported values via Interface,
// because they might be pointers that should not be
// writable or methods or function that should not be callable.
panic("reflect.Value.Interface: cannot return value obtained from unexported field or method")
}
+ if v.flag&flagMethod != 0 {
+ v = makeMethodValue("Interface", v)
+ }
k := v.kind()
if k == Interface {
@@ -981,7 +1035,7 @@ func (v Value) IsNil() bool {
switch k {
case Chan, Func, Map, Ptr:
if v.flag&flagMethod != 0 {
- panic("reflect: IsNil of method Value")
+ return false
}
ptr := v.val
if v.flag&flagIndir != 0 {
@@ -1100,7 +1154,7 @@ func (v Value) MapKeys() []Value {
// Method returns a function value corresponding to v's i'th method.
// The arguments to a Call on the returned function should not include
// a receiver; the returned function will always use v as the receiver.
-// Method panics if i is out of range.
+// Method panics if i is out of range or if v is a nil interface value.
func (v Value) Method(i int) Value {
if v.typ == nil {
panic(&ValueError{"reflect.Value.Method", Invalid})
@@ -1108,7 +1162,10 @@ func (v Value) Method(i int) Value {
if v.flag&flagMethod != 0 || i < 0 || i >= v.typ.NumMethod() {
panic("reflect: Method index out of range")
}
- fl := v.flag & (flagRO | flagAddr | flagIndir)
+ if v.typ.Kind() == Interface && v.IsNil() {
+ panic("reflect: Method on nil interface value")
+ }
+ fl := v.flag & (flagRO | flagIndir)
fl |= flag(Func) << flagKindShift
fl |= flag(i)<<flagMethodShift | flagMethod
return Value{v.typ, v.val, fl}
@@ -1232,7 +1289,14 @@ func (v Value) Pointer() uintptr {
return uintptr(p)
case Func:
if v.flag&flagMethod != 0 {
- panic("reflect.Value.Pointer of method Value")
+ // As the doc comment says, the returned pointer is an
+ // underlying code pointer but not necessarily enough to
+ // identify a single function uniquely. All method expressions
+ // created via reflect have the same underlying code pointer,
+ // so their Pointers are equal. The function used here must
+ // match the one used in makeMethodValue.
+ f := methodValueCall
+ return **(**uintptr)(unsafe.Pointer(&f))
}
p := v.val
if v.flag&flagIndir != 0 {
@@ -1267,7 +1331,7 @@ func (v Value) Recv() (x Value, ok bool) {
func (v Value) recv(nb bool) (val Value, ok bool) {
tt := (*chanType)(unsafe.Pointer(v.typ))
if ChanDir(tt.dir)&RecvDir == 0 {
- panic("recv on send-only channel")
+ panic("reflect: recv on send-only channel")
}
word, selected, ok := chanrecv(v.typ, v.iword(), nb)
if selected {
@@ -1295,7 +1359,7 @@ func (v Value) Send(x Value) {
func (v Value) send(x Value, nb bool) (selected bool) {
tt := (*chanType)(unsafe.Pointer(v.typ))
if ChanDir(tt.dir)&SendDir == 0 {
- panic("send on recv-only channel")
+ panic("reflect: send on recv-only channel")
}
x.mustBeExported()
x = x.assignTo("reflect.Value.Send", tt.elem, nil)
@@ -1578,7 +1642,7 @@ func (v Value) Type() Type {
// Method on interface.
tt := (*interfaceType)(unsafe.Pointer(v.typ))
if i < 0 || i >= len(tt.methods) {
- panic("reflect: broken Value")
+ panic("reflect: internal error: invalid method index")
}
m := &tt.methods[i]
return m.typ
@@ -1586,7 +1650,7 @@ func (v Value) Type() Type {
// Method on concrete type.
ut := v.typ.uncommon()
if ut == nil || i < 0 || i >= len(ut.methods) {
- panic("reflect: broken Value")
+ panic("reflect: internal error: invalid method index")
}
m := &ut.methods[i]
return m.mtyp
@@ -1635,14 +1699,22 @@ func (v Value) UnsafeAddr() uintptr {
}
// StringHeader is the runtime representation of a string.
-// It cannot be used safely or portably.
+// It cannot be used safely or portably and its representation may
+// change in a later release.
+// Moreover, the Data field is not sufficient to guarantee the data
+// it references will not be garbage collected, so programs must keep
+// a separate, correctly typed pointer to the underlying data.
type StringHeader struct {
Data uintptr
Len int
}
// SliceHeader is the runtime representation of a slice.
-// It cannot be used safely or portably.
+// It cannot be used safely or portably and its representation may
+// change in a later release.
+// Moreover, the Data field is not sufficient to guarantee the data
+// it references will not be garbage collected, so programs must keep
+// a separate, correctly typed pointer to the underlying data.
type SliceHeader struct {
Data uintptr
Len int
@@ -2030,7 +2102,7 @@ func NewAt(typ Type, p unsafe.Pointer) Value {
// For a conversion to an interface type, target is a suggested scratch space to use.
func (v Value) assignTo(context string, dst *rtype, target *interface{}) Value {
if v.flag&flagMethod != 0 {
- panic(context + ": cannot assign method value to type " + dst.String())
+ v = makeMethodValue(context, v)
}
switch {
@@ -2064,7 +2136,7 @@ func (v Value) assignTo(context string, dst *rtype, target *interface{}) Value {
// of the value v to type t, Convert panics.
func (v Value) Convert(t Type) Value {
if v.flag&flagMethod != 0 {
- panic("reflect.Value.Convert: cannot convert method values")
+ v = makeMethodValue("Convert", v)
}
op := convertOp(t.common(), v.typ)
if op == nil {
diff --git a/src/pkg/regexp/regexp.go b/src/pkg/regexp/regexp.go
index 3aa16dec6..c392b376f 100644
--- a/src/pkg/regexp/regexp.go
+++ b/src/pkg/regexp/regexp.go
@@ -8,6 +8,8 @@
// general syntax used by Perl, Python, and other languages.
// More precisely, it is the syntax accepted by RE2 and described at
// http://code.google.com/p/re2/wiki/Syntax, except for \C.
+// For an overview of the syntax, run
+// godoc regexp/syntax
//
// All characters are UTF-8-encoded code points.
//
@@ -27,11 +29,11 @@
// 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.
+// successive submatches of the expression. Submatches are matches of
+// parenthesized subexpressions (also known as capturing groups) 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
@@ -395,7 +397,7 @@ func (re *Regexp) Match(b []byte) bool {
// 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) {
+func MatchReader(pattern string, r io.RuneReader) (matched bool, err error) {
re, err := Compile(pattern)
if err != nil {
return false, err
@@ -406,7 +408,7 @@ func MatchReader(pattern string, r io.RuneReader) (matched bool, error error) {
// 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) {
+func MatchString(pattern string, s string) (matched bool, err error) {
re, err := Compile(pattern)
if err != nil {
return false, err
@@ -417,7 +419,7 @@ func MatchString(pattern string, s string) (matched bool, error error) {
// 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) {
+func Match(pattern string, b []byte) (matched bool, err error) {
re, err := Compile(pattern)
if err != nil {
return false, err
diff --git a/src/pkg/regexp/syntax/doc.go b/src/pkg/regexp/syntax/doc.go
index 843a6f6a4..bcb5d051b 100644
--- a/src/pkg/regexp/syntax/doc.go
+++ b/src/pkg/regexp/syntax/doc.go
@@ -47,9 +47,9 @@ Repetitions:
x{n}? exactly n x
Grouping:
- (re) numbered capturing group
- (?P<name>re) named & numbered capturing group
- (?:re) non-capturing group
+ (re) numbered capturing group (submatch)
+ (?P<name>re) named & numbered capturing group (submatch)
+ (?:re) non-capturing group (submatch)
(?flags) set flags within current group; non-capturing
(?flags:re) set flags during re; non-capturing
diff --git a/src/pkg/runtime/alg.c b/src/pkg/runtime/alg.c
index ad85b43ae..a78d9780c 100644
--- a/src/pkg/runtime/alg.c
+++ b/src/pkg/runtime/alg.c
@@ -8,6 +8,8 @@
#define M0 (sizeof(uintptr)==4 ? 2860486313UL : 33054211828000289ULL)
#define M1 (sizeof(uintptr)==4 ? 3267000013UL : 23344194077549503ULL)
+static bool use_aeshash;
+
/*
* map and chan helpers for
* dealing with unknown types
@@ -17,6 +19,10 @@ runtime·memhash(uintptr *h, uintptr s, void *a)
{
byte *b;
uintptr hash;
+ if(use_aeshash) {
+ runtime·aeshash(h, s, a);
+ return;
+ }
b = a;
hash = M0 ^ *h;
@@ -31,25 +37,11 @@ runtime·memhash(uintptr *h, uintptr s, void *a)
void
runtime·memequal(bool *eq, uintptr s, void *a, void *b)
{
- byte *ba, *bb, *aend;
-
if(a == b) {
*eq = 1;
return;
}
- ba = a;
- bb = b;
- aend = ba+s;
- while(ba != aend) {
- if(*ba != *bb) {
- *eq = 0;
- return;
- }
- ba++;
- bb++;
- }
- *eq = 1;
- return;
+ *eq = runtime·memeq(a, b, s);
}
void
@@ -317,6 +309,7 @@ void
runtime·strequal(bool *eq, uintptr s, void *a, void *b)
{
intgo alen;
+ byte *s1, *s2;
USED(s);
alen = ((String*)a)->len;
@@ -324,11 +317,13 @@ runtime·strequal(bool *eq, uintptr s, void *a, void *b)
*eq = false;
return;
}
- if(((String*)a)->str == ((String*)b)->str) {
+ s1 = ((String*)a)->str;
+ s2 = ((String*)b)->str;
+ if(s1 == s2) {
*eq = true;
return;
}
- runtime·memequal(eq, alen, ((String*)a)->str, ((String*)b)->str);
+ *eq = runtime·memeq(s1, s2, alen);
}
void
@@ -467,6 +462,42 @@ runtime·algarray[] =
// Runtime helpers.
+// used in asm_{386,amd64}.s
+byte runtime·aeskeysched[HashRandomBytes];
+
+void
+runtime·hashinit(void)
+{
+ // Install aes hash algorithm if we have the instructions we need
+ if((runtime·cpuid_ecx & (1 << 25)) != 0 && // aes (aesenc)
+ (runtime·cpuid_ecx & (1 << 9)) != 0 && // sse3 (pshufb)
+ (runtime·cpuid_ecx & (1 << 19)) != 0) { // sse4.1 (pinsr{d,q})
+ byte *rnd;
+ int32 n;
+ use_aeshash = true;
+ runtime·algarray[AMEM].hash = runtime·aeshash;
+ runtime·algarray[AMEM8].hash = runtime·aeshash;
+ runtime·algarray[AMEM16].hash = runtime·aeshash;
+ runtime·algarray[AMEM32].hash = runtime·aeshash32;
+ runtime·algarray[AMEM64].hash = runtime·aeshash64;
+ runtime·algarray[AMEM128].hash = runtime·aeshash;
+ runtime·algarray[ASTRING].hash = runtime·aeshashstr;
+
+ // Initialize with random data so hash collisions will be hard to engineer.
+ runtime·get_random_data(&rnd, &n);
+ if(n > HashRandomBytes)
+ n = HashRandomBytes;
+ runtime·memmove(runtime·aeskeysched, rnd, n);
+ if(n < HashRandomBytes) {
+ // Not very random, but better than nothing.
+ int64 t = runtime·nanotime();
+ while (n < HashRandomBytes) {
+ runtime·aeskeysched[n++] = (int8)(t >> (8 * (n % 8)));
+ }
+ }
+ }
+}
+
// func equal(t *Type, x T, y T) (ret bool)
#pragma textflag 7
void
diff --git a/src/pkg/runtime/arch_386.h b/src/pkg/runtime/arch_386.h
index 4df795f71..62ed11b40 100644
--- a/src/pkg/runtime/arch_386.h
+++ b/src/pkg/runtime/arch_386.h
@@ -1,3 +1,7 @@
+// 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.
+
enum {
thechar = '8',
BigEndian = 0,
diff --git a/src/pkg/runtime/arch_amd64.h b/src/pkg/runtime/arch_amd64.h
index e83dc9105..a5e43ca8d 100644
--- a/src/pkg/runtime/arch_amd64.h
+++ b/src/pkg/runtime/arch_amd64.h
@@ -1,3 +1,7 @@
+// 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.
+
enum {
thechar = '6',
BigEndian = 0,
diff --git a/src/pkg/runtime/arch_arm.h b/src/pkg/runtime/arch_arm.h
index f6af58514..27c70c105 100644
--- a/src/pkg/runtime/arch_arm.h
+++ b/src/pkg/runtime/arch_arm.h
@@ -1,6 +1,10 @@
+// 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.
+
enum {
thechar = '5',
BigEndian = 0,
CacheLineSize = 32,
- appendCrossover = 16
+ appendCrossover = 8
};
diff --git a/src/pkg/runtime/asm_386.s b/src/pkg/runtime/asm_386.s
index 96f04e0ae..531057ff8 100644
--- a/src/pkg/runtime/asm_386.s
+++ b/src/pkg/runtime/asm_386.s
@@ -6,8 +6,8 @@
TEXT _rt0_386(SB),7,$0
// copy arguments forward on an even stack
- MOVL 0(SP), AX // argc
- LEAL 4(SP), BX // argv
+ MOVL argc+0(FP), AX
+ MOVL argv+4(FP), BX
SUBL $128, SP // plenty of scratch
ANDL $~15, SP
MOVL AX, 120(SP) // save argc, argv away
@@ -20,15 +20,27 @@ TEXT _rt0_386(SB),7,$0
MOVL BX, g_stackguard(BP)
MOVL SP, g_stackbase(BP)
+ // find out information about the processor we're on
+ MOVL $0, AX
+ CPUID
+ CMPL AX, $0
+ JE nocpuinfo
+ MOVL $1, AX
+ CPUID
+ MOVL CX, runtime·cpuid_ecx(SB)
+ MOVL DX, runtime·cpuid_edx(SB)
+nocpuinfo:
+
// if there is an _cgo_init, call it to let it
// initialize and to set up GS. if not,
// we set up GS ourselves.
MOVL _cgo_init(SB), AX
TESTL AX, AX
JZ needtls
- PUSHL BP
+ MOVL $setmg_gcc<>(SB), BX
+ MOVL BX, 4(SP)
+ MOVL BP, 0(SP)
CALL AX
- POPL BP
// skip runtime·ldt0setup(SB) and tls test after _cgo_init for non-windows
CMPL runtime·iswindows(SB), $0
JEQ ok
@@ -72,6 +84,7 @@ ok:
MOVL AX, 4(SP)
CALL runtime·args(SB)
CALL runtime·osinit(SB)
+ CALL runtime·hashinit(SB)
CALL runtime·schedinit(SB)
// create a new goroutine to start program
@@ -95,7 +108,7 @@ TEXT runtime·breakpoint(SB),7,$0
RET
TEXT runtime·asminit(SB),7,$0
- // Linux, Windows start the FPU in extended double precision.
+ // Linux and MinGW start the FPU in extended double precision.
// Other operating systems use double precision.
// Change to double precision to match them,
// and to match other hardware that only has double.
@@ -632,6 +645,15 @@ settls:
MOVL BX, g(CX)
RET
+// void setmg_gcc(M*, G*); set m and g. for use by gcc
+TEXT setmg_gcc<>(SB), 7, $0
+ get_tls(AX)
+ MOVL mm+0(FP), DX
+ MOVL DX, m(AX)
+ MOVL gg+4(FP), DX
+ MOVL DX,g (AX)
+ RET
+
// check that SP is in range [g->stackbase, g->stackguard)
TEXT runtime·stackcheck(SB), 7, $0
get_tls(CX)
@@ -706,7 +728,376 @@ TEXT runtime·stackguard(SB),7,$0
get_tls(CX)
MOVL g(CX), BX
MOVL g_stackguard(BX), DX
- MOVL DX, guard+4(FP)
+ MOVL DX, limit+4(FP)
RET
GLOBL runtime·tls0(SB), $32
+
+// hash function using AES hardware instructions
+TEXT runtime·aeshash(SB),7,$0
+ MOVL 4(SP), DX // ptr to hash value
+ MOVL 8(SP), CX // size
+ MOVL 12(SP), AX // ptr to data
+ JMP runtime·aeshashbody(SB)
+
+TEXT runtime·aeshashstr(SB),7,$0
+ MOVL 4(SP), DX // ptr to hash value
+ MOVL 12(SP), AX // ptr to string struct
+ MOVL 4(AX), CX // length of string
+ MOVL (AX), AX // string data
+ JMP runtime·aeshashbody(SB)
+
+// AX: data
+// CX: length
+// DX: ptr to seed input / hash output
+TEXT runtime·aeshashbody(SB),7,$0
+ MOVL (DX), X0 // seed to low 32 bits of xmm0
+ PINSRD $1, CX, X0 // size to next 32 bits of xmm0
+ MOVO runtime·aeskeysched+0(SB), X2
+ MOVO runtime·aeskeysched+16(SB), X3
+aesloop:
+ CMPL CX, $16
+ JB aesloopend
+ MOVOU (AX), X1
+ AESENC X2, X0
+ AESENC X1, X0
+ SUBL $16, CX
+ ADDL $16, AX
+ JMP aesloop
+aesloopend:
+ TESTL CX, CX
+ JE finalize // no partial block
+
+ TESTL $16, AX
+ JNE highpartial
+
+ // address ends in 0xxxx. 16 bytes loaded
+ // at this address won't cross a page boundary, so
+ // we can load it directly.
+ MOVOU (AX), X1
+ ADDL CX, CX
+ PAND masks(SB)(CX*8), X1
+ JMP partial
+highpartial:
+ // address ends in 1xxxx. Might be up against
+ // a page boundary, so load ending at last byte.
+ // Then shift bytes down using pshufb.
+ MOVOU -16(AX)(CX*1), X1
+ ADDL CX, CX
+ PSHUFB shifts(SB)(CX*8), X1
+partial:
+ // incorporate partial block into hash
+ AESENC X3, X0
+ AESENC X1, X0
+finalize:
+ // finalize hash
+ AESENC X2, X0
+ AESENC X3, X0
+ AESENC X2, X0
+ MOVL X0, (DX)
+ RET
+
+TEXT runtime·aeshash32(SB),7,$0
+ MOVL 4(SP), DX // ptr to hash value
+ MOVL 12(SP), AX // ptr to data
+ MOVL (DX), X0 // seed
+ PINSRD $1, (AX), X0 // data
+ AESENC runtime·aeskeysched+0(SB), X0
+ AESENC runtime·aeskeysched+16(SB), X0
+ AESENC runtime·aeskeysched+0(SB), X0
+ MOVL X0, (DX)
+ RET
+
+TEXT runtime·aeshash64(SB),7,$0
+ MOVL 4(SP), DX // ptr to hash value
+ MOVL 12(SP), AX // ptr to data
+ MOVQ (AX), X0 // data
+ PINSRD $2, (DX), X0 // seed
+ AESENC runtime·aeskeysched+0(SB), X0
+ AESENC runtime·aeskeysched+16(SB), X0
+ AESENC runtime·aeskeysched+0(SB), X0
+ MOVL X0, (DX)
+ RET
+
+
+// simple mask to get rid of data in the high part of the register.
+TEXT masks(SB),7,$0
+ LONG $0x00000000
+ LONG $0x00000000
+ LONG $0x00000000
+ LONG $0x00000000
+
+ LONG $0x000000ff
+ LONG $0x00000000
+ LONG $0x00000000
+ LONG $0x00000000
+
+ LONG $0x0000ffff
+ LONG $0x00000000
+ LONG $0x00000000
+ LONG $0x00000000
+
+ LONG $0x00ffffff
+ LONG $0x00000000
+ LONG $0x00000000
+ LONG $0x00000000
+
+ LONG $0xffffffff
+ LONG $0x00000000
+ LONG $0x00000000
+ LONG $0x00000000
+
+ LONG $0xffffffff
+ LONG $0x000000ff
+ LONG $0x00000000
+ LONG $0x00000000
+
+ LONG $0xffffffff
+ LONG $0x0000ffff
+ LONG $0x00000000
+ LONG $0x00000000
+
+ LONG $0xffffffff
+ LONG $0x00ffffff
+ LONG $0x00000000
+ LONG $0x00000000
+
+ LONG $0xffffffff
+ LONG $0xffffffff
+ LONG $0x00000000
+ LONG $0x00000000
+
+ LONG $0xffffffff
+ LONG $0xffffffff
+ LONG $0x000000ff
+ LONG $0x00000000
+
+ LONG $0xffffffff
+ LONG $0xffffffff
+ LONG $0x0000ffff
+ LONG $0x00000000
+
+ LONG $0xffffffff
+ LONG $0xffffffff
+ LONG $0x00ffffff
+ LONG $0x00000000
+
+ LONG $0xffffffff
+ LONG $0xffffffff
+ LONG $0xffffffff
+ LONG $0x00000000
+
+ LONG $0xffffffff
+ LONG $0xffffffff
+ LONG $0xffffffff
+ LONG $0x000000ff
+
+ LONG $0xffffffff
+ LONG $0xffffffff
+ LONG $0xffffffff
+ LONG $0x0000ffff
+
+ LONG $0xffffffff
+ LONG $0xffffffff
+ LONG $0xffffffff
+ LONG $0x00ffffff
+
+ // these are arguments to pshufb. They move data down from
+ // the high bytes of the register to the low bytes of the register.
+ // index is how many bytes to move.
+TEXT shifts(SB),7,$0
+ LONG $0x00000000
+ LONG $0x00000000
+ LONG $0x00000000
+ LONG $0x00000000
+
+ LONG $0xffffff0f
+ LONG $0xffffffff
+ LONG $0xffffffff
+ LONG $0xffffffff
+
+ LONG $0xffff0f0e
+ LONG $0xffffffff
+ LONG $0xffffffff
+ LONG $0xffffffff
+
+ LONG $0xff0f0e0d
+ LONG $0xffffffff
+ LONG $0xffffffff
+ LONG $0xffffffff
+
+ LONG $0x0f0e0d0c
+ LONG $0xffffffff
+ LONG $0xffffffff
+ LONG $0xffffffff
+
+ LONG $0x0e0d0c0b
+ LONG $0xffffff0f
+ LONG $0xffffffff
+ LONG $0xffffffff
+
+ LONG $0x0d0c0b0a
+ LONG $0xffff0f0e
+ LONG $0xffffffff
+ LONG $0xffffffff
+
+ LONG $0x0c0b0a09
+ LONG $0xff0f0e0d
+ LONG $0xffffffff
+ LONG $0xffffffff
+
+ LONG $0x0b0a0908
+ LONG $0x0f0e0d0c
+ LONG $0xffffffff
+ LONG $0xffffffff
+
+ LONG $0x0a090807
+ LONG $0x0e0d0c0b
+ LONG $0xffffff0f
+ LONG $0xffffffff
+
+ LONG $0x09080706
+ LONG $0x0d0c0b0a
+ LONG $0xffff0f0e
+ LONG $0xffffffff
+
+ LONG $0x08070605
+ LONG $0x0c0b0a09
+ LONG $0xff0f0e0d
+ LONG $0xffffffff
+
+ LONG $0x07060504
+ LONG $0x0b0a0908
+ LONG $0x0f0e0d0c
+ LONG $0xffffffff
+
+ LONG $0x06050403
+ LONG $0x0a090807
+ LONG $0x0e0d0c0b
+ LONG $0xffffff0f
+
+ LONG $0x05040302
+ LONG $0x09080706
+ LONG $0x0d0c0b0a
+ LONG $0xffff0f0e
+
+ LONG $0x04030201
+ LONG $0x08070605
+ LONG $0x0c0b0a09
+ LONG $0xff0f0e0d
+
+TEXT runtime·memeq(SB),7,$0
+ MOVL a+0(FP), SI
+ MOVL b+4(FP), DI
+ MOVL count+8(FP), BX
+ JMP runtime·memeqbody(SB)
+
+
+TEXT bytes·Equal(SB),7,$0
+ MOVL a_len+4(FP), BX
+ MOVL b_len+16(FP), CX
+ XORL AX, AX
+ CMPL BX, CX
+ JNE eqret
+ MOVL a+0(FP), SI
+ MOVL b+12(FP), DI
+ CALL runtime·memeqbody(SB)
+eqret:
+ MOVB AX, ret+24(FP)
+ RET
+
+// a in SI
+// b in DI
+// count in BX
+TEXT runtime·memeqbody(SB),7,$0
+ XORL AX, AX
+
+ CMPL BX, $4
+ JB small
+
+ // 64 bytes at a time using xmm registers
+hugeloop:
+ CMPL BX, $64
+ JB bigloop
+ TESTL $0x4000000, runtime·cpuid_edx(SB) // check for sse2
+ JE bigloop
+ MOVOU (SI), X0
+ MOVOU (DI), X1
+ MOVOU 16(SI), X2
+ MOVOU 16(DI), X3
+ MOVOU 32(SI), X4
+ MOVOU 32(DI), X5
+ MOVOU 48(SI), X6
+ MOVOU 48(DI), X7
+ PCMPEQB X1, X0
+ PCMPEQB X3, X2
+ PCMPEQB X5, X4
+ PCMPEQB X7, X6
+ PAND X2, X0
+ PAND X6, X4
+ PAND X4, X0
+ PMOVMSKB X0, DX
+ ADDL $64, SI
+ ADDL $64, DI
+ SUBL $64, BX
+ CMPL DX, $0xffff
+ JEQ hugeloop
+ RET
+
+ // 4 bytes at a time using 32-bit register
+bigloop:
+ CMPL BX, $4
+ JBE leftover
+ MOVL (SI), CX
+ MOVL (DI), DX
+ ADDL $4, SI
+ ADDL $4, DI
+ SUBL $4, BX
+ CMPL CX, DX
+ JEQ bigloop
+ RET
+
+ // remaining 0-4 bytes
+leftover:
+ MOVL -4(SI)(BX*1), CX
+ MOVL -4(DI)(BX*1), DX
+ CMPL CX, DX
+ SETEQ AX
+ RET
+
+small:
+ CMPL BX, $0
+ JEQ equal
+
+ LEAL 0(BX*8), CX
+ NEGL CX
+
+ MOVL SI, DX
+ CMPB DX, $0xfc
+ JA si_high
+
+ // load at SI won't cross a page boundary.
+ MOVL (SI), SI
+ JMP si_finish
+si_high:
+ // address ends in 111111xx. Load up to bytes we want, move to correct position.
+ MOVL -4(SI)(BX*1), SI
+ SHRL CX, SI
+si_finish:
+
+ // same for DI.
+ MOVL DI, DX
+ CMPB DX, $0xfc
+ JA di_high
+ MOVL (DI), DI
+ JMP di_finish
+di_high:
+ MOVL -4(DI)(BX*1), DI
+ SHRL CX, DI
+di_finish:
+
+ SUBL SI, DI
+ SHLL CX, DI
+equal:
+ SETEQ AX
+ RET
diff --git a/src/pkg/runtime/asm_amd64.s b/src/pkg/runtime/asm_amd64.s
index 987958498..0dee1556d 100644
--- a/src/pkg/runtime/asm_amd64.s
+++ b/src/pkg/runtime/asm_amd64.s
@@ -6,8 +6,8 @@
TEXT _rt0_amd64(SB),7,$-8
// copy arguments forward on an even stack
- MOVQ 0(DI), AX // argc
- LEAQ 8(DI), BX // argv
+ MOVQ DI, AX // argc
+ MOVQ SI, BX // argv
SUBQ $(4*8+7), SP // 2args 2auto
ANDQ $~15, SP
MOVQ AX, 16(SP)
@@ -20,12 +20,24 @@ TEXT _rt0_amd64(SB),7,$-8
MOVQ BX, g_stackguard(DI)
MOVQ SP, g_stackbase(DI)
+ // find out information about the processor we're on
+ MOVQ $0, AX
+ CPUID
+ CMPQ AX, $0
+ JE nocpuinfo
+ MOVQ $1, AX
+ CPUID
+ MOVL CX, runtime·cpuid_ecx(SB)
+ MOVL DX, runtime·cpuid_edx(SB)
+nocpuinfo:
+
// if there is an _cgo_init, call it.
MOVQ _cgo_init(SB), AX
TESTQ AX, AX
JZ needtls
// g0 already in DI
MOVQ DI, CX // Win64 uses CX for first parameter
+ MOVQ $setmg_gcc<>(SB), SI
CALL AX
CMPL runtime·iswindows(SB), $0
JEQ ok
@@ -65,6 +77,7 @@ ok:
MOVQ AX, 8(SP)
CALL runtime·args(SB)
CALL runtime·osinit(SB)
+ CALL runtime·hashinit(SB)
CALL runtime·schedinit(SB)
// create a new goroutine to start program
@@ -442,6 +455,12 @@ TEXT runtime·xchg(SB), 7, $0
XCHGL AX, 0(BX)
RET
+TEXT runtime·xchg64(SB), 7, $0
+ MOVQ 8(SP), BX
+ MOVQ 16(SP), AX
+ XCHGQ AX, 0(BX)
+ RET
+
TEXT runtime·procyield(SB),7,$0
MOVL 8(SP), AX
again:
@@ -664,6 +683,13 @@ settls:
MOVQ BX, g(CX)
RET
+// void setmg_gcc(M*, G*); set m and g called from gcc.
+TEXT setmg_gcc<>(SB),7,$0
+ get_tls(AX)
+ MOVQ DI, m(AX)
+ MOVQ SI, g(AX)
+ RET
+
// check that SP is in range [g->stackbase, g->stackguard)
TEXT runtime·stackcheck(SB), 7, $0
get_tls(CX)
@@ -719,7 +745,277 @@ TEXT runtime·stackguard(SB),7,$0
get_tls(CX)
MOVQ g(CX), BX
MOVQ g_stackguard(BX), DX
- MOVQ DX, guard+8(FP)
+ MOVQ DX, limit+8(FP)
RET
GLOBL runtime·tls0(SB), $64
+
+// hash function using AES hardware instructions
+TEXT runtime·aeshash(SB),7,$0
+ MOVQ 8(SP), DX // ptr to hash value
+ MOVQ 16(SP), CX // size
+ MOVQ 24(SP), AX // ptr to data
+ JMP runtime·aeshashbody(SB)
+
+TEXT runtime·aeshashstr(SB),7,$0
+ MOVQ 8(SP), DX // ptr to hash value
+ MOVQ 24(SP), AX // ptr to string struct
+ MOVQ 8(AX), CX // length of string
+ MOVQ (AX), AX // string data
+ JMP runtime·aeshashbody(SB)
+
+// AX: data
+// CX: length
+// DX: ptr to seed input / hash output
+TEXT runtime·aeshashbody(SB),7,$0
+ MOVQ (DX), X0 // seed to low 64 bits of xmm0
+ PINSRQ $1, CX, X0 // size to high 64 bits of xmm0
+ MOVO runtime·aeskeysched+0(SB), X2
+ MOVO runtime·aeskeysched+16(SB), X3
+aesloop:
+ CMPQ CX, $16
+ JB aesloopend
+ MOVOU (AX), X1
+ AESENC X2, X0
+ AESENC X1, X0
+ SUBQ $16, CX
+ ADDQ $16, AX
+ JMP aesloop
+aesloopend:
+ TESTQ CX, CX
+ JE finalize // no partial block
+
+ TESTQ $16, AX
+ JNE highpartial
+
+ // address ends in 0xxxx. 16 bytes loaded
+ // at this address won't cross a page boundary, so
+ // we can load it directly.
+ MOVOU (AX), X1
+ ADDQ CX, CX
+ PAND masks(SB)(CX*8), X1
+ JMP partial
+highpartial:
+ // address ends in 1xxxx. Might be up against
+ // a page boundary, so load ending at last byte.
+ // Then shift bytes down using pshufb.
+ MOVOU -16(AX)(CX*1), X1
+ ADDQ CX, CX
+ PSHUFB shifts(SB)(CX*8), X1
+partial:
+ // incorporate partial block into hash
+ AESENC X3, X0
+ AESENC X1, X0
+finalize:
+ // finalize hash
+ AESENC X2, X0
+ AESENC X3, X0
+ AESENC X2, X0
+ MOVQ X0, (DX)
+ RET
+
+TEXT runtime·aeshash32(SB),7,$0
+ MOVQ 8(SP), DX // ptr to hash value
+ MOVQ 24(SP), AX // ptr to data
+ MOVQ (DX), X0 // seed
+ PINSRD $2, (AX), X0 // data
+ AESENC runtime·aeskeysched+0(SB), X0
+ AESENC runtime·aeskeysched+16(SB), X0
+ AESENC runtime·aeskeysched+0(SB), X0
+ MOVQ X0, (DX)
+ RET
+
+TEXT runtime·aeshash64(SB),7,$0
+ MOVQ 8(SP), DX // ptr to hash value
+ MOVQ 24(SP), AX // ptr to data
+ MOVQ (DX), X0 // seed
+ PINSRQ $1, (AX), X0 // data
+ AESENC runtime·aeskeysched+0(SB), X0
+ AESENC runtime·aeskeysched+16(SB), X0
+ AESENC runtime·aeskeysched+0(SB), X0
+ MOVQ X0, (DX)
+ RET
+
+// simple mask to get rid of data in the high part of the register.
+TEXT masks(SB),7,$0
+ QUAD $0x0000000000000000
+ QUAD $0x0000000000000000
+ QUAD $0x00000000000000ff
+ QUAD $0x0000000000000000
+ QUAD $0x000000000000ffff
+ QUAD $0x0000000000000000
+ QUAD $0x0000000000ffffff
+ QUAD $0x0000000000000000
+ QUAD $0x00000000ffffffff
+ QUAD $0x0000000000000000
+ QUAD $0x000000ffffffffff
+ QUAD $0x0000000000000000
+ QUAD $0x0000ffffffffffff
+ QUAD $0x0000000000000000
+ QUAD $0x00ffffffffffffff
+ QUAD $0x0000000000000000
+ QUAD $0xffffffffffffffff
+ QUAD $0x0000000000000000
+ QUAD $0xffffffffffffffff
+ QUAD $0x00000000000000ff
+ QUAD $0xffffffffffffffff
+ QUAD $0x000000000000ffff
+ QUAD $0xffffffffffffffff
+ QUAD $0x0000000000ffffff
+ QUAD $0xffffffffffffffff
+ QUAD $0x00000000ffffffff
+ QUAD $0xffffffffffffffff
+ QUAD $0x000000ffffffffff
+ QUAD $0xffffffffffffffff
+ QUAD $0x0000ffffffffffff
+ QUAD $0xffffffffffffffff
+ QUAD $0x00ffffffffffffff
+
+ // these are arguments to pshufb. They move data down from
+ // the high bytes of the register to the low bytes of the register.
+ // index is how many bytes to move.
+TEXT shifts(SB),7,$0
+ QUAD $0x0000000000000000
+ QUAD $0x0000000000000000
+ QUAD $0xffffffffffffff0f
+ QUAD $0xffffffffffffffff
+ QUAD $0xffffffffffff0f0e
+ QUAD $0xffffffffffffffff
+ QUAD $0xffffffffff0f0e0d
+ QUAD $0xffffffffffffffff
+ QUAD $0xffffffff0f0e0d0c
+ QUAD $0xffffffffffffffff
+ QUAD $0xffffff0f0e0d0c0b
+ QUAD $0xffffffffffffffff
+ QUAD $0xffff0f0e0d0c0b0a
+ QUAD $0xffffffffffffffff
+ QUAD $0xff0f0e0d0c0b0a09
+ QUAD $0xffffffffffffffff
+ QUAD $0x0f0e0d0c0b0a0908
+ QUAD $0xffffffffffffffff
+ QUAD $0x0e0d0c0b0a090807
+ QUAD $0xffffffffffffff0f
+ QUAD $0x0d0c0b0a09080706
+ QUAD $0xffffffffffff0f0e
+ QUAD $0x0c0b0a0908070605
+ QUAD $0xffffffffff0f0e0d
+ QUAD $0x0b0a090807060504
+ QUAD $0xffffffff0f0e0d0c
+ QUAD $0x0a09080706050403
+ QUAD $0xffffff0f0e0d0c0b
+ QUAD $0x0908070605040302
+ QUAD $0xffff0f0e0d0c0b0a
+ QUAD $0x0807060504030201
+ QUAD $0xff0f0e0d0c0b0a09
+
+TEXT runtime·memeq(SB),7,$0
+ MOVQ a+0(FP), SI
+ MOVQ b+8(FP), DI
+ MOVQ count+16(FP), BX
+ JMP runtime·memeqbody(SB)
+
+
+TEXT bytes·Equal(SB),7,$0
+ MOVQ a_len+8(FP), BX
+ MOVQ b_len+32(FP), CX
+ XORQ AX, AX
+ CMPQ BX, CX
+ JNE eqret
+ MOVQ a+0(FP), SI
+ MOVQ b+24(FP), DI
+ CALL runtime·memeqbody(SB)
+eqret:
+ MOVB AX, ret+48(FP)
+ RET
+
+// a in SI
+// b in DI
+// count in BX
+TEXT runtime·memeqbody(SB),7,$0
+ XORQ AX, AX
+
+ CMPQ BX, $8
+ JB small
+
+ // 64 bytes at a time using xmm registers
+hugeloop:
+ CMPQ BX, $64
+ JB bigloop
+ MOVOU (SI), X0
+ MOVOU (DI), X1
+ MOVOU 16(SI), X2
+ MOVOU 16(DI), X3
+ MOVOU 32(SI), X4
+ MOVOU 32(DI), X5
+ MOVOU 48(SI), X6
+ MOVOU 48(DI), X7
+ PCMPEQB X1, X0
+ PCMPEQB X3, X2
+ PCMPEQB X5, X4
+ PCMPEQB X7, X6
+ PAND X2, X0
+ PAND X6, X4
+ PAND X4, X0
+ PMOVMSKB X0, DX
+ ADDQ $64, SI
+ ADDQ $64, DI
+ SUBQ $64, BX
+ CMPL DX, $0xffff
+ JEQ hugeloop
+ RET
+
+ // 8 bytes at a time using 64-bit register
+bigloop:
+ CMPQ BX, $8
+ JBE leftover
+ MOVQ (SI), CX
+ MOVQ (DI), DX
+ ADDQ $8, SI
+ ADDQ $8, DI
+ SUBQ $8, BX
+ CMPQ CX, DX
+ JEQ bigloop
+ RET
+
+ // remaining 0-8 bytes
+leftover:
+ MOVQ -8(SI)(BX*1), CX
+ MOVQ -8(DI)(BX*1), DX
+ CMPQ CX, DX
+ SETEQ AX
+ RET
+
+small:
+ CMPQ BX, $0
+ JEQ equal
+
+ LEAQ 0(BX*8), CX
+ NEGQ CX
+
+ CMPB SI, $0xf8
+ JA si_high
+
+ // load at SI won't cross a page boundary.
+ MOVQ (SI), SI
+ JMP si_finish
+si_high:
+ // address ends in 11111xxx. Load up to bytes we want, move to correct position.
+ MOVQ -8(SI)(BX*1), SI
+ SHRQ CX, SI
+si_finish:
+
+ // same for DI.
+ CMPB DI, $0xf8
+ JA di_high
+ MOVQ (DI), DI
+ JMP di_finish
+di_high:
+ MOVQ -8(DI)(BX*1), DI
+ SHRQ CX, DI
+di_finish:
+
+ SUBQ SI, DI
+ SHLQ CX, DI
+equal:
+ SETEQ AX
+ RET
diff --git a/src/pkg/runtime/asm_arm.s b/src/pkg/runtime/asm_arm.s
index 45b53541b..fed9b3021 100644
--- a/src/pkg/runtime/asm_arm.s
+++ b/src/pkg/runtime/asm_arm.s
@@ -47,6 +47,7 @@ TEXT _rt0_arm(SB),7,$-4
MOVW R1, 8(R13)
BL runtime·args(SB)
BL runtime·osinit(SB)
+ BL runtime·hashinit(SB)
BL runtime·schedinit(SB)
// create a new goroutine to start program
@@ -325,7 +326,7 @@ TEXT runtime·cgocallback(SB),7,$12
// cgocallback_gofunc(void (*fn)(void*), void *frame, uintptr framesize)
// See cgocall.c for more details.
-TEXT runtime·cgocallback_gofunc(SB),7,$16
+TEXT runtime·cgocallback_gofunc(SB),7,$12
// Load m and g from thread-local storage.
MOVW _cgo_load_gm(SB), R0
CMP $0, R0
@@ -336,7 +337,7 @@ TEXT runtime·cgocallback_gofunc(SB),7,$16
// In this case, we're running on the thread stack, so there's
// lots of space, but the linker doesn't know. Hide the call from
// the linker analysis by using an indirect call.
- MOVW m, savedm-16(SP)
+ MOVW m, savedm-12(SP)
CMP $0, m
B.NE havem
MOVW $runtime·needm(SB), R0
@@ -347,10 +348,6 @@ havem:
// Save current m->g0->sched.sp on stack and then set it to SP.
// Save current sp in m->g0->sched.sp in preparation for
// switch back to m->curg stack.
- MOVW fn+0(FP), R0
- MOVW frame+4(FP), R1
- MOVW framesize+8(FP), R2
-
MOVW m_g0(m), R3
MOVW (g_sched+gobuf_sp)(R3), R4
MOVW.W R4, -4(R13)
@@ -367,23 +364,23 @@ havem:
// This has the added benefit that it looks to the traceback
// routine like cgocallbackg is going to return to that
// PC (because we defined cgocallbackg to have
- // a frame size of 16, the same amount that we use below),
+ // a frame size of 12, the same amount that we use below),
// so that the traceback will seamlessly trace back into
// the earlier calls.
+ MOVW fn+4(FP), R0
+ MOVW frame+8(FP), R1
+ MOVW framesize+12(FP), R2
- // Save current m->g0->sched.sp on stack and then set it to SP.
MOVW m_curg(m), g
MOVW (g_sched+gobuf_sp)(g), R4 // prepare stack as R4
// Push gobuf.pc
MOVW (g_sched+gobuf_pc)(g), R5
- SUB $4, R4
- MOVW R5, 0(R4)
+ MOVW.W R5, -16(R4)
// Push arguments to cgocallbackg.
// Frame size here must match the frame size above
// to trick traceback routines into doing the right thing.
- SUB $16, R4
MOVW R0, 4(R4)
MOVW R1, 8(R4)
MOVW R2, 12(R4)
@@ -393,10 +390,10 @@ havem:
BL runtime·cgocallbackg(SB)
// Restore g->gobuf (== m->curg->gobuf) from saved values.
- MOVW 16(R13), R5
+ MOVW 0(R13), R5
MOVW R5, (g_sched+gobuf_pc)(g)
- ADD $(16+4), R13 // SP clobbered! It is ok!
- MOVW R13, (g_sched+gobuf_sp)(g)
+ ADD $(12+4), R13, R4
+ MOVW R4, (g_sched+gobuf_sp)(g)
// Switch back to m->g0's stack and restore m->g0->sched.sp.
// (Unlike m->curg, the g0 goroutine never uses sched.pc,
@@ -410,7 +407,7 @@ havem:
// If the m on entry was nil, we called needm above to borrow an m
// for the duration of the call. Since the call is over, return it with dropm.
- MOVW savedm-16(SP), R6
+ MOVW savedm-12(SP), R6
CMP $0, R6
B.NE 3(PC)
MOVW $runtime·dropm(SB), R0
@@ -420,7 +417,7 @@ havem:
RET
// void setmg(M*, G*); set m and g. for use by needm.
-TEXT runtime·setmg(SB), 7, $-4
+TEXT runtime·setmg(SB), 7, $0
MOVW mm+0(FP), m
MOVW gg+4(FP), g
@@ -489,3 +486,34 @@ TEXT runtime·stackguard(SB),7,$0
MOVW R1, sp+0(FP)
MOVW R2, limit+4(FP)
RET
+
+// AES hashing not implemented for ARM
+TEXT runtime·aeshash(SB),7,$-4
+ MOVW $0, R0
+ MOVW (R0), R1
+TEXT runtime·aeshash32(SB),7,$-4
+ MOVW $0, R0
+ MOVW (R0), R1
+TEXT runtime·aeshash64(SB),7,$-4
+ MOVW $0, R0
+ MOVW (R0), R1
+TEXT runtime·aeshashstr(SB),7,$-4
+ MOVW $0, R0
+ MOVW (R0), R1
+
+TEXT runtime·memeq(SB),7,$-4
+ MOVW a+0(FP), R1
+ MOVW b+4(FP), R2
+ MOVW n+8(FP), R3
+ ADD R1, R3, R6
+ MOVW $1, R0
+_next:
+ CMP R1, R6
+ RET.EQ
+ MOVBU.P 1(R1), R4
+ MOVBU.P 1(R2), R5
+ CMP R4, R5
+ BEQ _next
+
+ MOVW $0, R0
+ RET
diff --git a/src/pkg/runtime/atomic_386.c b/src/pkg/runtime/atomic_386.c
index 79b7cbf96..1046eb81e 100644
--- a/src/pkg/runtime/atomic_386.c
+++ b/src/pkg/runtime/atomic_386.c
@@ -30,3 +30,16 @@ runtime·xadd64(uint64 volatile* addr, int64 v)
}
return old+v;
}
+
+#pragma textflag 7
+uint64
+runtime·xchg64(uint64 volatile* addr, uint64 v)
+{
+ uint64 old;
+
+ old = *addr;
+ while(!runtime·cas64(addr, &old, v)) {
+ // nothing
+ }
+ return old;
+}
diff --git a/src/pkg/runtime/atomic_arm.c b/src/pkg/runtime/atomic_arm.c
index 0b54840cc..a78b1dfe2 100644
--- a/src/pkg/runtime/atomic_arm.c
+++ b/src/pkg/runtime/atomic_arm.c
@@ -5,9 +5,9 @@
#include "runtime.h"
#include "arch_GOARCH.h"
-static union {
+static struct {
Lock l;
- byte pad [CacheLineSize];
+ byte pad[CacheLineSize-sizeof(Lock)];
} locktab[57];
#define LOCK(addr) (&locktab[((uintptr)(addr)>>3)%nelem(locktab)].l)
@@ -123,6 +123,19 @@ runtime·xadd64(uint64 volatile *addr, int64 delta)
#pragma textflag 7
uint64
+runtime·xchg64(uint64 volatile *addr, uint64 v)
+{
+ uint64 res;
+
+ runtime·lock(LOCK(addr));
+ res = *addr;
+ *addr = v;
+ runtime·unlock(LOCK(addr));
+ return res;
+}
+
+#pragma textflag 7
+uint64
runtime·atomicload64(uint64 volatile *addr)
{
uint64 res;
diff --git a/src/pkg/runtime/cgo/callbacks.c b/src/pkg/runtime/cgo/callbacks.c
index 51bd529ec..524f30428 100644
--- a/src/pkg/runtime/cgo/callbacks.c
+++ b/src/pkg/runtime/cgo/callbacks.c
@@ -12,8 +12,10 @@
// void crosscall2(void (*fn)(void *, int), void *, int);
//
// We need to export the symbol crosscall2 in order to support
-// callbacks from shared libraries.
-#pragma dynexport crosscall2 crosscall2
+// callbacks from shared libraries. This applies regardless of
+// linking mode.
+#pragma cgo_export_static crosscall2
+#pragma cgo_export_dynamic crosscall2
// Allocate memory. This allocates the requested number of bytes in
// memory controlled by the Go runtime. The allocated memory will be
@@ -43,7 +45,8 @@ _cgo_allocate_internal(uintptr len, byte *ret)
FLUSH(&ret);
}
-#pragma dynexport _cgo_allocate _cgo_allocate
+#pragma cgo_export_static _cgo_allocate
+#pragma cgo_export_dynamic _cgo_allocate
void
_cgo_allocate(void *a, int32 n)
{
@@ -71,7 +74,8 @@ _cgo_panic_internal(byte *p)
runtime·panic(err);
}
-#pragma dynexport _cgo_panic _cgo_panic
+#pragma cgo_export_static _cgo_panic
+#pragma cgo_export_dynamic _cgo_panic
void
_cgo_panic(void *a, int32 n)
{
diff --git a/src/pkg/runtime/cgo/gcc_386.S b/src/pkg/runtime/cgo/gcc_386.S
index 94ba5842f..bf4142793 100644
--- a/src/pkg/runtime/cgo/gcc_386.S
+++ b/src/pkg/runtime/cgo/gcc_386.S
@@ -40,3 +40,6 @@ EXT(__stack_chk_fail_local):
1:
jmp 1b
+#ifdef __ELF__
+.section .note.GNU-stack,"",@progbits
+#endif
diff --git a/src/pkg/runtime/cgo/gcc_amd64.S b/src/pkg/runtime/cgo/gcc_amd64.S
index 81b270195..32d0200cf 100644
--- a/src/pkg/runtime/cgo/gcc_amd64.S
+++ b/src/pkg/runtime/cgo/gcc_amd64.S
@@ -42,3 +42,7 @@ EXT(crosscall_amd64):
popq %rbp
popq %rbx
ret
+
+#ifdef __ELF__
+.section .note.GNU-stack,"",@progbits
+#endif
diff --git a/src/pkg/runtime/cgo/gcc_arm.S b/src/pkg/runtime/cgo/gcc_arm.S
index 809fcb9a0..3ec6e5d97 100644
--- a/src/pkg/runtime/cgo/gcc_arm.S
+++ b/src/pkg/runtime/cgo/gcc_arm.S
@@ -34,3 +34,6 @@ EXT(__stack_chk_fail_local):
1:
b 1b
+#ifdef __ELF__
+.section .note.GNU-stack,"",%progbits
+#endif
diff --git a/src/pkg/runtime/cgo/gcc_freebsd_386.c b/src/pkg/runtime/cgo/gcc_freebsd_386.c
index 7c62a1bc4..6797824c6 100644
--- a/src/pkg/runtime/cgo/gcc_freebsd_386.c
+++ b/src/pkg/runtime/cgo/gcc_freebsd_386.c
@@ -10,13 +10,15 @@
#include "libcgo.h"
static void* threadentry(void*);
+static void (*setmg_gcc)(void*, void*);
void
-x_cgo_init(G *g)
+x_cgo_init(G *g, void (*setmg)(void*, void*))
{
pthread_attr_t attr;
size_t size;
+ setmg_gcc = setmg;
pthread_attr_init(&attr);
pthread_attr_getstacksize(&attr, &size);
g->stackguard = (uintptr)&attr - size + 4096;
@@ -66,15 +68,9 @@ threadentry(void *v)
ts.g->stackguard = (uintptr)&ts - ts.g->stackguard + 4096;
/*
- * Set specific keys. On FreeBSD/ELF, the thread local storage
- * is just before %gs:0. Our dynamic 8.out's reserve 8 bytes
- * for the two words g and m at %gs:-8 and %gs:-4.
+ * Set specific keys.
*/
- asm volatile (
- "movl %0, %%gs:-8\n" // MOVL g, -8(GS)
- "movl %1, %%gs:-4\n" // MOVL m, -4(GS)
- :: "r"(ts.g), "r"(ts.m)
- );
+ setmg_gcc((void*)ts.m, (void*)ts.g);
crosscall_386(ts.fn);
return nil;
diff --git a/src/pkg/runtime/cgo/gcc_freebsd_amd64.c b/src/pkg/runtime/cgo/gcc_freebsd_amd64.c
index 6be8bd251..eb342a2ff 100644
--- a/src/pkg/runtime/cgo/gcc_freebsd_amd64.c
+++ b/src/pkg/runtime/cgo/gcc_freebsd_amd64.c
@@ -10,20 +10,21 @@
#include "libcgo.h"
static void* threadentry(void*);
+static void (*setmg_gcc)(void*, void*);
void
-x_cgo_init(G *g)
+x_cgo_init(G *g, void (*setmg)(void*, void*))
{
pthread_attr_t attr;
size_t size;
+ setmg_gcc = setmg;
pthread_attr_init(&attr);
pthread_attr_getstacksize(&attr, &size);
g->stackguard = (uintptr)&attr - size + 4096;
pthread_attr_destroy(&attr);
}
-
void
_cgo_sys_thread_start(ThreadStart *ts)
{
@@ -67,15 +68,10 @@ threadentry(void *v)
ts.g->stackguard = (uintptr)&ts - ts.g->stackguard + 4096;
/*
- * Set specific keys. On FreeBSD/ELF, the thread local storage
- * is just before %fs:0. Our dynamic 6.out's reserve 16 bytes
- * for the two words g and m at %fs:-16 and %fs:-8.
+ * Set specific keys.
*/
- asm volatile (
- "movq %0, %%fs:-16\n" // MOVL g, -16(FS)
- "movq %1, %%fs:-8\n" // MOVL m, -8(FS)
- :: "r"(ts.g), "r"(ts.m)
- );
+ setmg_gcc((void*)ts.m, (void*)ts.g);
+
crosscall_amd64(ts.fn);
return nil;
}
diff --git a/src/pkg/runtime/cgo/gcc_freebsd_arm.c b/src/pkg/runtime/cgo/gcc_freebsd_arm.c
index 3bcb0b270..73c990c28 100644
--- a/src/pkg/runtime/cgo/gcc_freebsd_arm.c
+++ b/src/pkg/runtime/cgo/gcc_freebsd_arm.c
@@ -2,6 +2,8 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
+#include <sys/types.h>
+#include <machine/sysarch.h>
#include <pthread.h>
#include <string.h>
#include "libcgo.h"
@@ -22,10 +24,20 @@ void x_cgo_load_gm(void) __attribute__((naked));
void
__aeabi_read_tp(void)
{
- // read @ 0xffff1000
__asm__ __volatile__ (
+#ifdef ARM_TP_ADDRESS
+ // ARM_TP_ADDRESS is (ARM_VECTORS_HIGH + 0x1000) or 0xffff1000
+ // GCC inline asm doesn't provide a way to provide a constant
+ // to "ldr r0, =??" pseudo instruction, so we hardcode the value
+ // and check it with cpp.
+#if ARM_TP_ADDRESS != 0xffff1000
+#error Wrong ARM_TP_ADDRESS!
+#endif
"ldr r0, =0xffff1000\n\t"
"ldr r0, [r0]\n\t"
+#else
+ "mrc p15, 0, r0, c13, c0, 3\n\t"
+#endif
"mov pc, lr\n\t"
);
}
diff --git a/src/pkg/runtime/cgo/gcc_linux_386.c b/src/pkg/runtime/cgo/gcc_linux_386.c
index 9357a63f7..c25c7b70f 100644
--- a/src/pkg/runtime/cgo/gcc_linux_386.c
+++ b/src/pkg/runtime/cgo/gcc_linux_386.c
@@ -8,13 +8,15 @@
#include "libcgo.h"
static void *threadentry(void*);
+static void (*setmg_gcc)(void*, void*);
void
-x_cgo_init(G *g)
+x_cgo_init(G *g, void (*setmg)(void*, void*))
{
pthread_attr_t attr;
size_t size;
+ setmg_gcc = setmg;
pthread_attr_init(&attr);
pthread_attr_getstacksize(&attr, &size);
g->stackguard = (uintptr)&attr - size + 4096;
@@ -69,18 +71,9 @@ threadentry(void *v)
ts.g->stackguard = (uintptr)&ts - ts.g->stackguard + 4096;
/*
- * Set specific keys. On Linux/ELF, the thread local storage
- * is just before %gs:0. Our dynamic 8.out's reserve 8 bytes
- * for the two words g and m at %gs:-8 and %gs:-4.
- * Xen requires us to access those words indirect from %gs:0
- * which points at itself.
+ * Set specific keys.
*/
- asm volatile (
- "movl %%gs:0, %%eax\n" // MOVL 0(GS), tmp
- "movl %0, -8(%%eax)\n" // MOVL g, -8(GS)
- "movl %1, -4(%%eax)\n" // MOVL m, -4(GS)
- :: "r"(ts.g), "r"(ts.m) : "%eax"
- );
+ setmg_gcc((void*)ts.m, (void*)ts.g);
crosscall_386(ts.fn);
return nil;
diff --git a/src/pkg/runtime/cgo/gcc_linux_amd64.c b/src/pkg/runtime/cgo/gcc_linux_amd64.c
index bc76117d3..bd7c88d99 100644
--- a/src/pkg/runtime/cgo/gcc_linux_amd64.c
+++ b/src/pkg/runtime/cgo/gcc_linux_amd64.c
@@ -8,13 +8,15 @@
#include "libcgo.h"
static void* threadentry(void*);
+static void (*setmg_gcc)(void*, void*);
void
-x_cgo_init(G* g)
+x_cgo_init(G* g, void (*setmg)(void*, void*))
{
pthread_attr_t attr;
size_t size;
+ setmg_gcc = setmg;
pthread_attr_init(&attr);
pthread_attr_getstacksize(&attr, &size);
g->stackguard = (uintptr)&attr - size + 4096;
@@ -64,15 +66,10 @@ threadentry(void *v)
ts.g->stackguard = (uintptr)&ts - ts.g->stackguard + 4096;
/*
- * Set specific keys. On Linux/ELF, the thread local storage
- * is just before %fs:0. Our dynamic 6.out's reserve 16 bytes
- * for the two words g and m at %fs:-16 and %fs:-8.
+ * Set specific keys.
*/
- asm volatile (
- "movq %0, %%fs:-16\n" // MOVL g, -16(FS)
- "movq %1, %%fs:-8\n" // MOVL m, -8(FS)
- :: "r"(ts.g), "r"(ts.m)
- );
+ setmg_gcc((void*)ts.m, (void*)ts.g);
+
crosscall_amd64(ts.fn);
return nil;
}
diff --git a/src/pkg/runtime/cgo/gcc_netbsd_386.c b/src/pkg/runtime/cgo/gcc_netbsd_386.c
index 09b271df4..b399e16dc 100644
--- a/src/pkg/runtime/cgo/gcc_netbsd_386.c
+++ b/src/pkg/runtime/cgo/gcc_netbsd_386.c
@@ -9,13 +9,15 @@
#include "libcgo.h"
static void* threadentry(void*);
+static void (*setmg_gcc)(void*, void*);
void
-x_cgo_init(G *g)
+x_cgo_init(G *g, void (*setmg)(void*, void*))
{
pthread_attr_t attr;
size_t size;
+ setmg_gcc = setmg;
pthread_attr_init(&attr);
pthread_attr_getstacksize(&attr, &size);
g->stackguard = (uintptr)&attr - size + 4096;
@@ -65,15 +67,9 @@ threadentry(void *v)
ts.g->stackguard = (uintptr)&ts - ts.g->stackguard + 4096;
/*
- * Set specific keys. On NetBSD/ELF, the thread local storage
- * is just before %gs:0. Our dynamic 8.out's reserve 8 bytes
- * for the two words g and m at %gs:-8 and %gs:-4.
+ * Set specific keys.
*/
- asm volatile (
- "movl %0, %%gs:-8\n" // MOVL g, -8(GS)
- "movl %1, %%gs:-4\n" // MOVL m, -4(GS)
- :: "r"(ts.g), "r"(ts.m)
- );
+ setmg_gcc((void*)ts.m, (void*)ts.g);
crosscall_386(ts.fn);
return nil;
diff --git a/src/pkg/runtime/cgo/gcc_netbsd_amd64.c b/src/pkg/runtime/cgo/gcc_netbsd_amd64.c
index 080c59ba4..f27e142ce 100644
--- a/src/pkg/runtime/cgo/gcc_netbsd_amd64.c
+++ b/src/pkg/runtime/cgo/gcc_netbsd_amd64.c
@@ -9,13 +9,15 @@
#include "libcgo.h"
static void* threadentry(void*);
+static void (*setmg_gcc)(void*, void*);
void
-x_cgo_init(G *g)
+x_cgo_init(G *g, void (*setmg)(void*, void*))
{
pthread_attr_t attr;
size_t size;
+ setmg_gcc = setmg;
pthread_attr_init(&attr);
pthread_attr_getstacksize(&attr, &size);
g->stackguard = (uintptr)&attr - size + 4096;
@@ -66,15 +68,10 @@ threadentry(void *v)
ts.g->stackguard = (uintptr)&ts - ts.g->stackguard + 4096;
/*
- * Set specific keys. On NetBSD/ELF, the thread local storage
- * is just before %fs:0. Our dynamic 6.out's reserve 16 bytes
- * for the two words g and m at %fs:-16 and %fs:-8.
+ * Set specific keys.
*/
- asm volatile (
- "movq %0, %%fs:-16\n" // MOVL g, -16(FS)
- "movq %1, %%fs:-8\n" // MOVL m, -8(FS)
- :: "r"(ts.g), "r"(ts.m)
- );
+ setmg_gcc((void*)ts.m, (void*)ts.g);
+
crosscall_amd64(ts.fn);
return nil;
}
diff --git a/src/pkg/runtime/cgo/gcc_openbsd_386.c b/src/pkg/runtime/cgo/gcc_openbsd_386.c
index 86c1365ad..6422d1b93 100644
--- a/src/pkg/runtime/cgo/gcc_openbsd_386.c
+++ b/src/pkg/runtime/cgo/gcc_openbsd_386.c
@@ -11,6 +11,7 @@
#include "libcgo.h"
static void* threadentry(void*);
+static void (*setmg_gcc)(void*, void*);
// TCB_SIZE is sizeof(struct thread_control_block),
// as defined in /usr/src/lib/librthread/tcb.h
@@ -48,9 +49,9 @@ tcb_fixup(int mainthread)
bcopy(oldtcb, newtcb + TLS_SIZE, TCB_SIZE);
__set_tcb(newtcb + TLS_SIZE);
- // The main thread TCB is a static allocation - do not try to free it.
- if(!mainthread)
- free(oldtcb);
+ // NOTE(jsing, minux): we can't free oldtcb without causing double-free
+ // problem. so newtcb will be memory leaks. Get rid of this when OpenBSD
+ // has proper support for PT_TLS.
}
static void *
@@ -82,12 +83,13 @@ pthread_create(pthread_t *thread, const pthread_attr_t *attr,
}
void
-x_cgo_init(G *g)
+x_cgo_init(G *g, void (*setmg)(void*, void*))
{
pthread_attr_t attr;
size_t size;
void *handle;
+ setmg_gcc = setmg;
pthread_attr_init(&attr);
pthread_attr_getstacksize(&attr, &size);
g->stackguard = (uintptr)&attr - size + 4096;
@@ -154,15 +156,9 @@ threadentry(void *v)
ts.g->stackguard = (uintptr)&ts - ts.g->stackguard + 4096;
/*
- * Set specific keys. On OpenBSD/ELF, the thread local storage
- * is just before %gs:0. Our dynamic 8.out's reserve 8 bytes
- * for the two words g and m at %gs:-8 and %gs:-4.
+ * Set specific keys.
*/
- asm volatile (
- "movl %0, %%gs:-8\n" // MOVL g, -8(GS)
- "movl %1, %%gs:-4\n" // MOVL m, -4(GS)
- :: "r"(ts.g), "r"(ts.m)
- );
+ setmg_gcc((void*)ts.m, (void*)ts.g);
crosscall_386(ts.fn);
return nil;
diff --git a/src/pkg/runtime/cgo/gcc_openbsd_amd64.c b/src/pkg/runtime/cgo/gcc_openbsd_amd64.c
index d3a5e36b0..5a5a17114 100644
--- a/src/pkg/runtime/cgo/gcc_openbsd_amd64.c
+++ b/src/pkg/runtime/cgo/gcc_openbsd_amd64.c
@@ -11,6 +11,7 @@
#include "libcgo.h"
static void* threadentry(void*);
+static void (*setmg_gcc)(void*, void*);
// TCB_SIZE is sizeof(struct thread_control_block),
// as defined in /usr/src/lib/librthread/tcb.h
@@ -48,9 +49,9 @@ tcb_fixup(int mainthread)
bcopy(oldtcb, newtcb + TLS_SIZE, TCB_SIZE);
__set_tcb(newtcb + TLS_SIZE);
- // The main thread TCB is a static allocation - do not try to free it.
- if(!mainthread)
- free(oldtcb);
+ // NOTE(jsing, minux): we can't free oldtcb without causing double-free
+ // problem. so newtcb will be memory leaks. Get rid of this when OpenBSD
+ // has proper support for PT_TLS.
}
static void *
@@ -82,12 +83,13 @@ pthread_create(pthread_t *thread, const pthread_attr_t *attr,
}
void
-x_cgo_init(G *g)
+x_cgo_init(G *g, void (*setmg)(void*, void*))
{
pthread_attr_t attr;
size_t size;
void *handle;
+ setmg_gcc = setmg;
pthread_attr_init(&attr);
pthread_attr_getstacksize(&attr, &size);
g->stackguard = (uintptr)&attr - size + 4096;
@@ -155,15 +157,10 @@ threadentry(void *v)
ts.g->stackguard = (uintptr)&ts - ts.g->stackguard + 4096;
/*
- * Set specific keys. On OpenBSD/ELF, the thread local storage
- * is just before %fs:0. Our dynamic 6.out's reserve 16 bytes
- * for the two words g and m at %fs:-16 and %fs:-8.
+ * Set specific keys.
*/
- asm volatile (
- "movq %0, %%fs:-16\n" // MOVL g, -16(FS)
- "movq %1, %%fs:-8\n" // MOVL m, -8(FS)
- :: "r"(ts.g), "r"(ts.m)
- );
+ setmg_gcc((void*)ts.m, (void*)ts.g);
+
crosscall_amd64(ts.fn);
return nil;
}
diff --git a/src/pkg/runtime/cgocall.c b/src/pkg/runtime/cgocall.c
index 590bf9b67..b82966546 100644
--- a/src/pkg/runtime/cgocall.c
+++ b/src/pkg/runtime/cgocall.c
@@ -95,7 +95,17 @@ static void unwindm(void);
// Call from Go to C.
-static FuncVal unlockOSThread = { runtime·unlockOSThread };
+static void endcgo(void);
+static FuncVal endcgoV = { endcgo };
+
+// Gives a hint that the next syscall
+// executed by the current goroutine will block.
+// Currently used only on windows.
+void
+net·runtime_blockingSyscallHint(void)
+{
+ g->blockingsyscall = true;
+}
void
runtime·cgocall(void (*fn)(void*), void *arg)
@@ -123,7 +133,7 @@ runtime·cgocall(void (*fn)(void*), void *arg)
* cgo callback. Add entry to defer stack in case of panic.
*/
runtime·lockOSThread();
- d.fn = &unlockOSThread;
+ d.fn = &endcgoV;
d.siz = 0;
d.link = g->defer;
d.argp = (void*)-1; // unused because unlockm never recovers
@@ -144,10 +154,24 @@ runtime·cgocall(void (*fn)(void*), void *arg)
* so it is safe to call while "in a system call", outside
* the $GOMAXPROCS accounting.
*/
- runtime·entersyscall();
+ if(g->blockingsyscall) {
+ g->blockingsyscall = false;
+ runtime·entersyscallblock();
+ } else
+ runtime·entersyscall();
runtime·asmcgocall(fn, arg);
runtime·exitsyscall();
+ if(g->defer != &d || d.fn != &endcgoV)
+ runtime·throw("runtime: bad defer entry in cgocallback");
+ g->defer = d.link;
+ endcgo();
+}
+
+static void
+endcgo(void)
+{
+ runtime·unlockOSThread();
m->ncgo--;
if(m->ncgo == 0) {
// We are going back to Go and are not in a recursive
@@ -156,11 +180,6 @@ runtime·cgocall(void (*fn)(void*), void *arg)
m->cgomal = nil;
}
- if(g->defer != &d || d.fn != &unlockOSThread)
- runtime·throw("runtime: bad defer entry in cgocallback");
- g->defer = d.link;
- runtime·unlockOSThread();
-
if(raceenabled)
runtime·raceacquire(&cgosync);
}
@@ -280,3 +299,9 @@ runtime·cgounimpl(void) // called from (incomplete) assembly
{
runtime·throw("runtime: cgo not implemented");
}
+
+// For cgo-using programs with external linking,
+// export "main" (defined in assembly) so that libc can handle basic
+// C runtime startup and call the Go program as if it were
+// the C main function.
+#pragma cgo_export_static main
diff --git a/src/pkg/runtime/chan.c b/src/pkg/runtime/chan.c
index 32995c6dd..fba36a4c3 100644
--- a/src/pkg/runtime/chan.c
+++ b/src/pkg/runtime/chan.c
@@ -809,16 +809,27 @@ sellock(Select *sel)
static void
selunlock(Select *sel)
{
- uint32 i;
- Hchan *c, *c0;
+ int32 i, n, r;
+ Hchan *c;
- c = nil;
- for(i=sel->ncase; i-->0;) {
- c0 = sel->lockorder[i];
- if(c0 && c0 != c) {
- c = c0;
- runtime·unlock(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);
}
}
@@ -1011,7 +1022,7 @@ loop:
c = cas->chan;
if(c->dataqsiz > 0)
- runtime·throw("selectgo: shouldnt happen");
+ runtime·throw("selectgo: shouldn't happen");
if(debug)
runtime·printf("wait-return: sel=%p c=%p cas=%p kind=%d\n",
diff --git a/src/pkg/runtime/crash_test.go b/src/pkg/runtime/crash_test.go
index 5f84cb5a2..929d4a963 100644
--- a/src/pkg/runtime/crash_test.go
+++ b/src/pkg/runtime/crash_test.go
@@ -14,6 +14,22 @@ import (
"text/template"
)
+// testEnv excludes GOGCTRACE from the environment
+// to prevent its output from breaking tests that
+// are trying to parse other command output.
+func testEnv(cmd *exec.Cmd) *exec.Cmd {
+ if cmd.Env != nil {
+ panic("environment already set")
+ }
+ for _, env := range os.Environ() {
+ if strings.HasPrefix(env, "GOGCTRACE=") {
+ continue
+ }
+ cmd.Env = append(cmd.Env, env)
+ }
+ return cmd
+}
+
func executeTest(t *testing.T, templ string, data interface{}) string {
checkStaleRuntime(t)
@@ -37,13 +53,13 @@ func executeTest(t *testing.T, templ string, data interface{}) string {
}
f.Close()
- got, _ := exec.Command("go", "run", src).CombinedOutput()
+ got, _ := testEnv(exec.Command("go", "run", src)).CombinedOutput()
return string(got)
}
func checkStaleRuntime(t *testing.T) {
// 'go run' uses the installed copy of runtime.a, which may be out of date.
- out, err := exec.Command("go", "list", "-f", "{{.Stale}}", "runtime").CombinedOutput()
+ out, err := testEnv(exec.Command("go", "list", "-f", "{{.Stale}}", "runtime")).CombinedOutput()
if err != nil {
t.Fatalf("failed to execute 'go list': %v\n%v", err, string(out))
}
@@ -91,6 +107,14 @@ func TestLockedDeadlock2(t *testing.T) {
testDeadlock(t, lockedDeadlockSource2)
}
+func TestGoexitDeadlock(t *testing.T) {
+ got := executeTest(t, goexitDeadlockSource, nil)
+ want := ""
+ if got != want {
+ t.Fatalf("expected %q, but got %q", want, got)
+ }
+}
+
const crashSource = `
package main
@@ -175,3 +199,21 @@ func main() {
select {}
}
`
+
+const goexitDeadlockSource = `
+package main
+import (
+ "runtime"
+)
+
+func F() {
+ for i := 0; i < 10; i++ {
+ }
+}
+
+func main() {
+ go F()
+ go F()
+ runtime.Goexit()
+}
+`
diff --git a/src/pkg/runtime/debug/garbage_test.go b/src/pkg/runtime/debug/garbage_test.go
index b93cfee56..149bafc6f 100644
--- a/src/pkg/runtime/debug/garbage_test.go
+++ b/src/pkg/runtime/debug/garbage_test.go
@@ -11,6 +11,8 @@ import (
)
func TestReadGCStats(t *testing.T) {
+ defer SetGCPercent(SetGCPercent(-1))
+
var stats GCStats
var mstats runtime.MemStats
var min, max time.Duration
diff --git a/src/pkg/runtime/defs2_linux.go b/src/pkg/runtime/defs2_linux.go
index 9b0702955..60ecc69bb 100644
--- a/src/pkg/runtime/defs2_linux.go
+++ b/src/pkg/runtime/defs2_linux.go
@@ -7,7 +7,7 @@
/*
* Input to cgo -cdefs
-GOARCH=386 cgo -cdefs defs2.go >386/defs.h
+GOARCH=386 go tool cgo -cdefs defs2_linux.go >defs_linux_386.h
The asm header tricks we have to use for Linux on amd64
(see defs.c and defs1.c) don't work here, so this is yet another
@@ -17,15 +17,19 @@ file. Sigh.
package runtime
/*
-#cgo CFLAGS: -I/home/rsc/pub/linux-2.6/arch/x86/include -I/home/rsc/pub/linux-2.6/include -D_LOOSE_KERNEL_NAMES -D__ARCH_SI_UID_T=__kernel_uid32_t
+#cgo CFLAGS: -I/tmp/linux/arch/x86/include -I/tmp/linux/include -D_LOOSE_KERNEL_NAMES -D__ARCH_SI_UID_T=__kernel_uid32_t
#define size_t __kernel_size_t
+#define pid_t int
#include <asm/signal.h>
#include <asm/mman.h>
#include <asm/sigcontext.h>
#include <asm/ucontext.h>
#include <asm/siginfo.h>
+#include <asm-generic/errno.h>
#include <asm-generic/fcntl.h>
+#include <asm-generic/poll.h>
+#include <linux/eventpoll.h>
// This is the sigaction structure from the Linux 2.1.68 kernel which
// is used with the rt_sigaction system call. For 386 this is not
@@ -35,12 +39,16 @@ struct kernel_sigaction {
__sighandler_t k_sa_handler;
unsigned long sa_flags;
void (*sa_restorer) (void);
- sigset_t sa_mask;
+ unsigned long long sa_mask;
};
*/
import "C"
const (
+ EINTR = C.EINTR
+ EAGAIN = C.EAGAIN
+ ENOMEM = C.ENOMEM
+
PROT_NONE = C.PROT_NONE
PROT_READ = C.PROT_READ
PROT_WRITE = C.PROT_WRITE
@@ -110,6 +118,17 @@ const (
O_RDONLY = C.O_RDONLY
O_CLOEXEC = C.O_CLOEXEC
+
+ EPOLLIN = C.POLLIN
+ EPOLLOUT = C.POLLOUT
+ EPOLLERR = C.POLLERR
+ EPOLLHUP = C.POLLHUP
+ EPOLLRDHUP = C.POLLRDHUP
+ EPOLLET = C.EPOLLET
+ EPOLL_CLOEXEC = C.EPOLL_CLOEXEC
+ EPOLL_CTL_ADD = C.EPOLL_CTL_ADD
+ EPOLL_CTL_DEL = C.EPOLL_CTL_DEL
+ EPOLL_CTL_MOD = C.EPOLL_CTL_MOD
)
type Fpreg C.struct__fpreg
@@ -124,3 +143,4 @@ type Sigaltstack C.struct_sigaltstack
type Sigcontext C.struct_sigcontext
type Ucontext C.struct_ucontext
type Itimerval C.struct_itimerval
+type EpollEvent C.struct_epoll_event
diff --git a/src/pkg/runtime/defs_darwin.go b/src/pkg/runtime/defs_darwin.go
index 7f22b0b8e..722013ba9 100644
--- a/src/pkg/runtime/defs_darwin.go
+++ b/src/pkg/runtime/defs_darwin.go
@@ -7,8 +7,8 @@
/*
Input to cgo.
-GOARCH=amd64 cgo -cdefs defs_darwin.go >defs_darwin_amd64.h
-GOARCH=386 cgo -cdefs defs_darwin.go >defs_darwin_386.h
+GOARCH=amd64 go tool cgo -cdefs defs_darwin.go >defs_darwin_amd64.h
+GOARCH=386 go tool cgo -cdefs defs_darwin.go >defs_darwin_386.h
*/
package runtime
@@ -19,12 +19,17 @@ package runtime
#include <mach/message.h>
#include <sys/types.h>
#include <sys/time.h>
+#include <errno.h>
#include <signal.h>
+#include <sys/event.h>
#include <sys/mman.h>
*/
import "C"
const (
+ EINTR = C.EINTR
+ EFAULT = C.EFAULT
+
PROT_NONE = C.PROT_NONE
PROT_READ = C.PROT_READ
PROT_WRITE = C.PROT_WRITE
@@ -128,6 +133,14 @@ const (
ITIMER_REAL = C.ITIMER_REAL
ITIMER_VIRTUAL = C.ITIMER_VIRTUAL
ITIMER_PROF = C.ITIMER_PROF
+
+ EV_ADD = C.EV_ADD
+ EV_DELETE = C.EV_DELETE
+ EV_CLEAR = C.EV_CLEAR
+ EV_RECEIPT = C.EV_RECEIPT
+ EV_ERROR = C.EV_ERROR
+ EVFILT_READ = C.EVFILT_READ
+ EVFILT_WRITE = C.EVFILT_WRITE
)
type MachBody C.mach_msg_body_t
@@ -144,6 +157,7 @@ type Sigval C.union_sigval
type Siginfo C.siginfo_t
type Timeval C.struct_timeval
type Itimerval C.struct_itimerval
+type Timespec C.struct_timespec
type FPControl C.struct_fp_control
type FPStatus C.struct_fp_status
@@ -161,3 +175,5 @@ type ExceptionState32 C.struct_i386_exception_state
type Mcontext32 C.struct_mcontext32
type Ucontext C.struct_ucontext
+
+type Kevent C.struct_kevent
diff --git a/src/pkg/runtime/defs_darwin_386.h b/src/pkg/runtime/defs_darwin_386.h
index 92732f460..7b210eebf 100644
--- a/src/pkg/runtime/defs_darwin_386.h
+++ b/src/pkg/runtime/defs_darwin_386.h
@@ -3,6 +3,9 @@
enum {
+ EINTR = 0x4,
+ EFAULT = 0xe,
+
PROT_NONE = 0x0,
PROT_READ = 0x1,
PROT_WRITE = 0x2,
@@ -106,6 +109,14 @@ enum {
ITIMER_REAL = 0x0,
ITIMER_VIRTUAL = 0x1,
ITIMER_PROF = 0x2,
+
+ EV_ADD = 0x1,
+ EV_DELETE = 0x2,
+ EV_CLEAR = 0x20,
+ EV_RECEIPT = 0x40,
+ EV_ERROR = 0x4000,
+ EVFILT_READ = -0x1,
+ EVFILT_WRITE = -0x2,
};
typedef struct MachBody MachBody;
@@ -117,6 +128,7 @@ typedef struct Sigaction Sigaction;
typedef struct Siginfo Siginfo;
typedef struct Timeval Timeval;
typedef struct Itimerval Itimerval;
+typedef struct Timespec Timespec;
typedef struct FPControl FPControl;
typedef struct FPStatus FPStatus;
typedef struct RegMMST RegMMST;
@@ -130,6 +142,7 @@ typedef struct FloatState32 FloatState32;
typedef struct ExceptionState32 ExceptionState32;
typedef struct Mcontext32 Mcontext32;
typedef struct Ucontext Ucontext;
+typedef struct Kevent Kevent;
#pragma pack on
@@ -170,7 +183,7 @@ struct StackT {
typedef byte Sighandler[4];
struct Sigaction {
- Sighandler __sigaction_u;
+ byte __sigaction_u[4];
void *sa_tramp;
uint32 sa_mask;
int32 sa_flags;
@@ -185,7 +198,7 @@ struct Siginfo {
uint32 si_uid;
int32 si_status;
byte *si_addr;
- Sigval si_value;
+ byte si_value[4];
int32 si_band;
uint32 __pad[7];
};
@@ -197,6 +210,10 @@ struct Itimerval {
Timeval it_interval;
Timeval it_value;
};
+struct Timespec {
+ int32 tv_sec;
+ int32 tv_nsec;
+};
struct FPControl {
byte Pad_cgo_0[2];
@@ -362,5 +379,14 @@ struct Ucontext {
Mcontext32 *uc_mcontext;
};
+struct Kevent {
+ uint32 ident;
+ int16 filter;
+ uint16 flags;
+ uint32 fflags;
+ int32 data;
+ byte *udata;
+};
+
#pragma pack off
diff --git a/src/pkg/runtime/defs_darwin_amd64.h b/src/pkg/runtime/defs_darwin_amd64.h
index d4fbfef49..2d464a9e5 100644
--- a/src/pkg/runtime/defs_darwin_amd64.h
+++ b/src/pkg/runtime/defs_darwin_amd64.h
@@ -3,6 +3,9 @@
enum {
+ EINTR = 0x4,
+ EFAULT = 0xe,
+
PROT_NONE = 0x0,
PROT_READ = 0x1,
PROT_WRITE = 0x2,
@@ -106,6 +109,14 @@ enum {
ITIMER_REAL = 0x0,
ITIMER_VIRTUAL = 0x1,
ITIMER_PROF = 0x2,
+
+ EV_ADD = 0x1,
+ EV_DELETE = 0x2,
+ EV_CLEAR = 0x20,
+ EV_RECEIPT = 0x40,
+ EV_ERROR = 0x4000,
+ EVFILT_READ = -0x1,
+ EVFILT_WRITE = -0x2,
};
typedef struct MachBody MachBody;
@@ -117,6 +128,7 @@ typedef struct Sigaction Sigaction;
typedef struct Siginfo Siginfo;
typedef struct Timeval Timeval;
typedef struct Itimerval Itimerval;
+typedef struct Timespec Timespec;
typedef struct FPControl FPControl;
typedef struct FPStatus FPStatus;
typedef struct RegMMST RegMMST;
@@ -130,6 +142,7 @@ typedef struct FloatState32 FloatState32;
typedef struct ExceptionState32 ExceptionState32;
typedef struct Mcontext32 Mcontext32;
typedef struct Ucontext Ucontext;
+typedef struct Kevent Kevent;
#pragma pack on
@@ -171,7 +184,7 @@ struct StackT {
typedef byte Sighandler[8];
struct Sigaction {
- Sighandler __sigaction_u;
+ byte __sigaction_u[8];
void *sa_tramp;
uint32 sa_mask;
int32 sa_flags;
@@ -186,7 +199,7 @@ struct Siginfo {
uint32 si_uid;
int32 si_status;
byte *si_addr;
- Sigval si_value;
+ byte si_value[8];
int64 si_band;
uint64 __pad[7];
};
@@ -199,6 +212,10 @@ struct Itimerval {
Timeval it_interval;
Timeval it_value;
};
+struct Timespec {
+ int64 tv_sec;
+ int64 tv_nsec;
+};
struct FPControl {
byte Pad_cgo_0[2];
@@ -365,5 +382,14 @@ struct Ucontext {
Mcontext64 *uc_mcontext;
};
+struct Kevent {
+ uint64 ident;
+ int16 filter;
+ uint16 flags;
+ uint32 fflags;
+ int64 data;
+ byte *udata;
+};
+
#pragma pack off
diff --git a/src/pkg/runtime/defs_freebsd.go b/src/pkg/runtime/defs_freebsd.go
index 084022715..93f0703e3 100644
--- a/src/pkg/runtime/defs_freebsd.go
+++ b/src/pkg/runtime/defs_freebsd.go
@@ -45,8 +45,8 @@ const (
SA_RESTART = C.SA_RESTART
SA_ONSTACK = C.SA_ONSTACK
- UMTX_OP_WAIT = C.UMTX_OP_WAIT
- UMTX_OP_WAKE = C.UMTX_OP_WAKE
+ UMTX_OP_WAIT_UINT = C.UMTX_OP_WAIT_UINT
+ UMTX_OP_WAKE = C.UMTX_OP_WAKE
EINTR = C.EINTR
diff --git a/src/pkg/runtime/defs_freebsd_386.h b/src/pkg/runtime/defs_freebsd_386.h
index d00c852c6..8fa37c5d6 100644
--- a/src/pkg/runtime/defs_freebsd_386.h
+++ b/src/pkg/runtime/defs_freebsd_386.h
@@ -18,8 +18,8 @@ enum {
SA_RESTART = 0x2,
SA_ONSTACK = 0x1,
- UMTX_OP_WAIT = 0x2,
- UMTX_OP_WAKE = 0x3,
+ UMTX_OP_WAIT_UINT = 0xb,
+ UMTX_OP_WAKE = 0x3,
EINTR = 0x4,
diff --git a/src/pkg/runtime/defs_freebsd_amd64.h b/src/pkg/runtime/defs_freebsd_amd64.h
index 6348c0482..56d849bce 100644
--- a/src/pkg/runtime/defs_freebsd_amd64.h
+++ b/src/pkg/runtime/defs_freebsd_amd64.h
@@ -18,8 +18,8 @@ enum {
SA_RESTART = 0x2,
SA_ONSTACK = 0x1,
- UMTX_OP_WAIT = 0x2,
- UMTX_OP_WAKE = 0x3,
+ UMTX_OP_WAIT_UINT = 0xb,
+ UMTX_OP_WAKE = 0x3,
EINTR = 0x4,
diff --git a/src/pkg/runtime/defs_freebsd_arm.h b/src/pkg/runtime/defs_freebsd_arm.h
index a744b808f..334652eec 100644
--- a/src/pkg/runtime/defs_freebsd_arm.h
+++ b/src/pkg/runtime/defs_freebsd_arm.h
@@ -18,8 +18,8 @@ enum {
SA_RESTART = 0x2,
SA_ONSTACK = 0x1,
- UMTX_OP_WAIT = 0x2,
- UMTX_OP_WAKE = 0x3,
+ UMTX_OP_WAIT_UINT = 0xb,
+ UMTX_OP_WAKE = 0x3,
EINTR = 0x4,
diff --git a/src/pkg/runtime/defs_linux.go b/src/pkg/runtime/defs_linux.go
index c0275e111..2f4e03a01 100644
--- a/src/pkg/runtime/defs_linux.go
+++ b/src/pkg/runtime/defs_linux.go
@@ -7,7 +7,7 @@
/*
Input to cgo -cdefs
-GOARCH=amd64 cgo -cdefs defs.go defs1.go >amd64/defs.h
+GOARCH=amd64 go tool cgo -cdefs defs_linux.go defs1_linux.go >defs_linux_amd64.h
*/
package runtime
@@ -25,10 +25,17 @@ package runtime
#include <asm/signal.h>
#include <asm/siginfo.h>
#include <asm/mman.h>
+#include <asm-generic/errno.h>
+#include <asm-generic/poll.h>
+#include <linux/eventpoll.h>
*/
import "C"
const (
+ EINTR = C.EINTR
+ EAGAIN = C.EAGAIN
+ ENOMEM = C.ENOMEM
+
PROT_NONE = C.PROT_NONE
PROT_READ = C.PROT_READ
PROT_WRITE = C.PROT_WRITE
@@ -95,6 +102,17 @@ const (
ITIMER_REAL = C.ITIMER_REAL
ITIMER_VIRTUAL = C.ITIMER_VIRTUAL
ITIMER_PROF = C.ITIMER_PROF
+
+ EPOLLIN = C.POLLIN
+ EPOLLOUT = C.POLLOUT
+ EPOLLERR = C.POLLERR
+ EPOLLHUP = C.POLLHUP
+ EPOLLRDHUP = C.POLLRDHUP
+ EPOLLET = C.EPOLLET
+ EPOLL_CLOEXEC = C.EPOLL_CLOEXEC
+ EPOLL_CTL_ADD = C.EPOLL_CTL_ADD
+ EPOLL_CTL_DEL = C.EPOLL_CTL_DEL
+ EPOLL_CTL_MOD = C.EPOLL_CTL_MOD
)
type Timespec C.struct_timespec
@@ -102,3 +120,4 @@ type Timeval C.struct_timeval
type Sigaction C.struct_sigaction
type Siginfo C.siginfo_t
type Itimerval C.struct_itimerval
+type EpollEvent C.struct_epoll_event
diff --git a/src/pkg/runtime/defs_linux_386.h b/src/pkg/runtime/defs_linux_386.h
index e257a6f85..27dae9e82 100644
--- a/src/pkg/runtime/defs_linux_386.h
+++ b/src/pkg/runtime/defs_linux_386.h
@@ -1,8 +1,12 @@
// Created by cgo -cdefs - DO NOT EDIT
-// cgo -cdefs defs2.go
+// cgo -cdefs defs2_linux.go
enum {
+ EINTR = 0x4,
+ EAGAIN = 0xb,
+ ENOMEM = 0xc,
+
PROT_NONE = 0x0,
PROT_READ = 0x1,
PROT_WRITE = 0x2,
@@ -72,6 +76,17 @@ enum {
O_RDONLY = 0x0,
O_CLOEXEC = 0x80000,
+
+ 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,
};
typedef struct Fpreg Fpreg;
@@ -86,6 +101,7 @@ typedef struct Sigaltstack Sigaltstack;
typedef struct Sigcontext Sigcontext;
typedef struct Ucontext Ucontext;
typedef struct Itimerval Itimerval;
+typedef struct EpollEvent EpollEvent;
#pragma pack on
@@ -186,6 +202,10 @@ struct Itimerval {
Timeval it_interval;
Timeval it_value;
};
+struct EpollEvent {
+ uint32 events;
+ uint64 data;
+};
#pragma pack off
diff --git a/src/pkg/runtime/defs_linux_amd64.h b/src/pkg/runtime/defs_linux_amd64.h
index bf5f79b0e..3e87df68a 100644
--- a/src/pkg/runtime/defs_linux_amd64.h
+++ b/src/pkg/runtime/defs_linux_amd64.h
@@ -1,8 +1,12 @@
// Created by cgo -cdefs - DO NOT EDIT
-// cgo -cdefs defs.go defs1.go
+// cgo -cdefs defs_linux.go defs1_linux.go
enum {
+ EINTR = 0x4,
+ EAGAIN = 0xb,
+ ENOMEM = 0xc,
+
PROT_NONE = 0x0,
PROT_READ = 0x1,
PROT_WRITE = 0x2,
@@ -69,6 +73,17 @@ enum {
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,
};
typedef struct Timespec Timespec;
@@ -76,6 +91,7 @@ typedef struct Timeval Timeval;
typedef struct Sigaction Sigaction;
typedef struct Siginfo Siginfo;
typedef struct Itimerval Itimerval;
+typedef struct EpollEvent EpollEvent;
#pragma pack on
@@ -104,11 +120,15 @@ struct Itimerval {
Timeval it_interval;
Timeval it_value;
};
+struct EpollEvent {
+ uint32 events;
+ uint64 data;
+};
#pragma pack off
// Created by cgo -cdefs - DO NOT EDIT
-// cgo -cdefs defs.go defs1.go
+// cgo -cdefs defs_linux.go defs1_linux.go
enum {
diff --git a/src/pkg/runtime/defs_linux_arm.h b/src/pkg/runtime/defs_linux_arm.h
index f72ec3d1b..92160966e 100644
--- a/src/pkg/runtime/defs_linux_arm.h
+++ b/src/pkg/runtime/defs_linux_arm.h
@@ -1,9 +1,11 @@
-// godefs -f-I/usr/src/linux-headers-2.6.26-2-versatile/include defs_arm.c
-
-// MACHINE GENERATED - DO NOT EDIT.
+// TODO: Generate using cgo like defs_linux_{386,amd64}.h
// Constants
enum {
+ EINTR = 0x4,
+ ENOMEM = 0xc,
+ EAGAIN = 0xb,
+
PROT_NONE = 0,
PROT_READ = 0x1,
PROT_WRITE = 0x2,
@@ -64,6 +66,17 @@ enum {
ITIMER_VIRTUAL = 0x1,
O_RDONLY = 0,
O_CLOEXEC = 02000000,
+
+ 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,
};
// Types
@@ -145,4 +158,11 @@ struct Sigaction {
void *sa_restorer;
uint64 sa_mask;
};
+
+typedef struct EpollEvent EpollEvent;
+struct EpollEvent {
+ uint32 events;
+ uint32 _pad;
+ uint64 data;
+};
#pragma pack off
diff --git a/src/pkg/runtime/defs_netbsd.go b/src/pkg/runtime/defs_netbsd.go
index 53e061041..c543593fa 100644
--- a/src/pkg/runtime/defs_netbsd.go
+++ b/src/pkg/runtime/defs_netbsd.go
@@ -9,6 +9,7 @@ Input to cgo.
GOARCH=amd64 go tool cgo -cdefs defs_netbsd.go defs_netbsd_amd64.go >defs_netbsd_amd64.h
GOARCH=386 go tool cgo -cdefs defs_netbsd.go defs_netbsd_386.go >defs_netbsd_386.h
+GOARCH=arm go tool cgo -cdefs defs_netbsd.go defs_netbsd_arm.go >defs_netbsd_arm.h
*/
// +godefs map __fpregset_t [644]byte
diff --git a/src/pkg/runtime/defs_netbsd_386.go b/src/pkg/runtime/defs_netbsd_386.go
index e9e36608e..c26f24607 100644
--- a/src/pkg/runtime/defs_netbsd_386.go
+++ b/src/pkg/runtime/defs_netbsd_386.go
@@ -7,7 +7,6 @@
/*
Input to cgo.
-GOARCH=amd64 go tool cgo -cdefs defs_netbsd.go defs_netbsd_amd64.go >defs_netbsd_amd64.h
GOARCH=386 go tool cgo -cdefs defs_netbsd.go defs_netbsd_386.go >defs_netbsd_386.h
*/
diff --git a/src/pkg/runtime/defs_netbsd_amd64.go b/src/pkg/runtime/defs_netbsd_amd64.go
index 68f586b2f..f18a7b1fe 100644
--- a/src/pkg/runtime/defs_netbsd_amd64.go
+++ b/src/pkg/runtime/defs_netbsd_amd64.go
@@ -8,7 +8,6 @@
Input to cgo.
GOARCH=amd64 go tool cgo -cdefs defs_netbsd.go defs_netbsd_amd64.go >defs_netbsd_amd64.h
-GOARCH=386 go tool cgo -cdefs defs_netbsd.go defs_netbsd_386.go >defs_netbsd_386.h
*/
package runtime
diff --git a/src/pkg/runtime/defs_netbsd_arm.go b/src/pkg/runtime/defs_netbsd_arm.go
new file mode 100644
index 000000000..cb0dce66b
--- /dev/null
+++ b/src/pkg/runtime/defs_netbsd_arm.go
@@ -0,0 +1,39 @@
+// 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 ignore
+
+/*
+Input to cgo.
+
+GOARCH=arm go tool cgo -cdefs defs_netbsd.go defs_netbsd_arm.go >defs_netbsd_arm.h
+*/
+
+package runtime
+
+/*
+#include <sys/types.h>
+#include <machine/mcontext.h>
+*/
+import "C"
+
+const (
+ REG_R0 = C._REG_R0
+ REG_R1 = C._REG_R1
+ REG_R2 = C._REG_R2
+ REG_R3 = C._REG_R3
+ REG_R4 = C._REG_R4
+ REG_R5 = C._REG_R5
+ REG_R6 = C._REG_R6
+ REG_R7 = C._REG_R7
+ REG_R8 = C._REG_R8
+ REG_R9 = C._REG_R9
+ REG_R10 = C._REG_R10
+ REG_R11 = C._REG_R11
+ REG_R12 = C._REG_R12
+ REG_R13 = C._REG_R13
+ REG_R14 = C._REG_R14
+ REG_R15 = C._REG_R15
+ REG_CPSR = C._REG_CPSR
+)
diff --git a/src/pkg/runtime/defs_netbsd_arm.h b/src/pkg/runtime/defs_netbsd_arm.h
index f67475c76..26b55222e 100644
--- a/src/pkg/runtime/defs_netbsd_arm.h
+++ b/src/pkg/runtime/defs_netbsd_arm.h
@@ -1,5 +1,5 @@
// Created by cgo -cdefs - DO NOT EDIT
-// cgo -cdefs defs_netbsd.go
+// cgo -cdefs defs_netbsd.go defs_netbsd_arm.go
enum {
@@ -138,3 +138,27 @@ struct UcontextT {
};
#pragma pack off
+// Created by cgo -cdefs - DO NOT EDIT
+// cgo -cdefs defs_netbsd.go defs_netbsd_arm.go
+
+
+enum {
+ REG_R0 = 0x0,
+ REG_R1 = 0x1,
+ REG_R2 = 0x2,
+ REG_R3 = 0x3,
+ REG_R4 = 0x4,
+ REG_R5 = 0x5,
+ REG_R6 = 0x6,
+ REG_R7 = 0x7,
+ REG_R8 = 0x8,
+ REG_R9 = 0x9,
+ REG_R10 = 0xa,
+ REG_R11 = 0xb,
+ REG_R12 = 0xc,
+ REG_R13 = 0xd,
+ REG_R14 = 0xe,
+ REG_R15 = 0xf,
+ REG_CPSR = 0x10,
+};
+
diff --git a/src/pkg/runtime/env_plan9.c b/src/pkg/runtime/env_plan9.c
index 848d73303..0483d7eef 100644
--- a/src/pkg/runtime/env_plan9.c
+++ b/src/pkg/runtime/env_plan9.c
@@ -20,7 +20,7 @@ runtime·getenv(int8 *s)
runtime·memmove((void*)file, (void*)"/env/", 5);
runtime·memmove((void*)(file+5), (void*)s, len);
- fd = runtime·open(file, OREAD);
+ fd = runtime·open((int8*)file, OREAD, 0);
if(fd < 0)
return nil;
n = runtime·seek(fd, 0, 2);
diff --git a/src/pkg/runtime/export_futex_test.go b/src/pkg/runtime/export_futex_test.go
new file mode 100644
index 000000000..bcab60fbe
--- /dev/null
+++ b/src/pkg/runtime/export_futex_test.go
@@ -0,0 +1,13 @@
+// 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 freebsd
+
+package runtime
+
+func futexsleep(addr *uint32, val uint32, ns int64)
+func futexwakeup(addr *uint32, val uint32)
+
+var Futexsleep = futexsleep
+var Futexwakeup = futexwakeup
diff --git a/src/pkg/runtime/extern.go b/src/pkg/runtime/extern.go
index fbaffd1d5..20f234253 100644
--- a/src/pkg/runtime/extern.go
+++ b/src/pkg/runtime/extern.go
@@ -3,10 +3,54 @@
// license that can be found in the LICENSE file.
/*
- Package runtime contains operations that interact with Go's runtime system,
- such as functions to control goroutines. It also includes the low-level type information
- used by the reflect package; see reflect's documentation for the programmable
- interface to the run-time type system.
+Package runtime contains operations that interact with Go's runtime system,
+such as functions to control goroutines. It also includes the low-level type information
+used by the reflect package; see reflect's documentation for the programmable
+interface to the run-time type system.
+
+Environment Variables
+
+The following environment variables ($name or %name%, depending on the host
+operating system) control the run-time behavior of Go programs. The meanings
+and use may change from release to release.
+
+The GOGC variable sets the initial 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. The default
+is GOGC=100. Setting GOGC=off disables the garbage collector entirely.
+The runtime/debug package's SetGCPercent function allows changing this
+percentage at run time. See http://golang.org/pkg/runtime/debug/#SetGCPercent.
+
+The GOGCTRACE variable controls debug output from the garbage collector.
+Setting GOGCTRACE=1 causes the garbage collector to emit a single line to standard
+error at each collection, summarizing the amount of memory collected and the
+length of the pause. Setting GOGCTRACE=2 emits the same summary but also
+repeats each collection.
+
+The GOMAXPROCS variable limits the number of operating system threads that
+can execute user-level Go code simultaneously. There is no limit to the number of threads
+that can be blocked in system calls on behalf of Go code; those do not count against
+the GOMAXPROCS limit. This package's GOMAXPROCS function queries and changes
+the limit.
+
+The GOTRACEBACK variable controls the amount of output generated when a Go
+program fails due to an unrecovered panic or an unexpected runtime condition.
+By default, a failure prints a stack trace for every extant goroutine, eliding functions
+internal to the run-time system, and then exits with exit code 2.
+If GOTRACEBACK=0, the per-goroutine stack traces are omitted entirely.
+If GOTRACEBACK=1, the default behavior is used.
+If GOTRACEBACK=2, the per-goroutine stack traces include run-time functions.
+If GOTRACEBACK=crash, the per-goroutine stack traces include run-time functions,
+and if possible the program crashes in an operating-specific manner instead of
+exiting. For example, on Unix systems, the program raises SIGABRT to trigger a
+core dump.
+
+The GOARCH, GOOS, GOPATH, and GOROOT environment variables complete
+the set of Go environment variables. They influence the building of Go programs
+(see http://golang.org/cmd/go and http://golang.org/pkg/go/build).
+GOARCH, GOOS, and GOROOT are recorded at compile time and made available by
+constants or functions in this package, but they do not influence the execution
+of the run-time system.
*/
package runtime
diff --git a/src/pkg/runtime/futex_test.go b/src/pkg/runtime/futex_test.go
new file mode 100644
index 000000000..51f4d0f12
--- /dev/null
+++ b/src/pkg/runtime/futex_test.go
@@ -0,0 +1,31 @@
+// 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 freebsd
+
+package runtime_test
+
+import (
+ . "runtime"
+ "testing"
+ "time"
+)
+
+func TestFutexsleep(t *testing.T) {
+ ch := make(chan bool, 1)
+ var dummy uint32
+ start := time.Now()
+ go func() {
+ Entersyscall()
+ Futexsleep(&dummy, 0, (1<<31+100)*1e9)
+ Exitsyscall()
+ ch <- true
+ }()
+ select {
+ case <-ch:
+ t.Errorf("futexsleep finished early after %s!", time.Since(start))
+ case <-time.After(time.Second):
+ Futexwakeup(&dummy, 1)
+ }
+}
diff --git a/src/pkg/runtime/gc_test.go b/src/pkg/runtime/gc_test.go
index e1e1b1d01..26fc77de1 100644
--- a/src/pkg/runtime/gc_test.go
+++ b/src/pkg/runtime/gc_test.go
@@ -7,12 +7,13 @@ package runtime_test
import (
"os"
"runtime"
+ "runtime/debug"
"testing"
)
func TestGcSys(t *testing.T) {
if os.Getenv("GOGC") == "off" {
- t.Fatalf("GOGC=off in environment; test cannot pass")
+ t.Skip("skipping test; GOGC=off in environment")
}
data := struct{ Short bool }{testing.Short()}
got := executeTest(t, testGCSysSource, &data)
@@ -82,3 +83,17 @@ func TestGcDeepNesting(t *testing.T) {
t.Fail()
}
}
+
+func TestGcHashmapIndirection(t *testing.T) {
+ defer debug.SetGCPercent(debug.SetGCPercent(1))
+ runtime.GC()
+ type T struct {
+ a [256]int
+ }
+ m := make(map[T]T)
+ for i := 0; i < 2000; i++ {
+ var a T
+ a.a[0] = i
+ m[a] = T{}
+ }
+}
diff --git a/src/pkg/runtime/hashmap.c b/src/pkg/runtime/hashmap.c
index 37111daa9..892f0a170 100644
--- a/src/pkg/runtime/hashmap.c
+++ b/src/pkg/runtime/hashmap.c
@@ -9,777 +9,1070 @@
#include "type.h"
#include "race.h"
-/* Hmap flag values */
-#define IndirectVal (1<<0) /* storing pointers to values */
-#define IndirectKey (1<<1) /* storing pointers to keys */
-#define CanFreeTable (1<<2) /* okay to free subtables */
-#define CanFreeKey (1<<3) /* okay to free pointers to keys */
-
-struct Hmap { /* a hash table; initialize with hash_init() */
- uintgo count; /* elements in table - must be first */
- uint8 datasize; /* amount of data to store in entry */
- uint8 flag;
- uint8 valoff; /* offset of value in key+value data block */
- int32 changes; /* inc'ed whenever a subtable is created/grown */
- uintptr hash0; /* hash seed */
- struct hash_subtable *st; /* first-level table */
+// This file contains the implementation of Go's map type.
+//
+// The 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.
+
+// Maximum number of key/value pairs a bucket can hold.
+#define BUCKETSIZE 8
+
+// Maximum average load of a bucket that triggers growth.
+#define LOAD 6.5
+
+// Picking LOAD: 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)
+// LOAD %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.
+
+// 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/gc/walk.c must be at most this value.
+#define MAXKEYSIZE 128
+#define MAXVALUESIZE 128
+
+typedef struct Bucket Bucket;
+struct Bucket
+{
+ uint8 tophash[BUCKETSIZE]; // top 8 bits of hash of each entry (0 = empty)
+ Bucket *overflow; // overflow bucket, if any
+ byte data[1]; // BUCKETSIZE keys followed by BUCKETSIZE 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.
-#define MaxData 255
+// Low-order bit of overflow field is used to mark a bucket as already evacuated
+// without destroying the overflow pointer.
+// Only buckets in oldbuckets will be marked as evacuated.
+// Evacuated bit will be set identically on the base bucket and any overflow buckets.
+#define evacuated(b) (((uintptr)(b)->overflow & 1) != 0)
+#define overflowptr(b) ((Bucket*)((uintptr)(b)->overflow & ~(uintptr)1))
-struct hash_entry {
- hash_hash_t hash; /* hash value of data */
- byte data[1]; /* user data has "datasize" bytes */
-};
+// Initialize bucket to the empty state. This only works if BUCKETSIZE==8!
+#define clearbucket(b) { *(uint64*)((b)->tophash) = 0; (b)->overflow = nil; }
-struct hash_subtable {
- uint8 power; /* bits used to index this table */
- uint8 used; /* bits in hash used before reaching this table */
- uint8 datasize; /* bytes of client data in an entry */
- uint8 max_probes; /* max number of probes when searching */
- int16 limit_bytes; /* max_probes * (datasize+sizeof (hash_hash_t)) */
- struct hash_entry *last; /* points to last element of entry[] */
- struct hash_entry entry[1]; /* 2**power+max_probes-1 elements of elemsize bytes */
+struct Hmap
+{
+ uintgo count; // # live cells == size of map. Must be first (used by len() builtin)
+ uint32 flags;
+ uint8 B; // log_2 of # of buckets (can hold up to LOAD * 2^B items)
+ uint8 keysize; // key size in bytes
+ uint8 valuesize; // value size in bytes
+ uint16 bucketsize; // bucket size in bytes
+
+ uintptr hash0; // hash seed
+ byte *buckets; // array of 2^B Buckets. may be nil if count==0.
+ byte *oldbuckets; // previous bucket array of half the size, non-nil only when growing
+ uintptr nevacuate; // progress counter for evacuation (buckets less than this have been evacuated)
};
-#define HASH_DATA_EQ(eq, t, h,x,y) ((eq)=0, (*t->key->alg->equal) (&(eq), t->key->size, (x), (y)), (eq))
-
-#define HASH_REHASH 0x2 /* an internal flag */
-/* the number of bits used is stored in the flags word too */
-#define HASH_USED(x) ((x) >> 2)
-#define HASH_MAKE_USED(x) ((x) << 2)
+// possible flags
+enum
+{
+ IndirectKey = 1, // storing pointers to keys
+ IndirectValue = 2, // storing pointers to values
+ Iterator = 4, // there may be an iterator using buckets
+ OldIterator = 8, // there may be an iterator using oldbuckets
+ CanFreeBucket = 16, // ok to free buckets
+ CanFreeKey = 32, // keys are indirect and ok to free keys
+};
-#define HASH_LOW 6
-#define HASH_ONE (((hash_hash_t)1) << HASH_LOW)
-#define HASH_MASK (HASH_ONE - 1)
-#define HASH_ADJUST(x) (((x) < HASH_ONE) << HASH_LOW)
+// Macros for dereferencing indirect keys
+#define IK(h, p) (((h)->flags & IndirectKey) != 0 ? *(byte**)(p) : (p))
+#define IV(h, p) (((h)->flags & IndirectValue) != 0 ? *(byte**)(p) : (p))
-#define HASH_BITS (sizeof (hash_hash_t) * 8)
+enum
+{
+ docheck = 0, // check invariants before and after every op. Slow!!!
+ debug = 0, // print every operation
+ checkgc = 0 || docheck, // check interaction of mallocgc() with the garbage collector
+};
+static void
+check(MapType *t, Hmap *h)
+{
+ uintptr bucket, oldbucket;
+ Bucket *b;
+ uintptr i;
+ uintptr hash;
+ uintgo cnt;
+ uint8 top;
+ bool eq;
+ byte *k, *v;
-#define HASH_SUBHASH HASH_MASK
-#define HASH_NIL 0
-#define HASH_NIL_MEMSET 0
+ cnt = 0;
-#define HASH_OFFSET(base, byte_offset) \
- ((struct hash_entry *) (((byte *) (base)) + (byte_offset)))
+ // check buckets
+ for(bucket = 0; bucket < (uintptr)1 << h->B; bucket++) {
+ if(h->oldbuckets != nil) {
+ oldbucket = bucket & (((uintptr)1 << (h->B - 1)) - 1);
+ b = (Bucket*)(h->oldbuckets + oldbucket * h->bucketsize);
+ if(!evacuated(b))
+ continue; // b is still uninitialized
+ }
+ for(b = (Bucket*)(h->buckets + bucket * h->bucketsize); b != nil; b = b->overflow) {
+ for(i = 0, k = b->data, v = k + h->keysize * BUCKETSIZE; i < BUCKETSIZE; i++, k += h->keysize, v += h->valuesize) {
+ if(b->tophash[i] == 0)
+ continue;
+ cnt++;
+ t->key->alg->equal(&eq, t->key->size, IK(h, k), IK(h, k));
+ if(!eq)
+ continue; // NaN!
+ hash = h->hash0;
+ t->key->alg->hash(&hash, t->key->size, IK(h, k));
+ top = hash >> (8*sizeof(uintptr) - 8);
+ if(top == 0)
+ top = 1;
+ if(top != b->tophash[i])
+ runtime·throw("bad hash");
+ }
+ }
+ }
-#define HASH_MAX_PROBES 15 /* max entries to probe before rehashing */
-#define HASH_MAX_POWER 12 /* max power of 2 to create sub-tables */
+ // check oldbuckets
+ if(h->oldbuckets != nil) {
+ for(oldbucket = 0; oldbucket < (uintptr)1 << (h->B - 1); oldbucket++) {
+ b = (Bucket*)(h->oldbuckets + oldbucket * h->bucketsize);
+ if(evacuated(b))
+ continue;
+ if(oldbucket < h->nevacuate)
+ runtime·throw("bucket became unevacuated");
+ for(; b != nil; b = overflowptr(b)) {
+ for(i = 0, k = b->data, v = k + h->keysize * BUCKETSIZE; i < BUCKETSIZE; i++, k += h->keysize, v += h->valuesize) {
+ if(b->tophash[i] == 0)
+ continue;
+ cnt++;
+ t->key->alg->equal(&eq, t->key->size, IK(h, k), IK(h, k));
+ if(!eq)
+ continue; // NaN!
+ hash = h->hash0;
+ t->key->alg->hash(&hash, t->key->size, IK(h, k));
+ top = hash >> (8*sizeof(uintptr) - 8);
+ if(top == 0)
+ top = 1;
+ if(top != b->tophash[i])
+ runtime·throw("bad hash (old)");
+ }
+ }
+ }
+ }
-/* return a hash layer with 2**power empty entries */
-static struct hash_subtable *
-hash_subtable_new (Hmap *h, int32 power, int32 used)
-{
- int32 elemsize = h->datasize + offsetof (struct hash_entry, data[0]);
- int32 bytes = elemsize << power;
- struct hash_subtable *st;
- int32 limit_bytes = HASH_MAX_PROBES * elemsize;
- int32 max_probes = HASH_MAX_PROBES;
-
- if (bytes < limit_bytes) {
- limit_bytes = bytes;
- max_probes = 1 << power;
+ if(cnt != h->count) {
+ runtime·printf("%D %D\n", (uint64)cnt, (uint64)h->count);
+ runtime·throw("entries missing");
}
- bytes += limit_bytes - elemsize;
- st = runtime·mallocgc(offsetof (struct hash_subtable, entry[0]) + bytes, UseSpanType ? FlagNoPointers : 0, 1, 1);
- st->power = power;
- st->used = used;
- st->datasize = h->datasize;
- st->max_probes = max_probes;
- st->limit_bytes = limit_bytes;
- st->last = HASH_OFFSET (st->entry, bytes) - 1;
- memset (st->entry, HASH_NIL_MEMSET, bytes);
- return (st);
}
static void
-init_sizes (int64 hint, int32 *init_power)
+hash_init(MapType *t, Hmap *h, uint32 hint)
{
- int32 log = 0;
- int32 i;
-
- for (i = 32; i != 0; i >>= 1) {
- if ((hint >> (log + i)) != 0) {
- log += i;
- }
+ uint8 B;
+ byte *buckets;
+ uintptr i;
+ uintptr keysize, valuesize, bucketsize;
+ uint8 flags;
+ Bucket *b;
+
+ flags = CanFreeBucket;
+
+ // figure out how big we have to make everything
+ keysize = t->key->size;
+ if(keysize > MAXKEYSIZE) {
+ flags |= IndirectKey | CanFreeKey;
+ keysize = sizeof(byte*);
}
- log += 1 + (((hint << 3) >> log) >= 11); /* round up for utilization */
- if (log <= 14) {
- *init_power = log;
+ valuesize = t->elem->size;
+ if(valuesize > MAXVALUESIZE) {
+ flags |= IndirectValue;
+ valuesize = sizeof(byte*);
+ }
+ bucketsize = offsetof(Bucket, data[0]) + (keysize + valuesize) * BUCKETSIZE;
+
+ // 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 > BUCKETSIZE)
+ runtime·throw("key align too big");
+ if(t->elem->align > BUCKETSIZE)
+ runtime·throw("value align too big");
+ if(t->key->size % t->key->align != 0)
+ runtime·throw("key size not a multiple of key align");
+ if(t->elem->size % t->elem->align != 0)
+ runtime·throw("value size not a multiple of value align");
+ if(BUCKETSIZE < 8)
+ runtime·throw("bucketsize too small for proper alignment");
+ if(BUCKETSIZE != 8)
+ runtime·throw("must redo clearbucket");
+ if(sizeof(void*) == 4 && t->key->align > 4)
+ runtime·throw("need padding in bucket (key)");
+ if(sizeof(void*) == 4 && t->elem->align > 4)
+ runtime·throw("need padding in bucket (value)");
+
+ // find size parameter which will hold the requested # of elements
+ B = 0;
+ while(hint > BUCKETSIZE && hint > LOAD * ((uintptr)1 << B))
+ B++;
+
+ // allocate initial hash table
+ // If hint is large zeroing this memory could take a while.
+ if(checkgc) mstats.next_gc = mstats.heap_alloc;
+ if(B == 0) {
+ // done lazily later.
+ buckets = nil;
} else {
- *init_power = 12;
+ buckets = runtime·mallocgc(bucketsize << B, 0, 1, 0);
+ for(i = 0; i < (uintptr)1 << B; i++) {
+ b = (Bucket*)(buckets + i * bucketsize);
+ clearbucket(b);
+ }
}
-}
-static void
-hash_init (Hmap *h, int32 datasize, int64 hint)
-{
- int32 init_power;
-
- if(datasize < sizeof (void *))
- datasize = sizeof (void *);
- datasize = ROUND(datasize, sizeof (void *));
- init_sizes (hint, &init_power);
- h->datasize = datasize;
- assert (h->datasize == datasize);
- assert (sizeof (void *) <= h->datasize);
+ // initialize Hmap
+ // Note: we save all these stores to the end so gciter doesn't see
+ // a partially initialized map.
h->count = 0;
- h->changes = 0;
- h->st = hash_subtable_new (h, init_power, 0);
+ h->B = B;
+ h->flags = flags;
+ h->keysize = keysize;
+ h->valuesize = valuesize;
+ h->bucketsize = bucketsize;
h->hash0 = runtime·fastrand1();
+ h->buckets = buckets;
+ h->oldbuckets = nil;
+ h->nevacuate = 0;
+ if(docheck)
+ check(t, h);
}
+// Moves entries in oldbuckets[i] to buckets[i] and buckets[i+2^k].
+// We leave the original bucket intact, except for the evacuated marks, so that
+// iterators can still iterate through the old buckets.
static void
-hash_remove_n (struct hash_subtable *st, struct hash_entry *dst_e, int32 n)
+evacuate(MapType *t, Hmap *h, uintptr oldbucket)
{
- int32 elemsize = st->datasize + offsetof (struct hash_entry, data[0]);
- struct hash_entry *src_e = HASH_OFFSET (dst_e, n * elemsize);
- struct hash_entry *last_e = st->last;
- int32 shift = HASH_BITS - (st->power + st->used);
- int32 index_mask = (((hash_hash_t)1) << st->power) - 1;
- int32 dst_i = (((byte *) dst_e) - ((byte *) st->entry)) / elemsize;
- int32 src_i = dst_i + n;
- hash_hash_t hash;
- int32 skip;
- int32 bytes;
-
- while (dst_e != src_e) {
- if (src_e <= last_e) {
- struct hash_entry *cp_e = src_e;
- int32 save_dst_i = dst_i;
- while (cp_e <= last_e && (hash = cp_e->hash) != HASH_NIL &&
- ((hash >> shift) & index_mask) <= dst_i) {
- cp_e = HASH_OFFSET (cp_e, elemsize);
- dst_i++;
+ Bucket *b;
+ Bucket *nextb;
+ Bucket *x, *y;
+ Bucket *newx, *newy;
+ uintptr xi, yi;
+ uintptr newbit;
+ uintptr hash;
+ uintptr i;
+ byte *k, *v;
+ byte *xk, *yk, *xv, *yv;
+ byte *ob;
+
+ b = (Bucket*)(h->oldbuckets + oldbucket * h->bucketsize);
+ newbit = (uintptr)1 << (h->B - 1);
+
+ if(!evacuated(b)) {
+ // TODO: reuse overflow buckets instead of using new ones, if there
+ // is no iterator using the old buckets. (If CanFreeBuckets and !OldIterator.)
+
+ x = (Bucket*)(h->buckets + oldbucket * h->bucketsize);
+ y = (Bucket*)(h->buckets + (oldbucket + newbit) * h->bucketsize);
+ clearbucket(x);
+ clearbucket(y);
+ xi = 0;
+ yi = 0;
+ xk = x->data;
+ yk = y->data;
+ xv = xk + h->keysize * BUCKETSIZE;
+ yv = yk + h->keysize * BUCKETSIZE;
+ do {
+ for(i = 0, k = b->data, v = k + h->keysize * BUCKETSIZE; i < BUCKETSIZE; i++, k += h->keysize, v += h->valuesize) {
+ if(b->tophash[i] == 0)
+ continue;
+ hash = h->hash0;
+ t->key->alg->hash(&hash, t->key->size, IK(h, k));
+ // NOTE: if key != key, then this hash could be (and probably will be)
+ // entirely different from the old hash. We effectively only update
+ // the B'th bit of the hash in this case.
+ if((hash & newbit) == 0) {
+ if(xi == BUCKETSIZE) {
+ if(checkgc) mstats.next_gc = mstats.heap_alloc;
+ newx = runtime·mallocgc(h->bucketsize, 0, 1, 0);
+ clearbucket(newx);
+ x->overflow = newx;
+ x = newx;
+ xi = 0;
+ xk = x->data;
+ xv = xk + h->keysize * BUCKETSIZE;
+ }
+ x->tophash[xi] = b->tophash[i];
+ if((h->flags & IndirectKey) != 0) {
+ *(byte**)xk = *(byte**)k; // copy pointer
+ } else {
+ t->key->alg->copy(t->key->size, xk, k); // copy value
+ }
+ if((h->flags & IndirectValue) != 0) {
+ *(byte**)xv = *(byte**)v;
+ } else {
+ t->elem->alg->copy(t->elem->size, xv, v);
+ }
+ xi++;
+ xk += h->keysize;
+ xv += h->valuesize;
+ } else {
+ if(yi == BUCKETSIZE) {
+ if(checkgc) mstats.next_gc = mstats.heap_alloc;
+ newy = runtime·mallocgc(h->bucketsize, 0, 1, 0);
+ clearbucket(newy);
+ y->overflow = newy;
+ y = newy;
+ yi = 0;
+ yk = y->data;
+ yv = yk + h->keysize * BUCKETSIZE;
+ }
+ y->tophash[yi] = b->tophash[i];
+ if((h->flags & IndirectKey) != 0) {
+ *(byte**)yk = *(byte**)k;
+ } else {
+ t->key->alg->copy(t->key->size, yk, k);
+ }
+ if((h->flags & IndirectValue) != 0) {
+ *(byte**)yv = *(byte**)v;
+ } else {
+ t->elem->alg->copy(t->elem->size, yv, v);
+ }
+ yi++;
+ yk += h->keysize;
+ yv += h->valuesize;
+ }
}
- bytes = ((byte *) cp_e) - (byte *) src_e;
- memmove (dst_e, src_e, bytes);
- dst_e = HASH_OFFSET (dst_e, bytes);
- src_e = cp_e;
- src_i += dst_i - save_dst_i;
- if (src_e <= last_e && (hash = src_e->hash) != HASH_NIL) {
- skip = ((hash >> shift) & index_mask) - dst_i;
+
+ // mark as evacuated so we don't do it again.
+ // this also tells any iterators that this data isn't golden anymore.
+ nextb = b->overflow;
+ b->overflow = (Bucket*)((uintptr)nextb + 1);
+
+ b = nextb;
+ } while(b != nil);
+
+ // Free old overflow buckets as much as we can.
+ if((h->flags & OldIterator) == 0) {
+ b = (Bucket*)(h->oldbuckets + oldbucket * h->bucketsize);
+ if((h->flags & CanFreeBucket) != 0) {
+ while((nextb = overflowptr(b)) != nil) {
+ b->overflow = nextb->overflow;
+ runtime·free(nextb);
+ }
} else {
- skip = src_i - dst_i;
+ // can't explicitly free overflow buckets, but at least
+ // we can unlink them.
+ b->overflow = (Bucket*)1;
}
- } else {
- skip = src_i - dst_i;
}
- bytes = skip * elemsize;
- memset (dst_e, HASH_NIL_MEMSET, bytes);
- dst_e = HASH_OFFSET (dst_e, bytes);
- dst_i += skip;
}
-}
-static int32
-hash_insert_internal (MapType*, struct hash_subtable **pst, int32 flags, hash_hash_t hash,
- Hmap *h, void *data, void **pres);
+ // advance evacuation mark
+ if(oldbucket == h->nevacuate) {
+ h->nevacuate = oldbucket + 1;
+ if(oldbucket + 1 == newbit) { // newbit == # of oldbuckets
+ // free main bucket array
+ if((h->flags & (OldIterator | CanFreeBucket)) == CanFreeBucket) {
+ ob = h->oldbuckets;
+ h->oldbuckets = nil;
+ runtime·free(ob);
+ } else {
+ h->oldbuckets = nil;
+ }
+ }
+ }
+ if(docheck)
+ check(t, h);
+}
static void
-hash_conv (MapType *t, Hmap *h,
- struct hash_subtable *st, int32 flags,
- hash_hash_t hash,
- struct hash_entry *e)
+grow_work(MapType *t, Hmap *h, uintptr bucket)
{
- int32 new_flags = (flags + HASH_MAKE_USED (st->power)) | HASH_REHASH;
- int32 shift = HASH_BITS - HASH_USED (new_flags);
- hash_hash_t prefix_mask = (-(hash_hash_t)1) << shift;
- int32 elemsize = h->datasize + offsetof (struct hash_entry, data[0]);
- void *dummy_result;
- struct hash_entry *de;
- int32 index_mask = (1 << st->power) - 1;
- hash_hash_t e_hash;
- struct hash_entry *pe = HASH_OFFSET (e, -elemsize);
-
- while (e != st->entry && (e_hash = pe->hash) != HASH_NIL && (e_hash & HASH_MASK) != HASH_SUBHASH) {
- e = pe;
- pe = HASH_OFFSET (pe, -elemsize);
- }
+ uintptr noldbuckets;
- de = e;
- while (e <= st->last &&
- (e_hash = e->hash) != HASH_NIL &&
- (e_hash & HASH_MASK) != HASH_SUBHASH) {
- struct hash_entry *target_e = HASH_OFFSET (st->entry, ((e_hash >> shift) & index_mask) * elemsize);
- struct hash_entry *ne = HASH_OFFSET (e, elemsize);
- hash_hash_t current = e_hash & prefix_mask;
- if (de < target_e) {
- memset (de, HASH_NIL_MEMSET, ((byte *) target_e) - (byte *) de);
- de = target_e;
- }
- if ((hash & prefix_mask) == current ||
- (ne <= st->last && (e_hash = ne->hash) != HASH_NIL &&
- (e_hash & prefix_mask) == current)) {
- struct hash_subtable *new_st = hash_subtable_new (h, 1, HASH_USED (new_flags));
- int32 rc = hash_insert_internal (t, &new_st, new_flags, e->hash, h, e->data, &dummy_result);
- assert (rc == 0);
- memcpy(dummy_result, e->data, h->datasize);
- e = ne;
- while (e <= st->last && (e_hash = e->hash) != HASH_NIL && (e_hash & prefix_mask) == current) {
- assert ((e_hash & HASH_MASK) != HASH_SUBHASH);
- rc = hash_insert_internal (t, &new_st, new_flags, e_hash, h, e->data, &dummy_result);
- assert (rc == 0);
- memcpy(dummy_result, e->data, h->datasize);
- e = HASH_OFFSET (e, elemsize);
- }
- memset (de->data, HASH_NIL_MEMSET, h->datasize);
- *(struct hash_subtable **)de->data = new_st;
- de->hash = current | HASH_SUBHASH;
- } else {
- if (e != de) {
- memcpy (de, e, elemsize);
- }
- e = HASH_OFFSET (e, elemsize);
- }
- de = HASH_OFFSET (de, elemsize);
- }
- if (e != de) {
- hash_remove_n (st, de, (((byte *) e) - (byte *) de) / elemsize);
- }
+ noldbuckets = (uintptr)1 << (h->B - 1);
+
+ // make sure we evacuate the oldbucket corresponding
+ // to the bucket we're about to use
+ evacuate(t, h, bucket & (noldbuckets - 1));
+
+ // evacuate one more oldbucket to make progress on growing
+ if(h->oldbuckets != nil)
+ evacuate(t, h, h->nevacuate);
}
static void
-hash_grow (MapType *t, Hmap *h, struct hash_subtable **pst, int32 flags)
+hash_grow(MapType *t, Hmap *h)
{
- struct hash_subtable *old_st = *pst;
- int32 elemsize = h->datasize + offsetof (struct hash_entry, data[0]);
- *pst = hash_subtable_new (h, old_st->power + 1, HASH_USED (flags));
- struct hash_entry *last_e = old_st->last;
- struct hash_entry *e;
- void *dummy_result;
- int32 used = 0;
-
- flags |= HASH_REHASH;
- for (e = old_st->entry; e <= last_e; e = HASH_OFFSET (e, elemsize)) {
- hash_hash_t hash = e->hash;
- if (hash != HASH_NIL) {
- int32 rc = hash_insert_internal (t, pst, flags, e->hash, h, e->data, &dummy_result);
- assert (rc == 0);
- memcpy(dummy_result, e->data, h->datasize);
- used++;
- }
+ byte *old_buckets;
+ byte *new_buckets;
+ uint8 flags;
+
+ // allocate a bigger hash table
+ if(h->oldbuckets != nil)
+ runtime·throw("evacuation not done in time");
+ old_buckets = h->buckets;
+ // NOTE: this could be a big malloc, but since we don't need zeroing it is probably fast.
+ if(checkgc) mstats.next_gc = mstats.heap_alloc;
+ new_buckets = runtime·mallocgc((uintptr)h->bucketsize << (h->B + 1), 0, 1, 0);
+ flags = (h->flags & ~(Iterator | OldIterator));
+ if((h->flags & Iterator) != 0) {
+ flags |= OldIterator;
+ // We can't free indirect keys any more, as
+ // they are potentially aliased across buckets.
+ flags &= ~CanFreeKey;
}
- if (h->flag & CanFreeTable)
- free (old_st);
+
+ // commit the grow (atomic wrt gc)
+ h->B++;
+ h->flags = flags;
+ h->oldbuckets = old_buckets;
+ h->buckets = new_buckets;
+ h->nevacuate = 0;
+
+ // the actual copying of the hash table data is done incrementally
+ // by grow_work() and evacuate().
+ if(docheck)
+ check(t, h);
}
-static int32
-hash_lookup (MapType *t, Hmap *h, void *data, void **pres)
+// returns ptr to value associated with key *keyp, or nil if none.
+// if it returns non-nil, updates *keyp to point to the currently stored key.
+static byte*
+hash_lookup(MapType *t, Hmap *h, byte **keyp)
{
- int32 elemsize = h->datasize + offsetof (struct hash_entry, data[0]);
- hash_hash_t hash;
- struct hash_subtable *st = h->st;
- int32 used = 0;
- hash_hash_t e_hash;
- struct hash_entry *e;
- struct hash_entry *end_e;
void *key;
+ uintptr hash;
+ uintptr bucket, oldbucket;
+ Bucket *b;
+ uint8 top;
+ uintptr i;
bool eq;
+ byte *k, *k2, *v;
+ key = *keyp;
+ if(docheck)
+ check(t, h);
+ if(h->count == 0)
+ return nil;
hash = h->hash0;
- (*t->key->alg->hash) (&hash, t->key->size, data);
- hash &= ~HASH_MASK;
- hash += HASH_ADJUST (hash);
- for (;;) {
- int32 shift = HASH_BITS - (st->power + used);
- int32 index_mask = (1 << st->power) - 1;
- int32 i = (hash >> shift) & index_mask; /* i is the natural position of hash */
-
- e = HASH_OFFSET (st->entry, i * elemsize); /* e points to element i */
- e_hash = e->hash;
- if ((e_hash & HASH_MASK) != HASH_SUBHASH) { /* a subtable */
- break;
+ t->key->alg->hash(&hash, t->key->size, key);
+ bucket = hash & (((uintptr)1 << h->B) - 1);
+ if(h->oldbuckets != nil) {
+ oldbucket = bucket & (((uintptr)1 << (h->B - 1)) - 1);
+ b = (Bucket*)(h->oldbuckets + oldbucket * h->bucketsize);
+ if(evacuated(b)) {
+ b = (Bucket*)(h->buckets + bucket * h->bucketsize);
}
- used += st->power;
- st = *(struct hash_subtable **)e->data;
- }
- end_e = HASH_OFFSET (e, st->limit_bytes);
- while (e != end_e && (e_hash = e->hash) != HASH_NIL && e_hash < hash) {
- e = HASH_OFFSET (e, elemsize);
+ } else {
+ b = (Bucket*)(h->buckets + bucket * h->bucketsize);
}
- while (e != end_e && ((e_hash = e->hash) ^ hash) < HASH_SUBHASH) {
- key = e->data;
- if (h->flag & IndirectKey)
- key = *(void**)e->data;
- if (HASH_DATA_EQ (eq, t, h, data, key)) { /* a match */
- *pres = e->data;
- return (1);
+ top = hash >> (sizeof(uintptr)*8 - 8);
+ if(top == 0)
+ top = 1;
+ do {
+ for(i = 0, k = b->data, v = k + h->keysize * BUCKETSIZE; i < BUCKETSIZE; i++, k += h->keysize, v += h->valuesize) {
+ if(b->tophash[i] == top) {
+ k2 = IK(h, k);
+ t->key->alg->equal(&eq, t->key->size, key, k2);
+ if(eq) {
+ *keyp = k2;
+ return IV(h, v);
+ }
+ }
}
- e = HASH_OFFSET (e, elemsize);
- }
- USED(e_hash);
- *pres = 0;
- return (0);
+ b = b->overflow;
+ } while(b != nil);
+ return nil;
}
-static int32
-hash_remove (MapType *t, Hmap *h, void *data)
+// When an item is not found, fast versions return a pointer to this zeroed memory.
+static uint8 empty_value[MAXVALUESIZE];
+
+// Specialized versions of mapaccess1 for specific types.
+// See ./hashmap_fast.c and ../../cmd/gc/walk.c.
+#define HASH_LOOKUP1 runtime·mapaccess1_fast32
+#define HASH_LOOKUP2 runtime·mapaccess2_fast32
+#define KEYTYPE uint32
+#define HASHFUNC runtime·algarray[AMEM32].hash
+#define EQFUNC(x,y) ((x) == (y))
+#define EQMAYBE(x,y) ((x) == (y))
+#define HASMAYBE false
+#define QUICKEQ(x) true
+#include "hashmap_fast.c"
+
+#undef HASH_LOOKUP1
+#undef HASH_LOOKUP2
+#undef KEYTYPE
+#undef HASHFUNC
+#undef EQFUNC
+#undef EQMAYBE
+#undef HASMAYBE
+#undef QUICKEQ
+
+#define HASH_LOOKUP1 runtime·mapaccess1_fast64
+#define HASH_LOOKUP2 runtime·mapaccess2_fast64
+#define KEYTYPE uint64
+#define HASHFUNC runtime·algarray[AMEM64].hash
+#define EQFUNC(x,y) ((x) == (y))
+#define EQMAYBE(x,y) ((x) == (y))
+#define HASMAYBE false
+#define QUICKEQ(x) true
+#include "hashmap_fast.c"
+
+#undef HASH_LOOKUP1
+#undef HASH_LOOKUP2
+#undef KEYTYPE
+#undef HASHFUNC
+#undef EQFUNC
+#undef EQMAYBE
+#undef HASMAYBE
+#undef QUICKEQ
+
+#define HASH_LOOKUP1 runtime·mapaccess1_faststr
+#define HASH_LOOKUP2 runtime·mapaccess2_faststr
+#define KEYTYPE String
+#define HASHFUNC runtime·algarray[ASTRING].hash
+#define EQFUNC(x,y) ((x).len == (y).len && ((x).str == (y).str || runtime·memeq((x).str, (y).str, (x).len)))
+#define EQMAYBE(x,y) ((x).len == (y).len)
+#define HASMAYBE true
+#define QUICKEQ(x) ((x).len < 32)
+#include "hashmap_fast.c"
+
+static void
+hash_insert(MapType *t, Hmap *h, void *key, void *value)
{
- int32 elemsize = h->datasize + offsetof (struct hash_entry, data[0]);
- hash_hash_t hash;
- struct hash_subtable *st = h->st;
- int32 used = 0;
- hash_hash_t e_hash;
- struct hash_entry *e;
- struct hash_entry *end_e;
+ uintptr hash;
+ uintptr bucket;
+ uintptr i;
bool eq;
- void *key;
-
+ Bucket *b;
+ Bucket *newb;
+ uint8 *inserti;
+ byte *insertk, *insertv;
+ uint8 top;
+ byte *k, *v;
+ byte *kmem, *vmem;
+
+ if(docheck)
+ check(t, h);
hash = h->hash0;
- (*t->key->alg->hash) (&hash, t->key->size, data);
- hash &= ~HASH_MASK;
- hash += HASH_ADJUST (hash);
- for (;;) {
- int32 shift = HASH_BITS - (st->power + used);
- int32 index_mask = (1 << st->power) - 1;
- int32 i = (hash >> shift) & index_mask; /* i is the natural position of hash */
-
- e = HASH_OFFSET (st->entry, i * elemsize); /* e points to element i */
- e_hash = e->hash;
- if ((e_hash & HASH_MASK) != HASH_SUBHASH) { /* a subtable */
- break;
+ t->key->alg->hash(&hash, t->key->size, key);
+ if(h->buckets == nil) {
+ h->buckets = runtime·mallocgc(h->bucketsize, 0, 1, 0);
+ b = (Bucket*)(h->buckets);
+ clearbucket(b);
+ }
+
+ again:
+ bucket = hash & (((uintptr)1 << h->B) - 1);
+ if(h->oldbuckets != nil)
+ grow_work(t, h, bucket);
+ b = (Bucket*)(h->buckets + bucket * h->bucketsize);
+ top = hash >> (sizeof(uintptr)*8 - 8);
+ if(top == 0)
+ top = 1;
+ inserti = 0;
+ insertk = nil;
+ insertv = nil;
+ while(true) {
+ for(i = 0, k = b->data, v = k + h->keysize * BUCKETSIZE; i < BUCKETSIZE; i++, k += h->keysize, v += h->valuesize) {
+ if(b->tophash[i] != top) {
+ if(b->tophash[i] == 0 && inserti == nil) {
+ inserti = &b->tophash[i];
+ insertk = k;
+ insertv = v;
+ }
+ continue;
+ }
+ t->key->alg->equal(&eq, t->key->size, key, IK(h, k));
+ if(!eq)
+ continue;
+ // already have a mapping for key. Update it.
+ t->key->alg->copy(t->key->size, IK(h, k), key); // Need to update key for keys which are distinct but equal (e.g. +0.0 and -0.0)
+ t->elem->alg->copy(t->elem->size, IV(h, v), value);
+ if(docheck)
+ check(t, h);
+ return;
}
- used += st->power;
- st = *(struct hash_subtable **)e->data;
+ if(b->overflow == nil)
+ break;
+ b = b->overflow;
}
- end_e = HASH_OFFSET (e, st->limit_bytes);
- while (e != end_e && (e_hash = e->hash) != HASH_NIL && e_hash < hash) {
- e = HASH_OFFSET (e, elemsize);
+
+ // did not find mapping for key. Allocate new cell & add entry.
+ if(h->count >= LOAD * ((uintptr)1 << h->B) && h->count >= BUCKETSIZE) {
+ hash_grow(t, h);
+ goto again; // Growing the table invalidates everything, so try again
}
- while (e != end_e && ((e_hash = e->hash) ^ hash) < HASH_SUBHASH) {
- key = e->data;
- if (h->flag & IndirectKey)
- key = *(void**)e->data;
- if (HASH_DATA_EQ (eq, t, h, data, key)) { /* a match */
- // Free key if indirect, but only if reflect can't be
- // holding a pointer to it. Deletions are rare,
- // indirect (large) keys are rare, reflect on maps
- // is rare. So in the rare, rare, rare case of deleting
- // an indirect key from a map that has been reflected on,
- // we leave the key for garbage collection instead of
- // freeing it here.
- if (h->flag & CanFreeKey)
- free (key);
- if (h->flag & IndirectVal)
- free (*(void**)((byte*)e->data + h->valoff));
- hash_remove_n (st, e, 1);
- h->count--;
- return (1);
- }
- e = HASH_OFFSET (e, elemsize);
+
+ if(inserti == nil) {
+ // all current buckets are full, allocate a new one.
+ if(checkgc) mstats.next_gc = mstats.heap_alloc;
+ newb = runtime·mallocgc(h->bucketsize, 0, 1, 0);
+ clearbucket(newb);
+ b->overflow = newb;
+ inserti = newb->tophash;
+ insertk = newb->data;
+ insertv = insertk + h->keysize * BUCKETSIZE;
+ }
+
+ // store new key/value at insert position
+ if((h->flags & IndirectKey) != 0) {
+ if(checkgc) mstats.next_gc = mstats.heap_alloc;
+ kmem = runtime·mallocgc(t->key->size, 0, 1, 0);
+ *(byte**)insertk = kmem;
+ insertk = kmem;
+ }
+ if((h->flags & IndirectValue) != 0) {
+ if(checkgc) mstats.next_gc = mstats.heap_alloc;
+ vmem = runtime·mallocgc(t->elem->size, 0, 1, 0);
+ *(byte**)insertv = vmem;
+ insertv = vmem;
}
- USED(e_hash);
- return (0);
+ t->key->alg->copy(t->key->size, insertk, key);
+ t->elem->alg->copy(t->elem->size, insertv, value);
+ *inserti = top;
+ h->count++;
+ if(docheck)
+ check(t, h);
}
-static int32
-hash_insert_internal (MapType *t, struct hash_subtable **pst, int32 flags, hash_hash_t hash,
- Hmap *h, void *data, void **pres)
+static void
+hash_remove(MapType *t, Hmap *h, void *key)
{
- int32 elemsize = h->datasize + offsetof (struct hash_entry, data[0]);
+ uintptr hash;
+ uintptr bucket;
+ Bucket *b;
+ uint8 top;
+ uintptr i;
+ byte *k, *v;
bool eq;
-
- if ((flags & HASH_REHASH) == 0) {
- hash += HASH_ADJUST (hash);
- hash &= ~HASH_MASK;
- }
- for (;;) {
- struct hash_subtable *st = *pst;
- int32 shift = HASH_BITS - (st->power + HASH_USED (flags));
- int32 index_mask = (1 << st->power) - 1;
- int32 i = (hash >> shift) & index_mask; /* i is the natural position of hash */
- struct hash_entry *start_e =
- HASH_OFFSET (st->entry, i * elemsize); /* start_e is the pointer to element i */
- struct hash_entry *e = start_e; /* e is going to range over [start_e, end_e) */
- struct hash_entry *end_e;
- hash_hash_t e_hash = e->hash;
-
- if ((e_hash & HASH_MASK) == HASH_SUBHASH) { /* a subtable */
- pst = (struct hash_subtable **) e->data;
- flags += HASH_MAKE_USED (st->power);
- continue;
- }
- end_e = HASH_OFFSET (start_e, st->limit_bytes);
- while (e != end_e && (e_hash = e->hash) != HASH_NIL && e_hash < hash) {
- e = HASH_OFFSET (e, elemsize);
- i++;
- }
- if (e != end_e && e_hash != HASH_NIL) {
- /* ins_e ranges over the elements that may match */
- struct hash_entry *ins_e = e;
- int32 ins_i = i;
- hash_hash_t ins_e_hash;
- void *key;
- while (ins_e != end_e && ((e_hash = ins_e->hash) ^ hash) < HASH_SUBHASH) {
- key = ins_e->data;
- if (h->flag & IndirectKey)
- key = *(void**)key;
- if (HASH_DATA_EQ (eq, t, h, data, key)) { /* a match */
- *pres = ins_e->data;
- return (1);
- }
- if (e_hash == hash) { /* adjust hash if it collides */
- assert ((flags & HASH_REHASH) == 0);
- hash++;
- if ((hash & HASH_MASK) == HASH_SUBHASH)
- runtime·throw("runtime: map hash collision overflow");
- }
- ins_e = HASH_OFFSET (ins_e, elemsize);
- ins_i++;
- if (e_hash <= hash) { /* set e to insertion point */
- e = ins_e;
- i = ins_i;
- }
+
+ if(docheck)
+ check(t, h);
+ if(h->count == 0)
+ return;
+ hash = h->hash0;
+ t->key->alg->hash(&hash, t->key->size, key);
+ bucket = hash & (((uintptr)1 << h->B) - 1);
+ if(h->oldbuckets != nil)
+ grow_work(t, h, bucket);
+ b = (Bucket*)(h->buckets + bucket * h->bucketsize);
+ top = hash >> (sizeof(uintptr)*8 - 8);
+ if(top == 0)
+ top = 1;
+ do {
+ for(i = 0, k = b->data, v = k + h->keysize * BUCKETSIZE; i < BUCKETSIZE; i++, k += h->keysize, v += h->valuesize) {
+ if(b->tophash[i] != top)
+ continue;
+ t->key->alg->equal(&eq, t->key->size, key, IK(h, k));
+ if(!eq)
+ continue;
+
+ if((h->flags & CanFreeKey) != 0) {
+ k = *(byte**)k;
}
- /* set ins_e to the insertion point for the new element */
- ins_e = e;
- ins_i = i;
- ins_e_hash = 0;
- /* move ins_e to point at the end of the contiguous block, but
- stop if any element can't be moved by one up */
- while (ins_e <= st->last && (ins_e_hash = ins_e->hash) != HASH_NIL &&
- ins_i + 1 - ((ins_e_hash >> shift) & index_mask) < st->max_probes &&
- (ins_e_hash & HASH_MASK) != HASH_SUBHASH) {
- ins_e = HASH_OFFSET (ins_e, elemsize);
- ins_i++;
+ if((h->flags & IndirectValue) != 0) {
+ v = *(byte**)v;
}
- if (e == end_e || ins_e > st->last || ins_e_hash != HASH_NIL) {
- e = end_e; /* can't insert; must grow or convert to subtable */
- } else { /* make space for element */
- memmove (HASH_OFFSET (e, elemsize), e, ((byte *) ins_e) - (byte *) e);
+
+ b->tophash[i] = 0;
+ h->count--;
+
+ if((h->flags & CanFreeKey) != 0) {
+ runtime·free(k);
}
+ if((h->flags & IndirectValue) != 0) {
+ runtime·free(v);
+ }
+ // TODO: consolidate buckets if they are mostly empty
+ // can only consolidate if there are no live iterators at this size.
+ if(docheck)
+ check(t, h);
+ return;
}
- if (e != end_e) {
- e->hash = hash;
- *pres = e->data;
- return (0);
- }
- h->changes++;
- if (st->power < HASH_MAX_POWER) {
- hash_grow (t, h, pst, flags);
- } else {
- hash_conv (t, h, st, flags, hash, start_e);
- }
- }
+ b = b->overflow;
+ } while(b != nil);
}
-static int32
-hash_insert (MapType *t, Hmap *h, void *data, void **pres)
+// TODO: shrink the map, the same way we grow it.
+
+// If you modify hash_iter, also change cmd/gc/range.c to indicate
+// the size of this structure.
+struct hash_iter
{
- uintptr hash;
- int32 rc;
+ uint8* key; // Must be in first position. Write nil to indicate iteration end (see cmd/gc/range.c).
+ uint8* value;
- hash = h->hash0;
- (*t->key->alg->hash) (&hash, t->key->size, data);
- rc = hash_insert_internal (t, &h->st, 0, hash, h, data, pres);
+ MapType *t;
+ Hmap *h;
- h->count += (rc == 0); /* increment count if element didn't previously exist */
- return (rc);
-}
+ // end point for iteration
+ uintptr endbucket;
+ bool wrapped;
-static uint32
-hash_count (Hmap *h)
-{
- return (h->count);
-}
+ // state of table at time iterator is initialized
+ uint8 B;
+ byte *buckets;
+
+ // iter state
+ uintptr bucket;
+ struct Bucket *bptr;
+ uintptr i;
+ intptr check_bucket;
+};
+// iterator state:
+// bucket: the current bucket ID
+// b: the current Bucket in the chain
+// i: the next offset to check in the current bucket
static void
-iter_restart (struct hash_iter *it, struct hash_subtable *st, int32 used)
+hash_iter_init(MapType *t, Hmap *h, struct hash_iter *it)
{
- int32 elemsize = it->elemsize;
- hash_hash_t last_hash = it->last_hash;
- struct hash_entry *e;
- hash_hash_t e_hash;
- struct hash_iter_sub *sub = &it->subtable_state[it->i];
- struct hash_entry *last;
-
- for (;;) {
- int32 shift = HASH_BITS - (st->power + used);
- int32 index_mask = (1 << st->power) - 1;
- int32 i = (last_hash >> shift) & index_mask;
-
- last = st->last;
- e = HASH_OFFSET (st->entry, i * elemsize);
- sub->start = st->entry;
- sub->last = last;
-
- if ((e->hash & HASH_MASK) != HASH_SUBHASH) {
+ uint32 old;
+
+ if(sizeof(struct hash_iter) / sizeof(uintptr) != 11) {
+ runtime·throw("hash_iter size incorrect"); // see ../../cmd/gc/range.c
+ }
+ it->t = t;
+ it->h = h;
+
+ // grab snapshot of bucket state
+ it->B = h->B;
+ it->buckets = h->buckets;
+
+ // iterator state
+ it->bucket = it->endbucket = runtime·fastrand1() & (((uintptr)1 << h->B) - 1);
+ it->wrapped = false;
+ it->bptr = nil;
+
+ // Remember we have an iterator.
+ // Can run concurrently with another hash_iter_init() and with reflect·mapiterinit().
+ for(;;) {
+ old = h->flags;
+ if((old&(Iterator|OldIterator)) == (Iterator|OldIterator))
+ break;
+ if(runtime·cas(&h->flags, old, old|Iterator|OldIterator))
break;
- }
- sub->e = HASH_OFFSET (e, elemsize);
- sub = &it->subtable_state[++(it->i)];
- used += st->power;
- st = *(struct hash_subtable **)e->data;
}
- while (e <= last && ((e_hash = e->hash) == HASH_NIL || e_hash <= last_hash)) {
- e = HASH_OFFSET (e, elemsize);
+
+ if(h->buckets == nil) {
+ // Empty map. Force next hash_next to exit without
+ // evalulating h->bucket.
+ it->wrapped = true;
}
- sub->e = e;
}
-static void *
-hash_next (struct hash_iter *it)
+// initializes it->key and it->value to the next key/value pair
+// in the iteration, or nil if we've reached the end.
+static void
+hash_next(struct hash_iter *it)
{
- int32 elemsize;
- struct hash_iter_sub *sub;
- struct hash_entry *e;
- struct hash_entry *last;
- hash_hash_t e_hash;
-
- if (it->changes != it->h->changes) { /* hash table's structure changed; recompute */
- if (~it->last_hash == 0)
- return (0);
- it->changes = it->h->changes;
- it->i = 0;
- iter_restart (it, it->h->st, 0);
- }
- elemsize = it->elemsize;
-
-Again:
- e_hash = 0;
- sub = &it->subtable_state[it->i];
- e = sub->e;
- last = sub->last;
-
- if (e != sub->start && it->last_hash != HASH_OFFSET (e, -elemsize)->hash) {
- struct hash_entry *start = HASH_OFFSET (e, -(elemsize * HASH_MAX_PROBES));
- struct hash_entry *pe = HASH_OFFSET (e, -elemsize);
- hash_hash_t last_hash = it->last_hash;
- if (start < sub->start) {
- start = sub->start;
- }
- while (e != start && ((e_hash = pe->hash) == HASH_NIL || last_hash < e_hash)) {
- e = pe;
- pe = HASH_OFFSET (pe, -elemsize);
- }
- while (e <= last && ((e_hash = e->hash) == HASH_NIL || e_hash <= last_hash)) {
- e = HASH_OFFSET (e, elemsize);
- }
- }
+ Hmap *h;
+ MapType *t;
+ uintptr bucket, oldbucket;
+ uintptr hash;
+ Bucket *b;
+ uintptr i;
+ intptr check_bucket;
+ bool eq;
+ byte *k, *v;
+ byte *rk, *rv;
- for (;;) {
- while (e <= last && (e_hash = e->hash) == HASH_NIL) {
- e = HASH_OFFSET (e, elemsize);
+ h = it->h;
+ t = it->t;
+ bucket = it->bucket;
+ b = it->bptr;
+ i = it->i;
+ check_bucket = it->check_bucket;
+
+next:
+ if(b == nil) {
+ if(bucket == it->endbucket && it->wrapped) {
+ // end of iteration
+ it->key = nil;
+ it->value = nil;
+ return;
}
- if (e > last) {
- if (it->i == 0) {
- if(!it->cycled) {
- // Wrap to zero and iterate up until it->cycle.
- it->cycled = true;
- it->last_hash = 0;
- it->subtable_state[0].e = it->h->st->entry;
- it->subtable_state[0].start = it->h->st->entry;
- it->subtable_state[0].last = it->h->st->last;
- goto Again;
- }
- // Set last_hash to impossible value and
- // break it->changes, so that check at top of
- // hash_next will be used if we get called again.
- it->last_hash = ~(uintptr_t)0;
- it->changes--;
- return (0);
+ if(h->oldbuckets != nil && 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 & (((uintptr)1 << (it->B - 1)) - 1);
+ b = (Bucket*)(h->oldbuckets + oldbucket * h->bucketsize);
+ if(!evacuated(b)) {
+ check_bucket = bucket;
} else {
- it->i--;
- sub = &it->subtable_state[it->i];
- e = sub->e;
- last = sub->last;
+ b = (Bucket*)(it->buckets + bucket * h->bucketsize);
+ check_bucket = -1;
}
- } else if ((e_hash & HASH_MASK) != HASH_SUBHASH) {
- if(it->cycled && e->hash > it->cycle) {
- // Already returned this.
- // Set last_hash to impossible value and
- // break it->changes, so that check at top of
- // hash_next will be used if we get called again.
- it->last_hash = ~(uintptr_t)0;
- it->changes--;
- return (0);
- }
- it->last_hash = e->hash;
- sub->e = HASH_OFFSET (e, elemsize);
- return (e->data);
} else {
- struct hash_subtable *st =
- *(struct hash_subtable **)e->data;
- sub->e = HASH_OFFSET (e, elemsize);
- it->i++;
- assert (it->i < sizeof (it->subtable_state) /
- sizeof (it->subtable_state[0]));
- sub = &it->subtable_state[it->i];
- sub->e = e = st->entry;
- sub->start = st->entry;
- sub->last = last = st->last;
+ b = (Bucket*)(it->buckets + bucket * h->bucketsize);
+ check_bucket = -1;
}
- }
-}
-
-static void
-hash_iter_init (MapType *t, Hmap *h, struct hash_iter *it)
-{
- it->elemsize = h->datasize + offsetof (struct hash_entry, data[0]);
- it->changes = h->changes;
- it->i = 0;
- it->h = h;
- it->t = t;
- it->last_hash = 0;
- it->subtable_state[0].e = h->st->entry;
- it->subtable_state[0].start = h->st->entry;
- it->subtable_state[0].last = h->st->last;
-
- // fastrand1 returns 31 useful bits.
- // We don't care about not having a bottom bit but we
- // do want top bits.
- if(sizeof(void*) == 8)
- it->cycle = (uint64)runtime·fastrand1()<<33 | (uint64)runtime·fastrand1()<<2;
- else
- it->cycle = runtime·fastrand1()<<1;
- it->cycled = false;
- it->last_hash = it->cycle;
- iter_restart(it, it->h->st, 0);
-}
-
-static void
-clean_st (Hmap *h, struct hash_subtable *st, int32 *slots, int32 *used)
-{
- int32 elemsize = st->datasize + offsetof (struct hash_entry, data[0]);
- struct hash_entry *e = st->entry;
- struct hash_entry *last = st->last;
- int32 lslots = (((byte *) (last+1)) - (byte *) e) / elemsize;
- int32 lused = 0;
-
- while (e <= last) {
- hash_hash_t hash = e->hash;
- if ((hash & HASH_MASK) == HASH_SUBHASH) {
- clean_st (h, *(struct hash_subtable **)e->data, slots, used);
- } else {
- lused += (hash != HASH_NIL);
+ bucket++;
+ if(bucket == ((uintptr)1 << it->B)) {
+ bucket = 0;
+ it->wrapped = true;
}
- e = HASH_OFFSET (e, elemsize);
+ i = 0;
}
- if (h->flag & CanFreeTable)
- free (st);
- *slots += lslots;
- *used += lused;
-}
-
-static void
-hash_destroy (Hmap *h)
-{
- int32 slots = 0;
- int32 used = 0;
-
- clean_st (h, h->st, &slots, &used);
- free (h);
-}
-
-static void
-hash_visit_internal (struct hash_subtable *st,
- int32 used, int32 level,
- void (*data_visit) (void *arg, int32 level, void *data),
- void *arg)
-{
- int32 elemsize = st->datasize + offsetof (struct hash_entry, data[0]);
- struct hash_entry *e = st->entry;
- int32 shift = HASH_BITS - (used + st->power);
- int32 i = 0;
-
- while (e <= st->last) {
- int32 index = ((e->hash >> (shift - 1)) >> 1) & ((1 << st->power) - 1);
- if ((e->hash & HASH_MASK) == HASH_SUBHASH) {
- (*data_visit) (arg, level, e->data);
- hash_visit_internal (*(struct hash_subtable **)e->data,
- used + st->power, level + 1, data_visit, arg);
- } else {
- (*data_visit) (arg, level, e->data);
- }
- if (e->hash != HASH_NIL) {
- assert (i < index + st->max_probes);
- assert (index <= i);
+ k = b->data + h->keysize * i;
+ v = b->data + h->keysize * BUCKETSIZE + h->valuesize * i;
+ for(; i < BUCKETSIZE; i++, k += h->keysize, v += h->valuesize) {
+ if(b->tophash[i] != 0) {
+ if(check_bucket >= 0) {
+ // Special case: iterator was started during a grow and the
+ // grow is not done yet. We're working on a bucket whose
+ // oldbucket has not been evacuated yet. So we iterate
+ // through the oldbucket, skipping any keys that will go
+ // to the other new bucket (each oldbucket expands to two
+ // buckets during a grow).
+ t->key->alg->equal(&eq, t->key->size, IK(h, k), IK(h, k));
+ if(!eq) {
+ // Hash is meaningless if k != k (NaNs). Return all
+ // NaNs during the first of the two new buckets.
+ if(bucket >= ((uintptr)1 << (it->B - 1))) {
+ continue;
+ }
+ } else {
+ // If the item in the oldbucket is not destined for
+ // the current new bucket in the iteration, skip it.
+ hash = h->hash0;
+ t->key->alg->hash(&hash, t->key->size, IK(h, k));
+ if((hash & (((uintptr)1 << it->B) - 1)) != check_bucket) {
+ continue;
+ }
+ }
+ }
+ if(!evacuated(b)) {
+ // this is the golden data, we can return it.
+ it->key = IK(h, k);
+ it->value = IV(h, v);
+ } else {
+ // The hash table has grown since the iterator was started.
+ // The golden data for this key is now somewhere else.
+ t->key->alg->equal(&eq, t->key->size, IK(h, k), IK(h, k));
+ if(eq) {
+ // 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 = IK(h, k);
+ rv = hash_lookup(t, it->h, &rk);
+ if(rv == 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 = IK(h, k);
+ it->value = IV(h, v);
+ }
+ }
+ it->bucket = bucket;
+ it->bptr = b;
+ it->i = i + 1;
+ it->check_bucket = check_bucket;
+ return;
}
- e = HASH_OFFSET (e, elemsize);
- i++;
}
+ b = overflowptr(b);
+ i = 0;
+ goto next;
}
-static void
-hash_visit (Hmap *h, void (*data_visit) (void *arg, int32 level, void *data), void *arg)
-{
- hash_visit_internal (h->st, 0, 0, data_visit, arg);
-}
+
+#define PHASE_BUCKETS 0
+#define PHASE_OLD_BUCKETS 1
+#define PHASE_TABLE 2
+#define PHASE_OLD_TABLE 3
+#define PHASE_DONE 4
// Initialize the iterator.
// Returns false if Hmap contains no pointers (in which case the iterator is not initialized).
bool
hash_gciter_init (Hmap *h, struct hash_gciter *it)
{
- // GC during map initialization
- if(h->st == nil)
+ // GC during map initialization or on an empty map.
+ if(h->buckets == nil)
return false;
- it->elemsize = h->datasize + offsetof (struct hash_entry, data[0]);
- it->flag = h->flag;
- it->valoff = h->valoff;
- it->i = 0;
- it->st = h->st;
- it->subtable_state[it->i].e = h->st->entry;
- it->subtable_state[it->i].last = h->st->last;
+ it->h = h;
+ it->phase = PHASE_BUCKETS;
+ it->bucket = 0;
+ it->b = nil;
+
+ // TODO: finish evacuating oldbuckets so that we can collect
+ // oldbuckets? We don't want to keep a partially evacuated
+ // table around forever, so each gc could make at least some
+ // evacuation progress. Need to be careful about concurrent
+ // access if we do concurrent gc. Even if not, we don't want
+ // to make the gc pause any longer than it has to be.
+
return true;
}
-// Returns true and fills *data with subtable/key/value data,
+// Returns true and fills *data with internal structure/key/value data,
// or returns false if the iterator has terminated.
+// Ugh, this interface is really annoying. I want a callback fn!
bool
-hash_gciter_next (struct hash_gciter *it, struct hash_gciter_data *data)
+hash_gciter_next(struct hash_gciter *it, struct hash_gciter_data *data)
{
- struct hash_entry *e;
- struct hash_gciter_sub *sub;
+ Hmap *h;
+ uintptr bucket, oldbucket;
+ Bucket *b, *oldb;
+ uintptr i;
+ byte *k, *v;
+
+ h = it->h;
+ bucket = it->bucket;
+ b = it->b;
+ i = it->i;
data->st = nil;
data->key_data = nil;
data->val_data = nil;
-
- // pointer to the first-level table
- if(it->st != nil) {
- data->st = it->st;
- it->st = nil;
- return true;
- }
-
-popped:
- sub = &it->subtable_state[it->i];
- e = sub->e;
- while (e <= sub->last) {
- if ((e->hash & HASH_MASK) == HASH_SUBHASH) {
- struct hash_subtable *st = *(struct hash_subtable **)e->data;
- data->st = st;
- sub->e = HASH_OFFSET (e, it->elemsize);
-
- // push
- it->i++;
- assert (it->i < nelem(it->subtable_state));
- sub++;
- sub->e = st->entry;
- sub->last = st->last;
-
- return true;
+ data->indirectkey = (h->flags & IndirectKey) != 0;
+ data->indirectval = (h->flags & IndirectValue) != 0;
+
+next:
+ switch (it->phase) {
+ case PHASE_BUCKETS:
+ if(b != nil) {
+ k = b->data + h->keysize * i;
+ v = b->data + h->keysize * BUCKETSIZE + h->valuesize * i;
+ for(; i < BUCKETSIZE; i++, k += h->keysize, v += h->valuesize) {
+ if(b->tophash[i] != 0) {
+ data->key_data = k;
+ data->val_data = v;
+ it->bucket = bucket;
+ it->b = b;
+ it->i = i + 1;
+ return true;
+ }
+ }
+ b = b->overflow;
+ if(b != nil) {
+ data->st = (byte*)b;
+ it->bucket = bucket;
+ it->b = b;
+ it->i = 0;
+ return true;
+ }
}
- if(e->hash != HASH_NIL) {
- void *key_data = e->data;
- void *val_data = (byte*)e->data + it->valoff;
- data->key_data = key_data;
- data->val_data = val_data;
- data->indirectkey = (it->flag & IndirectKey) != 0;
- data->indirectval = (it->flag & IndirectVal) != 0;
- sub->e = HASH_OFFSET (e, it->elemsize);
+ while(bucket < ((uintptr)1 << h->B)) {
+ if(h->oldbuckets != nil) {
+ oldbucket = bucket & (((uintptr)1 << (h->B - 1)) - 1);
+ oldb = (Bucket*)(h->oldbuckets + oldbucket * h->bucketsize);
+ if(!evacuated(oldb)) {
+ // new bucket isn't valid yet
+ bucket++;
+ continue;
+ }
+ }
+ b = (Bucket*)(h->buckets + bucket * h->bucketsize);
+ i = 0;
+ bucket++;
+ goto next;
+ }
+ it->phase = PHASE_OLD_BUCKETS;
+ bucket = 0;
+ b = nil;
+ goto next;
+ case PHASE_OLD_BUCKETS:
+ if(h->oldbuckets == nil) {
+ it->phase = PHASE_TABLE;
+ goto next;
+ }
+ if(b != nil) {
+ k = b->data + h->keysize * i;
+ v = b->data + h->keysize * BUCKETSIZE + h->valuesize * i;
+ for(; i < BUCKETSIZE; i++, k += h->keysize, v += h->valuesize) {
+ if(b->tophash[i] != 0) {
+ data->key_data = k;
+ data->val_data = v;
+ it->bucket = bucket;
+ it->b = b;
+ it->i = i + 1;
+ return true;
+ }
+ }
+ b = overflowptr(b);
+ if(b != nil) {
+ data->st = (byte*)b;
+ it->bucket = bucket;
+ it->b = b;
+ it->i = 0;
+ return true;
+ }
+ }
+ if(bucket < ((uintptr)1 << (h->B - 1))) {
+ b = (Bucket*)(h->oldbuckets + bucket * h->bucketsize);
+ bucket++;
+ i = 0;
+ goto next;
+ }
+ it->phase = PHASE_TABLE;
+ goto next;
+ case PHASE_TABLE:
+ it->phase = PHASE_OLD_TABLE;
+ data->st = h->buckets;
+ return true;
+ case PHASE_OLD_TABLE:
+ it->phase = PHASE_DONE;
+ if(h->oldbuckets != nil) {
+ data->st = h->oldbuckets;
return true;
+ } else {
+ goto next;
}
- e = HASH_OFFSET (e, it->elemsize);
- }
- if(it->i != 0) {
- // pop
- it->i--;
- goto popped;
}
+ if(it->phase != PHASE_DONE)
+ runtime·throw("bad phase at done");
return false;
}
@@ -787,35 +1080,20 @@ popped:
/// interfaces to go runtime
//
-static void**
-hash_valptr(Hmap *h, void *p)
-{
- p = (byte*)p + h->valoff;
- if(h->flag & IndirectVal)
- p = *(void**)p;
- return p;
-}
-
-
-static void**
-hash_keyptr(Hmap *h, void *p)
+void
+reflect·ismapkey(Type *typ, bool ret)
{
- if(h->flag & IndirectKey)
- p = *(void**)p;
- return p;
+ ret = typ != nil && typ->alg->hash != runtime·nohash;
+ FLUSH(&ret);
}
-static int32 debug = 0;
-
Hmap*
runtime·makemap_c(MapType *typ, int64 hint)
{
Hmap *h;
- Type *key, *val;
- uintptr ksize, vsize;
+ Type *key;
key = typ->key;
- val = typ->elem;
if(hint < 0 || (int32)hint != hint)
runtime·panicstring("makemap: size out of range");
@@ -824,7 +1102,6 @@ runtime·makemap_c(MapType *typ, int64 hint)
runtime·throw("runtime.makemap: unsupported map key type");
h = runtime·mal(sizeof(*h));
- h->flag |= CanFreeTable; /* until reflect gets involved, free is okay */
if(UseSpanType) {
if(false) {
@@ -833,34 +1110,14 @@ runtime·makemap_c(MapType *typ, int64 hint)
runtime·settype(h, (uintptr)typ | TypeInfo_Map);
}
- ksize = ROUND(key->size, sizeof(void*));
- vsize = ROUND(val->size, sizeof(void*));
- if(ksize > MaxData || vsize > MaxData || ksize+vsize > MaxData) {
- // Either key is too big, or value is, or combined they are.
- // Prefer to keep the key if possible, because we look at
- // keys more often than values.
- if(ksize > MaxData - sizeof(void*)) {
- // No choice but to indirect the key.
- h->flag |= IndirectKey;
- h->flag |= CanFreeKey; /* until reflect gets involved, free is okay */
- ksize = sizeof(void*);
- }
- if(vsize > MaxData - ksize) {
- // Have to indirect the value.
- h->flag |= IndirectVal;
- vsize = sizeof(void*);
- }
- }
-
- h->valoff = ksize;
- hash_init(h, ksize+vsize, hint);
+ hash_init(typ, h, hint);
// these calculations are compiler dependent.
// figure out offsets of map call arguments.
if(debug) {
runtime·printf("makemap: map=%p; keysize=%p; valsize=%p; keyalg=%p; valalg=%p\n",
- h, key->size, val->size, key->alg, val->alg);
+ h, key->size, typ->elem->size, key->alg, typ->elem->alg);
}
return h;
@@ -890,7 +1147,7 @@ runtime·mapaccess(MapType *t, Hmap *h, byte *ak, byte *av, bool *pres)
Type *elem;
elem = t->elem;
- if(h == nil) {
+ if(h == nil || h->count == 0) {
elem->alg->copy(elem->size, av, nil);
*pres = false;
return;
@@ -899,10 +1156,11 @@ runtime·mapaccess(MapType *t, Hmap *h, byte *ak, byte *av, bool *pres)
if(runtime·gcwaiting)
runtime·gosched();
- res = nil;
- if(hash_lookup(t, h, ak, (void**)&res)) {
+ res = hash_lookup(t, h, &ak);
+
+ if(res != nil) {
*pres = true;
- elem->alg->copy(elem->size, av, hash_valptr(h, res));
+ elem->alg->copy(elem->size, av, res);
} else {
*pres = false;
elem->alg->copy(elem->size, av, nil);
@@ -915,7 +1173,7 @@ void
runtime·mapaccess1(MapType *t, Hmap *h, ...)
{
byte *ak, *av;
- bool pres;
+ byte *res;
if(raceenabled && h != nil)
runtime·racereadpc(h, runtime·getcallerpc(&t), runtime·mapaccess1);
@@ -923,7 +1181,12 @@ runtime·mapaccess1(MapType *t, Hmap *h, ...)
ak = (byte*)(&h + 1);
av = ak + ROUND(t->key->size, Structrnd);
- runtime·mapaccess(t, h, ak, av, &pres);
+ if(h == nil || h->count == 0) {
+ t->elem->alg->copy(t->elem->size, av, nil);
+ } else {
+ res = hash_lookup(t, h, &ak);
+ t->elem->alg->copy(t->elem->size, av, res);
+ }
if(debug) {
runtime·prints("runtime.mapaccess1: map=");
@@ -932,8 +1195,6 @@ runtime·mapaccess1(MapType *t, Hmap *h, ...)
t->key->alg->print(t->key->size, ak);
runtime·prints("; val=");
t->elem->alg->print(t->elem->size, av);
- runtime·prints("; pres=");
- runtime·printbool(pres);
runtime·prints("\n");
}
}
@@ -960,7 +1221,7 @@ runtime·mapaccess2(MapType *t, Hmap *h, ...)
runtime·prints("; key=");
t->key->alg->print(t->key->size, ak);
runtime·prints("; val=");
- t->elem->alg->print(t->key->size, av);
+ t->elem->alg->print(t->elem->size, av);
runtime·prints("; pres=");
runtime·printbool(*ap);
runtime·prints("\n");
@@ -999,9 +1260,6 @@ reflect·mapaccess(MapType *t, Hmap *h, uintptr key, uintptr val, bool pres)
void
runtime·mapassign(MapType *t, Hmap *h, byte *ak, byte *av)
{
- byte *res;
- int32 hit;
-
if(h == nil)
runtime·panicstring("assignment to entry in nil map");
@@ -1010,19 +1268,9 @@ runtime·mapassign(MapType *t, Hmap *h, byte *ak, byte *av)
if(av == nil) {
hash_remove(t, h, ak);
- return;
- }
-
- res = nil;
- hit = hash_insert(t, h, ak, (void**)&res);
- if(!hit) {
- if(h->flag & IndirectKey)
- *(void**)res = runtime·mal(t->key->size);
- if(h->flag & IndirectVal)
- *(void**)(res+h->valoff) = runtime·mal(t->elem->size);
+ } else {
+ hash_insert(t, h, ak, av);
}
- t->key->alg->copy(t->key->size, hash_keyptr(h, res), ak);
- t->elem->alg->copy(t->elem->size, hash_valptr(h, res), av);
if(debug) {
runtime·prints("mapassign: map=");
@@ -1031,10 +1279,6 @@ runtime·mapassign(MapType *t, Hmap *h, byte *ak, byte *av)
t->key->alg->print(t->key->size, ak);
runtime·prints("; val=");
t->elem->alg->print(t->elem->size, av);
- runtime·prints("; hit=");
- runtime·printint(hit);
- runtime·prints("; res=");
- runtime·printpointer(res);
runtime·prints("\n");
}
}
@@ -1112,20 +1356,20 @@ void
runtime·mapiterinit(MapType *t, Hmap *h, struct hash_iter *it)
{
if(h == nil) {
- it->data = nil;
+ it->key = nil;
return;
}
if(raceenabled)
runtime·racereadpc(h, runtime·getcallerpc(&t), runtime·mapiterinit);
hash_iter_init(t, h, it);
- it->data = hash_next(it);
+ hash_next(it);
if(debug) {
runtime·prints("runtime.mapiterinit: map=");
runtime·printpointer(h);
runtime·prints("; iter=");
runtime·printpointer(it);
- runtime·prints("; data=");
- runtime·printpointer(it->data);
+ runtime·prints("; key=");
+ runtime·printpointer(it->key);
runtime·prints("\n");
}
}
@@ -1135,20 +1379,24 @@ runtime·mapiterinit(MapType *t, Hmap *h, struct hash_iter *it)
void
reflect·mapiterinit(MapType *t, Hmap *h, struct hash_iter *it)
{
- uint8 flag;
+ uint32 old, new;
if(h != nil && t->key->size > sizeof(void*)) {
// reflect·mapiterkey returns pointers to key data,
// and reflect holds them, so we cannot free key data
- // eagerly anymore. Updating h->flag now is racy,
- // but it's okay because this is the only possible store
- // after creation.
- flag = h->flag;
- if(flag & IndirectKey)
- flag &= ~CanFreeKey;
- else
- flag &= ~CanFreeTable;
- h->flag = flag;
+ // eagerly anymore.
+ // Can run concurrently with another reflect·mapiterinit() and with hash_iter_init().
+ for(;;) {
+ old = h->flags;
+ if(old & IndirectKey)
+ new = old & ~CanFreeKey;
+ else
+ new = old & ~CanFreeBucket;
+ if(new == old)
+ break;
+ if(runtime·cas(&h->flags, old, new))
+ break;
+ }
}
it = runtime·mal(sizeof *it);
@@ -1165,12 +1413,12 @@ runtime·mapiternext(struct hash_iter *it)
if(runtime·gcwaiting)
runtime·gosched();
- it->data = hash_next(it);
+ hash_next(it);
if(debug) {
runtime·prints("runtime.mapiternext: iter=");
runtime·printpointer(it);
- runtime·prints("; data=");
- runtime·printpointer(it->data);
+ runtime·prints("; key=");
+ runtime·printpointer(it->key);
runtime·prints("\n");
}
}
@@ -1188,25 +1436,23 @@ reflect·mapiternext(struct hash_iter *it)
void
runtime·mapiter1(struct hash_iter *it, ...)
{
- Hmap *h;
byte *ak, *res;
Type *key;
- h = it->h;
ak = (byte*)(&it + 1);
- res = it->data;
+ res = it->key;
if(res == nil)
runtime·throw("runtime.mapiter1: key:val nil pointer");
key = it->t->key;
- key->alg->copy(key->size, ak, hash_keyptr(h, res));
+ key->alg->copy(key->size, ak, res);
if(debug) {
- runtime·prints("mapiter2: iter=");
+ runtime·prints("mapiter1: iter=");
runtime·printpointer(it);
runtime·prints("; map=");
- runtime·printpointer(h);
+ runtime·printpointer(it->h);
runtime·prints("\n");
}
}
@@ -1217,11 +1463,11 @@ runtime·mapiterkey(struct hash_iter *it, void *ak)
byte *res;
Type *key;
- res = it->data;
+ res = it->key;
if(res == nil)
return false;
key = it->t->key;
- key->alg->copy(key->size, ak, hash_keyptr(it->h, res));
+ key->alg->copy(key->size, ak, res);
return true;
}
@@ -1237,14 +1483,13 @@ reflect·mapiterkey(struct hash_iter *it, uintptr key, bool ok)
key = 0;
ok = false;
- res = it->data;
+ res = it->key;
if(res == nil) {
key = 0;
ok = false;
} else {
tkey = it->t->key;
key = 0;
- res = (byte*)hash_keyptr(it->h, res);
if(tkey->size <= sizeof(key))
tkey->alg->copy(tkey->size, (byte*)&key, res);
else
@@ -1276,7 +1521,6 @@ reflect·maplen(Hmap *h, intgo len)
void
runtime·mapiter2(struct hash_iter *it, ...)
{
- Hmap *h;
byte *ak, *av, *res;
MapType *t;
@@ -1284,19 +1528,18 @@ runtime·mapiter2(struct hash_iter *it, ...)
ak = (byte*)(&it + 1);
av = ak + ROUND(t->key->size, t->elem->align);
- res = it->data;
+ res = it->key;
if(res == nil)
runtime·throw("runtime.mapiter2: key:val nil pointer");
- h = it->h;
- t->key->alg->copy(t->key->size, ak, hash_keyptr(h, res));
- t->elem->alg->copy(t->elem->size, av, hash_valptr(h, res));
+ t->key->alg->copy(t->key->size, ak, res);
+ t->elem->alg->copy(t->elem->size, av, it->value);
if(debug) {
runtime·prints("mapiter2: iter=");
runtime·printpointer(it);
runtime·prints("; map=");
- runtime·printpointer(h);
+ runtime·printpointer(it->h);
runtime·prints("\n");
}
}
diff --git a/src/pkg/runtime/hashmap.h b/src/pkg/runtime/hashmap.h
index 9b82f299e..2988417f6 100644
--- a/src/pkg/runtime/hashmap.h
+++ b/src/pkg/runtime/hashmap.h
@@ -2,180 +2,28 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-/* A hash table.
- Example, hashing nul-terminated char*s:
- hash_hash_t str_hash (void *v) {
- char *s;
- hash_hash_t hash = 0;
- for (s = *(char **)v; *s != 0; s++) {
- hash = (hash ^ *s) * 2654435769U;
- }
- return (hash);
- }
- int str_eq (void *a, void *b) {
- return (strcmp (*(char **)a, *(char **)b) == 0);
- }
- void str_del (void *arg, void *data) {
- *(char **)arg = *(char **)data;
- }
-
- struct hash *h = hash_new (sizeof (char *), &str_hash, &str_eq, &str_del, 3, 12, 15);
- ... 3=> 2**3 entries initial size
- ... 12=> 2**12 entries before sprouting sub-tables
- ... 15=> number of adjacent probes to attempt before growing
-
- Example lookup:
- char *key = "foobar";
- char **result_ptr;
- if (hash_lookup (h, &key, (void **) &result_ptr)) {
- printf ("found in table: %s\n", *result_ptr);
- } else {
- printf ("not found in table\n");
- }
-
- Example insertion:
- char *key = strdup ("foobar");
- char **result_ptr;
- if (hash_lookup (h, &key, (void **) &result_ptr)) {
- printf ("found in table: %s\n", *result_ptr);
- printf ("to overwrite, do *result_ptr = key\n");
- } else {
- printf ("not found in table; inserted as %s\n", *result_ptr);
- assert (*result_ptr == key);
- }
-
- Example deletion:
- char *key = "foobar";
- char *result;
- if (hash_remove (h, &key, &result)) {
- printf ("key found and deleted from table\n");
- printf ("called str_del (&result, data) to copy data to result: %s\n", result);
- } else {
- printf ("not found in table\n");
- }
-
- Example iteration over the elements of *h:
- char **data;
- struct hash_iter it;
- hash_iter_init (h, &it);
- for (data = hash_next (&it); data != 0; data = hash_next (&it)) {
- printf ("%s\n", *data);
- }
- */
-
-#define memset(a,b,c) runtime·memclr((byte*)(a), (uint32)(c))
-#define memcpy(a,b,c) runtime·memmove((byte*)(a),(byte*)(b),(uint32)(c))
-#define assert(a) if(!(a)) runtime·throw("hashmap assert")
-#define free(x) runtime·free(x)
-#define memmove(a,b,c) runtime·memmove(a, b, c)
-
struct Hmap; /* opaque */
-struct hash_subtable; /* opaque */
-struct hash_entry; /* opaque */
-
-typedef uintptr uintptr_t;
-typedef uintptr_t hash_hash_t;
-
-struct hash_iter {
- uint8* data; /* returned from next */
- int32 elemsize; /* size of elements in table */
- int32 changes; /* number of changes observed last time */
- int32 i; /* stack pointer in subtable_state */
- bool cycled; /* have reached the end and wrapped to 0 */
- hash_hash_t last_hash; /* last hash value returned */
- hash_hash_t cycle; /* hash value where we started */
- struct Hmap *h; /* the hash table */
- MapType *t; /* the map type */
- struct hash_iter_sub {
- struct hash_entry *e; /* pointer into subtable */
- struct hash_entry *start; /* start of subtable */
- struct hash_entry *last; /* last entry in subtable */
- } subtable_state[4]; /* Should be large enough unless the hashing is
- so bad that many distinct data values hash
- to the same hash value. */
-};
-
-/* Return a hashtable h 2**init_power empty entries, each with
- "datasize" data bytes.
- (*data_hash)(a) should return the hash value of data element *a.
- (*data_eq)(a,b) should return whether the data at "a" and the data at "b"
- are equal.
- (*data_del)(arg, a) will be invoked when data element *a is about to be removed
- from the table. "arg" is the argument passed to "hash_remove()".
-
- Growing is accomplished by resizing if the current tables size is less than
- a threshold, and by adding subtables otherwise. hint should be set
- the expected maximum size of the table.
- "datasize" should be in [sizeof (void*), ..., 255]. If you need a
- bigger "datasize", store a pointer to another piece of memory. */
-
-//struct hash *hash_new (int32 datasize,
-// hash_hash_t (*data_hash) (void *),
-// int32 (*data_eq) (void *, void *),
-// void (*data_del) (void *, void *),
-// int64 hint);
-
-/* Lookup *data in *h. If the data is found, return 1 and place a pointer to
- the found element in *pres. Otherwise return 0 and place 0 in *pres. */
-// int32 hash_lookup (struct hash *h, void *data, void **pres);
-
-/* Lookup *data in *h. If the data is found, execute (*data_del) (arg, p)
- where p points to the data in the table, then remove it from *h and return
- 1. Otherwise return 0. */
-// int32 hash_remove (struct hash *h, void *data, void *arg);
-
-/* Lookup *data in *h. If the data is found, return 1, and place a pointer
- to the found element in *pres. Otherwise, return 0, allocate a region
- for the data to be inserted, and place a pointer to the inserted element
- in *pres; it is the caller's responsibility to copy the data to be
- inserted to the pointer returned in *pres in this case.
-
- If using garbage collection, it is the caller's responsibility to
- add references for **pres if HASH_ADDED is returned. */
-// int32 hash_insert (struct hash *h, void *data, void **pres);
-
-/* Return the number of elements in the table. */
-// uint32 hash_count (struct hash *h);
-
-/* The following call is useful only if not using garbage collection on the
- table.
- Remove all sub-tables associated with *h.
- This undoes the effects of hash_init().
- If other memory pointed to by user data must be freed, the caller is
- responsible for doing so by iterating over *h first; see
- hash_iter_init()/hash_next(). */
-// void hash_destroy (struct hash *h);
-
-/*----- iteration -----*/
-
-/* Initialize *it from *h. */
-// void hash_iter_init (struct hash *h, struct hash_iter *it);
-
-/* Return the next used entry in the table with which *it was initialized. */
-// void *hash_next (struct hash_iter *it);
-
-/*---- test interface ----*/
-/* Call (*data_visit) (arg, level, data) for every data entry in the table,
- whether used or not. "level" is the subtable level, 0 means first level. */
-/* TESTING ONLY: DO NOT USE THIS ROUTINE IN NORMAL CODE */
-// void hash_visit (struct hash *h, void (*data_visit) (void *arg, int32 level, void *data), void *arg);
/* Used by the garbage collector */
struct hash_gciter
{
- int32 elemsize;
- uint8 flag;
- uint8 valoff;
- uint32 i; /* stack pointer in subtable_state */
- struct hash_subtable *st;
- struct hash_gciter_sub {
- struct hash_entry *e; /* pointer into subtable */
- struct hash_entry *last; /* last entry in subtable */
- } subtable_state[4];
+ Hmap *h;
+ int32 phase;
+ uintptr bucket;
+ struct Bucket *b;
+ uintptr i;
};
+
+// this data is used by the garbage collector to keep the map's
+// internal structures from being reclaimed. The iterator must
+// return in st every live object (ones returned by mallocgc) so
+// that those objects won't be collected, and it must return
+// every key & value in key_data/val_data so they can get scanned
+// for pointers they point to. Note that if you malloc storage
+// for keys and values, you need to do both.
struct hash_gciter_data
{
- struct hash_subtable *st; /* subtable pointer, or nil */
+ uint8 *st; /* internal structure, or nil */
uint8 *key_data; /* key data, or nil */
uint8 *val_data; /* value data, or nil */
bool indirectkey; /* storing pointers to keys */
diff --git a/src/pkg/runtime/hashmap_fast.c b/src/pkg/runtime/hashmap_fast.c
new file mode 100644
index 000000000..afff7b1aa
--- /dev/null
+++ b/src/pkg/runtime/hashmap_fast.c
@@ -0,0 +1,219 @@
+// 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.
+
+// Fast hashmap lookup specialized to a specific key type.
+// Included by hashmap.c once for each specialized type.
+
+// Note that this code differs from hash_lookup in that
+// it returns a pointer to the result, not the result itself.
+// The returned pointer is only valid until the next GC
+// point, so the caller must dereference it before then.
+
+// +build ignore
+
+#pragma textflag 7
+void
+HASH_LOOKUP1(MapType *t, Hmap *h, KEYTYPE key, byte *value)
+{
+ uintptr hash;
+ uintptr bucket, oldbucket;
+ Bucket *b;
+ uintptr i;
+ KEYTYPE *k;
+ byte *v;
+ uint8 top;
+ int8 keymaybe;
+ bool quickkey;
+
+ if(debug) {
+ runtime·prints("runtime.mapaccess1_fastXXX: map=");
+ runtime·printpointer(h);
+ runtime·prints("; key=");
+ t->key->alg->print(t->key->size, &key);
+ runtime·prints("\n");
+ }
+ if(h == nil || h->count == 0) {
+ value = empty_value;
+ FLUSH(&value);
+ return;
+ }
+ if(raceenabled)
+ runtime·racereadpc(h, runtime·getcallerpc(&t), HASH_LOOKUP1);
+ if(docheck)
+ check(t, h);
+
+ if(h->B == 0) {
+ // One-bucket table. Don't hash, just check each bucket entry.
+ if(HASMAYBE) {
+ keymaybe = -1;
+ }
+ quickkey = QUICKEQ(key);
+ b = (Bucket*)h->buckets;
+ for(i = 0, k = (KEYTYPE*)b->data, v = (byte*)(k + BUCKETSIZE); i < BUCKETSIZE; i++, k++, v += h->valuesize) {
+ if(b->tophash[i] != 0) {
+ if(quickkey && EQFUNC(key, *k)) {
+ value = v;
+ FLUSH(&value);
+ return;
+ }
+ if(HASMAYBE && EQMAYBE(key, *k)) {
+ // TODO: check if key.str matches. Add EQFUNCFAST?
+ if(keymaybe >= 0) {
+ // Two same-length strings in this bucket.
+ // use slow path.
+ // TODO: keep track of more than just 1. Especially
+ // if doing the TODO above.
+ goto dohash;
+ }
+ keymaybe = i;
+ }
+ }
+ }
+ if(HASMAYBE && keymaybe >= 0) {
+ k = (KEYTYPE*)b->data + keymaybe;
+ if(EQFUNC(key, *k)) {
+ value = (byte*)((KEYTYPE*)b->data + BUCKETSIZE) + keymaybe * h->valuesize;
+ FLUSH(&value);
+ return;
+ }
+ }
+ } else {
+dohash:
+ hash = h->hash0;
+ HASHFUNC(&hash, sizeof(KEYTYPE), &key);
+ bucket = hash & (((uintptr)1 << h->B) - 1);
+ if(h->oldbuckets != nil) {
+ oldbucket = bucket & (((uintptr)1 << (h->B - 1)) - 1);
+ b = (Bucket*)(h->oldbuckets + oldbucket * h->bucketsize);
+ if(evacuated(b)) {
+ b = (Bucket*)(h->buckets + bucket * h->bucketsize);
+ }
+ } else {
+ b = (Bucket*)(h->buckets + bucket * h->bucketsize);
+ }
+ top = hash >> (sizeof(uintptr)*8 - 8);
+ if(top == 0)
+ top = 1;
+ do {
+ for(i = 0, k = (KEYTYPE*)b->data, v = (byte*)(k + BUCKETSIZE); i < BUCKETSIZE; i++, k++, v += h->valuesize) {
+ if(b->tophash[i] == top && EQFUNC(key, *k)) {
+ value = v;
+ FLUSH(&value);
+ return;
+ }
+ }
+ b = b->overflow;
+ } while(b != nil);
+ }
+ value = empty_value;
+ FLUSH(&value);
+}
+
+#pragma textflag 7
+void
+HASH_LOOKUP2(MapType *t, Hmap *h, KEYTYPE key, byte *value, bool res)
+{
+ uintptr hash;
+ uintptr bucket, oldbucket;
+ Bucket *b;
+ uintptr i;
+ KEYTYPE *k;
+ byte *v;
+ uint8 top;
+ int8 keymaybe;
+ bool quickkey;
+
+ if(debug) {
+ runtime·prints("runtime.mapaccess2_fastXXX: map=");
+ runtime·printpointer(h);
+ runtime·prints("; key=");
+ t->key->alg->print(t->key->size, &key);
+ runtime·prints("\n");
+ }
+ if(h == nil || h->count == 0) {
+ value = empty_value;
+ res = false;
+ FLUSH(&value);
+ FLUSH(&res);
+ return;
+ }
+ if(raceenabled)
+ runtime·racereadpc(h, runtime·getcallerpc(&t), HASH_LOOKUP2);
+ if(docheck)
+ check(t, h);
+
+ if(h->B == 0) {
+ // One-bucket table. Don't hash, just check each bucket entry.
+ if(HASMAYBE) {
+ keymaybe = -1;
+ }
+ quickkey = QUICKEQ(key);
+ b = (Bucket*)h->buckets;
+ for(i = 0, k = (KEYTYPE*)b->data, v = (byte*)(k + BUCKETSIZE); i < BUCKETSIZE; i++, k++, v += h->valuesize) {
+ if(b->tophash[i] != 0) {
+ if(quickkey && EQFUNC(key, *k)) {
+ value = v;
+ res = true;
+ FLUSH(&value);
+ FLUSH(&res);
+ return;
+ }
+ if(HASMAYBE && EQMAYBE(key, *k)) {
+ // TODO: check if key.str matches. Add EQFUNCFAST?
+ if(keymaybe >= 0) {
+ // Two same-length strings in this bucket.
+ // use slow path.
+ // TODO: keep track of more than just 1. Especially
+ // if doing the TODO above.
+ goto dohash;
+ }
+ keymaybe = i;
+ }
+ }
+ }
+ if(HASMAYBE && keymaybe >= 0) {
+ k = (KEYTYPE*)b->data + keymaybe;
+ if(EQFUNC(key, *k)) {
+ value = (byte*)((KEYTYPE*)b->data + BUCKETSIZE) + keymaybe * h->valuesize;
+ res = true;
+ FLUSH(&value);
+ FLUSH(&res);
+ return;
+ }
+ }
+ } else {
+dohash:
+ hash = h->hash0;
+ HASHFUNC(&hash, sizeof(KEYTYPE), &key);
+ bucket = hash & (((uintptr)1 << h->B) - 1);
+ if(h->oldbuckets != nil) {
+ oldbucket = bucket & (((uintptr)1 << (h->B - 1)) - 1);
+ b = (Bucket*)(h->oldbuckets + oldbucket * h->bucketsize);
+ if(evacuated(b)) {
+ b = (Bucket*)(h->buckets + bucket * h->bucketsize);
+ }
+ } else {
+ b = (Bucket*)(h->buckets + bucket * h->bucketsize);
+ }
+ top = hash >> (sizeof(uintptr)*8 - 8);
+ if(top == 0)
+ top = 1;
+ do {
+ for(i = 0, k = (KEYTYPE*)b->data, v = (byte*)(k + BUCKETSIZE); i < BUCKETSIZE; i++, k++, v += h->valuesize) {
+ if(b->tophash[i] == top && EQFUNC(key, *k)) {
+ value = v;
+ res = true;
+ FLUSH(&value);
+ FLUSH(&res);
+ return;
+ }
+ }
+ b = b->overflow;
+ } while(b != nil);
+ }
+ value = empty_value;
+ res = false;
+ FLUSH(&value);
+ FLUSH(&res);
+}
diff --git a/src/pkg/runtime/lock_futex.c b/src/pkg/runtime/lock_futex.c
index 9b1f5f6db..3c2ef4ede 100644
--- a/src/pkg/runtime/lock_futex.c
+++ b/src/pkg/runtime/lock_futex.c
@@ -41,7 +41,7 @@ runtime·lock(Lock *l)
runtime·throw("runtime·lock: lock count");
// Speculative grab for lock.
- v = runtime·xchg(&l->key, MUTEX_LOCKED);
+ v = runtime·xchg((uint32*)&l->key, MUTEX_LOCKED);
if(v == MUTEX_UNLOCKED)
return;
@@ -64,7 +64,7 @@ runtime·lock(Lock *l)
// Try for lock, spinning.
for(i = 0; i < spin; i++) {
while(l->key == MUTEX_UNLOCKED)
- if(runtime·cas(&l->key, MUTEX_UNLOCKED, wait))
+ if(runtime·cas((uint32*)&l->key, MUTEX_UNLOCKED, wait))
return;
runtime·procyield(ACTIVE_SPIN_CNT);
}
@@ -72,17 +72,17 @@ runtime·lock(Lock *l)
// Try for lock, rescheduling.
for(i=0; i < PASSIVE_SPIN; i++) {
while(l->key == MUTEX_UNLOCKED)
- if(runtime·cas(&l->key, MUTEX_UNLOCKED, wait))
+ if(runtime·cas((uint32*)&l->key, MUTEX_UNLOCKED, wait))
return;
runtime·osyield();
}
// Sleep.
- v = runtime·xchg(&l->key, MUTEX_SLEEPING);
+ v = runtime·xchg((uint32*)&l->key, MUTEX_SLEEPING);
if(v == MUTEX_UNLOCKED)
return;
wait = MUTEX_SLEEPING;
- runtime·futexsleep(&l->key, MUTEX_SLEEPING, -1);
+ runtime·futexsleep((uint32*)&l->key, MUTEX_SLEEPING, -1);
}
}
@@ -94,11 +94,11 @@ runtime·unlock(Lock *l)
if(--m->locks < 0)
runtime·throw("runtime·unlock: lock count");
- v = runtime·xchg(&l->key, MUTEX_UNLOCKED);
+ v = runtime·xchg((uint32*)&l->key, MUTEX_UNLOCKED);
if(v == MUTEX_UNLOCKED)
runtime·throw("unlock of unlocked lock");
if(v == MUTEX_SLEEPING)
- runtime·futexwakeup(&l->key, 1);
+ runtime·futexwakeup((uint32*)&l->key, 1);
}
// One-time notifications.
@@ -111,9 +111,9 @@ runtime·noteclear(Note *n)
void
runtime·notewakeup(Note *n)
{
- if(runtime·xchg(&n->key, 1))
+ if(runtime·xchg((uint32*)&n->key, 1))
runtime·throw("notewakeup - double wakeup");
- runtime·futexwakeup(&n->key, 1);
+ runtime·futexwakeup((uint32*)&n->key, 1);
}
void
@@ -121,8 +121,8 @@ runtime·notesleep(Note *n)
{
if(m->profilehz > 0)
runtime·setprof(false);
- while(runtime·atomicload(&n->key) == 0)
- runtime·futexsleep(&n->key, 0, -1);
+ while(runtime·atomicload((uint32*)&n->key) == 0)
+ runtime·futexsleep((uint32*)&n->key, 0, -1);
if(m->profilehz > 0)
runtime·setprof(true);
}
@@ -137,15 +137,15 @@ runtime·notetsleep(Note *n, int64 ns)
return;
}
- if(runtime·atomicload(&n->key) != 0)
+ if(runtime·atomicload((uint32*)&n->key) != 0)
return;
if(m->profilehz > 0)
runtime·setprof(false);
deadline = runtime·nanotime() + ns;
for(;;) {
- runtime·futexsleep(&n->key, 0, ns);
- if(runtime·atomicload(&n->key) != 0)
+ runtime·futexsleep((uint32*)&n->key, 0, ns);
+ if(runtime·atomicload((uint32*)&n->key) != 0)
break;
now = runtime·nanotime();
if(now >= deadline)
diff --git a/src/pkg/runtime/lock_sema.c b/src/pkg/runtime/lock_sema.c
index 1d9c37fdb..ec4b15a98 100644
--- a/src/pkg/runtime/lock_sema.c
+++ b/src/pkg/runtime/lock_sema.c
@@ -41,7 +41,7 @@ runtime·lock(Lock *l)
runtime·throw("runtime·lock: lock count");
// Speculative grab for lock.
- if(runtime·casp(&l->waitm, nil, (void*)LOCKED))
+ if(runtime·casp((void**)&l->key, nil, (void*)LOCKED))
return;
if(m->waitsema == 0)
@@ -54,10 +54,10 @@ runtime·lock(Lock *l)
spin = ACTIVE_SPIN;
for(i=0;; i++) {
- v = (uintptr)runtime·atomicloadp(&l->waitm);
+ v = (uintptr)runtime·atomicloadp((void**)&l->key);
if((v&LOCKED) == 0) {
unlocked:
- if(runtime·casp(&l->waitm, (void*)v, (void*)(v|LOCKED)))
+ if(runtime·casp((void**)&l->key, (void*)v, (void*)(v|LOCKED)))
return;
i = 0;
}
@@ -72,9 +72,9 @@ unlocked:
// Queue this M.
for(;;) {
m->nextwaitm = (void*)(v&~LOCKED);
- if(runtime·casp(&l->waitm, (void*)v, (void*)((uintptr)m|LOCKED)))
+ if(runtime·casp((void**)&l->key, (void*)v, (void*)((uintptr)m|LOCKED)))
break;
- v = (uintptr)runtime·atomicloadp(&l->waitm);
+ v = (uintptr)runtime·atomicloadp((void**)&l->key);
if((v&LOCKED) == 0)
goto unlocked;
}
@@ -97,15 +97,15 @@ runtime·unlock(Lock *l)
runtime·throw("runtime·unlock: lock count");
for(;;) {
- v = (uintptr)runtime·atomicloadp(&l->waitm);
+ v = (uintptr)runtime·atomicloadp((void**)&l->key);
if(v == LOCKED) {
- if(runtime·casp(&l->waitm, (void*)LOCKED, nil))
+ 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(&l->waitm, (void*)v, mp->nextwaitm)) {
+ if(runtime·casp((void**)&l->key, (void*)v, mp->nextwaitm)) {
// Dequeued an M. Wake it.
runtime·semawakeup(mp);
break;
@@ -118,7 +118,7 @@ runtime·unlock(Lock *l)
void
runtime·noteclear(Note *n)
{
- n->waitm = nil;
+ n->key = 0;
}
void
@@ -127,8 +127,8 @@ runtime·notewakeup(Note *n)
M *mp;
do
- mp = runtime·atomicloadp(&n->waitm);
- while(!runtime·casp(&n->waitm, mp, (void*)LOCKED));
+ mp = runtime·atomicloadp((void**)&n->key);
+ while(!runtime·casp((void**)&n->key, mp, (void*)LOCKED));
// Successfully set waitm to LOCKED.
// What was it before?
@@ -148,8 +148,8 @@ runtime·notesleep(Note *n)
{
if(m->waitsema == 0)
m->waitsema = runtime·semacreate();
- if(!runtime·casp(&n->waitm, nil, m)) { // must be LOCKED (got wakeup)
- if(n->waitm != (void*)LOCKED)
+ 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;
}
@@ -176,8 +176,8 @@ runtime·notetsleep(Note *n, int64 ns)
m->waitsema = runtime·semacreate();
// Register for wakeup on n->waitm.
- if(!runtime·casp(&n->waitm, nil, m)) { // must be LOCKED (got wakeup already)
- if(n->waitm != (void*)LOCKED)
+ 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;
}
@@ -212,10 +212,10 @@ runtime·notetsleep(Note *n, int64 ns)
// 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(&n->waitm);
+ mp = runtime·atomicloadp((void**)&n->key);
if(mp == m) {
// No wakeup yet; unregister if possible.
- if(runtime·casp(&n->waitm, mp, nil))
+ if(runtime·casp((void**)&n->key, mp, nil))
return;
} else if(mp == (M*)LOCKED) {
// Wakeup happened so semaphore is available.
diff --git a/src/pkg/runtime/malloc.goc b/src/pkg/runtime/malloc.goc
index ac131b3af..f1d25a793 100644
--- a/src/pkg/runtime/malloc.goc
+++ b/src/pkg/runtime/malloc.goc
@@ -35,7 +35,7 @@ runtime·mallocgc(uintptr size, uint32 flag, int32 dogc, int32 zeroed)
MSpan *s;
void *v;
- if(runtime·gcwaiting && g != m->g0 && m->locks == 0)
+ if(runtime·gcwaiting && g != m->g0 && m->locks == 0 && dogc)
runtime·gosched();
if(m->mallocing)
runtime·throw("malloc/free - deadlock");
@@ -160,7 +160,7 @@ runtime·free(void *v)
if(sizeclass == 0) {
// Large object.
size = s->npages<<PageShift;
- *(uintptr*)(s->start<<PageShift) = 1; // mark as "needs to be zeroed"
+ *(uintptr*)(s->start<<PageShift) = (uintptr)0xfeedfeedfeedfeedll; // mark as "needs to be zeroed"
// 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, size);
@@ -170,7 +170,7 @@ runtime·free(void *v)
// Small object.
size = runtime·class_to_size[sizeclass];
if(size > sizeof(uintptr))
- ((uintptr*)v)[1] = 1; // mark as "needs to be zeroed"
+ ((uintptr*)v)[1] = (uintptr)0xfeedfeedfeedfeedll; // mark as "needs to be zeroed"
// Must mark v freed before calling MCache_Free:
// it might coalesce v and other blocks into a bigger span
// and change the bitmap further.
@@ -318,7 +318,10 @@ runtime·mallocinit(void)
runtime·InitSizes();
- limit = runtime·memlimit();
+ // limit = runtime·memlimit();
+ // See https://code.google.com/p/go/issues/detail?id=5049
+ // TODO(rsc): Fix after 1.1.
+ limit = 0;
// Set up the allocation arena, a contiguous area of memory where
// allocated data will be found. The arena begins with a bitmap large
@@ -516,7 +519,7 @@ runtime·settype_flush(M *mp, bool sysalloc)
nbytes3 = 8*sizeof(uintptr) + 1*ntypes;
if(!sysalloc) {
- data3 = runtime·mallocgc(nbytes3, FlagNoPointers, 0, 1);
+ data3 = runtime·mallocgc(nbytes3, FlagNoProfiling|FlagNoPointers, 0, 1);
} else {
data3 = runtime·SysAlloc(nbytes3);
if(data3 == nil)
@@ -554,7 +557,7 @@ runtime·settype_flush(M *mp, bool sysalloc)
nbytes2 = ntypes * sizeof(uintptr);
if(!sysalloc) {
- data2 = runtime·mallocgc(nbytes2, FlagNoPointers, 0, 1);
+ data2 = runtime·mallocgc(nbytes2, FlagNoProfiling|FlagNoPointers, 0, 1);
} else {
data2 = runtime·SysAlloc(nbytes2);
if(data2 == nil)
diff --git a/src/pkg/runtime/malloc.h b/src/pkg/runtime/malloc.h
index 38122bf8a..52b76d557 100644
--- a/src/pkg/runtime/malloc.h
+++ b/src/pkg/runtime/malloc.h
@@ -115,10 +115,18 @@ enum
HeapAllocChunk = 1<<20, // Chunk size for heap growth
// Number of bits in page to span calculations (4k pages).
- // On 64-bit, we limit the arena to 128GB, or 37 bits.
+ // On Windows 64-bit we limit the arena to 32GB or 35 bits (see below for reason).
+ // On other 64-bit platforms, we limit the arena to 128GB, or 37 bits.
// On 32-bit, we don't bother limiting anything, so we use the full 32-bit address.
#ifdef _64BIT
+#ifdef GOOS_windows
+ // Windows counts memory used by page table into committed memory
+ // of the process, so we can't reserve too much memory.
+ // See http://golang.org/issue/5402 and http://golang.org/issue/5236.
+ MHeapMap_Bits = 35 - PageShift,
+#else
MHeapMap_Bits = 37 - PageShift,
+#endif
#else
MHeapMap_Bits = 32 - PageShift,
#endif
@@ -134,7 +142,7 @@ enum
// This must be a #define instead of an enum because it
// is so large.
#ifdef _64BIT
-#define MaxMem (1ULL<<(MHeapMap_Bits+PageShift)) /* 128 GB */
+#define MaxMem (1ULL<<(MHeapMap_Bits+PageShift)) /* 128 GB or 32 GB */
#else
#define MaxMem ((uintptr)-1)
#endif
@@ -416,10 +424,10 @@ struct MHeap
byte *arena_end;
// central free lists for small size classes.
- // the union makes sure that the MCentrals are
+ // the padding makes sure that the MCentrals are
// spaced CacheLineSize bytes apart, so that each MCentral.Lock
// gets its own cache line.
- union {
+ struct {
MCentral;
byte pad[CacheLineSize];
} central[NumSizeClasses];
diff --git a/src/pkg/runtime/map_test.go b/src/pkg/runtime/map_test.go
new file mode 100644
index 000000000..9f9c40d15
--- /dev/null
+++ b/src/pkg/runtime/map_test.go
@@ -0,0 +1,373 @@
+// 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_test
+
+import (
+ "fmt"
+ "math"
+ "reflect"
+ "runtime"
+ "sort"
+ "strings"
+ "sync"
+ "testing"
+)
+
+// negative zero is a good test because:
+// 1) 0 and -0 are equal, yet have distinct representations.
+// 2) 0 is represented as all zeros, -0 isn't.
+// I'm not sure the language spec actually requires this behavior,
+// but it's what the current map implementation does.
+func TestNegativeZero(t *testing.T) {
+ m := make(map[float64]bool, 0)
+
+ m[+0.0] = true
+ m[math.Copysign(0.0, -1.0)] = true // should overwrite +0 entry
+
+ if len(m) != 1 {
+ t.Error("length wrong")
+ }
+
+ 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
+ m[+0.0] = true // should overwrite -0.0 entry
+
+ if len(m) != 1 {
+ t.Error("length wrong")
+ }
+
+ 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
+// a randomized hash value.
+func TestNan(t *testing.T) {
+ m := make(map[float64]int, 0)
+ nan := math.NaN()
+ m[nan] = 1
+ m[nan] = 2
+ m[nan] = 4
+ if len(m) != 3 {
+ t.Error("length wrong")
+ }
+ s := 0
+ for k, v := range m {
+ if k == k {
+ t.Error("nan disappeared")
+ }
+ if (v & (v - 1)) != 0 {
+ t.Error("value wrong")
+ }
+ s |= v
+ }
+ if s != 7 {
+ t.Error("values wrong")
+ }
+}
+
+// Maps aren't actually copied on assignment.
+func TestAlias(t *testing.T) {
+ m := make(map[int]int, 0)
+ m[0] = 5
+ n := m
+ n[0] = 6
+ if m[0] != 6 {
+ t.Error("alias didn't work")
+ }
+}
+
+func TestGrowWithNaN(t *testing.T) {
+ m := make(map[float64]int, 4)
+ nan := math.NaN()
+ m[nan] = 1
+ m[nan] = 2
+ m[nan] = 4
+ cnt := 0
+ s := 0
+ growflag := true
+ for k, v := range m {
+ if growflag {
+ // force a hashtable resize
+ for i := 0; i < 100; i++ {
+ m[float64(i)] = i
+ }
+ growflag = false
+ }
+ if k != k {
+ cnt++
+ s |= v
+ }
+ }
+ if cnt != 3 {
+ t.Error("NaN keys lost during grow")
+ }
+ if s != 7 {
+ t.Error("NaN values lost during grow")
+ }
+}
+
+type FloatInt struct {
+ x float64
+ y int
+}
+
+func TestGrowWithNegativeZero(t *testing.T) {
+ negzero := math.Copysign(0.0, -1.0)
+ m := make(map[FloatInt]int, 4)
+ m[FloatInt{0.0, 0}] = 1
+ m[FloatInt{0.0, 1}] = 2
+ m[FloatInt{0.0, 2}] = 4
+ m[FloatInt{0.0, 3}] = 8
+ growflag := true
+ s := 0
+ cnt := 0
+ negcnt := 0
+ // The first iteration should return the +0 key.
+ // The subsequent iterations should return the -0 key.
+ // I'm not really sure this is required by the spec,
+ // but it makes sense.
+ // TODO: are we allowed to get the first entry returned again???
+ for k, v := range m {
+ if v == 0 {
+ continue
+ } // ignore entries added to grow table
+ cnt++
+ if math.Copysign(1.0, k.x) < 0 {
+ if v&16 == 0 {
+ t.Error("key/value not updated together 1")
+ }
+ negcnt++
+ s |= v & 15
+ } else {
+ if v&16 == 16 {
+ t.Error("key/value not updated together 2", k, v)
+ }
+ s |= v
+ }
+ if growflag {
+ // force a hashtable resize
+ for i := 0; i < 100; i++ {
+ m[FloatInt{3.0, i}] = 0
+ }
+ // then change all the entries
+ // to negative zero
+ m[FloatInt{negzero, 0}] = 1 | 16
+ m[FloatInt{negzero, 1}] = 2 | 16
+ m[FloatInt{negzero, 2}] = 4 | 16
+ m[FloatInt{negzero, 3}] = 8 | 16
+ growflag = false
+ }
+ }
+ if s != 15 {
+ t.Error("entry missing", s)
+ }
+ if cnt != 4 {
+ t.Error("wrong number of entries returned by iterator", cnt)
+ }
+ if negcnt != 3 {
+ t.Error("update to negzero missed by iteration", negcnt)
+ }
+}
+
+func TestIterGrowAndDelete(t *testing.T) {
+ m := make(map[int]int, 4)
+ for i := 0; i < 100; i++ {
+ m[i] = i
+ }
+ growflag := true
+ for k := range m {
+ if growflag {
+ // grow the table
+ for i := 100; i < 1000; i++ {
+ m[i] = i
+ }
+ // delete all odd keys
+ for i := 1; i < 1000; i += 2 {
+ delete(m, i)
+ }
+ growflag = false
+ } else {
+ if k&1 == 1 {
+ t.Error("odd value returned")
+ }
+ }
+ }
+}
+
+// make sure old bucket arrays don't get GCd while
+// an iterator is still using them.
+func TestIterGrowWithGC(t *testing.T) {
+ m := make(map[int]int, 4)
+ for i := 0; i < 16; i++ {
+ m[i] = i
+ }
+ growflag := true
+ bitmask := 0
+ for k := range m {
+ if k < 16 {
+ bitmask |= 1 << uint(k)
+ }
+ if growflag {
+ // grow the table
+ for i := 100; i < 1000; i++ {
+ m[i] = i
+ }
+ // trigger a gc
+ runtime.GC()
+ growflag = false
+ }
+ }
+ if bitmask != 1<<16-1 {
+ t.Error("missing key", bitmask)
+ }
+}
+
+func testConcurrentReadsAfterGrowth(t *testing.T, useReflect bool) {
+ if runtime.GOMAXPROCS(-1) == 1 {
+ defer runtime.GOMAXPROCS(runtime.GOMAXPROCS(16))
+ }
+ numLoop := 10
+ numGrowStep := 250
+ numReader := 16
+ if testing.Short() {
+ numLoop, numGrowStep = 2, 500
+ }
+ for i := 0; i < numLoop; i++ {
+ m := make(map[int]int, 0)
+ for gs := 0; gs < numGrowStep; gs++ {
+ m[gs] = gs
+ var wg sync.WaitGroup
+ wg.Add(numReader * 2)
+ for nr := 0; nr < numReader; nr++ {
+ go func() {
+ defer wg.Done()
+ for _ = range m {
+ }
+ }()
+ go func() {
+ defer wg.Done()
+ for key := 0; key < gs; key++ {
+ _ = m[key]
+ }
+ }()
+ if useReflect {
+ wg.Add(1)
+ go func() {
+ defer wg.Done()
+ mv := reflect.ValueOf(m)
+ keys := mv.MapKeys()
+ for _, k := range keys {
+ mv.MapIndex(k)
+ }
+ }()
+ }
+ }
+ wg.Wait()
+ }
+ }
+}
+
+func TestConcurrentReadsAfterGrowth(t *testing.T) {
+ testConcurrentReadsAfterGrowth(t, false)
+}
+
+func TestConcurrentReadsAfterGrowthReflect(t *testing.T) {
+ testConcurrentReadsAfterGrowth(t, true)
+}
+
+func TestBigItems(t *testing.T) {
+ var key [256]string
+ for i := 0; i < 256; i++ {
+ key[i] = "foo"
+ }
+ m := make(map[[256]string][256]string, 4)
+ for i := 0; i < 100; i++ {
+ key[37] = fmt.Sprintf("string%02d", i)
+ m[key] = key
+ }
+ var keys [100]string
+ var values [100]string
+ i := 0
+ for k, v := range m {
+ keys[i] = k[37]
+ values[i] = v[37]
+ i++
+ }
+ sort.Strings(keys[:])
+ sort.Strings(values[:])
+ for i := 0; i < 100; i++ {
+ if keys[i] != fmt.Sprintf("string%02d", i) {
+ t.Errorf("#%d: missing key: %v", i, keys[i])
+ }
+ if values[i] != fmt.Sprintf("string%02d", i) {
+ t.Errorf("#%d: missing value: %v", i, values[i])
+ }
+ }
+}
+
+type empty struct {
+}
+
+func TestEmptyKeyAndValue(t *testing.T) {
+ a := make(map[int]empty, 4)
+ b := make(map[empty]int, 4)
+ c := make(map[empty]empty, 4)
+ a[0] = empty{}
+ b[empty{}] = 0
+ b[empty{}] = 1
+ c[empty{}] = empty{}
+
+ if len(a) != 1 {
+ t.Errorf("empty value insert problem")
+ }
+ if b[empty{}] != 1 {
+ t.Errorf("empty key returned wrong value")
+ }
+}
+
+// Tests a map with a single bucket, with same-lengthed short keys
+// ("quick keys") as well as long keys.
+func TestSingleBucketMapStringKeys_DupLen(t *testing.T) {
+ testMapLookups(t, map[string]string{
+ "x": "x1val",
+ "xx": "x2val",
+ "foo": "fooval",
+ "bar": "barval", // same key length as "foo"
+ "xxxx": "x4val",
+ strings.Repeat("x", 128): "longval1",
+ strings.Repeat("y", 128): "longval2",
+ })
+}
+
+// Tests a map with a single bucket, with all keys having different lengths.
+func TestSingleBucketMapStringKeys_NoDupLen(t *testing.T) {
+ testMapLookups(t, map[string]string{
+ "x": "x1val",
+ "xx": "x2val",
+ "foo": "fooval",
+ "xxxx": "x4val",
+ "xxxxx": "x5val",
+ "xxxxxx": "x6val",
+ strings.Repeat("x", 128): "longval",
+ })
+}
+
+func testMapLookups(t *testing.T, m map[string]string) {
+ for k, v := range m {
+ if m[k] != v {
+ t.Fatalf("m[%q] = %q; want %q", k, m[k], v)
+ }
+ }
+}
diff --git a/src/pkg/runtime/mapspeed_test.go b/src/pkg/runtime/mapspeed_test.go
new file mode 100644
index 000000000..3b7fbfd63
--- /dev/null
+++ b/src/pkg/runtime/mapspeed_test.go
@@ -0,0 +1,208 @@
+// 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_test
+
+import (
+ "fmt"
+ "strings"
+ "testing"
+)
+
+const size = 10
+
+func BenchmarkHashStringSpeed(b *testing.B) {
+ strings := make([]string, size)
+ for i := 0; i < size; i++ {
+ strings[i] = fmt.Sprintf("string#%d", i)
+ }
+ sum := 0
+ m := make(map[string]int, size)
+ for i := 0; i < size; i++ {
+ m[strings[i]] = 0
+ }
+ idx := 0
+ b.ResetTimer()
+ for i := 0; i < b.N; i++ {
+ sum += m[strings[idx]]
+ idx++
+ if idx == size {
+ idx = 0
+ }
+ }
+}
+
+func BenchmarkHashInt32Speed(b *testing.B) {
+ ints := make([]int32, size)
+ for i := 0; i < size; i++ {
+ ints[i] = int32(i)
+ }
+ sum := 0
+ m := make(map[int32]int, size)
+ for i := 0; i < size; i++ {
+ m[ints[i]] = 0
+ }
+ idx := 0
+ b.ResetTimer()
+ for i := 0; i < b.N; i++ {
+ sum += m[ints[idx]]
+ idx++
+ if idx == size {
+ idx = 0
+ }
+ }
+}
+
+func BenchmarkHashInt64Speed(b *testing.B) {
+ ints := make([]int64, size)
+ for i := 0; i < size; i++ {
+ ints[i] = int64(i)
+ }
+ sum := 0
+ m := make(map[int64]int, size)
+ for i := 0; i < size; i++ {
+ m[ints[i]] = 0
+ }
+ idx := 0
+ b.ResetTimer()
+ for i := 0; i < b.N; i++ {
+ sum += m[ints[idx]]
+ idx++
+ if idx == size {
+ idx = 0
+ }
+ }
+}
+func BenchmarkHashStringArraySpeed(b *testing.B) {
+ stringpairs := make([][2]string, size)
+ for i := 0; i < size; i++ {
+ for j := 0; j < 2; j++ {
+ stringpairs[i][j] = fmt.Sprintf("string#%d/%d", i, j)
+ }
+ }
+ sum := 0
+ m := make(map[[2]string]int, size)
+ for i := 0; i < size; i++ {
+ m[stringpairs[i]] = 0
+ }
+ idx := 0
+ b.ResetTimer()
+ for i := 0; i < b.N; i++ {
+ sum += m[stringpairs[idx]]
+ idx++
+ if idx == size {
+ idx = 0
+ }
+ }
+}
+
+func BenchmarkMegMap(b *testing.B) {
+ m := make(map[string]bool)
+ for suffix := 'A'; suffix <= 'G'; suffix++ {
+ m[strings.Repeat("X", 1<<20-1)+fmt.Sprint(suffix)] = true
+ }
+ key := strings.Repeat("X", 1<<20-1) + "k"
+ b.ResetTimer()
+ for i := 0; i < b.N; i++ {
+ _, _ = m[key]
+ }
+}
+
+func BenchmarkMegOneMap(b *testing.B) {
+ m := make(map[string]bool)
+ m[strings.Repeat("X", 1<<20)] = true
+ key := strings.Repeat("Y", 1<<20)
+ b.ResetTimer()
+ for i := 0; i < b.N; i++ {
+ _, _ = m[key]
+ }
+}
+
+func BenchmarkMegEqMap(b *testing.B) {
+ m := make(map[string]bool)
+ key1 := strings.Repeat("X", 1<<20)
+ key2 := strings.Repeat("X", 1<<20) // equal but different instance
+ m[key1] = true
+ b.ResetTimer()
+ for i := 0; i < b.N; i++ {
+ _, _ = m[key2]
+ }
+}
+
+func BenchmarkMegEmptyMap(b *testing.B) {
+ m := make(map[string]bool)
+ key := strings.Repeat("X", 1<<20)
+ b.ResetTimer()
+ for i := 0; i < b.N; i++ {
+ _, _ = m[key]
+ }
+}
+
+func BenchmarkSmallStrMap(b *testing.B) {
+ m := make(map[string]bool)
+ for suffix := 'A'; suffix <= 'G'; suffix++ {
+ m[fmt.Sprint(suffix)] = true
+ }
+ key := "k"
+ b.ResetTimer()
+ for i := 0; i < b.N; i++ {
+ _, _ = m[key]
+ }
+}
+
+func BenchmarkMapStringKeysEight_16(b *testing.B) { benchmarkMapStringKeysEight(b, 16) }
+func BenchmarkMapStringKeysEight_32(b *testing.B) { benchmarkMapStringKeysEight(b, 32) }
+func BenchmarkMapStringKeysEight_64(b *testing.B) { benchmarkMapStringKeysEight(b, 64) }
+func BenchmarkMapStringKeysEight_1M(b *testing.B) { benchmarkMapStringKeysEight(b, 1<<20) }
+
+func benchmarkMapStringKeysEight(b *testing.B, keySize int) {
+ m := make(map[string]bool)
+ for i := 0; i < 8; i++ {
+ m[strings.Repeat("K", i+1)] = true
+ }
+ key := strings.Repeat("K", keySize)
+ b.ResetTimer()
+ for i := 0; i < b.N; i++ {
+ _ = m[key]
+ }
+}
+
+func BenchmarkIntMap(b *testing.B) {
+ m := make(map[int]bool)
+ for i := 0; i < 8; i++ {
+ m[i] = true
+ }
+ b.ResetTimer()
+ for i := 0; i < b.N; i++ {
+ _, _ = m[7]
+ }
+}
+
+// Accessing the same keys in a row.
+func benchmarkRepeatedLookup(b *testing.B, lookupKeySize int) {
+ m := make(map[string]bool)
+ // At least bigger than a single bucket:
+ for i := 0; i < 64; i++ {
+ m[fmt.Sprintf("some key %d", i)] = true
+ }
+ base := strings.Repeat("x", lookupKeySize-1)
+ key1 := base + "1"
+ key2 := base + "2"
+ b.ResetTimer()
+ for i := 0; i < b.N/4; i++ {
+ _ = m[key1]
+ _ = m[key1]
+ _ = m[key2]
+ _ = m[key2]
+ }
+}
+
+func BenchmarkRepeatedLookupStrMapKey32(b *testing.B) { benchmarkRepeatedLookup(b, 32) }
+func BenchmarkRepeatedLookupStrMapKey1M(b *testing.B) { benchmarkRepeatedLookup(b, 1<<20) }
+
+func BenchmarkNewEmptyMap(b *testing.B) {
+ b.ReportAllocs()
+ for i := 0; i < b.N; i++ {
+ _ = make(map[int]int)
+ }
+}
diff --git a/src/pkg/runtime/mcentral.c b/src/pkg/runtime/mcentral.c
index ac8b5aa0d..ec2a91ad5 100644
--- a/src/pkg/runtime/mcentral.c
+++ b/src/pkg/runtime/mcentral.c
@@ -19,7 +19,6 @@
#include "malloc.h"
static bool MCentral_Grow(MCentral *c);
-static void* MCentral_Alloc(MCentral *c);
static void MCentral_Free(MCentral *c, void *v);
// Initialize a single central free list.
diff --git a/src/pkg/runtime/mem_darwin.c b/src/pkg/runtime/mem_darwin.c
index 04e719394..7aa607f8e 100644
--- a/src/pkg/runtime/mem_darwin.c
+++ b/src/pkg/runtime/mem_darwin.c
@@ -37,7 +37,12 @@ runtime·SysFree(void *v, uintptr n)
void*
runtime·SysReserve(void *v, uintptr n)
{
- return runtime·mmap(v, n, PROT_NONE, MAP_ANON|MAP_PRIVATE, -1, 0);
+ void *p;
+
+ p = runtime·mmap(v, n, PROT_NONE, MAP_ANON|MAP_PRIVATE, -1, 0);
+ if(p < (void*)4096)
+ return nil;
+ return p;
}
enum
@@ -52,7 +57,7 @@ runtime·SysMap(void *v, uintptr n)
mstats.sys += n;
p = runtime·mmap(v, n, PROT_READ|PROT_WRITE, MAP_ANON|MAP_FIXED|MAP_PRIVATE, -1, 0);
- if(p == (void*)-ENOMEM)
+ if(p == (void*)ENOMEM)
runtime·throw("runtime: out of memory");
if(p != v)
runtime·throw("runtime: cannot map pages in arena address space");
diff --git a/src/pkg/runtime/mem_freebsd.c b/src/pkg/runtime/mem_freebsd.c
index f217e9db1..805e74cff 100644
--- a/src/pkg/runtime/mem_freebsd.c
+++ b/src/pkg/runtime/mem_freebsd.c
@@ -8,6 +8,11 @@
#include "os_GOOS.h"
#include "malloc.h"
+enum
+{
+ ENOMEM = 12,
+};
+
void*
runtime·SysAlloc(uintptr n)
{
@@ -36,20 +41,20 @@ runtime·SysFree(void *v, uintptr n)
void*
runtime·SysReserve(void *v, uintptr n)
{
+ void *p;
+
// On 64-bit, people with ulimit -v set complain if we reserve too
// much address space. Instead, assume that the reservation is okay
// and check the assumption in SysMap.
if(sizeof(void*) == 8)
return v;
- return runtime·mmap(v, n, PROT_NONE, MAP_ANON|MAP_PRIVATE, -1, 0);
+ p = runtime·mmap(v, n, PROT_NONE, MAP_ANON|MAP_PRIVATE, -1, 0);
+ if(p < (void*)4096)
+ return nil;
+ return p;
}
-enum
-{
- ENOMEM = 12,
-};
-
void
runtime·SysMap(void *v, uintptr n)
{
@@ -60,7 +65,7 @@ runtime·SysMap(void *v, uintptr n)
// On 64-bit, we don't actually have v reserved, so tread carefully.
if(sizeof(void*) == 8) {
p = runtime·mmap(v, n, PROT_READ|PROT_WRITE, MAP_ANON|MAP_PRIVATE, -1, 0);
- if(p == (void*)-ENOMEM)
+ if(p == (void*)ENOMEM)
runtime·throw("runtime: out of memory");
if(p != v) {
runtime·printf("runtime: address space conflict: map(%p) = %p\n", v, p);
@@ -70,7 +75,7 @@ runtime·SysMap(void *v, uintptr n)
}
p = runtime·mmap(v, n, PROT_READ|PROT_WRITE, MAP_ANON|MAP_FIXED|MAP_PRIVATE, -1, 0);
- if(p == (void*)-ENOMEM)
+ if(p == (void*)ENOMEM)
runtime·throw("runtime: out of memory");
if(p != v)
runtime·throw("runtime: cannot map pages in arena address space");
diff --git a/src/pkg/runtime/mem_linux.c b/src/pkg/runtime/mem_linux.c
index ebcec1e86..1bae755fa 100644
--- a/src/pkg/runtime/mem_linux.c
+++ b/src/pkg/runtime/mem_linux.c
@@ -10,8 +10,6 @@
enum
{
- EAGAIN = 11,
- ENOMEM = 12,
_PAGE_SIZE = 4096,
};
diff --git a/src/pkg/runtime/mem_netbsd.c b/src/pkg/runtime/mem_netbsd.c
index 77ce04c4e..e5bdac0ef 100644
--- a/src/pkg/runtime/mem_netbsd.c
+++ b/src/pkg/runtime/mem_netbsd.c
@@ -50,10 +50,9 @@ runtime·SysReserve(void *v, uintptr n)
return v;
p = runtime·mmap(v, n, PROT_NONE, MAP_ANON|MAP_PRIVATE, -1, 0);
- if (p == ((void *)-ENOMEM))
+ if(p < (void*)4096)
return nil;
- else
- return p;
+ return p;
}
void
@@ -66,7 +65,7 @@ runtime·SysMap(void *v, uintptr n)
// On 64-bit, we don't actually have v reserved, so tread carefully.
if(sizeof(void*) == 8) {
p = runtime·mmap(v, n, PROT_READ|PROT_WRITE, MAP_ANON|MAP_PRIVATE, -1, 0);
- if(p == (void*)-ENOMEM)
+ if(p == (void*)ENOMEM)
runtime·throw("runtime: out of memory");
if(p != v) {
runtime·printf("runtime: address space conflict: map(%p) = %p\n", v, p);
@@ -76,7 +75,7 @@ runtime·SysMap(void *v, uintptr n)
}
p = runtime·mmap(v, n, PROT_READ|PROT_WRITE, MAP_ANON|MAP_FIXED|MAP_PRIVATE, -1, 0);
- if(p == (void*)-ENOMEM)
+ if(p == (void*)ENOMEM)
runtime·throw("runtime: out of memory");
if(p != v)
runtime·throw("runtime: cannot map pages in arena address space");
diff --git a/src/pkg/runtime/mem_openbsd.c b/src/pkg/runtime/mem_openbsd.c
index 77ce04c4e..e5bdac0ef 100644
--- a/src/pkg/runtime/mem_openbsd.c
+++ b/src/pkg/runtime/mem_openbsd.c
@@ -50,10 +50,9 @@ runtime·SysReserve(void *v, uintptr n)
return v;
p = runtime·mmap(v, n, PROT_NONE, MAP_ANON|MAP_PRIVATE, -1, 0);
- if (p == ((void *)-ENOMEM))
+ if(p < (void*)4096)
return nil;
- else
- return p;
+ return p;
}
void
@@ -66,7 +65,7 @@ runtime·SysMap(void *v, uintptr n)
// On 64-bit, we don't actually have v reserved, so tread carefully.
if(sizeof(void*) == 8) {
p = runtime·mmap(v, n, PROT_READ|PROT_WRITE, MAP_ANON|MAP_PRIVATE, -1, 0);
- if(p == (void*)-ENOMEM)
+ if(p == (void*)ENOMEM)
runtime·throw("runtime: out of memory");
if(p != v) {
runtime·printf("runtime: address space conflict: map(%p) = %p\n", v, p);
@@ -76,7 +75,7 @@ runtime·SysMap(void *v, uintptr n)
}
p = runtime·mmap(v, n, PROT_READ|PROT_WRITE, MAP_ANON|MAP_FIXED|MAP_PRIVATE, -1, 0);
- if(p == (void*)-ENOMEM)
+ if(p == (void*)ENOMEM)
runtime·throw("runtime: out of memory");
if(p != v)
runtime·throw("runtime: cannot map pages in arena address space");
diff --git a/src/pkg/runtime/memmove_amd64.s b/src/pkg/runtime/memmove_amd64.s
index e78be8145..6174407e3 100644
--- a/src/pkg/runtime/memmove_amd64.s
+++ b/src/pkg/runtime/memmove_amd64.s
@@ -23,11 +23,12 @@
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
+// void runtime·memmove(void*, void*, uintptr)
TEXT runtime·memmove(SB), 7, $0
MOVQ to+0(FP), DI
MOVQ fr+8(FP), SI
- MOVLQSX n+16(FP), BX
+ MOVQ n+16(FP), BX
/*
* check and set for backwards
@@ -38,7 +39,7 @@ TEXT runtime·memmove(SB), 7, $0
/*
* forward copy loop
*/
-forward:
+forward:
MOVQ BX, CX
SHRQ $3, CX
ANDQ $7, BX
diff --git a/src/pkg/runtime/memmove_linux_amd64_test.go b/src/pkg/runtime/memmove_linux_amd64_test.go
new file mode 100644
index 000000000..f7221f4f5
--- /dev/null
+++ b/src/pkg/runtime/memmove_linux_amd64_test.go
@@ -0,0 +1,61 @@
+// 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_test
+
+import (
+ "io/ioutil"
+ "os"
+ "reflect"
+ "syscall"
+ "testing"
+ "unsafe"
+)
+
+// TestMemmoveOverflow maps 3GB of memory and calls memmove on
+// the corresponding slice.
+func TestMemmoveOverflow(t *testing.T) {
+ // Create a temporary file.
+ tmp, err := ioutil.TempFile("", "go-memmovetest")
+ if err != nil {
+ t.Fatal(err)
+ }
+ _, err = tmp.Write(make([]byte, 65536))
+ if err != nil {
+ t.Fatal(err)
+ }
+ defer os.Remove(tmp.Name())
+ defer tmp.Close()
+
+ // Set up mappings.
+ base, _, errno := syscall.Syscall6(syscall.SYS_MMAP,
+ 0xa0<<32, 3<<30, syscall.PROT_READ|syscall.PROT_WRITE, syscall.MAP_PRIVATE|syscall.MAP_ANONYMOUS, ^uintptr(0), 0)
+ if errno != 0 {
+ t.Skipf("could not create memory mapping: %s", errno)
+ }
+ syscall.Syscall(syscall.SYS_MUNMAP, base, 3<<30, 0)
+
+ for off := uintptr(0); off < 3<<30; off += 65536 {
+ _, _, errno := syscall.Syscall6(syscall.SYS_MMAP,
+ base+off, 65536, syscall.PROT_READ|syscall.PROT_WRITE, syscall.MAP_SHARED|syscall.MAP_FIXED, tmp.Fd(), 0)
+ if errno != 0 {
+ t.Fatalf("could not map a page at requested 0x%x: %s", base+off, errno)
+ }
+ defer syscall.Syscall(syscall.SYS_MUNMAP, base+off, 65536, 0)
+ }
+
+ var s []byte
+ sp := (*reflect.SliceHeader)(unsafe.Pointer(&s))
+ sp.Data = base
+ sp.Len, sp.Cap = 3<<30, 3<<30
+
+ n := copy(s[1:], s)
+ if n != 3<<30-1 {
+ t.Fatalf("copied %d bytes, expected %d", n, 3<<30-1)
+ }
+ n = copy(s, s[1:])
+ if n != 3<<30-1 {
+ t.Fatalf("copied %d bytes, expected %d", n, 3<<30-1)
+ }
+}
diff --git a/src/pkg/runtime/mfixalloc.c b/src/pkg/runtime/mfixalloc.c
index c916d588f..c7dab8aea 100644
--- a/src/pkg/runtime/mfixalloc.c
+++ b/src/pkg/runtime/mfixalloc.c
@@ -30,6 +30,11 @@ void*
runtime·FixAlloc_Alloc(FixAlloc *f)
{
void *v;
+
+ if(f->size == 0) {
+ runtime·printf("runtime: use of FixAlloc_Alloc before FixAlloc_Init\n");
+ runtime·throw("runtime: internal error");
+ }
if(f->list) {
v = f->list;
diff --git a/src/pkg/runtime/mgc0.c b/src/pkg/runtime/mgc0.c
index 010f9cd96..f9dbdbb4a 100644
--- a/src/pkg/runtime/mgc0.c
+++ b/src/pkg/runtime/mgc0.c
@@ -18,6 +18,8 @@ enum {
Debug = 0,
DebugMark = 0, // run second pass to check mark
CollectStats = 0,
+ ScanStackByFrames = 0,
+ IgnorePreciseGC = 0,
// Four bits per word (see #defines below).
wordsPerBitmapWord = sizeof(void*)*8/4,
@@ -140,6 +142,7 @@ static Workbuf* getempty(Workbuf*);
static Workbuf* getfull(Workbuf*);
static void putempty(Workbuf*);
static Workbuf* handoff(Workbuf*);
+static void gchelperstart(void);
static struct {
uint64 full; // lock-free list of full blocks
@@ -191,7 +194,7 @@ static struct {
// markonly marks an object. It returns true if the object
// has been marked by this function, false otherwise.
-// This function isn't thread-safe and doesn't append the object to any buffer.
+// This function doesn't append the object to any buffer.
static bool
markonly(void *obj)
{
@@ -254,13 +257,23 @@ found:
// Only care about allocated and not marked.
if((bits & (bitAllocated|bitMarked)) != bitAllocated)
return false;
- *bitp |= bitMarked<<shift;
+ if(work.nproc == 1)
+ *bitp |= bitMarked<<shift;
+ else {
+ for(;;) {
+ x = *bitp;
+ if(x & (bitMarked<<shift))
+ return false;
+ if(runtime·casp((void**)bitp, (void*)x, (void*)(x|(bitMarked<<shift))))
+ break;
+ }
+ }
// The object is now marked
return true;
}
-// PtrTarget and BitTarget are structures used by intermediate buffers.
+// PtrTarget is a structure used by intermediate buffers.
// The intermediate buffers hold GC data before it
// is moved/flushed to the work buffer (Workbuf).
// The size of an intermediate buffer is very small,
@@ -272,25 +285,17 @@ struct PtrTarget
uintptr ti;
};
-typedef struct BitTarget BitTarget;
-struct BitTarget
-{
- void *p;
- uintptr ti;
- uintptr *bitp, shift;
-};
-
typedef struct BufferList BufferList;
struct BufferList
{
PtrTarget ptrtarget[IntermediateBufferCapacity];
- BitTarget bittarget[IntermediateBufferCapacity];
Obj obj[IntermediateBufferCapacity];
- BufferList *next;
+ uint32 busy;
+ byte pad[CacheLineSize];
};
-static BufferList *bufferList;
+#pragma dataflag 16 // no pointers
+static BufferList bufferList[MaxGcproc];
-static Lock lock;
static Type *itabtype;
static void enqueue(Obj obj, Workbuf **_wbuf, Obj **_wp, uintptr *_nobj);
@@ -301,7 +306,6 @@ static void enqueue(Obj obj, Workbuf **_wbuf, Obj **_wp, uintptr *_nobj);
// and are prepared to be scanned by the garbage collector.
//
// _wp, _wbuf, _nobj are input/output parameters and are specifying the work buffer.
-// bitbuf holds temporary data generated by this function.
//
// A simplified drawing explaining how the todo-list moves from a structure to another:
//
@@ -309,14 +313,12 @@ static void enqueue(Obj obj, Workbuf **_wbuf, Obj **_wp, uintptr *_nobj);
// (find pointers)
// Obj ------> PtrTarget (pointer targets)
// ↑ |
-// | | flushptrbuf (1st part,
-// | | find block start)
-// | ↓
-// `--------- BitTarget (pointer targets and the corresponding locations in bitmap)
-// flushptrbuf
-// (2nd part, mark and enqueue)
+// | |
+// `----------'
+// flushptrbuf
+// (find block start, mark and enqueue)
static void
-flushptrbuf(PtrTarget *ptrbuf, PtrTarget **ptrbufpos, Obj **_wp, Workbuf **_wbuf, uintptr *_nobj, BitTarget *bitbuf)
+flushptrbuf(PtrTarget *ptrbuf, PtrTarget **ptrbufpos, Obj **_wp, Workbuf **_wbuf, uintptr *_nobj)
{
byte *p, *arena_start, *obj;
uintptr size, *bitp, bits, shift, j, x, xbits, off, nobj, ti, n;
@@ -325,7 +327,6 @@ flushptrbuf(PtrTarget *ptrbuf, PtrTarget **ptrbufpos, Obj **_wp, Workbuf **_wbuf
Obj *wp;
Workbuf *wbuf;
PtrTarget *ptrbuf_end;
- BitTarget *bitbufpos, *bt;
arena_start = runtime·mheap->arena_start;
@@ -359,8 +360,6 @@ flushptrbuf(PtrTarget *ptrbuf, PtrTarget **ptrbufpos, Obj **_wp, Workbuf **_wbuf
{
// Multi-threaded version.
- bitbufpos = bitbuf;
-
while(ptrbuf < ptrbuf_end) {
obj = ptrbuf->p;
ti = ptrbuf->ti;
@@ -438,26 +437,22 @@ flushptrbuf(PtrTarget *ptrbuf, PtrTarget **ptrbufpos, Obj **_wp, Workbuf **_wbuf
// Only care about allocated and not marked.
if((bits & (bitAllocated|bitMarked)) != bitAllocated)
continue;
-
- *bitbufpos++ = (BitTarget){obj, ti, bitp, shift};
- }
-
- runtime·lock(&lock);
- for(bt=bitbuf; bt<bitbufpos; bt++){
- xbits = *bt->bitp;
- bits = xbits >> bt->shift;
- if((bits & bitMarked) != 0)
- continue;
-
- // Mark the block
- *bt->bitp = xbits | (bitMarked << bt->shift);
+ if(work.nproc == 1)
+ *bitp |= bitMarked<<shift;
+ else {
+ for(;;) {
+ x = *bitp;
+ if(x & (bitMarked<<shift))
+ goto continue_obj;
+ if(runtime·casp((void**)bitp, (void*)x, (void*)(x|(bitMarked<<shift))))
+ break;
+ }
+ }
// If object has no pointers, don't need to scan further.
if((bits & bitNoPointers) != 0)
continue;
- obj = bt->p;
-
// Ask span about size class.
// (Manually inlined copy of MHeap_Lookup.)
x = (uintptr)obj >> PageShift;
@@ -467,11 +462,11 @@ flushptrbuf(PtrTarget *ptrbuf, PtrTarget **ptrbufpos, Obj **_wp, Workbuf **_wbuf
PREFETCH(obj);
- *wp = (Obj){obj, s->elemsize, bt->ti};
+ *wp = (Obj){obj, s->elemsize, ti};
wp++;
nobj++;
+ continue_obj:;
}
- runtime·unlock(&lock);
// If another proc wants a pointer, give it some.
if(work.nwait > 0 && nobj > handoffThreshold && work.full == 0) {
@@ -559,6 +554,59 @@ struct Frame {
uintptr *loop_or_ret;
};
+// Sanity check for the derived type info objti.
+static void
+checkptr(void *obj, uintptr objti)
+{
+ uintptr *pc1, *pc2, type, tisize, i, j, x;
+ byte *objstart;
+ Type *t;
+ MSpan *s;
+
+ if(!Debug)
+ runtime·throw("checkptr is debug only");
+
+ if(obj < runtime·mheap->arena_start || obj >= runtime·mheap->arena_used)
+ return;
+ type = runtime·gettype(obj);
+ t = (Type*)(type & ~(uintptr)(PtrSize-1));
+ if(t == nil)
+ return;
+ x = (uintptr)obj >> PageShift;
+ if(sizeof(void*) == 8)
+ x -= (uintptr)(runtime·mheap->arena_start)>>PageShift;
+ s = runtime·mheap->map[x];
+ objstart = (byte*)((uintptr)s->start<<PageShift);
+ if(s->sizeclass != 0) {
+ i = ((byte*)obj - objstart)/s->elemsize;
+ objstart += i*s->elemsize;
+ }
+ tisize = *(uintptr*)objti;
+ // Sanity check for object size: it should fit into the memory block.
+ if((byte*)obj + tisize > objstart + s->elemsize)
+ runtime·throw("invalid gc type info");
+ if(obj != objstart)
+ return;
+ // If obj points to the beginning of the memory block,
+ // check type info as well.
+ if(t->string == nil ||
+ // Gob allocates unsafe pointers for indirection.
+ (runtime·strcmp(t->string->str, (byte*)"unsafe.Pointer") &&
+ // Runtime and gc think differently about closures.
+ runtime·strstr(t->string->str, (byte*)"struct { F uintptr") != t->string->str)) {
+ pc1 = (uintptr*)objti;
+ pc2 = (uintptr*)t->gc;
+ // A simple best-effort check until first GC_END.
+ for(j = 1; pc1[j] != GC_END && pc2[j] != GC_END; j++) {
+ if(pc1[j] != pc2[j]) {
+ runtime·printf("invalid gc type info for '%s' at %p, type info %p, block info %p\n",
+ t->string ? (int8*)t->string->str : (int8*)"?", j, pc1[j], pc2[j]);
+ runtime·throw("invalid gc type info");
+ }
+ }
+ }
+}
+
// scanblock scans a block of n bytes starting at pointer b for references
// to other objects, scanning any it finds recursively until there are no
// unscanned objects left. Instead of using an explicit recursion, it keeps
@@ -575,20 +623,19 @@ scanblock(Workbuf *wbuf, Obj *wp, uintptr nobj, bool keepworking)
byte *b, *arena_start, *arena_used;
uintptr n, i, end_b, elemsize, size, ti, objti, count, type;
uintptr *pc, precise_type, nominal_size;
- uintptr *map_ret, mapkey_size, mapval_size, mapkey_ti, mapval_ti;
+ uintptr *map_ret, mapkey_size, mapval_size, mapkey_ti, mapval_ti, *chan_ret;
void *obj;
Type *t;
Slice *sliceptr;
Frame *stack_ptr, stack_top, stack[GC_STACK_CAPACITY+4];
BufferList *scanbuffers;
PtrTarget *ptrbuf, *ptrbuf_end, *ptrbufpos;
- BitTarget *bitbuf;
Obj *objbuf, *objbuf_end, *objbufpos;
Eface *eface;
Iface *iface;
Hmap *hmap;
MapType *maptype;
- bool didmark, mapkey_kind, mapval_kind;
+ bool mapkey_kind, mapval_kind;
struct hash_gciter map_iter;
struct hash_gciter_data d;
Hchan *chan;
@@ -606,26 +653,13 @@ scanblock(Workbuf *wbuf, Obj *wp, uintptr nobj, bool keepworking)
precise_type = false;
nominal_size = 0;
- // Allocate ptrbuf, bitbuf
+ // Allocate ptrbuf
{
- runtime·lock(&lock);
-
- if(bufferList == nil) {
- bufferList = runtime·SysAlloc(sizeof(*bufferList));
- if(bufferList == nil)
- runtime·throw("runtime: cannot allocate memory");
- bufferList->next = nil;
- }
- scanbuffers = bufferList;
- bufferList = bufferList->next;
-
+ scanbuffers = &bufferList[m->helpgc];
ptrbuf = &scanbuffers->ptrtarget[0];
ptrbuf_end = &scanbuffers->ptrtarget[0] + nelem(scanbuffers->ptrtarget);
- bitbuf = &scanbuffers->bittarget[0];
objbuf = &scanbuffers->obj[0];
objbuf_end = &scanbuffers->obj[0] + nelem(scanbuffers->obj);
-
- runtime·unlock(&lock);
}
ptrbufpos = ptrbuf;
@@ -638,6 +672,7 @@ scanblock(Workbuf *wbuf, Obj *wp, uintptr nobj, bool keepworking)
mapkey_ti = mapval_ti = 0;
chan = nil;
chantype = nil;
+ chan_ret = nil;
goto next_block;
@@ -666,6 +701,17 @@ scanblock(Workbuf *wbuf, Obj *wp, uintptr nobj, bool keepworking)
} else {
stack_top.count = 1;
}
+ if(Debug) {
+ // Simple sanity check for provided type info ti:
+ // The declared size of the object must be not larger than the actual size
+ // (it can be smaller due to inferior pointers).
+ // It's difficult to make a comprehensive check due to inferior pointers,
+ // reflection, gob, etc.
+ if(pc[0] > n) {
+ runtime·printf("invalid gc type info: type info size %p, block size %p\n", pc[0], n);
+ runtime·throw("invalid gc type info");
+ }
+ }
} else if(UseSpanType) {
if(CollectStats)
runtime·xadd64(&gcstats.obj.notype, 1);
@@ -703,7 +749,7 @@ scanblock(Workbuf *wbuf, Obj *wp, uintptr nobj, bool keepworking)
mapval_kind = maptype->elem->kind;
mapval_ti = (uintptr)maptype->elem->gc | PRECISE;
- map_ret = 0;
+ map_ret = nil;
pc = mapProg;
} else {
goto next_block;
@@ -712,6 +758,7 @@ scanblock(Workbuf *wbuf, Obj *wp, uintptr nobj, bool keepworking)
case TypeInfo_Chan:
chan = (Hchan*)b;
chantype = (ChanType*)t;
+ chan_ret = nil;
pc = chanProg;
break;
default:
@@ -725,6 +772,9 @@ scanblock(Workbuf *wbuf, Obj *wp, uintptr nobj, bool keepworking)
pc = defaultProg;
}
+ if(IgnorePreciseGC)
+ pc = defaultProg;
+
pc++;
stack_top.b = (uintptr)b;
@@ -741,6 +791,8 @@ scanblock(Workbuf *wbuf, Obj *wp, uintptr nobj, bool keepworking)
obj = *(void**)(stack_top.b + pc[1]);
objti = pc[2];
pc += 3;
+ if(Debug)
+ checkptr(obj, objti);
break;
case GC_SLICE:
@@ -759,17 +811,29 @@ scanblock(Workbuf *wbuf, Obj *wp, uintptr nobj, bool keepworking)
case GC_STRING:
obj = *(void**)(stack_top.b + pc[1]);
+ markonly(obj);
pc += 2;
- break;
+ continue;
case GC_EFACE:
eface = (Eface*)(stack_top.b + pc[1]);
pc += 2;
- if(eface->type != nil && (eface->data >= arena_start && eface->data < arena_used)) {
- t = eface->type;
+ if(eface->type == nil)
+ continue;
+
+ // eface->type
+ t = eface->type;
+ if((void*)t >= arena_start && (void*)t < arena_used) {
+ *ptrbufpos++ = (PtrTarget){t, 0};
+ if(ptrbufpos == ptrbuf_end)
+ flushptrbuf(ptrbuf, &ptrbufpos, &wp, &wbuf, &nobj);
+ }
+
+ // eface->data
+ if(eface->data >= arena_start && eface->data < arena_used) {
if(t->size <= sizeof(void*)) {
if((t->kind & KindNoPointers))
- break;
+ continue;
obj = eface->data;
if((t->kind & ~KindNoPointers) == KindPtr)
@@ -785,13 +849,13 @@ scanblock(Workbuf *wbuf, Obj *wp, uintptr nobj, bool keepworking)
iface = (Iface*)(stack_top.b + pc[1]);
pc += 2;
if(iface->tab == nil)
- break;
+ continue;
// iface->tab
if((void*)iface->tab >= arena_start && (void*)iface->tab < arena_used) {
*ptrbufpos++ = (PtrTarget){iface->tab, (uintptr)itabtype->gc};
if(ptrbufpos == ptrbuf_end)
- flushptrbuf(ptrbuf, &ptrbufpos, &wp, &wbuf, &nobj, bitbuf);
+ flushptrbuf(ptrbuf, &ptrbufpos, &wp, &wbuf, &nobj);
}
// iface->data
@@ -799,7 +863,7 @@ scanblock(Workbuf *wbuf, Obj *wp, uintptr nobj, bool keepworking)
t = iface->tab->type;
if(t->size <= sizeof(void*)) {
if((t->kind & KindNoPointers))
- break;
+ continue;
obj = iface->data;
if((t->kind & ~KindNoPointers) == KindPtr)
@@ -812,13 +876,13 @@ scanblock(Workbuf *wbuf, Obj *wp, uintptr nobj, bool keepworking)
break;
case GC_DEFAULT_PTR:
- while((i = stack_top.b) <= end_b) {
+ while(stack_top.b <= end_b) {
+ obj = *(byte**)stack_top.b;
stack_top.b += PtrSize;
- obj = *(byte**)i;
if(obj >= arena_start && obj < arena_used) {
*ptrbufpos++ = (PtrTarget){obj, 0};
if(ptrbufpos == ptrbuf_end)
- flushptrbuf(ptrbuf, &ptrbufpos, &wp, &wbuf, &nobj, bitbuf);
+ flushptrbuf(ptrbuf, &ptrbufpos, &wp, &wbuf, &nobj);
}
}
goto next_block;
@@ -826,9 +890,8 @@ scanblock(Workbuf *wbuf, Obj *wp, uintptr nobj, bool keepworking)
case GC_END:
if(--stack_top.count != 0) {
// Next iteration of a loop if possible.
- elemsize = stack_top.elemsize;
- stack_top.b += elemsize;
- if(stack_top.b + elemsize <= end_b+PtrSize) {
+ stack_top.b += stack_top.elemsize;
+ if(stack_top.b + stack_top.elemsize <= end_b+PtrSize) {
pc = stack_top.loop_or_ret;
continue;
}
@@ -894,10 +957,7 @@ scanblock(Workbuf *wbuf, Obj *wp, uintptr nobj, bool keepworking)
pc += 3;
continue;
}
- runtime·lock(&lock);
- didmark = markonly(hmap);
- runtime·unlock(&lock);
- if(didmark) {
+ if(markonly(hmap)) {
maptype = (MapType*)pc[2];
if(hash_gciter_init(hmap, &map_iter)) {
mapkey_size = maptype->key->size;
@@ -923,31 +983,41 @@ scanblock(Workbuf *wbuf, Obj *wp, uintptr nobj, bool keepworking)
while(hash_gciter_next(&map_iter, &d)) {
// buffers: reserve space for 2 objects.
if(ptrbufpos+2 >= ptrbuf_end)
- flushptrbuf(ptrbuf, &ptrbufpos, &wp, &wbuf, &nobj, bitbuf);
+ flushptrbuf(ptrbuf, &ptrbufpos, &wp, &wbuf, &nobj);
if(objbufpos+2 >= objbuf_end)
flushobjbuf(objbuf, &objbufpos, &wp, &wbuf, &nobj);
- if(d.st != nil) {
- runtime·lock(&lock);
+ if(d.st != nil)
markonly(d.st);
- runtime·unlock(&lock);
- }
+
if(d.key_data != nil) {
if(!(mapkey_kind & KindNoPointers) || d.indirectkey) {
if(!d.indirectkey)
*objbufpos++ = (Obj){d.key_data, mapkey_size, mapkey_ti};
- else
+ else {
+ if(Debug) {
+ obj = *(void**)d.key_data;
+ if(!(arena_start <= obj && obj < arena_used))
+ runtime·throw("scanblock: inconsistent hashmap");
+ }
*ptrbufpos++ = (PtrTarget){*(void**)d.key_data, mapkey_ti};
+ }
}
if(!(mapval_kind & KindNoPointers) || d.indirectval) {
if(!d.indirectval)
*objbufpos++ = (Obj){d.val_data, mapval_size, mapval_ti};
- else
+ else {
+ if(Debug) {
+ obj = *(void**)d.val_data;
+ if(!(arena_start <= obj && obj < arena_used))
+ runtime·throw("scanblock: inconsistent hashmap");
+ }
*ptrbufpos++ = (PtrTarget){*(void**)d.val_data, mapval_ti};
+ }
}
}
}
- if(map_ret == 0)
+ if(map_ret == nil)
goto next_block;
pc = map_ret;
continue;
@@ -961,7 +1031,26 @@ scanblock(Workbuf *wbuf, Obj *wp, uintptr nobj, bool keepworking)
*objbufpos++ = (Obj){obj, size, objti};
if(objbufpos == objbuf_end)
flushobjbuf(objbuf, &objbufpos, &wp, &wbuf, &nobj);
- break;
+ continue;
+
+ case GC_CHAN_PTR:
+ // Similar to GC_MAP_PTR
+ chan = *(Hchan**)(stack_top.b + pc[1]);
+ if(chan == nil) {
+ pc += 3;
+ continue;
+ }
+ if(markonly(chan)) {
+ chantype = (ChanType*)pc[2];
+ if(!(chantype->elem->kind & KindNoPointers)) {
+ // Start chanProg.
+ chan_ret = pc+3;
+ pc = chanProg+1;
+ continue;
+ }
+ }
+ pc += 3;
+ continue;
case GC_CHAN:
// There are no heap pointers in struct Hchan,
@@ -981,7 +1070,10 @@ scanblock(Workbuf *wbuf, Obj *wp, uintptr nobj, bool keepworking)
flushobjbuf(objbuf, &objbufpos, &wp, &wbuf, &nobj);
}
}
- goto next_block;
+ if(chan_ret == nil)
+ goto next_block;
+ pc = chan_ret;
+ continue;
default:
runtime·throw("scanblock: invalid GC instruction");
@@ -991,7 +1083,7 @@ scanblock(Workbuf *wbuf, Obj *wp, uintptr nobj, bool keepworking)
if(obj >= arena_start && obj < arena_used) {
*ptrbufpos++ = (PtrTarget){obj, objti};
if(ptrbufpos == ptrbuf_end)
- flushptrbuf(ptrbuf, &ptrbufpos, &wp, &wbuf, &nobj, bitbuf);
+ flushptrbuf(ptrbuf, &ptrbufpos, &wp, &wbuf, &nobj);
}
}
@@ -1000,7 +1092,7 @@ scanblock(Workbuf *wbuf, Obj *wp, uintptr nobj, bool keepworking)
// the loop by setting b, n, ti to the parameters for the next block.
if(nobj == 0) {
- flushptrbuf(ptrbuf, &ptrbufpos, &wp, &wbuf, &nobj, bitbuf);
+ flushptrbuf(ptrbuf, &ptrbufpos, &wp, &wbuf, &nobj);
flushobjbuf(objbuf, &objbufpos, &wp, &wbuf, &nobj);
if(nobj == 0) {
@@ -1026,11 +1118,7 @@ scanblock(Workbuf *wbuf, Obj *wp, uintptr nobj, bool keepworking)
nobj--;
}
-endscan:
- runtime·lock(&lock);
- scanbuffers->next = bufferList;
- bufferList = scanbuffers;
- runtime·unlock(&lock);
+endscan:;
}
// debug_scanblock is the debug copy of scanblock.
@@ -1299,51 +1387,94 @@ addroot(Obj obj)
work.nroot++;
}
+// Scan a stack frame. The doframe parameter is a signal that the previously
+// scanned activation has an unknown argument size. When *doframe is true the
+// current activation must have its entire frame scanned. Otherwise, only the
+// locals need to be scanned.
+static void
+addframeroots(Func *f, byte*, byte *sp, void *doframe)
+{
+ uintptr outs;
+
+ if(thechar == '5')
+ sp += sizeof(uintptr);
+ if(f->locals == 0 || *(bool*)doframe == true)
+ addroot((Obj){sp, f->frame - sizeof(uintptr), 0});
+ else if(f->locals > 0) {
+ outs = f->frame - sizeof(uintptr) - f->locals;
+ addroot((Obj){sp + outs, f->locals, 0});
+ }
+ if(f->args > 0)
+ addroot((Obj){sp + f->frame, f->args, 0});
+ *(bool*)doframe = (f->args == ArgsSizeUnknown);
+}
+
static void
addstackroots(G *gp)
{
M *mp;
int32 n;
Stktop *stk;
- byte *sp, *guard;
+ byte *sp, *guard, *pc;
+ Func *f;
+ bool doframe;
stk = (Stktop*)gp->stackbase;
guard = (byte*)gp->stackguard;
if(gp == g) {
// Scanning our own stack: start at &gp.
- sp = (byte*)&gp;
+ sp = runtime·getcallersp(&gp);
+ pc = runtime·getcallerpc(&gp);
} else if((mp = gp->m) != nil && mp->helpgc) {
// gchelper's stack is in active use and has no interesting pointers.
return;
+ } else if(gp->gcstack != (uintptr)nil) {
+ // Scanning another goroutine that is about to enter or might
+ // have just exited a system call. It may be executing code such
+ // as schedlock and may have needed to start a new stack segment.
+ // Use the stack segment and stack pointer at the time of
+ // the system call instead, since that won't change underfoot.
+ sp = (byte*)gp->gcsp;
+ pc = gp->gcpc;
+ stk = (Stktop*)gp->gcstack;
+ guard = (byte*)gp->gcguard;
} else {
// Scanning another goroutine's stack.
// The goroutine is usually asleep (the world is stopped).
sp = (byte*)gp->sched.sp;
-
- // The exception is that if the goroutine is about to enter or might
- // have just exited a system call, it may be executing code such
- // as schedlock and may have needed to start a new stack segment.
- // Use the stack segment and stack pointer at the time of
- // the system call instead, since that won't change underfoot.
- if(gp->gcstack != (uintptr)nil) {
- stk = (Stktop*)gp->gcstack;
- sp = (byte*)gp->gcsp;
- guard = (byte*)gp->gcguard;
+ pc = gp->sched.pc;
+ if(ScanStackByFrames && pc == (byte*)runtime·goexit && gp->fnstart != nil) {
+ // The goroutine has not started. However, its incoming
+ // arguments are live at the top of the stack and must
+ // be scanned. No other live values should be on the
+ // stack.
+ f = runtime·findfunc((uintptr)gp->fnstart->fn);
+ if(f->args > 0) {
+ if(thechar == '5')
+ sp += sizeof(uintptr);
+ addroot((Obj){sp, f->args, 0});
+ }
+ return;
}
}
-
- n = 0;
- while(stk) {
- if(sp < guard-StackGuard || (byte*)stk < sp) {
- runtime·printf("scanstack inconsistent: g%D#%d sp=%p not in [%p,%p]\n", gp->goid, n, sp, guard-StackGuard, stk);
- runtime·throw("scanstack");
+ if (ScanStackByFrames) {
+ doframe = false;
+ runtime·gentraceback(pc, sp, nil, gp, 0, nil, 0x7fffffff, addframeroots, &doframe);
+ } else {
+ USED(pc);
+ n = 0;
+ while(stk) {
+ if(sp < guard-StackGuard || (byte*)stk < sp) {
+ runtime·printf("scanstack inconsistent: g%D#%d sp=%p not in [%p,%p]\n", gp->goid, n, sp, guard-StackGuard, stk);
+ runtime·throw("scanstack");
+ }
+ addroot((Obj){sp, (byte*)stk - sp, (uintptr)defaultProg | PRECISE | LOOP});
+ sp = (byte*)stk->gobuf.sp;
+ guard = stk->stackguard;
+ stk = (Stktop*)stk->stackbase;
+ n++;
}
- addroot((Obj){sp, (byte*)stk - sp, 0});
- sp = (byte*)stk->gobuf.sp;
- guard = stk->stackguard;
- stk = (Stktop*)stk->stackbase;
- n++;
}
}
@@ -1381,14 +1512,17 @@ addroots(void)
for(spanidx=0; spanidx<runtime·mheap->nspan; spanidx++) {
s = allspans[spanidx];
if(s->state == MSpanInUse) {
+ // The garbage collector ignores type pointers stored in MSpan.types:
+ // - Compiler-generated types are stored outside of heap.
+ // - The reflect package has runtime-generated types cached in its data structures.
+ // The garbage collector relies on finding the references via that cache.
switch(s->types.compression) {
case MTypes_Empty:
case MTypes_Single:
break;
case MTypes_Words:
case MTypes_Bytes:
- // TODO(atom): consider using defaultProg instead of 0
- addroot((Obj){(byte*)&s->types.data, sizeof(void*), 0});
+ markonly((byte*)s->types.data);
break;
}
}
@@ -1543,7 +1677,7 @@ sweepspan(ParFor *desc, uint32 idx)
if(cl == 0) {
// Free large span.
runtime·unmarkspan(p, 1<<PageShift);
- *(uintptr*)p = 1; // needs zeroing
+ *(uintptr*)p = (uintptr)0xdeaddeaddeaddeadll; // needs zeroing
runtime·MHeap_Free(runtime·mheap, s, 1);
c->local_alloc -= size;
c->local_nfree++;
@@ -1558,7 +1692,7 @@ sweepspan(ParFor *desc, uint32 idx)
break;
}
if(size > sizeof(uintptr))
- ((uintptr*)p)[1] = 1; // mark as "needs to be zeroed"
+ ((uintptr*)p)[1] = (uintptr)0xdeaddeaddeaddeadll; // mark as "needs to be zeroed"
end->next = (MLink*)p;
end = (MLink*)p;
@@ -1655,6 +1789,8 @@ runtime·memorydump(void)
void
runtime·gchelper(void)
{
+ gchelperstart();
+
// parallel mark for over gc roots
runtime·parfordo(work.markfor);
@@ -1668,6 +1804,7 @@ runtime·gchelper(void)
}
runtime·parfordo(work.sweepfor);
+ bufferList[m->helpgc].busy = 0;
if(runtime·xadd(&work.ndone, +1) == work.nproc-1)
runtime·notewakeup(&work.alldone);
}
@@ -1757,6 +1894,8 @@ runtime·gc(int32 force)
// a problem in the past.
if((((uintptr)&work.empty) & 7) != 0)
runtime·throw("runtime: gc work buffer is misaligned");
+ if((((uintptr)&work.full) & 7) != 0)
+ runtime·throw("runtime: gc work buffer is misaligned");
// The gc is turned off (via enablegc) until
// the bootstrap has completed.
@@ -1857,6 +1996,7 @@ gc(struct gc_args *args)
t1 = runtime·nanotime();
+ gchelperstart();
runtime·parfordo(work.markfor);
scanblock(nil, nil, 0, true);
@@ -1868,6 +2008,7 @@ gc(struct gc_args *args)
t2 = runtime·nanotime();
runtime·parfordo(work.sweepfor);
+ bufferList[m->helpgc].busy = 0;
t3 = runtime·nanotime();
if(work.nproc > 1)
@@ -2009,6 +2150,15 @@ runtime∕debug·setGCPercent(intgo in, intgo out)
}
static void
+gchelperstart(void)
+{
+ 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");
+}
+
+static void
runfinq(void)
{
Finalizer *f;
diff --git a/src/pkg/runtime/mgc0.h b/src/pkg/runtime/mgc0.h
index 87b604a36..d14fb37c2 100644
--- a/src/pkg/runtime/mgc0.h
+++ b/src/pkg/runtime/mgc0.h
@@ -16,6 +16,9 @@
// len Length of an array
// elemsize Size (in bytes) of an element
// size Size (in bytes)
+//
+// NOTE: There is a copy of these in ../reflect/type.go.
+// They must be kept in sync.
enum {
GC_END, // End of object, loop or subroutine. Args: none
GC_PTR, // A typed pointer. Args: (off, objgc)
@@ -24,6 +27,7 @@ enum {
GC_ARRAY_NEXT, // The next element of an array. Args: none
GC_CALL, // Call a subroutine. Args: (off, objgcrel)
GC_MAP_PTR, // Go map. Args: (off, MapType*)
+ GC_CHAN_PTR, // Go channel. Args: (off, ChanType*)
GC_STRING, // Go string. Args: (off)
GC_EFACE, // interface{}. Args: (off)
GC_IFACE, // interface{...}. Args: (off)
diff --git a/src/pkg/runtime/mheap.c b/src/pkg/runtime/mheap.c
index f45149d63..f4fbbee7a 100644
--- a/src/pkg/runtime/mheap.c
+++ b/src/pkg/runtime/mheap.c
@@ -121,6 +121,25 @@ HaveSpan:
s->state = MSpanInUse;
mstats.heap_idle -= s->npages<<PageShift;
mstats.heap_released -= s->npreleased<<PageShift;
+ if(s->npreleased > 0) {
+ // We have called runtime·SysUnused with these pages, and on
+ // Unix systems it called madvise. At this point at least
+ // some BSD-based kernels will return these pages either as
+ // zeros or with the old data. For our caller, the first word
+ // in the page indicates whether the span contains zeros or
+ // not (this word was set when the span was freed by
+ // MCentral_Free or runtime·MCentral_FreeSpan). If the first
+ // page in the span is returned as zeros, and some subsequent
+ // page is returned with the old data, then we will be
+ // returning a span that is assumed to be all zeros, but the
+ // actual data will not be all zeros. Avoid that problem by
+ // explicitly marking the span as not being zeroed, just in
+ // case. The beadbead constant we use here means nothing, it
+ // is just a unique constant not seen elsewhere in the
+ // runtime, as a clue in case it turns up unexpectedly in
+ // memory or in a stack trace.
+ *(uintptr*)(s->start<<PageShift) = (uintptr)0xbeadbeadbeadbeadULL;
+ }
s->npreleased = 0;
if(s->npages > npage) {
@@ -409,6 +428,9 @@ runtime·MHeap_Scavenger(void)
bool trace;
Note note, *notep;
+ g->issystem = true;
+ g->isbackground = true;
+
// If we go two minutes without a garbage collection, force one to run.
forcegc = 2*60*1e9;
// If a span goes unused for 5 minutes after a garbage collection,
diff --git a/src/pkg/runtime/mkasmh.sh b/src/pkg/runtime/mkasmh.sh
deleted file mode 100755
index f37fe2149..000000000
--- a/src/pkg/runtime/mkasmh.sh
+++ /dev/null
@@ -1,138 +0,0 @@
-#!/bin/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.
-
-trap "rm -f arch_GOARCH.h defs_GOOS_GOARCH.h os_GOOS.h signals_GOOS.h" EXIT INT TERM
-set -e
-
-SYS=$1
-export GOOS=$(echo $SYS | sed 's/_.*//')
-export GOARCH=$(echo $SYS | sed 's/.*_//')
-shift
-
-case "$GOARCH" in
-386) CC=8c;;
-amd64) CC=6c;;
-arm) CC=5c;;
-esac
-CC="$GOROOT/bin/tool/$CC"
-export CC
-
-export CFLAGS="-Dos_$GOOS -Darch_$GOARCH"
-
-cp arch_$GOARCH.h arch_GOARCH.h
-cp defs_${GOOS}_$GOARCH.h defs_GOOS_GOARCH.h
-cp os_$GOOS.h os_GOOS.h
-cp signals_$GOOS.h signals_GOOS.h
-
-cat <<'EOF'
-// Assembly constants.
-// AUTO-GENERATED by autogen.sh; DO NOT EDIT
-
-EOF
-if [ ! -x "$CC" ]; then
- echo "// dummy file for cmd/go to correctly generate buildscript"
- exit
-fi
-
-case "$GOARCH" in
-386)
- # The offsets 0 and 4 are also known to:
- # ../../cmd/8l/pass.c:/D_GS
- # cgo/gcc_linux_386.c:/^threadentry
- # cgo/gcc_darwin_386.c:/^threadentry
- case "$GOOS" in
- windows)
- echo '#define get_tls(r) MOVL 0x14(FS), r'
- echo '#define g(r) 0(r)'
- echo '#define m(r) 4(r)'
- ;;
- plan9)
- echo '#define get_tls(r) MOVL _tos(SB), r '
- echo '#define g(r) -8(r)'
- echo '#define m(r) -4(r)'
- ;;
- linux)
- # On Linux systems, what we call 0(GS) and 4(GS) for g and m
- # turn into %gs:-8 and %gs:-4 (using gcc syntax to denote
- # what the machine sees as opposed to 8l input).
- # 8l rewrites 0(GS) and 4(GS) into these.
- #
- # On Linux Xen, it is not allowed to use %gs:-8 and %gs:-4
- # directly. Instead, we have to store %gs:0 into a temporary
- # register and then use -8(%reg) and -4(%reg). This kind
- # of addressing is correct even when not running Xen.
- #
- # 8l can rewrite MOVL 0(GS), CX into the appropriate pair
- # of mov instructions, using CX as the intermediate register
- # (safe because CX is about to be written to anyway).
- # But 8l cannot handle other instructions, like storing into 0(GS),
- # which is where these macros come into play.
- # get_tls sets up the temporary and then g and r use it.
- #
- # The final wrinkle is that get_tls needs to read from %gs:0,
- # but in 8l input it's called 8(GS), because 8l is going to
- # subtract 8 from all the offsets, as described above.
- echo '#define get_tls(r) MOVL 8(GS), r'
- echo '#define g(r) -8(r)'
- echo '#define m(r) -4(r)'
- ;;
- *)
- echo '#define get_tls(r)'
- echo '#define g(r) 0(GS)'
- echo '#define m(r) 4(GS)'
- ;;
- esac
- ;;
-amd64)
- case "$GOOS" in
- windows)
- echo '#define get_tls(r) MOVQ 0x28(GS), r'
- echo '#define g(r) 0(r)'
- echo '#define m(r) 8(r)'
- ;;
- *)
- # The offsets 0 and 8 are known to:
- # ../../cmd/6l/pass.c:/D_GS
- # cgo/gcc_linux_amd64.c:/^threadentry
- # cgo/gcc_darwin_amd64.c:/^threadentry
- #
- echo '#define get_tls(r)'
- echo '#define g(r) 0(GS)'
- echo '#define m(r) 8(GS)'
- ;;
- esac
- ;;
-arm)
- echo '#define g R10'
- echo '#define m R9'
- echo '#define LR R14'
- ;;
-*)
- echo 'unknown $GOARCH: '$GOARCH 1>&2
- exit 1
- ;;
-esac
-echo
-
-"$CC" $CFLAGS -a proc.c |
-awk '
-{ gsub(/\r/, ""); }
-/^aggr G$/ { aggr="g" }
-/^aggr M$/ { aggr = "m" }
-/^aggr Gobuf$/ { aggr = "gobuf" }
-/^aggr WinCall$/ { aggr = "wincall" }
-/^}/ { aggr = "" }
-
-# Gobuf 24 sched;
-# 'Y' 48 stack0;
-# 'Y' 56 entry;
-# 'A' G 64 alllink;
-aggr != "" && /^ / {
- name=$NF;
- sub(/;/, "", name);
- offset=$(NF-1);
- printf("#define %s_%s %s\n", aggr, name, offset);
-}
-'
diff --git a/src/pkg/runtime/mprof.goc b/src/pkg/runtime/mprof.goc
index ebc1e3e66..63334e704 100644
--- a/src/pkg/runtime/mprof.goc
+++ b/src/pkg/runtime/mprof.goc
@@ -61,6 +61,8 @@ 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
@@ -511,7 +513,7 @@ saveg(byte *pc, byte *sp, G *gp, TRecord *r)
{
int32 n;
- n = runtime·gentraceback(pc, sp, 0, gp, 0, r->stk, nelem(r->stk));
+ n = runtime·gentraceback(pc, sp, 0, gp, 0, r->stk, nelem(r->stk), nil, nil);
if(n < nelem(r->stk))
r->stk[n] = 0;
}
diff --git a/src/pkg/runtime/netpoll.goc b/src/pkg/runtime/netpoll.goc
new file mode 100644
index 000000000..06b6d6172
--- /dev/null
+++ b/src/pkg/runtime/netpoll.goc
@@ -0,0 +1,351 @@
+// 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 linux
+
+package net
+
+#include "runtime.h"
+#include "defs_GOOS_GOARCH.h"
+#include "arch_GOARCH.h"
+#include "malloc.h"
+
+// 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(int32 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);
+
+#define READY ((G*)1)
+
+struct PollDesc
+{
+ PollDesc* link; // in pollcache, protected by pollcache.Lock
+ Lock; // protectes the following fields
+ int32 fd;
+ bool closing;
+ uintptr seq; // protects from stale timers and ready notifications
+ G* rg; // G waiting for read or READY (binary semaphore)
+ Timer rt; // read deadline timer (set if rt.fv != nil)
+ int64 rd; // read deadline
+ G* wg; // the same for writes
+ Timer wt;
+ int64 wd;
+};
+
+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 void netpollblock(PollDesc*, int32);
+static G* netpollunblock(PollDesc*, int32);
+static void deadline(int64, Eface);
+static void readDeadline(int64, Eface);
+static void writeDeadline(int64, Eface);
+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};
+
+func runtime_pollServerInit() {
+ runtime·netpollinit();
+}
+
+func runtime_pollOpen(fd int) (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) {
+ runtime·lock(pd);
+ err = checkerr(pd, mode);
+ if(err)
+ goto ret;
+ if(mode == 'r')
+ pd->rg = nil;
+ else if(mode == 'w')
+ pd->wg = nil;
+ret:
+ runtime·unlock(pd);
+}
+
+func runtime_pollWait(pd *PollDesc, mode int) (err int) {
+ runtime·lock(pd);
+ err = checkerr(pd, mode);
+ if(err)
+ goto ret;
+ netpollblock(pd, mode);
+ err = checkerr(pd, mode);
+ret:
+ runtime·unlock(pd);
+}
+
+func runtime_pollSetDeadline(pd *PollDesc, d int64, mode int) {
+ runtime·lock(pd);
+ if(pd->closing)
+ goto ret;
+ 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 = (Type*)pd->seq;
+ pd->rt.arg.data = pd;
+ runtime·addtimer(&pd->rt);
+ } else {
+ if(pd->rd > 0) {
+ pd->rt.fv = &readDeadlineFn;
+ pd->rt.when = pd->rd;
+ pd->rt.arg.type = (Type*)pd->seq;
+ pd->rt.arg.data = pd;
+ runtime·addtimer(&pd->rt);
+ }
+ if(pd->wd > 0) {
+ pd->wt.fv = &writeDeadlineFn;
+ pd->wt.when = pd->wd;
+ pd->wt.arg.type = (Type*)pd->seq;
+ pd->wt.arg.data = pd;
+ runtime·addtimer(&pd->wt);
+ }
+ }
+ret:
+ runtime·unlock(pd);
+}
+
+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++;
+ rg = netpollunblock(pd, 'r');
+ wg = netpollunblock(pd, 'w');
+ 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);
+}
+
+// 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;
+ runtime·lock(pd);
+ if(mode == 'r' || mode == 'r'+'w')
+ rg = netpollunblock(pd, 'r');
+ if(mode == 'w' || mode == 'r'+'w')
+ wg = netpollunblock(pd, 'w');
+ runtime·unlock(pd);
+ 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 void
+netpollblock(PollDesc *pd, int32 mode)
+{
+ G **gpp;
+
+ gpp = &pd->rg;
+ if(mode == 'w')
+ gpp = &pd->wg;
+ if(*gpp == READY) {
+ *gpp = nil;
+ return;
+ }
+ if(*gpp != nil)
+ runtime·throw("epoll: double wait");
+ *gpp = g;
+ runtime·park(runtime·unlock, &pd->Lock, "IO wait");
+ runtime·lock(pd);
+}
+
+static G*
+netpollunblock(PollDesc *pd, int32 mode)
+{
+ G **gpp, *old;
+
+ gpp = &pd->rg;
+ if(mode == 'w')
+ gpp = &pd->wg;
+ if(*gpp == READY)
+ return nil;
+ if(*gpp == nil) {
+ *gpp = READY;
+ return nil;
+ }
+ old = *gpp;
+ *gpp = nil;
+ return old;
+}
+
+static void
+deadlineimpl(int64 now, Eface arg, bool read, bool write)
+{
+ PollDesc *pd;
+ uint32 seq;
+ G *rg, *wg;
+
+ USED(now);
+ pd = (PollDesc*)arg.data;
+ // This is the seq when the timer was set.
+ // If it's stale, ignore the timer event.
+ seq = (uintptr)arg.type;
+ rg = wg = nil;
+ runtime·lock(pd);
+ 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;
+ pd->rt.fv = nil;
+ rg = netpollunblock(pd, 'r');
+ }
+ if(write) {
+ if(pd->wd <= 0 || (pd->wt.fv == nil && !read))
+ runtime·throw("deadlineimpl: inconsistent write deadline");
+ pd->wd = -1;
+ pd->wt.fv = nil;
+ wg = netpollunblock(pd, 'w');
+ }
+ runtime·unlock(pd);
+ if(rg)
+ runtime·ready(rg);
+ if(wg)
+ runtime·ready(wg);
+}
+
+static void
+deadline(int64 now, Eface arg)
+{
+ deadlineimpl(now, arg, true, true);
+}
+
+static void
+readDeadline(int64 now, Eface arg)
+{
+ deadlineimpl(now, arg, true, false);
+}
+
+static void
+writeDeadline(int64 now, Eface arg)
+{
+ deadlineimpl(now, arg, false, true);
+}
+
+static PollDesc*
+allocPollDesc(void)
+{
+ PollDesc *pd;
+ uint32 i, n;
+
+ runtime·lock(&pollcache);
+ if(pollcache.first == nil) {
+ n = PageSize/sizeof(*pd);
+ if(n == 0)
+ n = 1;
+ // Must be in non-GC memory because can be referenced
+ // only from epoll/kqueue internals.
+ pd = runtime·SysAlloc(n*sizeof(*pd));
+ 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/src/pkg/runtime/netpoll_epoll.c b/src/pkg/runtime/netpoll_epoll.c
new file mode 100644
index 000000000..9b5980700
--- /dev/null
+++ b/src/pkg/runtime/netpoll_epoll.c
@@ -0,0 +1,95 @@
+// 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 "runtime.h"
+#include "defs_GOOS_GOARCH.h"
+
+int32 runtime·epollcreate(int32 size);
+int32 runtime·epollcreate1(int32 flags);
+int32 runtime·epollctl(int32 epfd, int32 op, int32 fd, EpollEvent *ev);
+int32 runtime·epollwait(int32 epfd, EpollEvent *ev, int32 nev, int32 timeout);
+void runtime·closeonexec(int32 fd);
+
+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(int32 fd, PollDesc *pd)
+{
+ EpollEvent ev;
+ int32 res;
+
+ ev.events = EPOLLIN|EPOLLOUT|EPOLLRDHUP|EPOLLET;
+ ev.data = (uint64)pd;
+ res = runtime·epollctl(epfd, EPOLL_CTL_ADD, fd, &ev);
+ return -res;
+}
+
+int32
+runtime·netpollclose(int32 fd)
+{
+ EpollEvent ev;
+ int32 res;
+
+ res = runtime·epollctl(epfd, EPOLL_CTL_DEL, fd, &ev);
+ return -res;
+}
+
+// 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, mode);
+ }
+ if(block && gp == nil)
+ goto retry;
+ return gp;
+}
diff --git a/src/pkg/runtime/netpoll_kqueue.c b/src/pkg/runtime/netpoll_kqueue.c
new file mode 100644
index 000000000..0ed03d31f
--- /dev/null
+++ b/src/pkg/runtime/netpoll_kqueue.c
@@ -0,0 +1,108 @@
+// 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
+
+#include "runtime.h"
+#include "defs_GOOS_GOARCH.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(int32 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 = fd;
+ ev[0].filter = EVFILT_READ;
+ ev[0].flags = EV_ADD|EV_RECEIPT|EV_CLEAR;
+ ev[0].fflags = 0;
+ ev[0].data = 0;
+ ev[0].udata = (byte*)pd;
+ ev[1] = ev[0];
+ ev[1].filter = EVFILT_WRITE;
+ n = runtime·kevent(kq, ev, 2, ev, 2, nil);
+ if(n < 0)
+ return -n;
+ if(n != 2 ||
+ (ev[0].flags&EV_ERROR) == 0 || ev[0].ident != fd || ev[0].filter != EVFILT_READ ||
+ (ev[1].flags&EV_ERROR) == 0 || ev[1].ident != fd || ev[1].filter != EVFILT_WRITE)
+ return EFAULT; // just to mark out from other errors
+ if(ev[0].data != 0)
+ return ev[0].data;
+ if(ev[1].data != 0)
+ return ev[1].data;
+ return 0;
+}
+
+int32
+runtime·netpollclose(int32 fd)
+{
+ // Don't need to unregister because calling close()
+ // on fd will remove any kevents that reference the descriptor.
+ USED(fd);
+ return 0;
+}
+
+// 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;
+ 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];
+ if(ev->filter == EVFILT_READ)
+ runtime·netpollready(&gp, (PollDesc*)ev->udata, 'r');
+ if(ev->filter == EVFILT_WRITE)
+ runtime·netpollready(&gp, (PollDesc*)ev->udata, 'w');
+ }
+ if(block && gp == nil)
+ goto retry;
+ return gp;
+}
diff --git a/src/pkg/runtime/netpoll_stub.c b/src/pkg/runtime/netpoll_stub.c
new file mode 100644
index 000000000..39d19a4ce
--- /dev/null
+++ b/src/pkg/runtime/netpoll_stub.c
@@ -0,0 +1,18 @@
+// 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 freebsd netbsd openbsd plan9 windows
+
+#include "runtime.h"
+
+// Polls for ready network connections.
+// Returns list of goroutines that become runnable.
+G*
+runtime·netpoll(bool block)
+{
+ // Implementation for platforms that do not support
+ // integrated network poller.
+ USED(block);
+ return nil;
+}
diff --git a/src/pkg/runtime/thread_darwin.c b/src/pkg/runtime/os_darwin.c
index adb1ffe6a..276362a97 100644
--- a/src/pkg/runtime/thread_darwin.c
+++ b/src/pkg/runtime/os_darwin.c
@@ -5,6 +5,7 @@
#include "runtime.h"
#include "defs_GOOS_GOARCH.h"
#include "os_GOOS.h"
+#include "signal_unix.h"
#include "stack.h"
extern SigTab runtime·sigtab[];
@@ -69,13 +70,29 @@ runtime·osinit(void)
}
void
+runtime·get_random_data(byte **rnd, int32 *rnd_len)
+{
+ static byte urandom_data[HashRandomBytes];
+ int32 fd;
+ fd = runtime·open("/dev/urandom", 0 /* O_RDONLY */, 0);
+ if(runtime·read(fd, urandom_data, HashRandomBytes) == HashRandomBytes) {
+ *rnd = urandom_data;
+ *rnd_len = HashRandomBytes;
+ } else {
+ *rnd = nil;
+ *rnd_len = 0;
+ }
+ runtime·close(fd);
+}
+
+void
runtime·goenvs(void)
{
runtime·goenvs_unix();
// Register our thread-creation callback (see sys_darwin_{amd64,386}.s)
// but only if we're not using cgo. If we are using cgo we need
- // to let the C pthread libary install its own thread-creation callback.
+ // to let the C pthread library install its own thread-creation callback.
if(!runtime·iscgo) {
if(runtime·bsdthread_register() != 0) {
if(runtime·getenv("DYLD_INSERT_LIBRARIES"))
@@ -392,9 +409,14 @@ int32
runtime·mach_semacquire(uint32 sem, int64 ns)
{
int32 r;
+ int64 secs;
if(ns >= 0) {
- r = runtime·mach_semaphore_timedwait(sem, ns/1000000000LL, ns%1000000000LL);
+ secs = ns/1000000000LL;
+ // Avoid overflow
+ if(secs > 1LL<<30)
+ secs = 1LL<<30;
+ r = runtime·mach_semaphore_timedwait(sem, secs, ns%1000000000LL);
if(r == KERN_ABORTED || r == KERN_OPERATION_TIMED_OUT)
return -1;
if(r != 0)
@@ -518,15 +540,56 @@ static int8 badsignal[] = "runtime: signal received on thread not created by Go:
void
runtime·badsignal(int32 sig)
{
+ int32 len;
+
if (sig == SIGPROF) {
return; // Ignore SIGPROFs intended for a non-Go thread.
}
runtime·write(2, badsignal, sizeof badsignal - 1);
if (0 <= sig && sig < NSIG) {
- // Call runtime·findnull dynamically to circumvent static stack size check.
- static int32 (*findnull)(byte*) = runtime·findnull;
- runtime·write(2, runtime·sigtab[sig].name, findnull((byte*)runtime·sigtab[sig].name));
+ // Can't call findnull() because it will split stack.
+ for(len = 0; runtime·sigtab[sig].name[len]; len++)
+ ;
+ runtime·write(2, runtime·sigtab[sig].name, len);
}
runtime·write(2, "\n", 1);
runtime·exit(1);
}
+
+void
+runtime·setsig(int32 i, GoSighandler *fn, bool restart)
+{
+ Sigaction sa;
+
+ runtime·memclr((byte*)&sa, sizeof sa);
+ sa.sa_flags = SA_SIGINFO|SA_ONSTACK;
+ if(restart)
+ sa.sa_flags |= SA_RESTART;
+ sa.sa_mask = ~(uintptr)0;
+ sa.sa_tramp = (void*)runtime·sigtramp; // runtime·sigtramp's job is to call into real handler
+ *(uintptr*)sa.__sigaction_u = (uintptr)fn;
+ runtime·sigaction(i, &sa, nil);
+}
+
+GoSighandler*
+runtime·getsig(int32 i)
+{
+ Sigaction sa;
+
+ runtime·memclr((byte*)&sa, sizeof sa);
+ runtime·sigaction(i, nil, &sa);
+ return *(void**)sa.__sigaction_u;
+}
+
+void
+runtime·signalstack(byte *p, int32 n)
+{
+ StackT st;
+
+ st.ss_sp = (void*)p;
+ st.ss_size = n;
+ st.ss_flags = 0;
+ if(p == nil)
+ st.ss_flags = SS_DISABLE;
+ runtime·sigaltstack(&st, nil);
+}
diff --git a/src/pkg/runtime/os_darwin.h b/src/pkg/runtime/os_darwin.h
index 5fcb717cb..802410975 100644
--- a/src/pkg/runtime/os_darwin.h
+++ b/src/pkg/runtime/os_darwin.h
@@ -2,9 +2,6 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-#define SIG_DFL ((void*)0)
-#define SIG_IGN ((void*)1)
-#define SIGHUP 1
#define SS_DISABLE 4
int32 runtime·bsdthread_create(void*, M*, G*, void(*)(void));
@@ -27,8 +24,6 @@ void runtime·sigprocmask(int32, Sigset*, Sigset*);
struct Sigaction;
void runtime·sigaction(uintptr, struct Sigaction*, struct Sigaction*);
-void runtime·setsig(int32, void(*)(int32, Siginfo*, void*, G*), bool);
-void runtime·sighandler(int32 sig, Siginfo *info, void *context, G *gp);
struct StackT;
void runtime·sigaltstack(struct StackT*, struct StackT*);
@@ -36,7 +31,6 @@ void runtime·sigtramp(void);
void runtime·sigpanic(void);
void runtime·setitimer(int32, Itimerval*, Itimerval*);
-void runtime·raisesigpipe(void);
#define NSIG 32
#define SI_USER 0 /* empirically true, but not what headers say */
diff --git a/src/pkg/runtime/thread_freebsd.c b/src/pkg/runtime/os_freebsd.c
index 3ae14ee0a..f454ab349 100644
--- a/src/pkg/runtime/thread_freebsd.c
+++ b/src/pkg/runtime/os_freebsd.c
@@ -1,9 +1,11 @@
-// Use of this source file is governed by a BSD-style
-// license that can be found in the LICENSE file.`
+// 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 "defs_GOOS_GOARCH.h"
#include "os_GOOS.h"
+#include "signal_unix.h"
#include "stack.h"
extern SigTab runtime·sigtab[];
@@ -44,16 +46,21 @@ runtime·futexsleep(uint32 *addr, uint32 val, int64 ns)
{
int32 ret;
Timespec ts, *tsp;
+ int64 secs;
if(ns < 0)
tsp = nil;
else {
- ts.tv_sec = ns / 1000000000LL;
+ secs = ns / 1000000000LL;
+ // Avoid overflow
+ if(secs > 1LL<<30)
+ secs = 1LL<<30;
+ ts.tv_sec = secs;
ts.tv_nsec = ns % 1000000000LL;
tsp = &ts;
}
- ret = runtime·sys_umtx_op(addr, UMTX_OP_WAIT, val, nil, tsp);
+ ret = runtime·sys_umtx_op(addr, UMTX_OP_WAIT_UINT, val, nil, tsp);
if(ret >= 0 || ret == -EINTR)
return;
@@ -116,6 +123,22 @@ runtime·osinit(void)
}
void
+runtime·get_random_data(byte **rnd, int32 *rnd_len)
+{
+ static byte urandom_data[HashRandomBytes];
+ int32 fd;
+ fd = runtime·open("/dev/urandom", 0 /* O_RDONLY */, 0);
+ if(runtime·read(fd, urandom_data, HashRandomBytes) == HashRandomBytes) {
+ *rnd = urandom_data;
+ *rnd_len = HashRandomBytes;
+ } else {
+ *rnd = nil;
+ *rnd_len = 0;
+ }
+ runtime·close(fd);
+}
+
+void
runtime·goenvs(void)
{
runtime·goenvs_unix();
@@ -229,15 +252,73 @@ static int8 badsignal[] = "runtime: signal received on thread not created by Go:
void
runtime·badsignal(int32 sig)
{
+ int32 len;
+
if (sig == SIGPROF) {
return; // Ignore SIGPROFs intended for a non-Go thread.
}
runtime·write(2, badsignal, sizeof badsignal - 1);
if (0 <= sig && sig < NSIG) {
- // Call runtime·findnull dynamically to circumvent static stack size check.
- static int32 (*findnull)(byte*) = runtime·findnull;
- runtime·write(2, runtime·sigtab[sig].name, findnull((byte*)runtime·sigtab[sig].name));
+ // Can't call findnull() because it will split stack.
+ for(len = 0; runtime·sigtab[sig].name[len]; len++)
+ ;
+ runtime·write(2, runtime·sigtab[sig].name, len);
}
runtime·write(2, "\n", 1);
runtime·exit(1);
}
+
+extern void runtime·sigtramp(void);
+
+typedef struct sigaction {
+ union {
+ void (*__sa_handler)(int32);
+ void (*__sa_sigaction)(int32, Siginfo*, void *);
+ } __sigaction_u; /* signal handler */
+ int32 sa_flags; /* see signal options below */
+ Sigset sa_mask; /* signal mask to apply */
+} Sigaction;
+
+void
+runtime·setsig(int32 i, GoSighandler *fn, bool restart)
+{
+ Sigaction sa;
+
+ runtime·memclr((byte*)&sa, sizeof sa);
+ sa.sa_flags = SA_SIGINFO|SA_ONSTACK;
+ if(restart)
+ sa.sa_flags |= SA_RESTART;
+ sa.sa_mask.__bits[0] = ~(uint32)0;
+ sa.sa_mask.__bits[1] = ~(uint32)0;
+ sa.sa_mask.__bits[2] = ~(uint32)0;
+ sa.sa_mask.__bits[3] = ~(uint32)0;
+ if(fn == runtime·sighandler)
+ fn = (void*)runtime·sigtramp;
+ sa.__sigaction_u.__sa_sigaction = (void*)fn;
+ runtime·sigaction(i, &sa, nil);
+}
+
+GoSighandler*
+runtime·getsig(int32 i)
+{
+ Sigaction sa;
+
+ runtime·memclr((byte*)&sa, sizeof sa);
+ runtime·sigaction(i, nil, &sa);
+ if((void*)sa.__sigaction_u.__sa_sigaction == runtime·sigtramp)
+ return runtime·sighandler;
+ return (void*)sa.__sigaction_u.__sa_sigaction;
+}
+
+void
+runtime·signalstack(byte *p, int32 n)
+{
+ StackT st;
+
+ st.ss_sp = (void*)p;
+ st.ss_size = n;
+ st.ss_flags = 0;
+ if(p == nil)
+ st.ss_flags = SS_DISABLE;
+ runtime·sigaltstack(&st, nil);
+}
diff --git a/src/pkg/runtime/os_freebsd.h b/src/pkg/runtime/os_freebsd.h
index a37ad7cd8..e9be1362c 100644
--- a/src/pkg/runtime/os_freebsd.h
+++ b/src/pkg/runtime/os_freebsd.h
@@ -1,20 +1,18 @@
-#define SIG_DFL ((void*)0)
-#define SIG_IGN ((void*)1)
-#define SIGHUP 1
+// 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.
+
#define SS_DISABLE 4
int32 runtime·thr_new(ThrParam*, int32);
-void runtime·sighandler(int32 sig, Siginfo *info, void *context, G *gp);
void runtime·sigpanic(void);
void runtime·sigaltstack(Sigaltstack*, Sigaltstack*);
struct sigaction;
void runtime·sigaction(int32, struct sigaction*, struct sigaction*);
void runtime·sigprocmask(Sigset *, Sigset *);
-void runtime·setsig(int32, void(*)(int32, Siginfo*, void*, G*), bool);
void runtime·setitimer(int32, Itimerval*, Itimerval*);
int32 runtime·sysctl(uint32*, uint32, byte*, uintptr*, byte*, uintptr);
-void runtime·raisesigpipe(void);
#define NSIG 33
#define SI_USER 0x10001
diff --git a/src/pkg/runtime/os_freebsd_arm.c b/src/pkg/runtime/os_freebsd_arm.c
new file mode 100644
index 000000000..7eaa45c44
--- /dev/null
+++ b/src/pkg/runtime/os_freebsd_arm.c
@@ -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.
+
+#include "runtime.h"
+#include "defs_GOOS_GOARCH.h"
+#include "os_GOOS.h"
+
+void
+runtime·checkgoarm(void)
+{
+ // TODO(minux)
+}
+
+#pragma textflag 7
+int64
+runtime·cputicks(void)
+{
+ // Currently cputicks() is used in blocking profiler and to seed runtime·fastrand1().
+ // runtime·nanotime() is a poor approximation of CPU ticks that is enough for the profiler.
+ // TODO: need more entropy to better seed fastrand1.
+ return runtime·nanotime();
+}
diff --git a/src/pkg/runtime/thread_linux.c b/src/pkg/runtime/os_linux.c
index 78ddef878..6b86d2b17 100644
--- a/src/pkg/runtime/thread_linux.c
+++ b/src/pkg/runtime/os_linux.c
@@ -5,14 +5,11 @@
#include "runtime.h"
#include "defs_GOOS_GOARCH.h"
#include "os_GOOS.h"
+#include "signal_unix.h"
#include "stack.h"
extern SigTab runtime·sigtab[];
-int32 runtime·open(uint8*, int32, int32);
-int32 runtime·close(int32);
-int32 runtime·read(int32, void*, int32);
-
static Sigset sigset_none;
static Sigset sigset_all = { ~(uint32)0, ~(uint32)0 };
@@ -29,9 +26,6 @@ enum
{
FUTEX_WAIT = 0,
FUTEX_WAKE = 1,
-
- EINTR = 4,
- EAGAIN = 11,
};
// Atomically,
@@ -42,15 +36,17 @@ void
runtime·futexsleep(uint32 *addr, uint32 val, int64 ns)
{
Timespec ts, *tsp;
+ int64 secs;
if(ns < 0)
tsp = nil;
else {
- ts.tv_sec = ns/1000000000LL;
- ts.tv_nsec = ns%1000000000LL;
+ secs = ns/1000000000LL;
// Avoid overflow
- if(ts.tv_sec > 1<<30)
- ts.tv_sec = 1<<30;
+ if(secs > 1LL<<30)
+ secs = 1LL<<30;
+ ts.tv_sec = secs;
+ ts.tv_nsec = ns%1000000000LL;
tsp = &ts;
}
@@ -164,6 +160,32 @@ runtime·osinit(void)
runtime·ncpu = getproccount();
}
+// Random bytes initialized at startup. These come
+// from the ELF AT_RANDOM auxiliary vector (vdso_linux_amd64.c).
+byte* runtime·startup_random_data;
+uint32 runtime·startup_random_data_len;
+
+void
+runtime·get_random_data(byte **rnd, int32 *rnd_len)
+{
+ if(runtime·startup_random_data != nil) {
+ *rnd = runtime·startup_random_data;
+ *rnd_len = runtime·startup_random_data_len;
+ } else {
+ static byte urandom_data[HashRandomBytes];
+ int32 fd;
+ fd = runtime·open("/dev/urandom", 0 /* O_RDONLY */, 0);
+ if(runtime·read(fd, urandom_data, HashRandomBytes) == HashRandomBytes) {
+ *rnd = urandom_data;
+ *rnd_len = HashRandomBytes;
+ } else {
+ *rnd = nil;
+ *rnd_len = 0;
+ }
+ runtime·close(fd);
+ }
+}
+
void
runtime·goenvs(void)
{
@@ -203,8 +225,8 @@ runtime·sigpanic(void)
if(g->sigcode0 == BUS_ADRERR && g->sigcode1 < 0x1000) {
if(g->sigpc == 0)
runtime·panicstring("call of nil func value");
- }
runtime·panicstring("invalid memory address or nil pointer dereference");
+ }
runtime·printf("unexpected fault address %p\n", g->sigcode1);
runtime·throw("fault");
case SIGSEGV:
@@ -278,15 +300,75 @@ static int8 badsignal[] = "runtime: signal received on thread not created by Go:
void
runtime·badsignal(int32 sig)
{
+ int32 len;
+
if (sig == SIGPROF) {
return; // Ignore SIGPROFs intended for a non-Go thread.
}
runtime·write(2, badsignal, sizeof badsignal - 1);
if (0 <= sig && sig < NSIG) {
- // Call runtime·findnull dynamically to circumvent static stack size check.
- static int32 (*findnull)(byte*) = runtime·findnull;
- runtime·write(2, runtime·sigtab[sig].name, findnull((byte*)runtime·sigtab[sig].name));
+ // Can't call findnull() because it will split stack.
+ for(len = 0; runtime·sigtab[sig].name[len]; len++)
+ ;
+ runtime·write(2, runtime·sigtab[sig].name, len);
}
runtime·write(2, "\n", 1);
runtime·exit(1);
}
+
+#ifdef GOARCH_386
+#define sa_handler k_sa_handler
+#endif
+
+/*
+ * This assembler routine takes the args from registers, puts them on the stack,
+ * and calls sighandler().
+ */
+extern void runtime·sigtramp(void);
+extern void runtime·sigreturn(void); // calls runtime·sigreturn
+
+void
+runtime·setsig(int32 i, GoSighandler *fn, bool restart)
+{
+ Sigaction sa;
+
+ runtime·memclr((byte*)&sa, sizeof sa);
+ sa.sa_flags = SA_ONSTACK | SA_SIGINFO | SA_RESTORER;
+ if(restart)
+ sa.sa_flags |= SA_RESTART;
+ sa.sa_mask = ~0ULL;
+ // TODO(adonovan): Linux manpage says "sa_restorer element is
+ // obsolete and should not be used". Avoid it here, and test.
+ sa.sa_restorer = (void*)runtime·sigreturn;
+ if(fn == runtime·sighandler)
+ fn = (void*)runtime·sigtramp;
+ sa.sa_handler = fn;
+ if(runtime·rt_sigaction(i, &sa, nil, sizeof(sa.sa_mask)) != 0)
+ runtime·throw("rt_sigaction failure");
+}
+
+GoSighandler*
+runtime·getsig(int32 i)
+{
+ Sigaction sa;
+
+ runtime·memclr((byte*)&sa, sizeof sa);
+ if(runtime·rt_sigaction(i, nil, &sa, sizeof(sa.sa_mask)) != 0)
+ runtime·throw("rt_sigaction read failure");
+ if((void*)sa.sa_handler == runtime·sigtramp)
+ return runtime·sighandler;
+ return (void*)sa.sa_handler;
+}
+
+void
+runtime·signalstack(byte *p, int32 n)
+{
+ Sigaltstack st;
+
+ st.ss_sp = p;
+ st.ss_size = n;
+ st.ss_flags = 0;
+ if(p == nil)
+ st.ss_flags = SS_DISABLE;
+ runtime·sigaltstack(&st, nil);
+}
diff --git a/src/pkg/runtime/os_linux.h b/src/pkg/runtime/os_linux.h
index a23fe0f73..b2d3f6f2a 100644
--- a/src/pkg/runtime/os_linux.h
+++ b/src/pkg/runtime/os_linux.h
@@ -2,9 +2,6 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-#define SIG_DFL ((void*)0)
-#define SIG_IGN ((void*)1)
-#define SIGHUP 1
#define SS_DISABLE 2
// Linux-specific system calls
@@ -13,14 +10,11 @@ int32 runtime·clone(int32, void*, M*, G*, void(*)(void));
struct Sigaction;
int32 runtime·rt_sigaction(uintptr, struct Sigaction*, void*, uintptr);
-void runtime·setsig(int32, void(*)(int32, Siginfo*, void*, G*), bool);
-void runtime·sighandler(int32 sig, Siginfo *info, void *context, G *gp);
void runtime·sigaltstack(Sigaltstack*, Sigaltstack*);
void runtime·sigpanic(void);
void runtime·setitimer(int32, Itimerval*, Itimerval*);
-void runtime·raisesigpipe(void);
#define NSIG 65
#define SI_USER 0
diff --git a/src/pkg/runtime/os_linux_386.c b/src/pkg/runtime/os_linux_386.c
new file mode 100644
index 000000000..18becb6e6
--- /dev/null
+++ b/src/pkg/runtime/os_linux_386.c
@@ -0,0 +1,37 @@
+// 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 "defs_GOOS_GOARCH.h"
+#include "os_GOOS.h"
+
+#define AT_NULL 0
+#define AT_RANDOM 25
+#define AT_SYSINFO 32
+extern uint32 runtime·_vdso;
+
+#pragma textflag 7
+void
+runtime·linux_setup_vdso(int32 argc, byte **argv)
+{
+ byte **envp;
+ uint32 *auxv;
+
+ // skip envp to get to ELF auxiliary vector.
+ for(envp = &argv[argc+1]; *envp != nil; envp++)
+ ;
+ envp++;
+
+ for(auxv=(uint32*)envp; auxv[0] != AT_NULL; auxv += 2) {
+ if(auxv[0] == AT_SYSINFO) {
+ runtime·_vdso = auxv[1];
+ continue;
+ }
+ if(auxv[0] == AT_RANDOM) {
+ runtime·startup_random_data = (byte*)auxv[1];
+ runtime·startup_random_data_len = 16;
+ continue;
+ }
+ }
+}
diff --git a/src/pkg/runtime/os_linux_arm.c b/src/pkg/runtime/os_linux_arm.c
new file mode 100644
index 000000000..dd0fa9415
--- /dev/null
+++ b/src/pkg/runtime/os_linux_arm.c
@@ -0,0 +1,82 @@
+// 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 "defs_GOOS_GOARCH.h"
+#include "os_GOOS.h"
+
+#define AT_NULL 0
+#define AT_PLATFORM 15 // introduced in at least 2.6.11
+#define AT_HWCAP 16 // introduced in at least 2.6.11
+#define AT_RANDOM 25 // introduced in 2.6.29
+#define HWCAP_VFP (1 << 6) // introduced in at least 2.6.11
+#define HWCAP_VFPv3 (1 << 13) // introduced in 2.6.30
+static uint32 runtime·randomNumber;
+uint8 runtime·armArch = 6; // we default to ARMv6
+uint32 runtime·hwcap; // set by setup_auxv
+uint8 runtime·goarm; // set by 5l
+
+void
+runtime·checkgoarm(void)
+{
+ if(runtime·goarm > 5 && !(runtime·hwcap & HWCAP_VFP)) {
+ runtime·printf("runtime: this CPU has no floating point hardware, so it cannot run\n");
+ runtime·printf("this GOARM=%d binary. Recompile using GOARM=5.\n", runtime·goarm);
+ runtime·exit(1);
+ }
+ if(runtime·goarm > 6 && !(runtime·hwcap & HWCAP_VFPv3)) {
+ runtime·printf("runtime: this CPU has no VFPv3 floating point hardware, so it cannot run\n");
+ runtime·printf("this GOARM=%d binary. Recompile using GOARM=6.\n", runtime·goarm);
+ runtime·exit(1);
+ }
+}
+
+#pragma textflag 7
+void
+runtime·setup_auxv(int32 argc, void *argv_list)
+{
+ byte **argv;
+ byte **envp;
+ byte *rnd;
+ uint32 *auxv;
+ uint32 t;
+
+ argv = &argv_list;
+
+ // skip envp to get to ELF auxiliary vector.
+ for(envp = &argv[argc+1]; *envp != nil; envp++)
+ ;
+ envp++;
+
+ for(auxv=(uint32*)envp; auxv[0] != AT_NULL; auxv += 2) {
+ switch(auxv[0]) {
+ case AT_RANDOM: // kernel provided 16-byte worth of random data
+ if(auxv[1]) {
+ rnd = (byte*)auxv[1];
+ runtime·randomNumber = rnd[4] | rnd[5]<<8 | rnd[6]<<16 | rnd[7]<<24;
+ }
+ break;
+ case AT_PLATFORM: // v5l, v6l, v7l
+ if(auxv[1]) {
+ t = *(uint8*)(auxv[1]+1);
+ if(t >= '5' && t <= '7')
+ runtime·armArch = t - '0';
+ }
+ break;
+ case AT_HWCAP: // CPU capability bit flags
+ runtime·hwcap = auxv[1];
+ break;
+ }
+ }
+}
+
+#pragma textflag 7
+int64
+runtime·cputicks(void)
+{
+ // Currently cputicks() is used in blocking profiler and to seed runtime·fastrand1().
+ // runtime·nanotime() is a poor approximation of CPU ticks that is enough for the profiler.
+ // runtime·randomNumber provides better seeding of fastrand1.
+ return runtime·nanotime() + runtime·randomNumber;
+}
diff --git a/src/pkg/runtime/thread_netbsd.c b/src/pkg/runtime/os_netbsd.c
index f333c6dd8..7679ec255 100644
--- a/src/pkg/runtime/thread_netbsd.c
+++ b/src/pkg/runtime/os_netbsd.c
@@ -1,9 +1,11 @@
-// Use of this source file is governed by a BSD-style
-// license that can be found in the LICENSE file.`
+// 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 "defs_GOOS_GOARCH.h"
#include "os_GOOS.h"
+#include "signal_unix.h"
#include "stack.h"
enum
@@ -181,6 +183,22 @@ runtime·osinit(void)
}
void
+runtime·get_random_data(byte **rnd, int32 *rnd_len)
+{
+ static byte urandom_data[HashRandomBytes];
+ int32 fd;
+ fd = runtime·open("/dev/urandom", 0 /* O_RDONLY */, 0);
+ if(runtime·read(fd, urandom_data, HashRandomBytes) == HashRandomBytes) {
+ *rnd = urandom_data;
+ *rnd_len = HashRandomBytes;
+ } else {
+ *rnd = nil;
+ *rnd_len = 0;
+ }
+ runtime·close(fd);
+}
+
+void
runtime·goenvs(void)
{
runtime·goenvs_unix();
@@ -274,15 +292,73 @@ static int8 badsignal[] = "runtime: signal received on thread not created by Go:
void
runtime·badsignal(int32 sig)
{
+ int32 len;
+
if (sig == SIGPROF) {
return; // Ignore SIGPROFs intended for a non-Go thread.
}
runtime·write(2, badsignal, sizeof badsignal - 1);
if (0 <= sig && sig < NSIG) {
- // Call runtime·findnull dynamically to circumvent static stack size check.
- static int32 (*findnull)(byte*) = runtime·findnull;
- runtime·write(2, runtime·sigtab[sig].name, findnull((byte*)runtime·sigtab[sig].name));
+ // Can't call findnull() because it will split stack.
+ for(len = 0; runtime·sigtab[sig].name[len]; len++)
+ ;
+ runtime·write(2, runtime·sigtab[sig].name, len);
}
runtime·write(2, "\n", 1);
runtime·exit(1);
}
+
+extern void runtime·sigtramp(void);
+
+typedef struct sigaction {
+ union {
+ void (*_sa_handler)(int32);
+ void (*_sa_sigaction)(int32, Siginfo*, void *);
+ } _sa_u; /* signal handler */
+ uint32 sa_mask[4]; /* signal mask to apply */
+ int32 sa_flags; /* see signal options below */
+} Sigaction;
+
+void
+runtime·setsig(int32 i, GoSighandler *fn, bool restart)
+{
+ Sigaction sa;
+
+ runtime·memclr((byte*)&sa, sizeof sa);
+ sa.sa_flags = SA_SIGINFO|SA_ONSTACK;
+ if(restart)
+ sa.sa_flags |= SA_RESTART;
+ sa.sa_mask[0] = ~0U;
+ sa.sa_mask[1] = ~0U;
+ sa.sa_mask[2] = ~0U;
+ sa.sa_mask[3] = ~0U;
+ if (fn == runtime·sighandler)
+ fn = (void*)runtime·sigtramp;
+ sa._sa_u._sa_sigaction = (void*)fn;
+ runtime·sigaction(i, &sa, nil);
+}
+
+GoSighandler*
+runtime·getsig(int32 i)
+{
+ Sigaction sa;
+
+ runtime·memclr((byte*)&sa, sizeof sa);
+ runtime·sigaction(i, nil, &sa);
+ if((void*)sa._sa_u._sa_sigaction == runtime·sigtramp)
+ return runtime·sighandler;
+ return (void*)sa._sa_u._sa_sigaction;
+}
+
+void
+runtime·signalstack(byte *p, int32 n)
+{
+ StackT st;
+
+ st.ss_sp = (void*)p;
+ st.ss_size = n;
+ st.ss_flags = 0;
+ if(p == nil)
+ st.ss_flags = SS_DISABLE;
+ runtime·sigaltstack(&st, nil);
+}
diff --git a/src/pkg/runtime/os_netbsd.h b/src/pkg/runtime/os_netbsd.h
index 19d72fd25..c193ae0b4 100644
--- a/src/pkg/runtime/os_netbsd.h
+++ b/src/pkg/runtime/os_netbsd.h
@@ -2,9 +2,6 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-#define SIG_DFL ((void*)0)
-#define SIG_IGN ((void*)1)
-#define SIGHUP 1
#define SS_DISABLE 4
#define SIG_BLOCK 1
@@ -13,9 +10,6 @@
struct sigaction;
-void runtime·raisesigpipe(void);
-void runtime·setsig(int32, void(*)(int32, Siginfo*, void*, G*), bool);
-void runtime·sighandler(int32 sig, Siginfo *info, void *context, G *gp);
void runtime·sigpanic(void);
void runtime·setitimer(int32, Itimerval*, Itimerval*);
@@ -23,6 +17,7 @@ void runtime·sigaction(int32, struct sigaction*, struct sigaction*);
void runtime·sigaltstack(Sigaltstack*, Sigaltstack*);
void runtime·sigprocmask(int32, Sigset*, Sigset*);
int32 runtime·sysctl(uint32*, uint32, byte*, uintptr*, byte*, uintptr);
+extern void runtime·lwp_tramp(void);
#define NSIG 33
#define SI_USER 0
diff --git a/src/pkg/runtime/os_netbsd_386.c b/src/pkg/runtime/os_netbsd_386.c
new file mode 100644
index 000000000..23e9db3c1
--- /dev/null
+++ b/src/pkg/runtime/os_netbsd_386.c
@@ -0,0 +1,17 @@
+// 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 "defs_GOOS_GOARCH.h"
+#include "os_GOOS.h"
+
+void
+runtime·lwp_mcontext_init(McontextT *mc, void *stack, M *mp, G *gp, void (*fn)(void))
+{
+ mc->__gregs[REG_EIP] = (uint32)runtime·lwp_tramp;
+ mc->__gregs[REG_UESP] = (uint32)stack;
+ mc->__gregs[REG_EBX] = (uint32)mp;
+ mc->__gregs[REG_EDX] = (uint32)gp;
+ mc->__gregs[REG_ESI] = (uint32)fn;
+}
diff --git a/src/pkg/runtime/os_netbsd_amd64.c b/src/pkg/runtime/os_netbsd_amd64.c
new file mode 100644
index 000000000..226846cbb
--- /dev/null
+++ b/src/pkg/runtime/os_netbsd_amd64.c
@@ -0,0 +1,18 @@
+// 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 "defs_GOOS_GOARCH.h"
+#include "os_GOOS.h"
+
+void
+runtime·lwp_mcontext_init(McontextT *mc, void *stack, M *mp, G *gp, void (*fn)(void))
+{
+ // Machine dependent mcontext initialisation for LWP.
+ mc->__gregs[REG_RIP] = (uint64)runtime·lwp_tramp;
+ mc->__gregs[REG_RSP] = (uint64)stack;
+ mc->__gregs[REG_R8] = (uint64)mp;
+ mc->__gregs[REG_R9] = (uint64)gp;
+ mc->__gregs[REG_R12] = (uint64)fn;
+}
diff --git a/src/pkg/runtime/os_netbsd_arm.c b/src/pkg/runtime/os_netbsd_arm.c
new file mode 100644
index 000000000..385e6406d
--- /dev/null
+++ b/src/pkg/runtime/os_netbsd_arm.c
@@ -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.
+
+#include "runtime.h"
+#include "defs_GOOS_GOARCH.h"
+#include "os_GOOS.h"
+#include "signal_GOOS_GOARCH.h"
+
+void
+runtime·lwp_mcontext_init(McontextT *mc, void *stack, M *mp, G *gp, void (*fn)(void))
+{
+ mc->__gregs[REG_R15] = (uint32)runtime·lwp_tramp;
+ mc->__gregs[REG_R13] = (uint32)stack;
+ mc->__gregs[REG_R0] = (uint32)mp;
+ mc->__gregs[REG_R1] = (uint32)gp;
+ mc->__gregs[REG_R2] = (uint32)fn;
+}
+
+void
+runtime·checkgoarm(void)
+{
+ // TODO(minux)
+}
+
+#pragma textflag 7
+int64
+runtime·cputicks() {
+ // Currently cputicks() is used in blocking profiler and to seed runtime·fastrand1().
+ // runtime·nanotime() is a poor approximation of CPU ticks that is enough for the profiler.
+ // TODO: need more entropy to better seed fastrand1.
+ return runtime·nanotime();
+}
diff --git a/src/pkg/runtime/thread_openbsd.c b/src/pkg/runtime/os_openbsd.c
index 700c48147..4ce102ec2 100644
--- a/src/pkg/runtime/thread_openbsd.c
+++ b/src/pkg/runtime/os_openbsd.c
@@ -1,9 +1,11 @@
-// Use of this source file is governed by a BSD-style
-// license that can be found in the LICENSE file.`
+// 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 "defs_GOOS_GOARCH.h"
#include "os_GOOS.h"
+#include "signal_unix.h"
#include "stack.h"
enum
@@ -61,6 +63,7 @@ int32
runtime·semasleep(int64 ns)
{
Timespec ts;
+ int64 secs;
// spin-mutex lock
while(runtime·xchg(&m->waitsemalock, 1))
@@ -75,7 +78,11 @@ runtime·semasleep(int64 ns)
runtime·thrsleep(&m->waitsemacount, 0, nil, &m->waitsemalock, nil);
else {
ns += runtime·nanotime();
- ts.tv_sec = ns/1000000000LL;
+ secs = ns/1000000000LL;
+ // Avoid overflow
+ if(secs >= 1LL<<31)
+ secs = (1LL<<31) - 1;
+ ts.tv_sec = secs;
ts.tv_nsec = ns%1000000000LL;
runtime·thrsleep(&m->waitsemacount, CLOCK_REALTIME, &ts, &m->waitsemalock, nil);
}
@@ -160,6 +167,22 @@ runtime·osinit(void)
}
void
+runtime·get_random_data(byte **rnd, int32 *rnd_len)
+{
+ static byte urandom_data[HashRandomBytes];
+ int32 fd;
+ fd = runtime·open("/dev/urandom", 0 /* O_RDONLY */, 0);
+ if(runtime·read(fd, urandom_data, HashRandomBytes) == HashRandomBytes) {
+ *rnd = urandom_data;
+ *rnd_len = HashRandomBytes;
+ } else {
+ *rnd = nil;
+ *rnd_len = 0;
+ }
+ runtime·close(fd);
+}
+
+void
runtime·goenvs(void)
{
runtime·goenvs_unix();
@@ -251,15 +274,70 @@ static int8 badsignal[] = "runtime: signal received on thread not created by Go:
void
runtime·badsignal(int32 sig)
{
+ int32 len;
+
if (sig == SIGPROF) {
return; // Ignore SIGPROFs intended for a non-Go thread.
}
runtime·write(2, badsignal, sizeof badsignal - 1);
if (0 <= sig && sig < NSIG) {
- // Call runtime·findnull dynamically to circumvent static stack size check.
- static int32 (*findnull)(byte*) = runtime·findnull;
- runtime·write(2, runtime·sigtab[sig].name, findnull((byte*)runtime·sigtab[sig].name));
+ // Can't call findnull() because it will split stack.
+ for(len = 0; runtime·sigtab[sig].name[len]; len++)
+ ;
+ runtime·write(2, runtime·sigtab[sig].name, len);
}
runtime·write(2, "\n", 1);
runtime·exit(1);
}
+
+extern void runtime·sigtramp(void);
+
+typedef struct sigaction {
+ union {
+ void (*__sa_handler)(int32);
+ void (*__sa_sigaction)(int32, Siginfo*, void *);
+ } __sigaction_u; /* signal handler */
+ uint32 sa_mask; /* signal mask to apply */
+ int32 sa_flags; /* see signal options below */
+} Sigaction;
+
+void
+runtime·setsig(int32 i, GoSighandler *fn, bool restart)
+{
+ Sigaction sa;
+
+ runtime·memclr((byte*)&sa, sizeof sa);
+ sa.sa_flags = SA_SIGINFO|SA_ONSTACK;
+ if(restart)
+ sa.sa_flags |= SA_RESTART;
+ sa.sa_mask = ~0U;
+ if(fn == runtime·sighandler)
+ fn = (void*)runtime·sigtramp;
+ sa.__sigaction_u.__sa_sigaction = (void*)fn;
+ runtime·sigaction(i, &sa, nil);
+}
+
+GoSighandler*
+runtime·getsig(int32 i)
+{
+ Sigaction sa;
+
+ runtime·memclr((byte*)&sa, sizeof sa);
+ runtime·sigaction(i, nil, &sa);
+ if((void*)sa.__sigaction_u.__sa_sigaction == runtime·sigtramp)
+ return runtime·sighandler;
+ return (void*)sa.__sigaction_u.__sa_sigaction;
+}
+
+void
+runtime·signalstack(byte *p, int32 n)
+{
+ StackT st;
+
+ st.ss_sp = (void*)p;
+ st.ss_size = n;
+ st.ss_flags = 0;
+ if(p == nil)
+ st.ss_flags = SS_DISABLE;
+ runtime·sigaltstack(&st, nil);
+}
diff --git a/src/pkg/runtime/os_openbsd.h b/src/pkg/runtime/os_openbsd.h
index a599aad05..dbfa4b69f 100644
--- a/src/pkg/runtime/os_openbsd.h
+++ b/src/pkg/runtime/os_openbsd.h
@@ -2,9 +2,6 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-#define SIG_DFL ((void*)0)
-#define SIG_IGN ((void*)1)
-#define SIGHUP 1
#define SS_DISABLE 4
#define SIG_BLOCK 1
@@ -13,14 +10,11 @@
struct sigaction;
-void runtime·raisesigpipe(void);
-void runtime·setsig(int32, void(*)(int32, Siginfo*, void*, G*), bool);
void runtime·sigpanic(void);
void runtime·setitimer(int32, Itimerval*, Itimerval*);
void runtime·sigaction(int32, struct sigaction*, struct sigaction*);
void runtime·sigaltstack(Sigaltstack*, Sigaltstack*);
-void runtime·sighandler(int32 sig, Siginfo *info, void *context, G *gp);
Sigset runtime·sigprocmask(int32, Sigset);
int32 runtime·sysctl(uint32*, uint32, byte*, uintptr*, byte*, uintptr);
diff --git a/src/pkg/runtime/thread_plan9.c b/src/pkg/runtime/os_plan9.c
index 7f94623e7..c7ed59fc9 100644
--- a/src/pkg/runtime/thread_plan9.c
+++ b/src/pkg/runtime/os_plan9.c
@@ -19,6 +19,10 @@ runtime·mpreinit(M *mp)
// Initialize stack and goroutine for note handling.
mp->gsignal = runtime·malg(32*1024);
mp->notesig = (int8*)runtime·malloc(ERRMAX*sizeof(int8));
+
+ // Initialize stack for handling strings from the
+ // errstr system call, as used in package syscall.
+ mp->errstr = (byte*)runtime·malloc(ERRMAX*sizeof(byte));
}
// Called to initialize a new m (including the bootstrap m).
@@ -44,7 +48,7 @@ getproccount(void)
int32 fd, i, n, ncpu;
byte buf[2048];
- fd = runtime·open((byte*)"/dev/sysstat", OREAD);
+ fd = runtime·open("/dev/sysstat", OREAD, 0);
if(fd < 0)
return 1;
ncpu = 0;
@@ -68,7 +72,7 @@ getpid(void)
int32 fd;
runtime·memclr(b, sizeof(b));
- fd = runtime·open((byte*)"#c/pid", 0);
+ fd = runtime·open("#c/pid", 0, 0);
if(fd >= 0) {
runtime·read(fd, b, sizeof(b));
runtime·close(fd);
@@ -88,6 +92,20 @@ runtime·osinit(void)
}
void
+runtime·crash(void)
+{
+ runtime·notify(nil);
+ *(int32*)0 = 0;
+}
+
+void
+runtime·get_random_data(byte **rnd, int32 *rnd_len)
+{
+ *rnd = nil;
+ *rnd_len = 0;
+}
+
+void
runtime·goenvs(void)
{
}
@@ -191,7 +209,7 @@ runtime·postnote(int32 pid, int8* msg)
p--;
runtime·memmove((void*)p, (void*)"/note", 5);
- fd = runtime·open(buf, OWRITE);
+ fd = runtime·open((int8*)buf, OWRITE, 0);
if(fd < 0)
return -1;
diff --git a/src/pkg/runtime/os_plan9.h b/src/pkg/runtime/os_plan9.h
index c2cdf5b44..f0474cda5 100644
--- a/src/pkg/runtime/os_plan9.h
+++ b/src/pkg/runtime/os_plan9.h
@@ -3,12 +3,9 @@
// license that can be found in the LICENSE file.
// Plan 9-specific system calls
-int32 runtime·open(uint8 *file, int32 mode);
int32 runtime·pread(int32 fd, void *buf, int32 nbytes, int64 offset);
int32 runtime·pwrite(int32 fd, void *buf, int32 nbytes, int64 offset);
-int32 runtime·read(int32 fd, void *buf, int32 nbytes);
int64 runtime·seek(int32 fd, int64 offset, int32 whence);
-int32 runtime·close(int32 fd);
void runtime·exits(int8* msg);
intptr runtime·brk_(void*);
int32 runtime·sleep(int32 ms);
@@ -19,7 +16,6 @@ int32 runtime·plan9_semrelease(uint32 *addr, int32 count);
int32 runtime·notify(void (*fn)(void*, int8*));
int32 runtime·noted(int32);
void runtime·sigtramp(void*, int8*);
-int32 runtime·sighandler(void*, int8*, G*);
void runtime·sigpanic(void);
void runtime·goexitsall(int8*);
void runtime·setfpmasks(void);
diff --git a/src/pkg/runtime/signal_plan9_386.c b/src/pkg/runtime/os_plan9_386.c
index 17bc11749..3396e44e7 100644
--- a/src/pkg/runtime/signal_plan9_386.c
+++ b/src/pkg/runtime/os_plan9_386.c
@@ -28,6 +28,7 @@ runtime·dumpregs(Ureg *u)
int32
runtime·sighandler(void *v, int8 *s, G *gp)
{
+ bool crash;
Ureg *ureg;
uintptr *sp;
SigTab *sig, *nsig;
@@ -93,11 +94,15 @@ Throw:
runtime·printf("PC=%X\n", ureg->pc);
runtime·printf("\n");
- if(runtime·gotraceback()) {
+ if(runtime·gotraceback(&crash)) {
runtime·traceback((void*)ureg->pc, (void*)ureg->sp, 0, gp);
runtime·tracebackothers(gp);
runtime·dumpregs(ureg);
}
+
+ if(crash)
+ runtime·crash();
+
runtime·goexitsall("");
runtime·exits(s);
@@ -112,6 +117,12 @@ runtime·sigenable(uint32 sig)
}
void
+runtime·sigdisable(uint32 sig)
+{
+ USED(sig);
+}
+
+void
runtime·resetcpuprofiler(int32 hz)
{
// TODO: Enable profiling interrupts.
diff --git a/src/pkg/runtime/signal_plan9_amd64.c b/src/pkg/runtime/os_plan9_amd64.c
index e4f946abc..cf0a82b6b 100644
--- a/src/pkg/runtime/signal_plan9_amd64.c
+++ b/src/pkg/runtime/os_plan9_amd64.c
@@ -36,6 +36,7 @@ runtime·dumpregs(Ureg *u)
int32
runtime·sighandler(void *v, int8 *s, G *gp)
{
+ bool crash;
Ureg *ureg;
uintptr *sp;
SigTab *sig, *nsig;
@@ -101,11 +102,15 @@ Throw:
runtime·printf("PC=%X\n", ureg->ip);
runtime·printf("\n");
- if(runtime·gotraceback()) {
+ if(runtime·gotraceback(&crash)) {
runtime·traceback((void*)ureg->ip, (void*)ureg->sp, 0, gp);
runtime·tracebackothers(gp);
runtime·dumpregs(ureg);
}
+
+ if(crash)
+ runtime·crash();
+
runtime·goexitsall("");
runtime·exits(s);
@@ -119,6 +124,12 @@ runtime·sigenable(uint32 sig)
}
void
+runtime·sigdisable(uint32 sig)
+{
+ USED(sig);
+}
+
+void
runtime·resetcpuprofiler(int32 hz)
{
// TODO: Enable profiling interrupts.
diff --git a/src/pkg/runtime/thread_windows.c b/src/pkg/runtime/os_windows.c
index ae4e82e50..b28affe31 100644
--- a/src/pkg/runtime/thread_windows.c
+++ b/src/pkg/runtime/os_windows.c
@@ -11,6 +11,9 @@
#pragma dynimport runtime·CreateEvent CreateEventA "kernel32.dll"
#pragma dynimport runtime·CreateThread CreateThread "kernel32.dll"
#pragma dynimport runtime·CreateWaitableTimer CreateWaitableTimerA "kernel32.dll"
+#pragma dynimport runtime·CryptAcquireContextW CryptAcquireContextW "advapi32.dll"
+#pragma dynimport runtime·CryptGenRandom CryptGenRandom "advapi32.dll"
+#pragma dynimport runtime·CryptReleaseContext CryptReleaseContext "advapi32.dll"
#pragma dynimport runtime·DuplicateHandle DuplicateHandle "kernel32.dll"
#pragma dynimport runtime·ExitProcess ExitProcess "kernel32.dll"
#pragma dynimport runtime·FreeEnvironmentStringsW FreeEnvironmentStringsW "kernel32.dll"
@@ -31,11 +34,17 @@
#pragma dynimport runtime·timeBeginPeriod timeBeginPeriod "winmm.dll"
#pragma dynimport runtime·WaitForSingleObject WaitForSingleObject "kernel32.dll"
#pragma dynimport runtime·WriteFile WriteFile "kernel32.dll"
+#pragma dynimport runtime·NtWaitForSingleObject NtWaitForSingleObject "ntdll.dll"
+
+extern void *runtime·NtWaitForSingleObject;
extern void *runtime·CloseHandle;
extern void *runtime·CreateEvent;
extern void *runtime·CreateThread;
extern void *runtime·CreateWaitableTimer;
+extern void *runtime·CryptAcquireContextW;
+extern void *runtime·CryptGenRandom;
+extern void *runtime·CryptReleaseContext;
extern void *runtime·DuplicateHandle;
extern void *runtime·ExitProcess;
extern void *runtime·FreeEnvironmentStringsW;
@@ -79,6 +88,24 @@ runtime·osinit(void)
}
void
+runtime·get_random_data(byte **rnd, int32 *rnd_len)
+{
+ uintptr handle;
+ *rnd = nil;
+ *rnd_len = 0;
+ if(runtime·stdcall(runtime·CryptAcquireContextW, 5, &handle, nil, nil,
+ (uintptr)1 /* PROV_RSA_FULL */,
+ (uintptr)0xf0000000U /* CRYPT_VERIFYCONTEXT */) != 0) {
+ static byte random_data[HashRandomBytes];
+ if(runtime·stdcall(runtime·CryptGenRandom, 3, handle, (uintptr)HashRandomBytes, random_data)) {
+ *rnd = random_data;
+ *rnd_len = HashRandomBytes;
+ }
+ runtime·stdcall(runtime·CryptReleaseContext, 2, handle, (uintptr)0);
+ }
+}
+
+void
runtime·goenvs(void)
{
extern Slice syscall·envs;
@@ -135,22 +162,6 @@ runtime·write(int32 fd, void *buf, int32 n)
return written;
}
-#pragma textflag 7
-void
-runtime·osyield(void)
-{
- runtime·stdcall(runtime·Sleep, 1, (uintptr)0);
-}
-
-void
-runtime·usleep(uint32 us)
-{
- us /= 1000;
- if(us == 0)
- us = 1;
- runtime·stdcall(runtime·Sleep, 1, (uintptr)us);
-}
-
#define INFINITE ((uintptr)0xFFFFFFFF)
int32
@@ -444,3 +455,16 @@ int32 runtime·badcallbacklen = sizeof runtime·badcallbackmsg - 1;
int8 runtime·badsignalmsg[] = "runtime: signal received on thread not created by Go.\n";
int32 runtime·badsignallen = sizeof runtime·badsignalmsg - 1;
+
+void
+runtime·crash(void)
+{
+ // TODO: This routine should do whatever is needed
+ // to make the Windows program abort/crash as it
+ // would if Go was not intercepting signals.
+ // On Unix the routine would remove the custom signal
+ // handler and then raise a signal (like SIGABRT).
+ // Something like that should happen here.
+ // It's okay to leave this empty for now: if crash returns
+ // the ordinary exit-after-panic happens.
+}
diff --git a/src/pkg/runtime/signal_windows_386.c b/src/pkg/runtime/os_windows_386.c
index d76d5bf4b..20fbea13d 100644
--- a/src/pkg/runtime/signal_windows_386.c
+++ b/src/pkg/runtime/os_windows_386.c
@@ -27,6 +27,7 @@ runtime·dumpregs(Context *r)
uint32
runtime·sighandler(ExceptionRecord *info, Context *r, G *gp)
{
+ bool crash;
uintptr *sp;
switch(info->ExceptionCode) {
@@ -74,11 +75,15 @@ runtime·sighandler(ExceptionRecord *info, Context *r, G *gp)
}
runtime·printf("\n");
- if(runtime·gotraceback()){
+ if(runtime·gotraceback(&crash)){
runtime·traceback((void*)r->Eip, (void*)r->Esp, 0, gp);
runtime·tracebackothers(gp);
runtime·dumpregs(r);
}
+
+ if(crash)
+ runtime·crash();
+
runtime·exit(2);
return 0;
@@ -91,6 +96,12 @@ runtime·sigenable(uint32 sig)
}
void
+runtime·sigdisable(uint32 sig)
+{
+ USED(sig);
+}
+
+void
runtime·dosigprof(Context *r, G *gp)
{
runtime·sigprof((uint8*)r->Eip, (uint8*)r->Esp, nil, gp);
diff --git a/src/pkg/runtime/signal_windows_amd64.c b/src/pkg/runtime/os_windows_amd64.c
index 3729aa57b..881c73c93 100644
--- a/src/pkg/runtime/signal_windows_amd64.c
+++ b/src/pkg/runtime/os_windows_amd64.c
@@ -35,6 +35,7 @@ runtime·dumpregs(Context *r)
uint32
runtime·sighandler(ExceptionRecord *info, Context *r, G *gp)
{
+ bool crash;
uintptr *sp;
switch(info->ExceptionCode) {
@@ -81,11 +82,14 @@ runtime·sighandler(ExceptionRecord *info, Context *r, G *gp)
}
runtime·printf("\n");
- if(runtime·gotraceback()){
+ if(runtime·gotraceback(&crash)){
runtime·traceback((void*)r->Rip, (void*)r->Rsp, 0, gp);
runtime·tracebackothers(gp);
runtime·dumpregs(r);
}
+
+ if(crash)
+ runtime·crash();
runtime·exit(2);
return 0;
@@ -98,6 +102,12 @@ runtime·sigenable(uint32 sig)
}
void
+runtime·sigdisable(uint32 sig)
+{
+ USED(sig);
+}
+
+void
runtime·dosigprof(Context *r, G *gp)
{
runtime·sigprof((uint8*)r->Rip, (uint8*)r->Rsp, nil, gp);
diff --git a/src/pkg/runtime/panic.c b/src/pkg/runtime/panic.c
index 2f553f417..d0cf3ad6f 100644
--- a/src/pkg/runtime/panic.c
+++ b/src/pkg/runtime/panic.c
@@ -5,6 +5,7 @@
#include "runtime.h"
#include "arch_GOARCH.h"
#include "stack.h"
+#include "malloc.h"
// Code related to defer, panic and recover.
@@ -383,7 +384,10 @@ nomatch:
void
runtime·startpanic(void)
{
- if(m->mcache == nil) // can happen if called from signal handler or throw
+ if(runtime·mheap == 0 || 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();
if(m->dying) {
runtime·printf("panic during panic\n");
@@ -398,12 +402,13 @@ void
runtime·dopanic(int32 unused)
{
static bool didothers;
+ bool crash;
if(g->sig != 0)
runtime·printf("[signal %x code=%p addr=%p pc=%p]\n",
g->sig, g->sigcode0, g->sigcode1, g->sigpc);
- if(runtime·gotraceback()){
+ if(runtime·gotraceback(&crash)){
if(g != m->g0) {
runtime·printf("\n");
runtime·goroutineheader(g);
@@ -424,6 +429,9 @@ runtime·dopanic(int32 unused)
runtime·lock(&deadlock);
runtime·lock(&deadlock);
}
+
+ if(crash)
+ runtime·crash();
runtime·exit(2);
}
diff --git a/src/pkg/runtime/parfor.c b/src/pkg/runtime/parfor.c
index aa5537d02..a4468c2af 100644
--- a/src/pkg/runtime/parfor.c
+++ b/src/pkg/runtime/parfor.c
@@ -46,6 +46,7 @@ void
runtime·parforsetup(ParFor *desc, uint32 nthr, uint32 n, void *ctx, bool wait, void (*body)(ParFor*, uint32))
{
uint32 i, begin, end;
+ uint64 *pos;
if(desc == nil || nthr == 0 || nthr > desc->nthrmax || body == nil) {
runtime·printf("desc=%p nthr=%d count=%d body=%p\n", desc, nthr, n, body);
@@ -67,7 +68,10 @@ runtime·parforsetup(ParFor *desc, uint32 nthr, uint32 n, void *ctx, bool wait,
for(i=0; i<nthr; i++) {
begin = (uint64)n*i / nthr;
end = (uint64)n*(i+1) / nthr;
- desc->thr[i].pos = (uint64)begin | (((uint64)end)<<32);
+ pos = &desc->thr[i].pos;
+ if(((uintptr)pos & 7) != 0)
+ runtime·throw("parforsetup: pos is not aligned");
+ *pos = (uint64)begin | (((uint64)end)<<32);
}
}
diff --git a/src/pkg/runtime/proc.c b/src/pkg/runtime/proc.c
index 4ce0a718c..018a453d6 100644
--- a/src/pkg/runtime/proc.c
+++ b/src/pkg/runtime/proc.c
@@ -49,6 +49,7 @@ struct Sched {
Note stopnote;
uint32 sysmonwait;
Note sysmonnote;
+ uint64 lastpoll;
int32 profilehz; // cpu profiling rate
};
@@ -71,8 +72,6 @@ M* runtime·extram;
int8* runtime·goos;
int32 runtime·ncpu;
static int32 newprocs;
-// Keep trace of scavenger's goroutine for deadlock detection.
-static G *scvg;
void runtime·mstart(void);
static void runqput(P*, G*);
@@ -109,6 +108,7 @@ static void globrunqput(G*);
static G* globrunqget(P*);
static P* pidleget(void);
static void pidleput(P*);
+static void injectglist(G*);
// The bootstrap sequence is:
//
@@ -137,6 +137,7 @@ runtime·schedinit(void)
// so that we don't need to call malloc when we crash.
// runtime·findfunc(0);
+ runtime·sched.lastpoll = runtime·nanotime();
procs = 1;
p = runtime·getenv("GOMAXPROCS");
if(p != nil && (n = runtime·atoi(p)) > 0) {
@@ -174,8 +175,7 @@ runtime·main(void)
runtime·lockOSThread();
if(m != &runtime·m0)
runtime·throw("runtime·main not on m0");
- scvg = runtime·newproc1(&scavenger, nil, 0, 0, runtime·main);
- scvg->issystem = true;
+ runtime·newproc1(&scavenger, nil, 0, 0, runtime·main);
main·init();
runtime·unlockOSThread();
@@ -232,7 +232,7 @@ runtime·tracebackothers(G *me)
G *gp;
int32 traceback;
- traceback = runtime·gotraceback();
+ traceback = runtime·gotraceback(nil);
for(gp = runtime·allg; gp != nil; gp = gp->alllink) {
if(gp == me || gp->status == Gdead)
continue;
@@ -332,7 +332,7 @@ runtime·helpgc(int32 nproc)
mp = mget();
if(mp == nil)
runtime·throw("runtime·gcprocs inconsistency");
- mp->helpgc = 1;
+ mp->helpgc = n;
mp->mcache = runtime·allp[pos]->mcache;
pos++;
runtime·notewakeup(&mp->park);
@@ -386,16 +386,19 @@ runtime·stoptheworld(void)
static void
mhelpgc(void)
{
- m->helpgc = 1;
+ m->helpgc = -1;
}
void
runtime·starttheworld(void)
{
- P *p;
+ P *p, *p1;
M *mp;
+ G *gp;
bool add;
+ gp = runtime·netpoll(false); // non-blocking
+ injectglist(gp);
add = needaddgcproc();
runtime·lock(&runtime·sched);
if(newprocs) {
@@ -405,6 +408,7 @@ runtime·starttheworld(void)
procresize(runtime·gomaxprocs);
runtime·gcwaiting = 0;
+ p1 = nil;
while(p = pidleget()) {
// 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.
@@ -414,8 +418,9 @@ runtime·starttheworld(void)
}
mp = mget();
if(mp == nil) {
- pidleput(p);
- break;
+ p->link = p1;
+ p1 = p;
+ continue;
}
if(mp->nextp)
runtime·throw("starttheworld: inconsistent mp->nextp");
@@ -428,6 +433,13 @@ runtime·starttheworld(void)
}
runtime·unlock(&runtime·sched);
+ while(p1) {
+ p = p1;
+ p1 = p1->link;
+ add = false;
+ newm(nil, p);
+ }
+
if(add) {
// If GC could have used another helper proc, start one now,
// in the hope that it will be available next time.
@@ -473,7 +485,7 @@ runtime·mstart(void)
m->mstartfn();
if(m->helpgc) {
- m->helpgc = false;
+ m->helpgc = 0;
stopm();
} else if(m != &runtime·m0) {
acquirep(m->nextp);
@@ -683,6 +695,7 @@ runtime·dropm(void)
// Undo whatever initialization minit did during needm.
runtime·unminit();
+ m->seh = nil; // reset dangling typed pointer
// Clear m and g, and return m to the extra list.
// After the call to setmg we can only call nosplit functions.
@@ -782,8 +795,8 @@ retry:
runtime·notesleep(&m->park);
runtime·noteclear(&m->park);
if(m->helpgc) {
- m->helpgc = 0;
runtime·gchelper();
+ m->helpgc = 0;
m->mcache = nil;
goto retry;
}
@@ -862,6 +875,13 @@ handoffp(P *p)
startm(p, false);
return;
}
+ // If this is the last running P and nobody is polling network,
+ // need to wakeup another M to poll network.
+ if(runtime·sched.npidle == runtime·gomaxprocs-1 && runtime·atomicload64(&runtime·sched.lastpoll) != 0) {
+ runtime·unlock(&runtime·sched);
+ startm(p, false);
+ return;
+ }
pidleput(p);
runtime·unlock(&runtime·sched);
}
@@ -970,7 +990,7 @@ execute(G *gp)
}
// Finds a runnable goroutine to execute.
-// Tries to steal from other P's and get g from global queue.
+// Tries to steal from other P's, get g from global queue, poll network.
static G*
findrunnable(void)
{
@@ -995,6 +1015,13 @@ top:
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.
@@ -1049,10 +1076,54 @@ stop:
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;
}
+// Injects the list of runnable G's into the scheduler.
+// Can run concurrently with GC.
+static void
+injectglist(G *glist)
+{
+ 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);
+}
+
// One round of scheduler: find a runnable goroutine and execute it.
// Never returns.
static void
@@ -1114,6 +1185,7 @@ park0(G *gp)
if(m->waitunlockf) {
m->waitunlockf(m->waitlock);
m->waitunlockf = nil;
+ m->waitlock = nil;
}
if(m->lockedg) {
stoplockedm();
@@ -1164,6 +1236,11 @@ goexit0(G *gp)
gp->lockedm = nil;
m->curg = nil;
m->lockedg = nil;
+ if(m->locked & ~LockExternal) {
+ runtime·printf("invalid m->locked = %d", m->locked);
+ runtime·throw("internal lockOSThread error");
+ }
+ m->locked = 0;
runtime·unwindstack(gp, nil);
gfput(m->p, gp);
schedule();
@@ -1251,7 +1328,7 @@ void
p = releasep();
handoffp(p);
- if(g == scvg) // do not consider blocked scavenger for deadlock detection
+ if(g->isbackground) // do not consider blocked scavenger for deadlock detection
inclocked(1);
runtime·gosave(&g->sched); // re-save for traceback
}
@@ -1283,7 +1360,7 @@ runtime·exitsyscall(void)
return;
}
- if(g == scvg) // do not consider blocked scavenger for deadlock detection
+ if(g->isbackground) // do not consider blocked scavenger for deadlock detection
inclocked(-1);
// Try to get any other idle P.
m->p = nil;
@@ -1710,7 +1787,7 @@ runtime·sigprof(uint8 *pc, uint8 *sp, uint8 *lr, G *gp)
runtime·unlock(&prof);
return;
}
- n = runtime·gentraceback(pc, sp, lr, gp, 0, prof.pcbuf, nelem(prof.pcbuf));
+ n = runtime·gentraceback(pc, sp, lr, gp, 0, prof.pcbuf, nelem(prof.pcbuf), nil, nil);
if(n > 0)
prof.fn(prof.pcbuf, n);
runtime·unlock(&prof);
@@ -1885,7 +1962,7 @@ checkdead(void)
}
grunning = 0;
for(gp = runtime·allg; gp; gp = gp->alllink) {
- if(gp == scvg)
+ if(gp->isbackground)
continue;
s = gp->status;
if(s == Gwaiting)
@@ -1905,6 +1982,8 @@ static void
sysmon(void)
{
uint32 idle, delay;
+ int64 now, lastpoll;
+ G *gp;
uint32 ticks[MaxGomaxprocs];
idle = 0; // how many cycles in succession we had not wokeup somebody
@@ -1929,6 +2008,14 @@ sysmon(void)
} 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) {
+ gp = runtime·netpoll(false); // non-blocking
+ injectglist(gp);
+ }
+ // retake P's blocked in syscalls
if(retake(ticks))
idle = 0;
else
diff --git a/src/pkg/runtime/race.c b/src/pkg/runtime/race.c
index cfd97041a..ce250b5b6 100644
--- a/src/pkg/runtime/race.c
+++ b/src/pkg/runtime/race.c
@@ -36,11 +36,14 @@ static bool onstack(uintptr argp);
uintptr
runtime·raceinit(void)
{
- uintptr racectx;
+ uintptr racectx, start, size;
m->racecall = true;
runtime∕race·Initialize(&racectx);
- runtime∕race·MapShadow(noptrdata, enoptrbss - noptrdata);
+ // Round data segment to page boundaries, because it's used in mmap().
+ start = (uintptr)noptrdata & ~(PageSize-1);
+ size = ROUND((uintptr)enoptrbss - start, PageSize);
+ runtime∕race·MapShadow((void*)start, size);
m->racecall = false;
return racectx;
}
diff --git a/src/pkg/runtime/race/doc.go b/src/pkg/runtime/race/doc.go
new file mode 100644
index 000000000..aef805dad
--- /dev/null
+++ b/src/pkg/runtime/race/doc.go
@@ -0,0 +1,9 @@
+// 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 race implements data race detection logic.
+// No public interface is provided.
+// For details about the race detector see
+// http://golang.org/doc/articles/race_detector.html
+package race
diff --git a/src/pkg/runtime/race/race.go b/src/pkg/runtime/race/race.go
index b0a5c9a50..ee13057e3 100644
--- a/src/pkg/runtime/race/race.go
+++ b/src/pkg/runtime/race/race.go
@@ -4,7 +4,6 @@
// +build race,linux,amd64 race,darwin,amd64 race,windows,amd64
-// Package race provides low-level facilities for data race detection.
package race
/*
diff --git a/src/pkg/runtime/race/race_test.go b/src/pkg/runtime/race/race_test.go
index c77569c37..47d34d7ad 100644
--- a/src/pkg/runtime/race/race_test.go
+++ b/src/pkg/runtime/race/race_test.go
@@ -147,7 +147,7 @@ func runTests() ([]byte, error) {
// It is required because the tests contain a lot of data races on the same addresses
// (the tests are simple and the memory is constantly reused).
for _, env := range os.Environ() {
- if strings.HasPrefix(env, "GOMAXPROCS=") {
+ if strings.HasPrefix(env, "GOMAXPROCS=") || strings.HasPrefix(env, "GOGCTRACE=") {
continue
}
cmd.Env = append(cmd.Env, env)
diff --git a/src/pkg/runtime/race/testdata/atomic_test.go b/src/pkg/runtime/race/testdata/atomic_test.go
index 0c5c2c008..fc569b96c 100644
--- a/src/pkg/runtime/race/testdata/atomic_test.go
+++ b/src/pkg/runtime/race/testdata/atomic_test.go
@@ -6,6 +6,7 @@ package race_test
import (
"runtime"
+ "sync"
"sync/atomic"
"testing"
"unsafe"
@@ -269,3 +270,21 @@ func TestRaceAtomicAddStore(t *testing.T) {
a = 42
<-c
}
+
+// A nil pointer in an atomic operation should not deadlock
+// the rest of the program. Used to hang indefinitely.
+func TestNoRaceAtomicCrash(t *testing.T) {
+ var mutex sync.Mutex
+ var nilptr *int32
+ panics := 0
+ defer func() {
+ if x := recover(); x != nil {
+ mutex.Lock()
+ panics++
+ mutex.Unlock()
+ } else {
+ panic("no panic")
+ }
+ }()
+ atomic.AddInt32(nilptr, 1)
+}
diff --git a/src/pkg/runtime/race/testdata/map_test.go b/src/pkg/runtime/race/testdata/map_test.go
index 6f86a50b7..35db8db69 100644
--- a/src/pkg/runtime/race/testdata/map_test.go
+++ b/src/pkg/runtime/race/testdata/map_test.go
@@ -94,8 +94,7 @@ func TestNoRaceMapRangeRange(t *testing.T) {
<-ch
}
-// Map len is not instrumented.
-func TestRaceFailingMapLen(t *testing.T) {
+func TestRaceMapLen(t *testing.T) {
m := make(map[string]bool)
ch := make(chan bool, 1)
go func() {
@@ -117,8 +116,7 @@ func TestRaceMapDelete(t *testing.T) {
<-ch
}
-// Map len is not instrumented.
-func TestRaceFailingMapLenDelete(t *testing.T) {
+func TestRaceMapLenDelete(t *testing.T) {
m := make(map[string]bool)
ch := make(chan bool, 1)
go func() {
diff --git a/src/pkg/runtime/race/testdata/mop_test.go b/src/pkg/runtime/race/testdata/mop_test.go
index f2daa3730..fa7abe0ef 100644
--- a/src/pkg/runtime/race/testdata/mop_test.go
+++ b/src/pkg/runtime/race/testdata/mop_test.go
@@ -227,6 +227,37 @@ func TestRaceCaseFallthrough(t *testing.T) {
<-ch
}
+func TestRaceCaseType(t *testing.T) {
+ var x, y int
+ var i interface{} = x
+ c := make(chan int, 1)
+ go func() {
+ switch i.(type) {
+ case nil:
+ case int:
+ }
+ c <- 1
+ }()
+ i = y
+ <-c
+}
+
+func TestRaceCaseTypeBody(t *testing.T) {
+ var x, y int
+ var i interface{} = &x
+ c := make(chan int, 1)
+ go func() {
+ switch i := i.(type) {
+ case nil:
+ case *int:
+ *i = y
+ }
+ c <- 1
+ }()
+ x = y
+ <-c
+}
+
func TestNoRaceRange(t *testing.T) {
ch := make(chan int, 3)
a := [...]int{1, 2, 3}
@@ -306,6 +337,102 @@ func TestNoRacePlus(t *testing.T) {
<-ch
}
+func TestRaceComplement(t *testing.T) {
+ var x, y, z int
+ ch := make(chan int, 2)
+
+ go func() {
+ x = ^y
+ ch <- 1
+ }()
+ go func() {
+ y = ^z
+ ch <- 1
+ }()
+ <-ch
+ <-ch
+}
+
+func TestRaceDiv(t *testing.T) {
+ var x, y, z int
+ ch := make(chan int, 2)
+
+ go func() {
+ x = y / (z + 1)
+ ch <- 1
+ }()
+ go func() {
+ y = z
+ ch <- 1
+ }()
+ <-ch
+ <-ch
+}
+
+func TestRaceDivConst(t *testing.T) {
+ var x, y, z uint32
+ ch := make(chan int, 2)
+
+ go func() {
+ x = y / 3 // involves only a HMUL node
+ ch <- 1
+ }()
+ go func() {
+ y = z
+ ch <- 1
+ }()
+ <-ch
+ <-ch
+}
+
+func TestRaceMod(t *testing.T) {
+ var x, y, z int
+ ch := make(chan int, 2)
+
+ go func() {
+ x = y % (z + 1)
+ ch <- 1
+ }()
+ go func() {
+ y = z
+ ch <- 1
+ }()
+ <-ch
+ <-ch
+}
+
+func TestRaceModConst(t *testing.T) {
+ var x, y, z int
+ ch := make(chan int, 2)
+
+ go func() {
+ x = y % 3
+ ch <- 1
+ }()
+ go func() {
+ y = z
+ ch <- 1
+ }()
+ <-ch
+ <-ch
+}
+
+func TestRaceRotate(t *testing.T) {
+ var x, y, z uint32
+ ch := make(chan int, 2)
+
+ go func() {
+ x = y<<12 | y>>20
+ ch <- 1
+ }()
+ go func() {
+ y = z
+ ch <- 1
+ }()
+ <-ch
+ <-ch
+}
+
// May crash if the instrumentation is reckless.
func TestNoRaceEnoughRegisters(t *testing.T) {
// from erf.go
@@ -480,6 +607,30 @@ func TestRaceIfaceWW(t *testing.T) {
a = b
}
+func TestRaceIfaceCmp(t *testing.T) {
+ var a, b Writer
+ a = DummyWriter{1}
+ ch := make(chan bool, 1)
+ go func() {
+ a = DummyWriter{1}
+ ch <- true
+ }()
+ _ = a == b
+ <-ch
+}
+
+func TestRaceIfaceCmpNil(t *testing.T) {
+ var a Writer
+ a = DummyWriter{1}
+ ch := make(chan bool, 1)
+ go func() {
+ a = DummyWriter{1}
+ ch <- true
+ }()
+ _ = a == nil
+ <-ch
+}
+
func TestRaceEfaceConv(t *testing.T) {
c := make(chan bool)
v := 0
@@ -874,8 +1025,7 @@ func TestRaceAnd(t *testing.T) {
<-c
}
-// OANDAND is not instrumented in the compiler.
-func TestRaceFailingAnd2(t *testing.T) {
+func TestRaceAnd2(t *testing.T) {
c := make(chan bool)
x, y := 0, 0
go func() {
@@ -911,8 +1061,7 @@ func TestRaceOr(t *testing.T) {
<-c
}
-// OOROR is not instrumented in the compiler.
-func TestRaceFailingOr2(t *testing.T) {
+func TestRaceOr2(t *testing.T) {
c := make(chan bool)
x, y := 0, 0
go func() {
@@ -1057,6 +1206,15 @@ func (p InterImpl) Foo(x int) {
_, _, _ = x, y, z
}
+type InterImpl2 InterImpl
+
+func (p *InterImpl2) Foo(x int) {
+ if p == nil {
+ InterImpl{}.Foo(x)
+ }
+ InterImpl(*p).Foo(x)
+}
+
func TestRaceInterCall(t *testing.T) {
c := make(chan bool, 1)
p := InterImpl{}
@@ -1118,6 +1276,54 @@ func TestRaceMethodCall2(t *testing.T) {
<-c
}
+// Method value with concrete value receiver.
+func TestRaceMethodValue(t *testing.T) {
+ c := make(chan bool, 1)
+ i := InterImpl{}
+ go func() {
+ i = InterImpl{}
+ c <- true
+ }()
+ _ = i.Foo
+ <-c
+}
+
+// Method value with interface receiver.
+func TestRaceMethodValue2(t *testing.T) {
+ c := make(chan bool, 1)
+ var i Inter = InterImpl{}
+ go func() {
+ i = InterImpl{}
+ c <- true
+ }()
+ _ = i.Foo
+ <-c
+}
+
+// Method value with implicit dereference.
+func TestRaceMethodValue3(t *testing.T) {
+ c := make(chan bool, 1)
+ i := &InterImpl{}
+ go func() {
+ *i = InterImpl{}
+ c <- true
+ }()
+ _ = i.Foo // dereferences i.
+ <-c
+}
+
+// Method value implicitly taking receiver address.
+func TestNoRaceMethodValue(t *testing.T) {
+ c := make(chan bool, 1)
+ i := InterImpl2{}
+ go func() {
+ i = InterImpl2{}
+ c <- true
+ }()
+ _ = i.Foo // takes the address of i only.
+ <-c
+}
+
func TestRacePanicArg(t *testing.T) {
c := make(chan bool, 1)
err := errors.New("err")
@@ -1244,6 +1450,17 @@ func TestRaceSliceSlice2(t *testing.T) {
<-c
}
+func TestRaceSliceString(t *testing.T) {
+ c := make(chan bool, 1)
+ x := "hello"
+ go func() {
+ x = "world"
+ c <- true
+ }()
+ _ = x[2:3]
+ <-c
+}
+
// http://golang.org/issue/4453
func TestRaceFailingSliceStruct(t *testing.T) {
type X struct {
@@ -1260,6 +1477,21 @@ func TestRaceFailingSliceStruct(t *testing.T) {
<-c
}
+func TestRaceFailingAppendSliceStruct(t *testing.T) {
+ type X struct {
+ x, y int
+ }
+ c := make(chan bool, 1)
+ x := make([]X, 10)
+ go func() {
+ y := make([]X, 0, 10)
+ y = append(y, x...)
+ c <- true
+ }()
+ x[1].y = 42
+ <-c
+}
+
func TestRaceStructInd(t *testing.T) {
c := make(chan bool, 1)
type Item struct {
diff --git a/src/pkg/runtime/race/testdata/regression_test.go b/src/pkg/runtime/race/testdata/regression_test.go
index afe8cc5ec..f08ee3ed3 100644
--- a/src/pkg/runtime/race/testdata/regression_test.go
+++ b/src/pkg/runtime/race/testdata/regression_test.go
@@ -45,6 +45,18 @@ func InstrumentMapLen3() {
_ = len(*m[0])
}
+func TestRaceUnaddressableMapLen(t *testing.T) {
+ m := make(map[int]map[int]int)
+ ch := make(chan int, 1)
+ m[0] = make(map[int]int)
+ go func() {
+ _ = len(m[0])
+ ch <- 0
+ }()
+ m[0][0] = 1
+ <-ch
+}
+
type Rect struct {
x, y int
}
diff --git a/src/pkg/runtime/race/testdata/slice_test.go b/src/pkg/runtime/race/testdata/slice_test.go
index 773463662..c85df5e3d 100644
--- a/src/pkg/runtime/race/testdata/slice_test.go
+++ b/src/pkg/runtime/race/testdata/slice_test.go
@@ -338,8 +338,7 @@ func TestRaceSliceVarCopy2(t *testing.T) {
<-c
}
-// Not implemented.
-func TestRaceFailingSliceAppend(t *testing.T) {
+func TestRaceSliceAppend(t *testing.T) {
c := make(chan bool, 1)
s := make([]int, 10, 20)
go func() {
@@ -463,3 +462,24 @@ func TestRaceSliceRuneToString(t *testing.T) {
s[9] = 42
<-c
}
+
+func TestRaceConcatString(t *testing.T) {
+ s := "hello"
+ c := make(chan string, 1)
+ go func() {
+ c <- s + " world"
+ }()
+ s = "world"
+ <-c
+}
+
+func TestRaceCompareString(t *testing.T) {
+ s1 := "hello"
+ s2 := "world"
+ c := make(chan bool, 1)
+ go func() {
+ c <- s1 == s2
+ }()
+ s1 = s2
+ <-c
+}
diff --git a/src/pkg/runtime/race/testdata/sync_test.go b/src/pkg/runtime/race/testdata/sync_test.go
index e80ba3b74..93af0b1e6 100644
--- a/src/pkg/runtime/race/testdata/sync_test.go
+++ b/src/pkg/runtime/race/testdata/sync_test.go
@@ -195,3 +195,22 @@ func TestRaceGoroutineCreationStack(t *testing.T) {
x = 2
<-ch
}
+
+// A nil pointer in a mutex method call should not
+// corrupt the race detector state.
+// Used to hang indefinitely.
+func TestNoRaceNilMutexCrash(t *testing.T) {
+ var mutex sync.Mutex
+ panics := 0
+ defer func() {
+ if x := recover(); x != nil {
+ mutex.Lock()
+ panics++
+ mutex.Unlock()
+ } else {
+ panic("no panic")
+ }
+ }()
+ var othermutex *sync.RWMutex
+ othermutex.RLock()
+}
diff --git a/src/pkg/runtime/rt0_darwin_386.s b/src/pkg/runtime/rt0_darwin_386.s
index 30b497f5e..4b4c1f294 100644
--- a/src/pkg/runtime/rt0_darwin_386.s
+++ b/src/pkg/runtime/rt0_darwin_386.s
@@ -2,7 +2,13 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// Darwin and Linux use the same linkage to main
+TEXT _rt0_386_darwin(SB),7,$8
+ MOVL 8(SP), AX
+ LEAL 12(SP), BX
+ MOVL AX, 0(SP)
+ MOVL BX, 4(SP)
+ CALL main(SB)
+ INT $3
-TEXT _rt0_386_darwin(SB),7,$0
+TEXT main(SB),7,$0
JMP _rt0_386(SB)
diff --git a/src/pkg/runtime/rt0_darwin_amd64.s b/src/pkg/runtime/rt0_darwin_amd64.s
index 4cfab5876..45e69a015 100644
--- a/src/pkg/runtime/rt0_darwin_amd64.s
+++ b/src/pkg/runtime/rt0_darwin_amd64.s
@@ -2,9 +2,12 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// Darwin and Linux use the same linkage to main
-
TEXT _rt0_amd64_darwin(SB),7,$-8
+ LEAQ 8(SP), SI // argv
+ MOVQ 0(SP), DI // argc
+ MOVQ $main(SB), AX
+ JMP AX
+
+TEXT main(SB),7,$-8
MOVQ $_rt0_amd64(SB), AX
- MOVQ SP, DI
JMP AX
diff --git a/src/pkg/runtime/rt0_freebsd_386.s b/src/pkg/runtime/rt0_freebsd_386.s
index 3ca981b3a..c84482cdb 100644
--- a/src/pkg/runtime/rt0_freebsd_386.s
+++ b/src/pkg/runtime/rt0_freebsd_386.s
@@ -2,8 +2,13 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// Darwin and Linux use the same linkage to main
+TEXT _rt0_386_freebsd(SB),7,$8
+ MOVL 8(SP), AX
+ LEAL 12(SP), BX
+ MOVL AX, 0(SP)
+ MOVL BX, 4(SP)
+ CALL main(SB)
+ INT $3
-TEXT _rt0_386_freebsd(SB),7,$0
+TEXT main(SB),7,$0
JMP _rt0_386(SB)
-
diff --git a/src/pkg/runtime/rt0_freebsd_amd64.s b/src/pkg/runtime/rt0_freebsd_amd64.s
index 5d2eeeeff..e6c6fb9ca 100644
--- a/src/pkg/runtime/rt0_freebsd_amd64.s
+++ b/src/pkg/runtime/rt0_freebsd_amd64.s
@@ -2,8 +2,12 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// Darwin and Linux use the same linkage to main
-
TEXT _rt0_amd64_freebsd(SB),7,$-8
- MOVQ $_rt0_amd64(SB), DX
- JMP DX
+ LEAQ 8(DI), SI // argv
+ MOVQ 0(DI), DI // argc
+ MOVQ $main(SB), AX
+ JMP AX
+
+TEXT main(SB),7,$-8
+ MOVQ $_rt0_amd64(SB), AX
+ JMP AX
diff --git a/src/pkg/runtime/rt0_linux_386.s b/src/pkg/runtime/rt0_linux_386.s
index 83149540e..73cca5d98 100644
--- a/src/pkg/runtime/rt0_linux_386.s
+++ b/src/pkg/runtime/rt0_linux_386.s
@@ -2,11 +2,17 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// Darwin and Linux use the same linkage to main
-
-TEXT _rt0_386_linux(SB),7,$0
+TEXT _rt0_386_linux(SB),7,$8
+ MOVL 8(SP), AX
+ LEAL 12(SP), BX
+ MOVL AX, 0(SP)
+ MOVL BX, 4(SP)
CALL runtime·linux_setup_vdso(SB)
- JMP _rt0_386(SB)
+ CALL main(SB)
+ INT $3
+
+TEXT main(SB),7,$0
+ JMP _rt0_386(SB)
TEXT _fallback_vdso(SB),7,$0
INT $0x80
diff --git a/src/pkg/runtime/rt0_linux_amd64.s b/src/pkg/runtime/rt0_linux_amd64.s
index dac9ae181..dfc9c0421 100644
--- a/src/pkg/runtime/rt0_linux_amd64.s
+++ b/src/pkg/runtime/rt0_linux_amd64.s
@@ -2,9 +2,12 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// Darwin and Linux use the same linkage to main
-
TEXT _rt0_amd64_linux(SB),7,$-8
+ LEAQ 8(SP), SI // argv
+ MOVQ 0(SP), DI // argc
+ MOVQ $main(SB), AX
+ JMP AX
+
+TEXT main(SB),7,$-8
MOVQ $_rt0_amd64(SB), AX
- MOVQ SP, DI
JMP AX
diff --git a/src/pkg/runtime/rt0_netbsd_386.s b/src/pkg/runtime/rt0_netbsd_386.s
index 829e4133b..b4c029c53 100644
--- a/src/pkg/runtime/rt0_netbsd_386.s
+++ b/src/pkg/runtime/rt0_netbsd_386.s
@@ -2,5 +2,13 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-TEXT _rt0_386_netbsd(SB),7,$0
- JMP _rt0_386(SB)
+TEXT _rt0_386_netbsd(SB),7,$8
+ MOVL 8(SP), AX
+ LEAL 12(SP), BX
+ MOVL AX, 0(SP)
+ MOVL BX, 4(SP)
+ CALL main(SB)
+ INT $3
+
+TEXT main(SB),7,$0
+ JMP _rt0_386(SB)
diff --git a/src/pkg/runtime/rt0_netbsd_amd64.s b/src/pkg/runtime/rt0_netbsd_amd64.s
index 85482b98d..9e7b78edc 100644
--- a/src/pkg/runtime/rt0_netbsd_amd64.s
+++ b/src/pkg/runtime/rt0_netbsd_amd64.s
@@ -3,6 +3,11 @@
// license that can be found in the LICENSE file.
TEXT _rt0_amd64_netbsd(SB),7,$-8
- MOVQ $_rt0_amd64(SB), DX
- MOVQ SP, DI
- JMP DX
+ LEAQ 8(SP), SI // argv
+ MOVQ 0(SP), DI // argc
+ MOVQ $main(SB), AX
+ JMP AX
+
+TEXT main(SB),7,$-8
+ MOVQ $_rt0_amd64(SB), AX
+ JMP AX
diff --git a/src/pkg/runtime/rt0_openbsd_386.s b/src/pkg/runtime/rt0_openbsd_386.s
index e7e0da78f..9c00a7334 100644
--- a/src/pkg/runtime/rt0_openbsd_386.s
+++ b/src/pkg/runtime/rt0_openbsd_386.s
@@ -2,5 +2,13 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-TEXT _rt0_386_openbsd(SB),7,$0
- JMP _rt0_386(SB)
+TEXT _rt0_386_openbsd(SB),7,$8
+ MOVL 8(SP), AX
+ LEAL 12(SP), BX
+ MOVL AX, 0(SP)
+ MOVL BX, 4(SP)
+ CALL main(SB)
+ INT $3
+
+TEXT main(SB),7,$0
+ JMP _rt0_386(SB)
diff --git a/src/pkg/runtime/rt0_openbsd_amd64.s b/src/pkg/runtime/rt0_openbsd_amd64.s
index e7fce5969..245a4c0f9 100644
--- a/src/pkg/runtime/rt0_openbsd_amd64.s
+++ b/src/pkg/runtime/rt0_openbsd_amd64.s
@@ -3,6 +3,11 @@
// license that can be found in the LICENSE file.
TEXT _rt0_amd64_openbsd(SB),7,$-8
- MOVQ $_rt0_amd64(SB), DX
- MOVQ SP, DI
- JMP DX
+ LEAQ 8(SP), SI // argv
+ MOVQ 0(SP), DI // argc
+ MOVQ $main(SB), AX
+ JMP AX
+
+TEXT main(SB),7,$-8
+ MOVQ $_rt0_amd64(SB), AX
+ JMP AX
diff --git a/src/pkg/runtime/rt0_plan9_386.s b/src/pkg/runtime/rt0_plan9_386.s
index 56f3a0f6c..7af1eae7c 100644
--- a/src/pkg/runtime/rt0_plan9_386.s
+++ b/src/pkg/runtime/rt0_plan9_386.s
@@ -26,6 +26,13 @@ argv_fix:
LOOP argv_fix
CALL runtime·asminit(SB)
+
+ MOVL 0(SP), AX
+ LEAL 4(SP), BX
+ PUSHL BX
+ PUSHL AX
+ PUSHL $-1
+
JMP _rt0_386(SB)
DATA runtime·isplan9(SB)/4, $1
diff --git a/src/pkg/runtime/rt0_plan9_amd64.s b/src/pkg/runtime/rt0_plan9_amd64.s
index 2b1fa2ae1..16e5e82b7 100644
--- a/src/pkg/runtime/rt0_plan9_amd64.s
+++ b/src/pkg/runtime/rt0_plan9_amd64.s
@@ -2,9 +2,10 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-TEXT _rt0_amd64_plan9(SB),7, $0
+TEXT _rt0_amd64_plan9(SB),7,$-8
+ LEAQ 8(SP), SI // argv
+ MOVQ 0(SP), DI // argc
MOVQ $_rt0_amd64(SB), AX
- MOVQ SP, DI
JMP AX
DATA runtime·isplan9(SB)/4, $1
diff --git a/src/pkg/runtime/rt0_windows_386.s b/src/pkg/runtime/rt0_windows_386.s
index a06aa787e..6e34c6c17 100644
--- a/src/pkg/runtime/rt0_windows_386.s
+++ b/src/pkg/runtime/rt0_windows_386.s
@@ -2,8 +2,17 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-TEXT _rt0_386_windows(SB),7,$0
+TEXT _rt0_386_windows(SB),7,$12
+ MOVL 12(SP), AX
+ LEAL 16(SP), BX
+ MOVL AX, 4(SP)
+ MOVL BX, 8(SP)
+ MOVL $-1, 0(SP) // return PC for main
+ JMP main(SB)
+
+TEXT main(SB),7,$0
JMP _rt0_386(SB)
+
DATA runtime·iswindows(SB)/4, $1
GLOBL runtime·iswindows(SB), $4
diff --git a/src/pkg/runtime/rt0_windows_amd64.s b/src/pkg/runtime/rt0_windows_amd64.s
index dc1408adc..b48c05570 100644
--- a/src/pkg/runtime/rt0_windows_amd64.s
+++ b/src/pkg/runtime/rt0_windows_amd64.s
@@ -4,9 +4,14 @@
#include "zasm_GOOS_GOARCH.h"
-TEXT _rt0_amd64_windows(SB),7,$-8
+TEXT _rt0_amd64_windows(SB),7,$-8
+ LEAQ 8(SP), SI // argv
+ MOVQ 0(SP), DI // argc
+ MOVQ $main(SB), AX
+ JMP AX
+
+TEXT main(SB),7,$-8
MOVQ $_rt0_amd64(SB), AX
- MOVQ SP, DI
JMP AX
DATA runtime·iswindows(SB)/4, $1
diff --git a/src/pkg/runtime/runtime-gdb.py b/src/pkg/runtime/runtime-gdb.py
index eff9a4003..cb70ca028 100644
--- a/src/pkg/runtime/runtime-gdb.py
+++ b/src/pkg/runtime/runtime-gdb.py
@@ -84,26 +84,35 @@ class MapTypePrinter:
return str(self.val.type)
def children(self):
- stab = self.val['st']
- i = 0
- for v in self.traverse_hash(stab):
- yield ("[%d]" % i, v['key'])
- yield ("[%d]" % (i + 1), v['val'])
- i += 2
-
- def traverse_hash(self, stab):
- ptr = stab['entry'].address
- last = stab['last']
- while ptr <= last:
- v = ptr.dereference()
- ptr = ptr + 1
- if v['hash'] == 0: continue
- if v['hash'] & 63 == 63: # subtable
- for v in self.traverse_hash(v['key'].cast(self.val['st'].type)):
- yield v
- else:
- yield v
-
+ B = self.val['b']
+ buckets = self.val['buckets']
+ oldbuckets = self.val['oldbuckets']
+ flags = self.val['flags']
+ inttype = self.val['hash0'].type
+ cnt = 0
+ for bucket in xrange(2 ** B):
+ bp = buckets + bucket
+ if oldbuckets:
+ oldbucket = bucket & (2 ** (B - 1) - 1)
+ oldbp = oldbuckets + oldbucket
+ oldb = oldbp.dereference()
+ if (oldb['overflow'].cast(inttype) & 1) == 0: # old bucket not evacuated yet
+ if bucket >= 2 ** (B - 1): continue # already did old bucket
+ bp = oldbp
+ while bp:
+ b = bp.dereference()
+ for i in xrange(8):
+ if b['tophash'][i] != 0:
+ k = b['keys'][i]
+ v = b['values'][i]
+ if flags & 1:
+ k = k.dereference()
+ if flags & 2:
+ v = v.dereference()
+ yield '%d' % cnt, k
+ yield '%d' % (cnt + 1), v
+ cnt += 2
+ bp = b['overflow']
class ChanTypePrinter:
"""Pretty print chan[T] types.
diff --git a/src/pkg/runtime/runtime.c b/src/pkg/runtime/runtime.c
index 4d57cbafd..d62408118 100644
--- a/src/pkg/runtime/runtime.c
+++ b/src/pkg/runtime/runtime.c
@@ -17,21 +17,34 @@ enum {
*/
void runtime·sigpanic(void);
+// The GOTRACEBACK environment variable controls the
+// behavior of a Go program that is crashing and exiting.
+// GOTRACEBACK=0 suppress all tracebacks
+// GOTRACEBACK=1 default behavior - show tracebacks but exclude runtime frames
+// GOTRACEBACK=2 show tracebacks including runtime frames
+// GOTRACEBACK=crash show tracebacks including runtime frames, then crash (core dump etc)
int32
-runtime·gotraceback(void)
+runtime·gotraceback(bool *crash)
{
byte *p;
+ if(crash != nil)
+ *crash = false;
p = runtime·getenv("GOTRACEBACK");
if(p == nil || p[0] == '\0')
return 1; // default is on
+ if(runtime·strcmp(p, (byte*)"crash") == 0) {
+ if(crash != nil)
+ *crash = true;
+ return 2; // extra information
+ }
return runtime·atoi(p);
}
int32
-runtime·mcmp(byte *s1, byte *s2, uint32 n)
+runtime·mcmp(byte *s1, byte *s2, uintptr n)
{
- uint32 i;
+ uintptr i;
byte c1, c2;
for(i=0; i<n; i++) {
@@ -75,6 +88,11 @@ runtime·args(int32 c, uint8 **v)
int32 runtime·isplan9;
int32 runtime·iswindows;
+// Information about what cpu features are available.
+// Set on startup in asm_{x86/amd64}.s.
+uint32 runtime·cpuid_ecx;
+uint32 runtime·cpuid_edx;
+
void
runtime·goargs(void)
{
@@ -156,6 +174,10 @@ TestAtomic64(void)
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
diff --git a/src/pkg/runtime/runtime.h b/src/pkg/runtime/runtime.h
index 08f43a69b..cb72b92d6 100644
--- a/src/pkg/runtime/runtime.h
+++ b/src/pkg/runtime/runtime.h
@@ -50,11 +50,11 @@ typedef uint8 byte;
typedef struct Func Func;
typedef struct G G;
typedef struct Gobuf Gobuf;
-typedef union Lock Lock;
+typedef struct Lock Lock;
typedef struct M M;
typedef struct P P;
typedef struct Mem Mem;
-typedef union Note Note;
+typedef struct Note Note;
typedef struct Slice Slice;
typedef struct Stktop Stktop;
typedef struct String String;
@@ -85,6 +85,7 @@ typedef struct LFNode LFNode;
typedef struct ParFor ParFor;
typedef struct ParForThread ParForThread;
typedef struct CgoMal CgoMal;
+typedef struct PollDesc PollDesc;
/*
* Per-CPU declaration.
@@ -146,19 +147,28 @@ enum
// Global <-> per-M stack segment cache transfer batch size.
StackCacheBatch = 16,
};
-
+enum
+{
+ // This value is generated by the linker and should be kept in
+ // sync with cmd/ld/lib.h
+ ArgsSizeUnknown = 0x80000000,
+};
/*
* structures
*/
-union Lock
+struct Lock
{
- uint32 key; // futex-based impl
- M* waitm; // linked list of waiting M's (sema-based impl)
+ // 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;
};
-union Note
+struct Note
{
- uint32 key; // futex-based impl
- M* waitm; // waiting M (sema-based impl)
+ // 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
{
@@ -235,8 +245,10 @@ struct G
int8* waitreason; // if status==Gwaiting
G* schedlink;
bool ispanic;
- bool issystem;
- int8 raceignore; // ignore race detection events
+ bool issystem; // do not output in stack dump
+ bool isbackground; // ignore in deadlock detector
+ bool blockingsyscall; // hint that the next syscall will block
+ int8 raceignore; // ignore race detection events
M* m; // for debuggers, but offset not hard-coded
M* lockedm;
int32 sig;
@@ -309,7 +321,7 @@ struct M
bool needextram;
void* racepc;
void (*waitunlockf)(Lock*);
- Lock* waitlock;
+ void* waitlock;
uint32 moreframesize_minalloc;
uintptr settype_buf[1024];
@@ -320,6 +332,7 @@ struct M
#endif
#ifdef GOOS_plan9
int8* notesig;
+ byte* errstr;
#endif
SEH* seh;
uintptr end[];
@@ -381,6 +394,8 @@ enum
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
+ SigIgnored = 1<<6, // the signal was ignored before we registered for it
};
// NOTE(rsc): keep in sync with extern.go:/type.Func.
@@ -482,6 +497,7 @@ struct ParFor
bool wait; // if true, wait while all threads finish processing,
// otherwise parfor may return while other threads are still working
ParForThread *thr; // array of thread descriptors
+ uint32 pad; // to align ParForThread.pos for 64-bit atomic operations
// stats
uint64 nsteal;
uint64 nstealcnt;
@@ -495,7 +511,7 @@ struct ParFor
struct CgoMal
{
CgoMal *next;
- byte *alloc;
+ void *alloc;
};
/*
@@ -555,11 +571,25 @@ struct Alg
extern Alg runtime·algarray[Amax];
+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·memhash(uintptr*, uintptr, void*);
void runtime·nohash(uintptr*, uintptr, void*);
void runtime·strhash(uintptr*, uintptr, void*);
void runtime·interhash(uintptr*, uintptr, void*);
void runtime·nilinterhash(uintptr*, uintptr, void*);
+void runtime·aeshash(uintptr*, uintptr, void*);
+void runtime·aeshash32(uintptr*, uintptr, void*);
+void runtime·aeshash64(uintptr*, uintptr, void*);
+void runtime·aeshashstr(uintptr*, uintptr, void*);
void runtime·memequal(bool*, uintptr, void*, void*);
void runtime·noequal(bool*, uintptr, void*, void*);
@@ -567,6 +597,8 @@ void runtime·strequal(bool*, uintptr, void*, void*);
void runtime·interequal(bool*, uintptr, void*, void*);
void runtime·nilinterequal(bool*, uintptr, void*, void*);
+bool runtime·memeq(void*, void*, uintptr);
+
void runtime·memprint(uintptr, void*);
void runtime·strprint(uintptr, void*);
void runtime·interprint(uintptr, void*);
@@ -578,7 +610,6 @@ void runtime·memcopy16(uintptr, void*, void*);
void runtime·memcopy32(uintptr, void*, void*);
void runtime·memcopy64(uintptr, void*, void*);
void runtime·memcopy128(uintptr, void*, void*);
-void runtime·memcopy(uintptr, void*, void*);
void runtime·strcopy(uintptr, void*, void*);
void runtime·algslicecopy(uintptr, void*, void*);
void runtime·intercopy(uintptr, void*, void*);
@@ -635,6 +666,8 @@ extern bool runtime·iscgo;
extern void (*runtime·sysargs)(int32, uint8**);
extern uint32 runtime·maxstring;
extern uint32 runtime·Hchansize;
+extern uint32 runtime·cpuid_ecx;
+extern uint32 runtime·cpuid_edx;
/*
* common functions and data
@@ -666,8 +699,8 @@ void runtime·panicstring(int8*);
void runtime·prints(int8*);
void runtime·printf(int8*, ...);
byte* runtime·mchr(byte*, byte, byte*);
-int32 runtime·mcmp(byte*, byte*, uint32);
-void runtime·memmove(void*, void*, uint32);
+int32 runtime·mcmp(byte*, byte*, uintptr);
+void runtime·memmove(void*, void*, uintptr);
void* runtime·mal(uintptr);
String runtime·catstring(String, String);
String runtime·gostring(byte*);
@@ -677,11 +710,15 @@ String runtime·gostringnocopy(byte*);
String runtime·gostringw(uint16*);
void runtime·initsig(void);
void runtime·sigenable(uint32 sig);
-int32 runtime·gotraceback(void);
+void runtime·sigdisable(uint32 sig);
+int32 runtime·gotraceback(bool *crash);
void runtime·goroutineheader(G*);
void runtime·traceback(uint8 *pc, uint8 *sp, uint8 *lr, G* gp);
void runtime·tracebackothers(G*);
+int32 runtime·open(int8*, int32, int32);
+int32 runtime·read(int32, void*, int32);
int32 runtime·write(int32, void*, int32);
+int32 runtime·close(int32);
int32 runtime·mincore(void*, uintptr, byte*);
bool runtime·cas(uint32*, uint32, uint32);
bool runtime·cas64(uint64*, uint64*, uint64);
@@ -691,6 +728,7 @@ bool runtime·casp(void**, void*, void*);
uint32 runtime·xadd(uint32 volatile*, int32);
uint64 runtime·xadd64(uint64 volatile*, int64);
uint32 runtime·xchg(uint32 volatile*, uint32);
+uint64 runtime·xchg64(uint64 volatile*, uint64);
uint32 runtime·atomicload(uint32 volatile*);
void runtime·atomicstore(uint32 volatile*, uint32);
void runtime·atomicstore64(uint64 volatile*, uint64);
@@ -748,7 +786,7 @@ void runtime·exitsyscall(void);
G* runtime·newproc1(FuncVal*, byte*, int32, int32, void*);
bool runtime·sigsend(int32 sig);
int32 runtime·callers(int32, uintptr*, int32);
-int32 runtime·gentraceback(byte*, byte*, byte*, G*, int32, uintptr*, int32);
+int32 runtime·gentraceback(byte*, byte*, byte*, G*, int32, uintptr*, int32, void (*)(Func*, byte*, byte*, void*), void*);
int64 runtime·nanotime(void);
void runtime·dopanic(int32);
void runtime·startpanic(void);
@@ -761,6 +799,14 @@ int64 runtime·cputicks(void);
int64 runtime·tickspersecond(void);
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(int32, PollDesc*);
+int32 runtime·netpollclose(int32);
+void runtime·netpollready(G**, PollDesc*, int32);
+void runtime·crash(void);
#pragma varargck argpos runtime·printf 1
#pragma varargck type "d" int32
@@ -929,7 +975,6 @@ void runtime·mapassign(MapType*, Hmap*, byte*, byte*);
void runtime·mapaccess(MapType*, Hmap*, byte*, byte*, bool*);
void runtime·mapiternext(struct hash_iter*);
bool runtime·mapiterkey(struct hash_iter*, void*);
-void runtime·mapiterkeyvalue(struct hash_iter*, void*, void*);
Hmap* runtime·makemap_c(MapType*, int64);
Hchan* runtime·makechan_c(ChanType*, int64);
diff --git a/src/pkg/runtime/sema.goc b/src/pkg/runtime/sema.goc
index c4b5247b3..4df01fc4e 100644
--- a/src/pkg/runtime/sema.goc
+++ b/src/pkg/runtime/sema.goc
@@ -44,13 +44,13 @@ struct SemaRoot
// Prime to not correlate with any user patterns.
#define SEMTABLESZ 251
-union semtable
+struct semtable
{
SemaRoot;
- uint8 pad[CacheLineSize];
+ uint8 pad[CacheLineSize-sizeof(SemaRoot)];
};
#pragma dataflag 16 /* mark semtable as 'no pointers', hiding from garbage collector */
-static union semtable semtable[SEMTABLESZ];
+static struct semtable semtable[SEMTABLESZ];
static SemaRoot*
semroot(uint32 *addr)
diff --git a/src/pkg/runtime/signal_386.c b/src/pkg/runtime/signal_386.c
new file mode 100644
index 000000000..72b4a66f8
--- /dev/null
+++ b/src/pkg/runtime/signal_386.c
@@ -0,0 +1,123 @@
+// 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 freebsd linux netbsd openbsd
+
+#include "runtime.h"
+#include "defs_GOOS_GOARCH.h"
+#include "os_GOOS.h"
+#include "signal_GOOS_GOARCH.h"
+#include "signals_GOOS.h"
+
+void
+runtime·dumpregs(Siginfo *info, void *ctxt)
+{
+ USED(info);
+ USED(ctxt);
+
+ runtime·printf("eax %x\n", SIG_EAX(info, ctxt));
+ runtime·printf("ebx %x\n", SIG_EBX(info, ctxt));
+ runtime·printf("ecx %x\n", SIG_ECX(info, ctxt));
+ runtime·printf("edx %x\n", SIG_EDX(info, ctxt));
+ runtime·printf("edi %x\n", SIG_EDI(info, ctxt));
+ runtime·printf("esi %x\n", SIG_ESI(info, ctxt));
+ runtime·printf("ebp %x\n", SIG_EBP(info, ctxt));
+ runtime·printf("esp %x\n", SIG_ESP(info, ctxt));
+ runtime·printf("eip %x\n", SIG_EIP(info, ctxt));
+ runtime·printf("eflags %x\n", SIG_EFLAGS(info, ctxt));
+ runtime·printf("cs %x\n", SIG_CS(info, ctxt));
+ runtime·printf("fs %x\n", SIG_FS(info, ctxt));
+ runtime·printf("gs %x\n", SIG_GS(info, ctxt));
+}
+
+void
+runtime·sighandler(int32 sig, Siginfo *info, void *ctxt, G *gp)
+{
+ uintptr *sp;
+ SigTab *t;
+ bool crash;
+
+ if(sig == SIGPROF) {
+ if(gp != m->g0 && gp != m->gsignal)
+ runtime·sigprof((byte*)SIG_EIP(info, ctxt), (byte*)SIG_ESP(info, ctxt), nil, gp);
+ return;
+ }
+
+ t = &runtime·sigtab[sig];
+ if(SIG_CODE0(info, ctxt) != SI_USER && (t->flags & SigPanic)) {
+ if(gp == nil || gp == m->g0)
+ goto Throw;
+
+ // 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 = SIG_CODE0(info, ctxt);
+ gp->sigcode1 = SIG_CODE1(info, ctxt);
+ gp->sigpc = SIG_EIP(info, ctxt);
+
+#ifdef GOOS_darwin
+ // Work around Leopard bug that doesn't set FPE_INTDIV.
+ // Look at instruction to see if it is a divide.
+ // Not necessary in Snow Leopard (si_code will be != 0).
+ if(sig == SIGFPE && gp->sigcode0 == 0) {
+ byte *pc;
+ pc = (byte*)gp->sigpc;
+ if(pc[0] == 0x66) // 16-bit instruction prefix
+ pc++;
+ if(pc[0] == 0xF6 || pc[0] == 0xF7)
+ gp->sigcode0 = FPE_INTDIV;
+ }
+#endif
+
+ // Only push runtime·sigpanic if eip != 0.
+ // If eip == 0, probably panicked because of a
+ // call to a nil func. Not pushing that onto sp will
+ // make the trace look like a call to runtime·sigpanic instead.
+ // (Otherwise the trace will end at runtime·sigpanic and we
+ // won't get to see who faulted.)
+ if(SIG_EIP(info, ctxt) != 0) {
+ sp = (uintptr*)SIG_ESP(info, ctxt);
+ *--sp = SIG_EIP(info, ctxt);
+ SIG_ESP(info, ctxt) = (uintptr)sp;
+ }
+ SIG_EIP(info, ctxt) = (uintptr)runtime·sigpanic;
+ return;
+ }
+
+ if(SIG_CODE0(info, ctxt) == SI_USER || (t->flags & SigNotify))
+ if(runtime·sigsend(sig))
+ return;
+ if(t->flags & SigKill)
+ runtime·exit(2);
+ if(!(t->flags & SigThrow))
+ return;
+
+Throw:
+ runtime·startpanic();
+
+ if(sig < 0 || sig >= NSIG)
+ runtime·printf("Signal %d\n", sig);
+ else
+ runtime·printf("%s\n", runtime·sigtab[sig].name);
+
+ runtime·printf("PC=%x\n", SIG_EIP(info, ctxt));
+ if(m->lockedg != nil && m->ncgo > 0 && gp == m->g0) {
+ runtime·printf("signal arrived during cgo execution\n");
+ gp = m->lockedg;
+ }
+ runtime·printf("\n");
+
+ if(runtime·gotraceback(&crash)){
+ runtime·traceback((void*)SIG_EIP(info, ctxt), (void*)SIG_ESP(info, ctxt), 0, gp);
+ runtime·tracebackothers(gp);
+ runtime·dumpregs(info, ctxt);
+ }
+
+ if(crash)
+ runtime·crash();
+
+ runtime·exit(2);
+}
diff --git a/src/pkg/runtime/signal_amd64.c b/src/pkg/runtime/signal_amd64.c
new file mode 100644
index 000000000..ce17bf36d
--- /dev/null
+++ b/src/pkg/runtime/signal_amd64.c
@@ -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 freebsd linux netbsd openbsd
+
+#include "runtime.h"
+#include "defs_GOOS_GOARCH.h"
+#include "os_GOOS.h"
+#include "signal_GOOS_GOARCH.h"
+#include "signals_GOOS.h"
+
+void
+runtime·dumpregs(Siginfo *info, void *ctxt)
+{
+ USED(info);
+ USED(ctxt);
+
+ runtime·printf("rax %X\n", SIG_RAX(info, ctxt));
+ runtime·printf("rbx %X\n", SIG_RBX(info, ctxt));
+ runtime·printf("rcx %X\n", SIG_RCX(info, ctxt));
+ runtime·printf("rdx %X\n", SIG_RDX(info, ctxt));
+ runtime·printf("rdi %X\n", SIG_RDI(info, ctxt));
+ runtime·printf("rsi %X\n", SIG_RSI(info, ctxt));
+ runtime·printf("rbp %X\n", SIG_RBP(info, ctxt));
+ runtime·printf("rsp %X\n", SIG_RSP(info, ctxt));
+ runtime·printf("r8 %X\n", SIG_R8(info, ctxt) );
+ runtime·printf("r9 %X\n", SIG_R9(info, ctxt) );
+ runtime·printf("r10 %X\n", SIG_R10(info, ctxt));
+ runtime·printf("r11 %X\n", SIG_R11(info, ctxt));
+ runtime·printf("r12 %X\n", SIG_R12(info, ctxt));
+ runtime·printf("r13 %X\n", SIG_R13(info, ctxt));
+ runtime·printf("r14 %X\n", SIG_R14(info, ctxt));
+ runtime·printf("r15 %X\n", SIG_R15(info, ctxt));
+ runtime·printf("rip %X\n", SIG_RIP(info, ctxt));
+ runtime·printf("rflags %X\n", SIG_RFLAGS(info, ctxt));
+ runtime·printf("cs %X\n", SIG_CS(info, ctxt));
+ runtime·printf("fs %X\n", SIG_FS(info, ctxt));
+ runtime·printf("gs %X\n", SIG_GS(info, ctxt));
+}
+
+void
+runtime·sighandler(int32 sig, Siginfo *info, void *ctxt, G *gp)
+{
+ uintptr *sp;
+ SigTab *t;
+ bool crash;
+
+ if(sig == SIGPROF) {
+ if(gp != m->g0 && gp != m->gsignal)
+ runtime·sigprof((byte*)SIG_RIP(info, ctxt), (byte*)SIG_RSP(info, ctxt), nil, gp);
+ return;
+ }
+
+ t = &runtime·sigtab[sig];
+ if(SIG_CODE0(info, ctxt) != SI_USER && (t->flags & SigPanic)) {
+ if(gp == nil || gp == m->g0)
+ goto Throw;
+
+ // 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 = SIG_CODE0(info, ctxt);
+ gp->sigcode1 = SIG_CODE1(info, ctxt);
+ gp->sigpc = SIG_RIP(info, ctxt);
+
+#ifdef GOOS_darwin
+ // Work around Leopard bug that doesn't set FPE_INTDIV.
+ // Look at instruction to see if it is a divide.
+ // Not necessary in Snow Leopard (si_code will be != 0).
+ if(sig == SIGFPE && gp->sigcode0 == 0) {
+ byte *pc;
+ pc = (byte*)gp->sigpc;
+ if((pc[0]&0xF0) == 0x40) // 64-bit REX prefix
+ pc++;
+ else if(pc[0] == 0x66) // 16-bit instruction prefix
+ pc++;
+ if(pc[0] == 0xF6 || pc[0] == 0xF7)
+ gp->sigcode0 = FPE_INTDIV;
+ }
+#endif
+
+ // Only push runtime·sigpanic if rip != 0.
+ // If rip == 0, probably panicked because of a
+ // call to a nil func. Not pushing that onto sp will
+ // make the trace look like a call to runtime·sigpanic instead.
+ // (Otherwise the trace will end at runtime·sigpanic and we
+ // won't get to see who faulted.)
+ if(SIG_RIP(info, ctxt) != 0) {
+ sp = (uintptr*)SIG_RSP(info, ctxt);
+ *--sp = SIG_RIP(info, ctxt);
+ SIG_RSP(info, ctxt) = (uintptr)sp;
+ }
+ SIG_RIP(info, ctxt) = (uintptr)runtime·sigpanic;
+ return;
+ }
+
+ if(SIG_CODE0(info, ctxt) == SI_USER || (t->flags & SigNotify))
+ if(runtime·sigsend(sig))
+ return;
+ if(t->flags & SigKill)
+ runtime·exit(2);
+ if(!(t->flags & SigThrow))
+ return;
+
+Throw:
+ runtime·startpanic();
+
+ if(sig < 0 || sig >= NSIG)
+ runtime·printf("Signal %d\n", sig);
+ else
+ runtime·printf("%s\n", runtime·sigtab[sig].name);
+
+ runtime·printf("PC=%X\n", SIG_RIP(info, ctxt));
+ if(m->lockedg != nil && m->ncgo > 0 && gp == m->g0) {
+ runtime·printf("signal arrived during cgo execution\n");
+ gp = m->lockedg;
+ }
+ runtime·printf("\n");
+
+ if(runtime·gotraceback(&crash)){
+ runtime·traceback((void*)SIG_RIP(info, ctxt), (void*)SIG_RSP(info, ctxt), 0, gp);
+ runtime·tracebackothers(gp);
+ runtime·dumpregs(info, ctxt);
+ }
+
+ if(crash)
+ runtime·crash();
+
+ runtime·exit(2);
+}
diff --git a/src/pkg/runtime/signal_arm.c b/src/pkg/runtime/signal_arm.c
new file mode 100644
index 000000000..adf61de6b
--- /dev/null
+++ b/src/pkg/runtime/signal_arm.c
@@ -0,0 +1,124 @@
+// 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 freebsd linux netbsd openbsd
+
+#include "runtime.h"
+#include "defs_GOOS_GOARCH.h"
+#include "os_GOOS.h"
+#include "signal_GOOS_GOARCH.h"
+#include "signals_GOOS.h"
+
+void
+runtime·dumpregs(Siginfo *info, void *ctxt)
+{
+ USED(info);
+ USED(ctxt);
+
+ runtime·printf("trap %x\n", SIG_TRAP(info, ctxt));
+ runtime·printf("error %x\n", SIG_ERROR(info, ctxt));
+ runtime·printf("oldmask %x\n", SIG_OLDMASK(info, ctxt));
+ runtime·printf("r0 %x\n", SIG_R0(info, ctxt));
+ runtime·printf("r1 %x\n", SIG_R1(info, ctxt));
+ runtime·printf("r2 %x\n", SIG_R2(info, ctxt));
+ runtime·printf("r3 %x\n", SIG_R3(info, ctxt));
+ runtime·printf("r4 %x\n", SIG_R4(info, ctxt));
+ runtime·printf("r5 %x\n", SIG_R5(info, ctxt));
+ runtime·printf("r6 %x\n", SIG_R6(info, ctxt));
+ runtime·printf("r7 %x\n", SIG_R7(info, ctxt));
+ runtime·printf("r8 %x\n", SIG_R8(info, ctxt));
+ runtime·printf("r9 %x\n", SIG_R9(info, ctxt));
+ runtime·printf("r10 %x\n", SIG_R10(info, ctxt));
+ runtime·printf("fp %x\n", SIG_FP(info, ctxt));
+ runtime·printf("ip %x\n", SIG_IP(info, ctxt));
+ runtime·printf("sp %x\n", SIG_SP(info, ctxt));
+ runtime·printf("lr %x\n", SIG_LR(info, ctxt));
+ runtime·printf("pc %x\n", SIG_PC(info, ctxt));
+ runtime·printf("cpsr %x\n", SIG_CPSR(info, ctxt));
+ runtime·printf("fault %x\n", SIG_FAULT(info, ctxt));
+}
+
+void
+runtime·sighandler(int32 sig, Siginfo *info, void *ctxt, G *gp)
+{
+ SigTab *t;
+ bool crash;
+
+ if(sig == SIGPROF) {
+ if(gp != m->g0 && gp != m->gsignal)
+ runtime·sigprof((uint8*)SIG_PC(info, ctxt), (uint8*)SIG_SP(info, ctxt), (uint8*)SIG_LR(info, ctxt), gp);
+ return;
+ }
+
+ t = &runtime·sigtab[sig];
+ if(SIG_CODE0(info, ctxt) != SI_USER && (t->flags & SigPanic)) {
+ if(gp == nil || gp == m->g0)
+ goto Throw;
+
+ // 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 = SIG_CODE0(info, ctxt);
+ gp->sigcode1 = SIG_FAULT(info, ctxt);
+ gp->sigpc = SIG_PC(info, ctxt);
+
+ // We arrange lr, and pc to pretend the panicking
+ // function calls sigpanic directly.
+ // Always save LR to stack so that panics in leaf
+ // functions are correctly handled. This smashes
+ // the stack frame but we're not going back there
+ // anyway.
+ SIG_SP(info, ctxt) -= 4;
+ *(uint32*)SIG_SP(info, ctxt) = SIG_LR(info, ctxt);
+ // 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(gp->sigpc != 0)
+ SIG_LR(info, ctxt) = gp->sigpc;
+ // In case we are panicking from external C code
+ SIG_R10(info, ctxt) = (uintptr)gp;
+ SIG_R9(info, ctxt) = (uintptr)m;
+ SIG_PC(info, ctxt) = (uintptr)runtime·sigpanic;
+ return;
+ }
+
+ if(SIG_CODE0(info, ctxt) == SI_USER || (t->flags & SigNotify))
+ if(runtime·sigsend(sig))
+ return;
+ if(t->flags & SigKill)
+ runtime·exit(2);
+ if(!(t->flags & SigThrow))
+ return;
+
+Throw:
+ if(runtime·panicking) // traceback already printed
+ runtime·exit(2);
+ runtime·panicking = 1;
+
+ if(sig < 0 || sig >= NSIG)
+ runtime·printf("Signal %d\n", sig);
+ else
+ runtime·printf("%s\n", runtime·sigtab[sig].name);
+
+ runtime·printf("PC=%x\n", SIG_PC(info, ctxt));
+ if(m->lockedg != nil && m->ncgo > 0 && gp == m->g0) {
+ runtime·printf("signal arrived during cgo execution\n");
+ gp = m->lockedg;
+ }
+ runtime·printf("\n");
+
+ if(runtime·gotraceback(&crash)){
+ runtime·traceback((void*)SIG_PC(info, ctxt), (void*)SIG_SP(info, ctxt), (void*)SIG_LR(info, ctxt), gp);
+ runtime·tracebackothers(gp);
+ runtime·printf("\n");
+ runtime·dumpregs(info, ctxt);
+ }
+
+ if(crash)
+ runtime·crash();
+
+ runtime·exit(2);
+}
diff --git a/src/pkg/runtime/signal_darwin_386.c b/src/pkg/runtime/signal_darwin_386.c
deleted file mode 100644
index 132ca931b..000000000
--- a/src/pkg/runtime/signal_darwin_386.c
+++ /dev/null
@@ -1,155 +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 "runtime.h"
-#include "defs_GOOS_GOARCH.h"
-#include "os_GOOS.h"
-#include "signals_GOOS.h"
-
-void
-runtime·dumpregs(Regs32 *r)
-{
- runtime·printf("eax %x\n", r->eax);
- runtime·printf("ebx %x\n", r->ebx);
- runtime·printf("ecx %x\n", r->ecx);
- runtime·printf("edx %x\n", r->edx);
- runtime·printf("edi %x\n", r->edi);
- runtime·printf("esi %x\n", r->esi);
- runtime·printf("ebp %x\n", r->ebp);
- runtime·printf("esp %x\n", r->esp);
- runtime·printf("eip %x\n", r->eip);
- runtime·printf("eflags %x\n", r->eflags);
- runtime·printf("cs %x\n", r->cs);
- runtime·printf("fs %x\n", r->fs);
- runtime·printf("gs %x\n", r->gs);
-}
-
-void
-runtime·sighandler(int32 sig, Siginfo *info, void *context, G *gp)
-{
- Ucontext *uc;
- Mcontext32 *mc;
- Regs32 *r;
- uintptr *sp;
- byte *pc;
- SigTab *t;
-
- uc = context;
- mc = uc->uc_mcontext;
- r = &mc->ss;
-
- if(sig == SIGPROF) {
- if(gp != m->g0 && gp != m->gsignal)
- runtime·sigprof((uint8*)r->eip, (uint8*)r->esp, nil, gp);
- return;
- }
-
- t = &runtime·sigtab[sig];
- if(info->si_code != SI_USER && (t->flags & SigPanic)) {
- if(gp == nil || gp == m->g0)
- goto Throw;
- // Work around Leopard bug that doesn't set FPE_INTDIV.
- // Look at instruction to see if it is a divide.
- // Not necessary in Snow Leopard (si_code will be != 0).
- if(sig == SIGFPE && info->si_code == 0) {
- pc = (byte*)r->eip;
- if(pc[0] == 0x66) // 16-bit instruction prefix
- pc++;
- if(pc[0] == 0xF6 || pc[0] == 0xF7)
- info->si_code = FPE_INTDIV;
- }
-
- // 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 = info->si_code;
- gp->sigcode1 = (uintptr)info->si_addr;
- gp->sigpc = r->eip;
-
- // Only push runtime·sigpanic if r->eip != 0.
- // If r->eip == 0, probably panicked because of a
- // call to a nil func. Not pushing that onto sp will
- // make the trace look like a call to runtime·sigpanic instead.
- // (Otherwise the trace will end at runtime·sigpanic and we
- // won't get to see who faulted.)
- if(r->eip != 0) {
- sp = (uintptr*)r->esp;
- *--sp = r->eip;
- r->esp = (uintptr)sp;
- }
- r->eip = (uintptr)runtime·sigpanic;
- return;
- }
-
- if(info->si_code == SI_USER || (t->flags & SigNotify))
- if(runtime·sigsend(sig))
- return;
- if(t->flags & SigKill)
- runtime·exit(2);
- if(!(t->flags & SigThrow))
- return;
-
-Throw:
- runtime·startpanic();
-
- if(sig < 0 || sig >= NSIG){
- runtime·printf("Signal %d\n", sig);
- }else{
- runtime·printf("%s\n", runtime·sigtab[sig].name);
- }
-
- runtime·printf("PC=%x\n", r->eip);
- if(m->lockedg != nil && m->ncgo > 0 && gp == m->g0) {
- runtime·printf("signal arrived during cgo execution\n");
- gp = m->lockedg;
- }
- runtime·printf("\n");
-
- if(runtime·gotraceback()){
- runtime·traceback((void*)r->eip, (void*)r->esp, 0, gp);
- runtime·tracebackothers(gp);
- runtime·dumpregs(r);
- }
-
- runtime·exit(2);
-}
-
-void
-runtime·signalstack(byte *p, int32 n)
-{
- StackT st;
-
- st.ss_sp = p;
- st.ss_size = n;
- st.ss_flags = 0;
- if(p == nil)
- st.ss_flags = SS_DISABLE;
- runtime·sigaltstack(&st, nil);
-}
-
-void
-runtime·setsig(int32 i, void (*fn)(int32, Siginfo*, void*, G*), bool restart)
-{
- Sigaction sa;
-
- // If SIGHUP handler is SIG_IGN, assume running
- // under nohup and do not set explicit handler.
- if(i == SIGHUP) {
- runtime·memclr((byte*)&sa, sizeof sa);
- runtime·sigaction(i, nil, &sa);
- if(*(void**)sa.__sigaction_u == SIG_IGN)
- return;
- }
-
- runtime·memclr((byte*)&sa, sizeof sa);
- sa.sa_flags = SA_SIGINFO|SA_ONSTACK;
- if(restart)
- sa.sa_flags |= SA_RESTART;
- sa.sa_mask = ~0U;
- sa.sa_tramp = (void*)runtime·sigtramp; // runtime·sigtramp's job is to call into real handler
- *(uintptr*)sa.__sigaction_u = (uintptr)fn;
- runtime·sigaction(i, &sa, nil);
-}
diff --git a/src/pkg/runtime/signal_darwin_386.h b/src/pkg/runtime/signal_darwin_386.h
new file mode 100644
index 000000000..5459e10a1
--- /dev/null
+++ b/src/pkg/runtime/signal_darwin_386.h
@@ -0,0 +1,23 @@
+// 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.
+
+#define SIG_REGS(ctxt) (((Ucontext*)(ctxt))->uc_mcontext->ss)
+
+#define SIG_EAX(info, ctxt) (SIG_REGS(ctxt).eax)
+#define SIG_EBX(info, ctxt) (SIG_REGS(ctxt).ebx)
+#define SIG_ECX(info, ctxt) (SIG_REGS(ctxt).ecx)
+#define SIG_EDX(info, ctxt) (SIG_REGS(ctxt).edx)
+#define SIG_EDI(info, ctxt) (SIG_REGS(ctxt).edi)
+#define SIG_ESI(info, ctxt) (SIG_REGS(ctxt).esi)
+#define SIG_EBP(info, ctxt) (SIG_REGS(ctxt).ebp)
+#define SIG_ESP(info, ctxt) (SIG_REGS(ctxt).esp)
+#define SIG_EIP(info, ctxt) (SIG_REGS(ctxt).eip)
+#define SIG_EFLAGS(info, ctxt) (SIG_REGS(ctxt).eflags)
+
+#define SIG_CS(info, ctxt) (SIG_REGS(ctxt).cs)
+#define SIG_FS(info, ctxt) (SIG_REGS(ctxt).fs)
+#define SIG_GS(info, ctxt) (SIG_REGS(ctxt).gs)
+
+#define SIG_CODE0(info, ctxt) ((info)->si_code)
+#define SIG_CODE1(info, ctxt) ((uintptr)(info)->si_addr)
diff --git a/src/pkg/runtime/signal_darwin_amd64.c b/src/pkg/runtime/signal_darwin_amd64.c
deleted file mode 100644
index 4b7256bf4..000000000
--- a/src/pkg/runtime/signal_darwin_amd64.c
+++ /dev/null
@@ -1,165 +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 "runtime.h"
-#include "defs_GOOS_GOARCH.h"
-#include "os_GOOS.h"
-#include "signals_GOOS.h"
-
-void
-runtime·dumpregs(Regs64 *r)
-{
- runtime·printf("rax %X\n", r->rax);
- runtime·printf("rbx %X\n", r->rbx);
- runtime·printf("rcx %X\n", r->rcx);
- runtime·printf("rdx %X\n", r->rdx);
- runtime·printf("rdi %X\n", r->rdi);
- runtime·printf("rsi %X\n", r->rsi);
- runtime·printf("rbp %X\n", r->rbp);
- runtime·printf("rsp %X\n", r->rsp);
- runtime·printf("r8 %X\n", r->r8 );
- runtime·printf("r9 %X\n", r->r9 );
- runtime·printf("r10 %X\n", r->r10);
- runtime·printf("r11 %X\n", r->r11);
- runtime·printf("r12 %X\n", r->r12);
- runtime·printf("r13 %X\n", r->r13);
- runtime·printf("r14 %X\n", r->r14);
- runtime·printf("r15 %X\n", r->r15);
- runtime·printf("rip %X\n", r->rip);
- runtime·printf("rflags %X\n", r->rflags);
- runtime·printf("cs %X\n", r->cs);
- runtime·printf("fs %X\n", r->fs);
- runtime·printf("gs %X\n", r->gs);
-}
-
-void
-runtime·sighandler(int32 sig, Siginfo *info, void *context, G *gp)
-{
- Ucontext *uc;
- Mcontext64 *mc;
- Regs64 *r;
- uintptr *sp;
- byte *pc;
- SigTab *t;
-
- uc = context;
- mc = uc->uc_mcontext;
- r = &mc->ss;
-
- if(sig == SIGPROF) {
- if(gp != m->g0 && gp != m->gsignal)
- runtime·sigprof((uint8*)r->rip, (uint8*)r->rsp, nil, gp);
- return;
- }
-
- t = &runtime·sigtab[sig];
- if(info->si_code != SI_USER && (t->flags & SigPanic)) {
- if(gp == nil || gp == m->g0)
- goto Throw;
- // Work around Leopard bug that doesn't set FPE_INTDIV.
- // Look at instruction to see if it is a divide.
- // Not necessary in Snow Leopard (si_code will be != 0).
- if(sig == SIGFPE && info->si_code == 0) {
- pc = (byte*)r->rip;
- if((pc[0]&0xF0) == 0x40) // 64-bit REX prefix
- pc++;
- else if(pc[0] == 0x66) // 16-bit instruction prefix
- pc++;
- if(pc[0] == 0xF6 || pc[0] == 0xF7)
- info->si_code = FPE_INTDIV;
- }
-
- // 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 = info->si_code;
- gp->sigcode1 = (uintptr)info->si_addr;
- gp->sigpc = r->rip;
-
- // Only push runtime·sigpanic if r->rip != 0.
- // If r->rip == 0, probably panicked because of a
- // call to a nil func. Not pushing that onto sp will
- // make the trace look like a call to runtime·sigpanic instead.
- // (Otherwise the trace will end at runtime·sigpanic and we
- // won't get to see who faulted.)
- if(r->rip != 0) {
- sp = (uintptr*)r->rsp;
- *--sp = r->rip;
- r->rsp = (uintptr)sp;
- }
- r->rip = (uintptr)runtime·sigpanic;
- return;
- }
-
- if(info->si_code == SI_USER || (t->flags & SigNotify))
- if(runtime·sigsend(sig))
- return;
- if(t->flags & SigKill)
- runtime·exit(2);
- if(!(t->flags & SigThrow))
- return;
-
-Throw:
- runtime·startpanic();
-
- if(sig < 0 || sig >= NSIG){
- runtime·printf("Signal %d\n", sig);
- }else{
- runtime·printf("%s\n", runtime·sigtab[sig].name);
- }
-
- runtime·printf("PC=%X\n", r->rip);
- if(m->lockedg != nil && m->ncgo > 0 && gp == m->g0) {
- runtime·printf("signal arrived during cgo execution\n");
- gp = m->lockedg;
- }
- runtime·printf("\n");
-
- if(runtime·gotraceback()){
- runtime·traceback((void*)r->rip, (void*)r->rsp, 0, gp);
- runtime·tracebackothers(gp);
- runtime·dumpregs(r);
- }
-
- runtime·exit(2);
-}
-
-void
-runtime·signalstack(byte *p, int32 n)
-{
- StackT st;
-
- st.ss_sp = p;
- st.ss_size = n;
- st.ss_flags = 0;
- if(p == nil)
- st.ss_flags = SS_DISABLE;
- runtime·sigaltstack(&st, nil);
-}
-
-void
-runtime·setsig(int32 i, void (*fn)(int32, Siginfo*, void*, G*), bool restart)
-{
- Sigaction sa;
-
- // If SIGHUP handler is SIG_IGN, assume running
- // under nohup and do not set explicit handler.
- if(i == SIGHUP) {
- runtime·memclr((byte*)&sa, sizeof sa);
- runtime·sigaction(i, nil, &sa);
- if(*(void**)sa.__sigaction_u == SIG_IGN)
- return;
- }
-
- runtime·memclr((byte*)&sa, sizeof sa);
- sa.sa_flags = SA_SIGINFO|SA_ONSTACK;
- if(restart)
- sa.sa_flags |= SA_RESTART;
- sa.sa_mask = ~0ULL;
- sa.sa_tramp = runtime·sigtramp; // runtime·sigtramp's job is to call into real handler
- *(uintptr*)sa.__sigaction_u = (uintptr)fn;
- runtime·sigaction(i, &sa, nil);
-}
diff --git a/src/pkg/runtime/signal_darwin_amd64.h b/src/pkg/runtime/signal_darwin_amd64.h
new file mode 100644
index 000000000..e3da6de3a
--- /dev/null
+++ b/src/pkg/runtime/signal_darwin_amd64.h
@@ -0,0 +1,31 @@
+// 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.
+
+#define SIG_REGS(ctxt) (((Ucontext*)(ctxt))->uc_mcontext->ss)
+
+#define SIG_RAX(info, ctxt) (SIG_REGS(ctxt).rax)
+#define SIG_RBX(info, ctxt) (SIG_REGS(ctxt).rbx)
+#define SIG_RCX(info, ctxt) (SIG_REGS(ctxt).rcx)
+#define SIG_RDX(info, ctxt) (SIG_REGS(ctxt).rdx)
+#define SIG_RDI(info, ctxt) (SIG_REGS(ctxt).rdi)
+#define SIG_RSI(info, ctxt) (SIG_REGS(ctxt).rsi)
+#define SIG_RBP(info, ctxt) (SIG_REGS(ctxt).rbp)
+#define SIG_RSP(info, ctxt) (SIG_REGS(ctxt).rsp)
+#define SIG_R8(info, ctxt) (SIG_REGS(ctxt).r8)
+#define SIG_R9(info, ctxt) (SIG_REGS(ctxt).r9)
+#define SIG_R10(info, ctxt) (SIG_REGS(ctxt).r10)
+#define SIG_R11(info, ctxt) (SIG_REGS(ctxt).r11)
+#define SIG_R12(info, ctxt) (SIG_REGS(ctxt).r12)
+#define SIG_R13(info, ctxt) (SIG_REGS(ctxt).r13)
+#define SIG_R14(info, ctxt) (SIG_REGS(ctxt).r14)
+#define SIG_R15(info, ctxt) (SIG_REGS(ctxt).r15)
+#define SIG_RIP(info, ctxt) (SIG_REGS(ctxt).rip)
+#define SIG_RFLAGS(info, ctxt) (SIG_REGS(ctxt).rflags)
+
+#define SIG_CS(info, ctxt) (SIG_REGS(ctxt).cs)
+#define SIG_FS(info, ctxt) (SIG_REGS(ctxt).fs)
+#define SIG_GS(info, ctxt) (SIG_REGS(ctxt).gs)
+
+#define SIG_CODE0(info, ctxt) ((info)->si_code)
+#define SIG_CODE1(info, ctxt) ((uintptr)(info)->si_addr)
diff --git a/src/pkg/runtime/signal_freebsd_386.c b/src/pkg/runtime/signal_freebsd_386.c
deleted file mode 100644
index 254e5e277..000000000
--- a/src/pkg/runtime/signal_freebsd_386.c
+++ /dev/null
@@ -1,154 +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 "runtime.h"
-#include "defs_GOOS_GOARCH.h"
-#include "signals_GOOS.h"
-#include "os_GOOS.h"
-
-extern void runtime·sigtramp(void);
-
-typedef struct sigaction {
- union {
- void (*__sa_handler)(int32);
- void (*__sa_sigaction)(int32, Siginfo*, void *);
- } __sigaction_u; /* signal handler */
- int32 sa_flags; /* see signal options below */
- Sigset sa_mask; /* signal mask to apply */
-} Sigaction;
-
-void
-runtime·dumpregs(Mcontext *r)
-{
- runtime·printf("eax %x\n", r->mc_eax);
- runtime·printf("ebx %x\n", r->mc_ebx);
- runtime·printf("ecx %x\n", r->mc_ecx);
- runtime·printf("edx %x\n", r->mc_edx);
- runtime·printf("edi %x\n", r->mc_edi);
- runtime·printf("esi %x\n", r->mc_esi);
- runtime·printf("ebp %x\n", r->mc_ebp);
- runtime·printf("esp %x\n", r->mc_esp);
- runtime·printf("eip %x\n", r->mc_eip);
- runtime·printf("eflags %x\n", r->mc_eflags);
- runtime·printf("cs %x\n", r->mc_cs);
- runtime·printf("fs %x\n", r->mc_fs);
- runtime·printf("gs %x\n", r->mc_gs);
-}
-
-void
-runtime·sighandler(int32 sig, Siginfo *info, void *context, G *gp)
-{
- Ucontext *uc;
- Mcontext *r;
- uintptr *sp;
- SigTab *t;
-
- uc = context;
- r = &uc->uc_mcontext;
-
- if(sig == SIGPROF) {
- runtime·sigprof((uint8*)r->mc_eip, (uint8*)r->mc_esp, nil, gp);
- return;
- }
-
- t = &runtime·sigtab[sig];
- if(info->si_code != SI_USER && (t->flags & SigPanic)) {
- if(gp == nil || gp == m->g0)
- goto Throw;
- // 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 = info->si_code;
- gp->sigcode1 = (uintptr)info->si_addr;
- gp->sigpc = r->mc_eip;
-
- // Only push runtime·sigpanic if r->mc_eip != 0.
- // If r->mc_eip == 0, probably panicked because of a
- // call to a nil func. Not pushing that onto sp will
- // make the trace look like a call to runtime·sigpanic instead.
- // (Otherwise the trace will end at runtime·sigpanic and we
- // won't get to see who faulted.)
- if(r->mc_eip != 0) {
- sp = (uintptr*)r->mc_esp;
- *--sp = r->mc_eip;
- r->mc_esp = (uintptr)sp;
- }
- r->mc_eip = (uintptr)runtime·sigpanic;
- return;
- }
-
- if(info->si_code == SI_USER || (t->flags & SigNotify))
- if(runtime·sigsend(sig))
- return;
- if(t->flags & SigKill)
- runtime·exit(2);
- if(!(t->flags & SigThrow))
- return;
-
-Throw:
- runtime·startpanic();
-
- if(sig < 0 || sig >= NSIG)
- runtime·printf("Signal %d\n", sig);
- else
- runtime·printf("%s\n", runtime·sigtab[sig].name);
-
- runtime·printf("PC=%X\n", r->mc_eip);
- if(m->lockedg != nil && m->ncgo > 0 && gp == m->g0) {
- runtime·printf("signal arrived during cgo execution\n");
- gp = m->lockedg;
- }
- runtime·printf("\n");
-
- if(runtime·gotraceback()){
- runtime·traceback((void*)r->mc_eip, (void*)r->mc_esp, 0, gp);
- runtime·tracebackothers(gp);
- runtime·dumpregs(r);
- }
-
- runtime·exit(2);
-}
-
-void
-runtime·signalstack(byte *p, int32 n)
-{
- Sigaltstack st;
-
- st.ss_sp = (int8*)p;
- st.ss_size = n;
- st.ss_flags = 0;
- if(p == nil)
- st.ss_flags = SS_DISABLE;
- runtime·sigaltstack(&st, nil);
-}
-
-void
-runtime·setsig(int32 i, void (*fn)(int32, Siginfo*, void*, G*), bool restart)
-{
- Sigaction sa;
-
- // If SIGHUP handler is SIG_IGN, assume running
- // under nohup and do not set explicit handler.
- if(i == SIGHUP) {
- runtime·memclr((byte*)&sa, sizeof sa);
- runtime·sigaction(i, nil, &sa);
- if(sa.__sigaction_u.__sa_sigaction == SIG_IGN)
- return;
- }
-
- runtime·memclr((byte*)&sa, sizeof sa);
- sa.sa_flags = SA_SIGINFO|SA_ONSTACK;
- if(restart)
- sa.sa_flags |= SA_RESTART;
- sa.sa_mask.__bits[0] = ~(uint32)0;
- sa.sa_mask.__bits[1] = ~(uint32)0;
- sa.sa_mask.__bits[2] = ~(uint32)0;
- sa.sa_mask.__bits[3] = ~(uint32)0;
- if (fn == runtime·sighandler)
- fn = (void*)runtime·sigtramp;
- sa.__sigaction_u.__sa_sigaction = (void*)fn;
- runtime·sigaction(i, &sa, nil);
-}
diff --git a/src/pkg/runtime/signal_freebsd_386.h b/src/pkg/runtime/signal_freebsd_386.h
new file mode 100644
index 000000000..a24f1ee96
--- /dev/null
+++ b/src/pkg/runtime/signal_freebsd_386.h
@@ -0,0 +1,23 @@
+// 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.
+
+#define SIG_REGS(ctxt) (((Ucontext*)(ctxt))->uc_mcontext)
+
+#define SIG_EAX(info, ctxt) (SIG_REGS(ctxt).mc_eax)
+#define SIG_EBX(info, ctxt) (SIG_REGS(ctxt).mc_ebx)
+#define SIG_ECX(info, ctxt) (SIG_REGS(ctxt).mc_ecx)
+#define SIG_EDX(info, ctxt) (SIG_REGS(ctxt).mc_edx)
+#define SIG_EDI(info, ctxt) (SIG_REGS(ctxt).mc_edi)
+#define SIG_ESI(info, ctxt) (SIG_REGS(ctxt).mc_esi)
+#define SIG_EBP(info, ctxt) (SIG_REGS(ctxt).mc_ebp)
+#define SIG_ESP(info, ctxt) (SIG_REGS(ctxt).mc_esp)
+#define SIG_EIP(info, ctxt) (SIG_REGS(ctxt).mc_eip)
+#define SIG_EFLAGS(info, ctxt) (SIG_REGS(ctxt).mc_eflags)
+
+#define SIG_CS(info, ctxt) (SIG_REGS(ctxt).mc_cs)
+#define SIG_FS(info, ctxt) (SIG_REGS(ctxt).mc_fs)
+#define SIG_GS(info, ctxt) (SIG_REGS(ctxt).mc_gs)
+
+#define SIG_CODE0(info, ctxt) ((info)->si_code)
+#define SIG_CODE1(info, ctxt) ((uintptr)(info)->si_addr)
diff --git a/src/pkg/runtime/signal_freebsd_amd64.c b/src/pkg/runtime/signal_freebsd_amd64.c
deleted file mode 100644
index 7dbf36075..000000000
--- a/src/pkg/runtime/signal_freebsd_amd64.c
+++ /dev/null
@@ -1,162 +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 "runtime.h"
-#include "defs_GOOS_GOARCH.h"
-#include "signals_GOOS.h"
-#include "os_GOOS.h"
-
-extern void runtime·sigtramp(void);
-
-typedef struct sigaction {
- union {
- void (*__sa_handler)(int32);
- void (*__sa_sigaction)(int32, Siginfo*, void *);
- } __sigaction_u; /* signal handler */
- int32 sa_flags; /* see signal options below */
- Sigset sa_mask; /* signal mask to apply */
-} Sigaction;
-
-void
-runtime·dumpregs(Mcontext *r)
-{
- runtime·printf("rax %X\n", r->mc_rax);
- runtime·printf("rbx %X\n", r->mc_rbx);
- runtime·printf("rcx %X\n", r->mc_rcx);
- runtime·printf("rdx %X\n", r->mc_rdx);
- runtime·printf("rdi %X\n", r->mc_rdi);
- runtime·printf("rsi %X\n", r->mc_rsi);
- runtime·printf("rbp %X\n", r->mc_rbp);
- runtime·printf("rsp %X\n", r->mc_rsp);
- runtime·printf("r8 %X\n", r->mc_r8 );
- runtime·printf("r9 %X\n", r->mc_r9 );
- runtime·printf("r10 %X\n", r->mc_r10);
- runtime·printf("r11 %X\n", r->mc_r11);
- runtime·printf("r12 %X\n", r->mc_r12);
- runtime·printf("r13 %X\n", r->mc_r13);
- runtime·printf("r14 %X\n", r->mc_r14);
- runtime·printf("r15 %X\n", r->mc_r15);
- runtime·printf("rip %X\n", r->mc_rip);
- runtime·printf("rflags %X\n", r->mc_flags);
- runtime·printf("cs %X\n", r->mc_cs);
- runtime·printf("fs %X\n", r->mc_fs);
- runtime·printf("gs %X\n", r->mc_gs);
-}
-
-void
-runtime·sighandler(int32 sig, Siginfo *info, void *context, G *gp)
-{
- Ucontext *uc;
- Mcontext *r;
- uintptr *sp;
- SigTab *t;
-
- uc = context;
- r = &uc->uc_mcontext;
-
- if(sig == SIGPROF) {
- runtime·sigprof((uint8*)r->mc_rip, (uint8*)r->mc_rsp, nil, gp);
- return;
- }
-
- t = &runtime·sigtab[sig];
- if(info->si_code != SI_USER && (t->flags & SigPanic)) {
- if(gp == nil || gp == m->g0)
- goto Throw;
- // 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 = info->si_code;
- gp->sigcode1 = (uintptr)info->si_addr;
- gp->sigpc = r->mc_rip;
-
- // Only push runtime·sigpanic if r->mc_rip != 0.
- // If r->mc_rip == 0, probably panicked because of a
- // call to a nil func. Not pushing that onto sp will
- // make the trace look like a call to runtime·sigpanic instead.
- // (Otherwise the trace will end at runtime·sigpanic and we
- // won't get to see who faulted.)
- if(r->mc_rip != 0) {
- sp = (uintptr*)r->mc_rsp;
- *--sp = r->mc_rip;
- r->mc_rsp = (uintptr)sp;
- }
- r->mc_rip = (uintptr)runtime·sigpanic;
- return;
- }
-
- if(info->si_code == SI_USER || (t->flags & SigNotify))
- if(runtime·sigsend(sig))
- return;
- if(t->flags & SigKill)
- runtime·exit(2);
- if(!(t->flags & SigThrow))
- return;
-
-Throw:
- runtime·startpanic();
-
- if(sig < 0 || sig >= NSIG)
- runtime·printf("Signal %d\n", sig);
- else
- runtime·printf("%s\n", runtime·sigtab[sig].name);
-
- runtime·printf("PC=%X\n", r->mc_rip);
- if(m->lockedg != nil && m->ncgo > 0 && gp == m->g0) {
- runtime·printf("signal arrived during cgo execution\n");
- gp = m->lockedg;
- }
- runtime·printf("\n");
-
- if(runtime·gotraceback()){
- runtime·traceback((void*)r->mc_rip, (void*)r->mc_rsp, 0, gp);
- runtime·tracebackothers(gp);
- runtime·dumpregs(r);
- }
-
- runtime·exit(2);
-}
-
-void
-runtime·signalstack(byte *p, int32 n)
-{
- Sigaltstack st;
-
- st.ss_sp = (int8*)p;
- st.ss_size = n;
- st.ss_flags = 0;
- if(p == nil)
- st.ss_flags = SS_DISABLE;
- runtime·sigaltstack(&st, nil);
-}
-
-void
-runtime·setsig(int32 i, void (*fn)(int32, Siginfo*, void*, G*), bool restart)
-{
- Sigaction sa;
-
- // If SIGHUP handler is SIG_IGN, assume running
- // under nohup and do not set explicit handler.
- if(i == SIGHUP) {
- runtime·memclr((byte*)&sa, sizeof sa);
- runtime·sigaction(i, nil, &sa);
- if(sa.__sigaction_u.__sa_sigaction == SIG_IGN)
- return;
- }
-
- runtime·memclr((byte*)&sa, sizeof sa);
- sa.sa_flags = SA_SIGINFO|SA_ONSTACK;
- if(restart)
- sa.sa_flags |= SA_RESTART;
- sa.sa_mask.__bits[0] = ~(uint32)0;
- sa.sa_mask.__bits[1] = ~(uint32)0;
- sa.sa_mask.__bits[2] = ~(uint32)0;
- sa.sa_mask.__bits[3] = ~(uint32)0;
- if (fn == runtime·sighandler)
- fn = (void*)runtime·sigtramp;
- sa.__sigaction_u.__sa_sigaction = (void*)fn;
- runtime·sigaction(i, &sa, nil);
-}
diff --git a/src/pkg/runtime/signal_freebsd_amd64.h b/src/pkg/runtime/signal_freebsd_amd64.h
new file mode 100644
index 000000000..7d35b7f85
--- /dev/null
+++ b/src/pkg/runtime/signal_freebsd_amd64.h
@@ -0,0 +1,31 @@
+// 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.
+
+#define SIG_REGS(ctxt) (((Ucontext*)(ctxt))->uc_mcontext)
+
+#define SIG_RAX(info, ctxt) (SIG_REGS(ctxt).mc_rax)
+#define SIG_RBX(info, ctxt) (SIG_REGS(ctxt).mc_rbx)
+#define SIG_RCX(info, ctxt) (SIG_REGS(ctxt).mc_rcx)
+#define SIG_RDX(info, ctxt) (SIG_REGS(ctxt).mc_rdx)
+#define SIG_RDI(info, ctxt) (SIG_REGS(ctxt).mc_rdi)
+#define SIG_RSI(info, ctxt) (SIG_REGS(ctxt).mc_rsi)
+#define SIG_RBP(info, ctxt) (SIG_REGS(ctxt).mc_rbp)
+#define SIG_RSP(info, ctxt) (SIG_REGS(ctxt).mc_rsp)
+#define SIG_R8(info, ctxt) (SIG_REGS(ctxt).mc_r8)
+#define SIG_R9(info, ctxt) (SIG_REGS(ctxt).mc_r9)
+#define SIG_R10(info, ctxt) (SIG_REGS(ctxt).mc_r10)
+#define SIG_R11(info, ctxt) (SIG_REGS(ctxt).mc_r11)
+#define SIG_R12(info, ctxt) (SIG_REGS(ctxt).mc_r12)
+#define SIG_R13(info, ctxt) (SIG_REGS(ctxt).mc_r13)
+#define SIG_R14(info, ctxt) (SIG_REGS(ctxt).mc_r14)
+#define SIG_R15(info, ctxt) (SIG_REGS(ctxt).mc_r15)
+#define SIG_RIP(info, ctxt) (SIG_REGS(ctxt).mc_rip)
+#define SIG_RFLAGS(info, ctxt) (SIG_REGS(ctxt).mc_rflags)
+
+#define SIG_CS(info, ctxt) (SIG_REGS(ctxt).mc_cs)
+#define SIG_FS(info, ctxt) (SIG_REGS(ctxt).mc_fs)
+#define SIG_GS(info, ctxt) (SIG_REGS(ctxt).mc_gs)
+
+#define SIG_CODE0(info, ctxt) ((info)->si_code)
+#define SIG_CODE1(info, ctxt) ((uintptr)(info)->si_addr)
diff --git a/src/pkg/runtime/signal_freebsd_arm.c b/src/pkg/runtime/signal_freebsd_arm.c
deleted file mode 100644
index 50c3221bb..000000000
--- a/src/pkg/runtime/signal_freebsd_arm.c
+++ /dev/null
@@ -1,193 +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.
-
-#include "runtime.h"
-#include "defs_GOOS_GOARCH.h"
-#include "signals_GOOS.h"
-#include "os_GOOS.h"
-
-#define r0 __gregs[0]
-#define r1 __gregs[1]
-#define r2 __gregs[2]
-#define r3 __gregs[3]
-#define r4 __gregs[4]
-#define r5 __gregs[5]
-#define r6 __gregs[6]
-#define r7 __gregs[7]
-#define r8 __gregs[8]
-#define r9 __gregs[9]
-#define r10 __gregs[10]
-#define r11 __gregs[11]
-#define r12 __gregs[12]
-#define r13 __gregs[13]
-#define r14 __gregs[14]
-#define r15 __gregs[15]
-#define cpsr __gregs[16]
-
-void
-runtime·dumpregs(Mcontext *r)
-{
- runtime·printf("r0 %x\n", r->r0);
- runtime·printf("r1 %x\n", r->r1);
- runtime·printf("r2 %x\n", r->r2);
- runtime·printf("r3 %x\n", r->r3);
- runtime·printf("r4 %x\n", r->r4);
- runtime·printf("r5 %x\n", r->r5);
- runtime·printf("r6 %x\n", r->r6);
- runtime·printf("r7 %x\n", r->r7);
- runtime·printf("r8 %x\n", r->r8);
- runtime·printf("r9 %x\n", r->r9);
- runtime·printf("r10 %x\n", r->r10);
- runtime·printf("fp %x\n", r->r11);
- runtime·printf("ip %x\n", r->r12);
- runtime·printf("sp %x\n", r->r13);
- runtime·printf("lr %x\n", r->r14);
- runtime·printf("pc %x\n", r->r15);
- runtime·printf("cpsr %x\n", r->cpsr);
-}
-
-extern void runtime·sigtramp(void);
-
-typedef struct sigaction {
- union {
- void (*__sa_handler)(int32);
- void (*__sa_sigaction)(int32, Siginfo*, void *);
- } __sigaction_u; /* signal handler */
- int32 sa_flags; /* see signal options below */
- Sigset sa_mask; /* signal mask to apply */
-} Sigaction;
-
-void
-runtime·sighandler(int32 sig, Siginfo *info, void *context, G *gp)
-{
- Ucontext *uc;
- Mcontext *r;
- SigTab *t;
-
- uc = context;
- r = &uc->uc_mcontext;
-
- if(sig == SIGPROF) {
- runtime·sigprof((uint8*)r->r15, (uint8*)r->r13, (uint8*)r->r14, gp);
- return;
- }
-
- t = &runtime·sigtab[sig];
- if(info->si_code != SI_USER && (t->flags & SigPanic)) {
- if(gp == nil || gp == m->g0)
- goto Throw;
- // 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 = info->si_code;
- gp->sigcode1 = (uintptr)info->si_addr;
- gp->sigpc = r->r15;
-
- // Only push runtime·sigpanic if r->mc_rip != 0.
- // If r->mc_rip == 0, probably panicked because of a
- // call to a nil func. Not pushing that onto sp will
- // make the trace look like a call to runtime·sigpanic instead.
- // (Otherwise the trace will end at runtime·sigpanic and we
- // won't get to see who faulted.)
- if(r->r15 != 0)
- r->r14 = r->r15;
- // In case we are panicking from external C code
- r->r10 = (uintptr)gp;
- r->r9 = (uintptr)m;
- r->r15 = (uintptr)runtime·sigpanic;
- return;
- }
-
- if(info->si_code == SI_USER || (t->flags & SigNotify))
- if(runtime·sigsend(sig))
- return;
- if(t->flags & SigKill)
- runtime·exit(2);
- if(!(t->flags & SigThrow))
- return;
-
-Throw:
- runtime·startpanic();
-
- if(sig < 0 || sig >= NSIG)
- runtime·printf("Signal %d\n", sig);
- else
- runtime·printf("%s\n", runtime·sigtab[sig].name);
-
- runtime·printf("PC=%x\n", r->r15);
- if(m->lockedg != nil && m->ncgo > 0 && gp == m->g0) {
- runtime·printf("signal arrived during cgo execution\n");
- gp = m->lockedg;
- }
- runtime·printf("\n");
-
- if(runtime·gotraceback()){
- runtime·traceback((void*)r->r15, (void*)r->r13, (void*)r->r14, gp);
- runtime·tracebackothers(gp);
- runtime·printf("\n");
- runtime·dumpregs(r);
- }
-
-// breakpoint();
- runtime·exit(2);
-}
-
-void
-runtime·signalstack(byte *p, int32 n)
-{
- Sigaltstack st;
-
- st.ss_sp = (uint8*)p;
- st.ss_size = n;
- st.ss_flags = 0;
- if(p == nil)
- st.ss_flags = SS_DISABLE;
- runtime·sigaltstack(&st, nil);
-}
-
-void
-runtime·setsig(int32 i, void (*fn)(int32, Siginfo*, void*, G*), bool restart)
-{
- Sigaction sa;
-
- // If SIGHUP handler is SIG_IGN, assume running
- // under nohup and do not set explicit handler.
- if(i == SIGHUP) {
- runtime·memclr((byte*)&sa, sizeof sa);
- runtime·sigaction(i, nil, &sa);
- if(sa.__sigaction_u.__sa_sigaction == SIG_IGN)
- return;
- }
-
- runtime·memclr((byte*)&sa, sizeof sa);
- sa.sa_flags = SA_SIGINFO|SA_ONSTACK;
- if(restart)
- sa.sa_flags |= SA_RESTART;
- sa.sa_mask.__bits[0] = ~(uint32)0;
- sa.sa_mask.__bits[1] = ~(uint32)0;
- sa.sa_mask.__bits[2] = ~(uint32)0;
- sa.sa_mask.__bits[3] = ~(uint32)0;
- if (fn == runtime·sighandler)
- fn = (void*)runtime·sigtramp;
- sa.__sigaction_u.__sa_sigaction = (void*)fn;
- runtime·sigaction(i, &sa, nil);
-}
-
-void
-runtime·checkgoarm(void)
-{
- // TODO(minux)
-}
-
-#pragma textflag 7
-int64
-runtime·cputicks(void)
-{
- // Currently cputicks() is used in blocking profiler and to seed runtime·fastrand1().
- // runtime·nanotime() is a poor approximation of CPU ticks that is enough for the profiler.
- // TODO: need more entropy to better seed fastrand1.
- return runtime·nanotime();
-}
diff --git a/src/pkg/runtime/signal_freebsd_arm.h b/src/pkg/runtime/signal_freebsd_arm.h
new file mode 100644
index 000000000..87a45aa27
--- /dev/null
+++ b/src/pkg/runtime/signal_freebsd_arm.h
@@ -0,0 +1,28 @@
+// 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.
+
+#define SIG_REGS(ctxt) (((Ucontext*)(ctxt))->uc_mcontext)
+
+#define SIG_R0(info, ctxt) (SIG_REGS(ctxt).__gregs[0])
+#define SIG_R1(info, ctxt) (SIG_REGS(ctxt).__gregs[1])
+#define SIG_R2(info, ctxt) (SIG_REGS(ctxt).__gregs[2])
+#define SIG_R3(info, ctxt) (SIG_REGS(ctxt).__gregs[3])
+#define SIG_R4(info, ctxt) (SIG_REGS(ctxt).__gregs[4])
+#define SIG_R5(info, ctxt) (SIG_REGS(ctxt).__gregs[5])
+#define SIG_R6(info, ctxt) (SIG_REGS(ctxt).__gregs[6])
+#define SIG_R7(info, ctxt) (SIG_REGS(ctxt).__gregs[7])
+#define SIG_R8(info, ctxt) (SIG_REGS(ctxt).__gregs[8])
+#define SIG_R9(info, ctxt) (SIG_REGS(ctxt).__gregs[9])
+#define SIG_R10(info, ctxt) (SIG_REGS(ctxt).__gregs[10])
+#define SIG_FP(info, ctxt) (SIG_REGS(ctxt).__gregs[11])
+#define SIG_IP(info, ctxt) (SIG_REGS(ctxt).__gregs[12])
+#define SIG_SP(info, ctxt) (SIG_REGS(ctxt).__gregs[13])
+#define SIG_LR(info, ctxt) (SIG_REGS(ctxt).__gregs[14])
+#define SIG_PC(info, ctxt) (SIG_REGS(ctxt).__gregs[15])
+#define SIG_CPSR(info, ctxt) (SIG_REGS(ctxt).__gregs[16])
+#define SIG_FAULT(info, ctxt) ((uintptr)(info)->si_addr)
+#define SIG_TRAP(info, ctxt) (0)
+#define SIG_ERROR(info, ctxt) (0)
+#define SIG_OLDMASK(info, ctxt) (0)
+#define SIG_CODE0(info, ctxt) ((uintptr)(info)->si_code)
diff --git a/src/pkg/runtime/signal_linux_386.c b/src/pkg/runtime/signal_linux_386.c
deleted file mode 100644
index 9b45ec3bd..000000000
--- a/src/pkg/runtime/signal_linux_386.c
+++ /dev/null
@@ -1,175 +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 "runtime.h"
-#include "defs_GOOS_GOARCH.h"
-#include "signals_GOOS.h"
-#include "os_GOOS.h"
-
-void
-runtime·dumpregs(Sigcontext *r)
-{
- runtime·printf("eax %x\n", r->eax);
- runtime·printf("ebx %x\n", r->ebx);
- runtime·printf("ecx %x\n", r->ecx);
- runtime·printf("edx %x\n", r->edx);
- runtime·printf("edi %x\n", r->edi);
- runtime·printf("esi %x\n", r->esi);
- runtime·printf("ebp %x\n", r->ebp);
- runtime·printf("esp %x\n", r->esp);
- runtime·printf("eip %x\n", r->eip);
- runtime·printf("eflags %x\n", r->eflags);
- runtime·printf("cs %x\n", r->cs);
- runtime·printf("fs %x\n", r->fs);
- runtime·printf("gs %x\n", r->gs);
-}
-
-/*
- * This assembler routine takes the args from registers, puts them on the stack,
- * and calls sighandler().
- */
-extern void runtime·sigtramp(void);
-extern void runtime·sigreturn(void); // calls runtime·sigreturn
-
-void
-runtime·sighandler(int32 sig, Siginfo *info, void *context, G *gp)
-{
- Ucontext *uc;
- Sigcontext *r;
- uintptr *sp;
- SigTab *t;
-
- uc = context;
- r = &uc->uc_mcontext;
-
- if(sig == SIGPROF) {
- runtime·sigprof((uint8*)r->eip, (uint8*)r->esp, nil, gp);
- return;
- }
-
- t = &runtime·sigtab[sig];
- if(info->si_code != SI_USER && (t->flags & SigPanic)) {
- if(gp == nil || gp == m->g0)
- goto Throw;
- // 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 = info->si_code;
- gp->sigcode1 = ((uintptr*)info)[3];
- gp->sigpc = r->eip;
-
- // Only push runtime·sigpanic if r->eip != 0.
- // If r->eip == 0, probably panicked because of a
- // call to a nil func. Not pushing that onto sp will
- // make the trace look like a call to runtime·sigpanic instead.
- // (Otherwise the trace will end at runtime·sigpanic and we
- // won't get to see who faulted.)
- if(r->eip != 0) {
- sp = (uintptr*)r->esp;
- *--sp = r->eip;
- r->esp = (uintptr)sp;
- }
- r->eip = (uintptr)runtime·sigpanic;
- return;
- }
-
- if(info->si_code == SI_USER || (t->flags & SigNotify))
- if(runtime·sigsend(sig))
- return;
- if(t->flags & SigKill)
- runtime·exit(2);
- if(!(t->flags & SigThrow))
- return;
-
-Throw:
- runtime·startpanic();
-
- if(sig < 0 || sig >= NSIG)
- runtime·printf("Signal %d\n", sig);
- else
- runtime·printf("%s\n", runtime·sigtab[sig].name);
-
- runtime·printf("PC=%X\n", r->eip);
- if(m->lockedg != nil && m->ncgo > 0 && gp == m->g0) {
- runtime·printf("signal arrived during cgo execution\n");
- gp = m->lockedg;
- }
- runtime·printf("\n");
-
- if(runtime·gotraceback()){
- runtime·traceback((void*)r->eip, (void*)r->esp, 0, gp);
- runtime·tracebackothers(gp);
- runtime·dumpregs(r);
- }
-
- runtime·exit(2);
-}
-
-void
-runtime·signalstack(byte *p, int32 n)
-{
- Sigaltstack st;
-
- st.ss_sp = p;
- st.ss_size = n;
- st.ss_flags = 0;
- if(p == nil)
- st.ss_flags = SS_DISABLE;
- runtime·sigaltstack(&st, nil);
-}
-
-void
-runtime·setsig(int32 i, void (*fn)(int32, Siginfo*, void*, G*), bool restart)
-{
- Sigaction sa;
-
- // If SIGHUP handler is SIG_IGN, assume running
- // under nohup and do not set explicit handler.
- if(i == SIGHUP) {
- runtime·memclr((byte*)&sa, sizeof sa);
- if(runtime·rt_sigaction(i, nil, &sa, sizeof(sa.sa_mask)) != 0)
- runtime·throw("rt_sigaction read failure");
- if(sa.k_sa_handler == SIG_IGN)
- return;
- }
-
- runtime·memclr((byte*)&sa, sizeof sa);
- sa.sa_flags = SA_ONSTACK | SA_SIGINFO | SA_RESTORER;
- if(restart)
- sa.sa_flags |= SA_RESTART;
- sa.sa_mask = ~0ULL;
- sa.sa_restorer = (void*)runtime·sigreturn;
- if(fn == runtime·sighandler)
- fn = (void*)runtime·sigtramp;
- sa.k_sa_handler = fn;
- if(runtime·rt_sigaction(i, &sa, nil, sizeof(sa.sa_mask)) != 0)
- runtime·throw("rt_sigaction failure");
-}
-
-#define AT_NULL 0
-#define AT_SYSINFO 32
-extern uint32 runtime·_vdso;
-
-#pragma textflag 7
-void
-runtime·linux_setup_vdso(int32 argc, void *argv_list)
-{
- byte **argv = &argv_list;
- byte **envp;
- uint32 *auxv;
-
- // skip envp to get to ELF auxiliary vector.
- for(envp = &argv[argc+1]; *envp != nil; envp++)
- ;
- envp++;
-
- for(auxv=(uint32*)envp; auxv[0] != AT_NULL; auxv += 2) {
- if(auxv[0] == AT_SYSINFO) {
- runtime·_vdso = auxv[1];
- break;
- }
- }
-}
diff --git a/src/pkg/runtime/signal_linux_386.h b/src/pkg/runtime/signal_linux_386.h
new file mode 100644
index 000000000..f77f1c9d5
--- /dev/null
+++ b/src/pkg/runtime/signal_linux_386.h
@@ -0,0 +1,24 @@
+// 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.
+
+#define SIG_REGS(ctxt) (*((Sigcontext*)&((Ucontext*)(ctxt))->uc_mcontext))
+
+#define SIG_EAX(info, ctxt) (SIG_REGS(ctxt).eax)
+#define SIG_EBX(info, ctxt) (SIG_REGS(ctxt).ebx)
+#define SIG_ECX(info, ctxt) (SIG_REGS(ctxt).ecx)
+#define SIG_EDX(info, ctxt) (SIG_REGS(ctxt).edx)
+#define SIG_EDI(info, ctxt) (SIG_REGS(ctxt).edi)
+#define SIG_ESI(info, ctxt) (SIG_REGS(ctxt).esi)
+#define SIG_EBP(info, ctxt) (SIG_REGS(ctxt).ebp)
+#define SIG_ESP(info, ctxt) (SIG_REGS(ctxt).esp)
+#define SIG_EIP(info, ctxt) (SIG_REGS(ctxt).eip)
+#define SIG_EFLAGS(info, ctxt) (SIG_REGS(ctxt).eflags)
+
+#define SIG_CS(info, ctxt) (SIG_REGS(ctxt).cs)
+#define SIG_FS(info, ctxt) (SIG_REGS(ctxt).fs)
+#define SIG_GS(info, ctxt) (SIG_REGS(ctxt).gs)
+
+#define SIG_CODE0(info, ctxt) ((info)->si_code)
+#define SIG_CODE1(info, ctxt) (((uintptr*)(info))[2])
+
diff --git a/src/pkg/runtime/signal_linux_amd64.c b/src/pkg/runtime/signal_linux_amd64.c
deleted file mode 100644
index c4e39a6ab..000000000
--- a/src/pkg/runtime/signal_linux_amd64.c
+++ /dev/null
@@ -1,162 +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 "runtime.h"
-#include "defs_GOOS_GOARCH.h"
-#include "signals_GOOS.h"
-#include "os_GOOS.h"
-
-void
-runtime·dumpregs(Sigcontext *r)
-{
- runtime·printf("rax %X\n", r->rax);
- runtime·printf("rbx %X\n", r->rbx);
- runtime·printf("rcx %X\n", r->rcx);
- runtime·printf("rdx %X\n", r->rdx);
- runtime·printf("rdi %X\n", r->rdi);
- runtime·printf("rsi %X\n", r->rsi);
- runtime·printf("rbp %X\n", r->rbp);
- runtime·printf("rsp %X\n", r->rsp);
- runtime·printf("r8 %X\n", r->r8 );
- runtime·printf("r9 %X\n", r->r9 );
- runtime·printf("r10 %X\n", r->r10);
- runtime·printf("r11 %X\n", r->r11);
- runtime·printf("r12 %X\n", r->r12);
- runtime·printf("r13 %X\n", r->r13);
- runtime·printf("r14 %X\n", r->r14);
- runtime·printf("r15 %X\n", r->r15);
- runtime·printf("rip %X\n", r->rip);
- runtime·printf("rflags %X\n", r->eflags);
- runtime·printf("cs %X\n", (uint64)r->cs);
- runtime·printf("fs %X\n", (uint64)r->fs);
- runtime·printf("gs %X\n", (uint64)r->gs);
-}
-
-/*
- * This assembler routine takes the args from registers, puts them on the stack,
- * and calls sighandler().
- */
-extern void runtime·sigtramp(void);
-extern void runtime·sigreturn(void); // calls runtime·sigreturn
-
-void
-runtime·sighandler(int32 sig, Siginfo *info, void *context, G *gp)
-{
- Ucontext *uc;
- Mcontext *mc;
- Sigcontext *r;
- uintptr *sp;
- SigTab *t;
-
- uc = context;
- mc = &uc->uc_mcontext;
- r = (Sigcontext*)mc; // same layout, more conveient names
-
- if(sig == SIGPROF) {
- runtime·sigprof((uint8*)r->rip, (uint8*)r->rsp, nil, gp);
- return;
- }
-
- t = &runtime·sigtab[sig];
- if(info->si_code != SI_USER && (t->flags & SigPanic)) {
- if(gp == nil || gp == m->g0)
- goto Throw;
- // 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 = info->si_code;
- gp->sigcode1 = ((uintptr*)info)[2];
- gp->sigpc = r->rip;
-
- // Only push runtime·sigpanic if r->rip != 0.
- // If r->rip == 0, probably panicked because of a
- // call to a nil func. Not pushing that onto sp will
- // make the trace look like a call to runtime·sigpanic instead.
- // (Otherwise the trace will end at runtime·sigpanic and we
- // won't get to see who faulted.)
- if(r->rip != 0) {
- sp = (uintptr*)r->rsp;
- *--sp = r->rip;
- r->rsp = (uintptr)sp;
- }
- r->rip = (uintptr)runtime·sigpanic;
- return;
- }
-
- if(info->si_code == SI_USER || (t->flags & SigNotify))
- if(runtime·sigsend(sig))
- return;
- if(t->flags & SigKill)
- runtime·exit(2);
- if(!(t->flags & SigThrow))
- return;
-
-Throw:
- runtime·startpanic();
-
- if(sig < 0 || sig >= NSIG)
- runtime·printf("Signal %d\n", sig);
- else
- runtime·printf("%s\n", runtime·sigtab[sig].name);
-
- runtime·printf("PC=%X\n", r->rip);
- if(m->lockedg != nil && m->ncgo > 0 && gp == m->g0) {
- runtime·printf("signal arrived during cgo execution\n");
- gp = m->lockedg;
- }
- runtime·printf("\n");
-
- if(runtime·gotraceback()){
- runtime·traceback((void*)r->rip, (void*)r->rsp, 0, gp);
- runtime·tracebackothers(gp);
- runtime·dumpregs(r);
- }
-
- runtime·exit(2);
-}
-
-void
-runtime·signalstack(byte *p, int32 n)
-{
- Sigaltstack st;
-
- st.ss_sp = p;
- st.ss_size = n;
- st.ss_flags = 0;
- if(p == nil)
- st.ss_flags = SS_DISABLE;
- runtime·sigaltstack(&st, nil);
-}
-
-void
-runtime·setsig(int32 i, void (*fn)(int32, Siginfo*, void*, G*), bool restart)
-{
- Sigaction sa;
-
- // If SIGHUP handler is SIG_IGN, assume running
- // under nohup and do not set explicit handler.
- if(i == SIGHUP) {
- runtime·memclr((byte*)&sa, sizeof sa);
- if(runtime·rt_sigaction(i, nil, &sa, sizeof(sa.sa_mask)) != 0)
- runtime·throw("rt_sigaction read failure");
- if(sa.sa_handler == SIG_IGN)
- return;
- }
-
- runtime·memclr((byte*)&sa, sizeof sa);
- sa.sa_flags = SA_ONSTACK | SA_SIGINFO | SA_RESTORER;
- if(restart)
- sa.sa_flags |= SA_RESTART;
- sa.sa_mask = ~0ULL;
- // TODO(adonovan): Linux manpage says "sa_restorer element is
- // obsolete and should not be used". Avoid it here, and test.
- sa.sa_restorer = (void*)runtime·sigreturn;
- if(fn == runtime·sighandler)
- fn = (void*)runtime·sigtramp;
- sa.sa_handler = fn;
- if(runtime·rt_sigaction(i, &sa, nil, sizeof(sa.sa_mask)) != 0)
- runtime·throw("rt_sigaction failure");
-}
diff --git a/src/pkg/runtime/signal_linux_amd64.h b/src/pkg/runtime/signal_linux_amd64.h
new file mode 100644
index 000000000..5a9a3e5da
--- /dev/null
+++ b/src/pkg/runtime/signal_linux_amd64.h
@@ -0,0 +1,32 @@
+// 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.
+
+#define SIG_REGS(ctxt) (*((Sigcontext*)&((Ucontext*)(ctxt))->uc_mcontext))
+
+#define SIG_RAX(info, ctxt) (SIG_REGS(ctxt).rax)
+#define SIG_RBX(info, ctxt) (SIG_REGS(ctxt).rbx)
+#define SIG_RCX(info, ctxt) (SIG_REGS(ctxt).rcx)
+#define SIG_RDX(info, ctxt) (SIG_REGS(ctxt).rdx)
+#define SIG_RDI(info, ctxt) (SIG_REGS(ctxt).rdi)
+#define SIG_RSI(info, ctxt) (SIG_REGS(ctxt).rsi)
+#define SIG_RBP(info, ctxt) (SIG_REGS(ctxt).rbp)
+#define SIG_RSP(info, ctxt) (SIG_REGS(ctxt).rsp)
+#define SIG_R8(info, ctxt) (SIG_REGS(ctxt).r8)
+#define SIG_R9(info, ctxt) (SIG_REGS(ctxt).r9)
+#define SIG_R10(info, ctxt) (SIG_REGS(ctxt).r10)
+#define SIG_R11(info, ctxt) (SIG_REGS(ctxt).r11)
+#define SIG_R12(info, ctxt) (SIG_REGS(ctxt).r12)
+#define SIG_R13(info, ctxt) (SIG_REGS(ctxt).r13)
+#define SIG_R14(info, ctxt) (SIG_REGS(ctxt).r14)
+#define SIG_R15(info, ctxt) (SIG_REGS(ctxt).r15)
+#define SIG_RIP(info, ctxt) (SIG_REGS(ctxt).rip)
+#define SIG_RFLAGS(info, ctxt) ((uint64)SIG_REGS(ctxt).eflags)
+
+#define SIG_CS(info, ctxt) ((uint64)SIG_REGS(ctxt).cs)
+#define SIG_FS(info, ctxt) ((uint64)SIG_REGS(ctxt).fs)
+#define SIG_GS(info, ctxt) ((uint64)SIG_REGS(ctxt).gs)
+
+#define SIG_CODE0(info, ctxt) ((info)->si_code)
+#define SIG_CODE1(info, ctxt) (((uintptr*)(info))[2])
+
diff --git a/src/pkg/runtime/signal_linux_arm.c b/src/pkg/runtime/signal_linux_arm.c
deleted file mode 100644
index c26caa7cd..000000000
--- a/src/pkg/runtime/signal_linux_arm.c
+++ /dev/null
@@ -1,241 +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 "runtime.h"
-#include "defs_GOOS_GOARCH.h"
-#include "signals_GOOS.h"
-#include "os_GOOS.h"
-
-void
-runtime·dumpregs(Sigcontext *r)
-{
- runtime·printf("trap %x\n", r->trap_no);
- runtime·printf("error %x\n", r->error_code);
- runtime·printf("oldmask %x\n", r->oldmask);
- runtime·printf("r0 %x\n", r->arm_r0);
- runtime·printf("r1 %x\n", r->arm_r1);
- runtime·printf("r2 %x\n", r->arm_r2);
- runtime·printf("r3 %x\n", r->arm_r3);
- runtime·printf("r4 %x\n", r->arm_r4);
- runtime·printf("r5 %x\n", r->arm_r5);
- runtime·printf("r6 %x\n", r->arm_r6);
- runtime·printf("r7 %x\n", r->arm_r7);
- runtime·printf("r8 %x\n", r->arm_r8);
- runtime·printf("r9 %x\n", r->arm_r9);
- runtime·printf("r10 %x\n", r->arm_r10);
- runtime·printf("fp %x\n", r->arm_fp);
- runtime·printf("ip %x\n", r->arm_ip);
- runtime·printf("sp %x\n", r->arm_sp);
- runtime·printf("lr %x\n", r->arm_lr);
- runtime·printf("pc %x\n", r->arm_pc);
- runtime·printf("cpsr %x\n", r->arm_cpsr);
- runtime·printf("fault %x\n", r->fault_address);
-}
-
-/*
- * This assembler routine takes the args from registers, puts them on the stack,
- * and calls sighandler().
- */
-extern void runtime·sigtramp(void);
-extern void runtime·sigreturn(void); // calls runtime·sigreturn
-
-void
-runtime·sighandler(int32 sig, Siginfo *info, void *context, G *gp)
-{
- Ucontext *uc;
- Sigcontext *r;
- SigTab *t;
-
- uc = context;
- r = &uc->uc_mcontext;
-
- if(sig == SIGPROF) {
- runtime·sigprof((uint8*)r->arm_pc, (uint8*)r->arm_sp, (uint8*)r->arm_lr, gp);
- return;
- }
-
- t = &runtime·sigtab[sig];
- if(info->si_code != SI_USER && (t->flags & SigPanic)) {
- if(gp == nil || gp == m->g0)
- goto Throw;
- // 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 = info->si_code;
- gp->sigcode1 = r->fault_address;
- gp->sigpc = r->arm_pc;
-
- // We arrange lr, and pc to pretend the panicking
- // function calls sigpanic directly.
- // Always save LR to stack so that panics in leaf
- // functions are correctly handled. This smashes
- // the stack frame but we're not going back there
- // anyway.
- r->arm_sp -= 4;
- *(uint32 *)r->arm_sp = r->arm_lr;
- // 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(r->arm_pc != 0)
- r->arm_lr = r->arm_pc;
- // In case we are panicking from external C code
- r->arm_r10 = (uintptr)gp;
- r->arm_r9 = (uintptr)m;
- r->arm_pc = (uintptr)runtime·sigpanic;
- return;
- }
-
- if(info->si_code == SI_USER || (t->flags & SigNotify))
- if(runtime·sigsend(sig))
- return;
- if(t->flags & SigKill)
- runtime·exit(2);
- if(!(t->flags & SigThrow))
- return;
-
-Throw:
- if(runtime·panicking) // traceback already printed
- runtime·exit(2);
- runtime·panicking = 1;
-
- if(sig < 0 || sig >= NSIG)
- runtime·printf("Signal %d\n", sig);
- else
- runtime·printf("%s\n", runtime·sigtab[sig].name);
-
- runtime·printf("PC=%x\n", r->arm_pc);
- if(m->lockedg != nil && m->ncgo > 0 && gp == m->g0) {
- runtime·printf("signal arrived during cgo execution\n");
- gp = m->lockedg;
- }
- runtime·printf("\n");
-
- if(runtime·gotraceback()){
- runtime·traceback((void*)r->arm_pc, (void*)r->arm_sp, (void*)r->arm_lr, gp);
- runtime·tracebackothers(gp);
- runtime·printf("\n");
- runtime·dumpregs(r);
- }
-
-// breakpoint();
- runtime·exit(2);
-}
-
-void
-runtime·signalstack(byte *p, int32 n)
-{
- Sigaltstack st;
-
- st.ss_sp = p;
- st.ss_size = n;
- st.ss_flags = 0;
- if(p == nil)
- st.ss_flags = SS_DISABLE;
- runtime·sigaltstack(&st, nil);
-}
-
-void
-runtime·setsig(int32 i, void (*fn)(int32, Siginfo*, void*, G*), bool restart)
-{
- Sigaction sa;
-
- // If SIGHUP handler is SIG_IGN, assume running
- // under nohup and do not set explicit handler.
- if(i == SIGHUP) {
- runtime·memclr((byte*)&sa, sizeof sa);
- if(runtime·rt_sigaction(i, nil, &sa, sizeof(sa.sa_mask)) != 0)
- runtime·throw("rt_sigaction read failure");
- if(sa.sa_handler == SIG_IGN)
- return;
- }
-
- runtime·memclr((byte*)&sa, sizeof sa);
- sa.sa_flags = SA_ONSTACK | SA_SIGINFO | SA_RESTORER;
- if(restart)
- sa.sa_flags |= SA_RESTART;
- sa.sa_mask = ~0ULL;
- sa.sa_restorer = (void*)runtime·sigreturn;
- if(fn == runtime·sighandler)
- fn = (void*)runtime·sigtramp;
- sa.sa_handler = fn;
- if(runtime·rt_sigaction(i, &sa, nil, sizeof(sa.sa_mask)) != 0)
- runtime·throw("rt_sigaction failure");
-}
-
-#define AT_NULL 0
-#define AT_PLATFORM 15 // introduced in at least 2.6.11
-#define AT_HWCAP 16 // introduced in at least 2.6.11
-#define AT_RANDOM 25 // introduced in 2.6.29
-#define HWCAP_VFP (1 << 6) // introduced in at least 2.6.11
-#define HWCAP_VFPv3 (1 << 13) // introduced in 2.6.30
-static uint32 runtime·randomNumber;
-uint8 runtime·armArch = 6; // we default to ARMv6
-uint32 runtime·hwcap; // set by setup_auxv
-uint8 runtime·goarm; // set by 5l
-
-void
-runtime·checkgoarm(void)
-{
- if(runtime·goarm > 5 && !(runtime·hwcap & HWCAP_VFP)) {
- runtime·printf("runtime: this CPU has no floating point hardware, so it cannot run\n");
- runtime·printf("this GOARM=%d binary. Recompile using GOARM=5.\n", runtime·goarm);
- runtime·exit(1);
- }
- if(runtime·goarm > 6 && !(runtime·hwcap & HWCAP_VFPv3)) {
- runtime·printf("runtime: this CPU has no VFPv3 floating point hardware, so it cannot run\n");
- runtime·printf("this GOARM=%d binary. Recompile using GOARM=6.\n", runtime·goarm);
- runtime·exit(1);
- }
-}
-
-#pragma textflag 7
-void
-runtime·setup_auxv(int32 argc, void *argv_list)
-{
- byte **argv;
- byte **envp;
- byte *rnd;
- uint32 *auxv;
- uint32 t;
-
- argv = &argv_list;
-
- // skip envp to get to ELF auxiliary vector.
- for(envp = &argv[argc+1]; *envp != nil; envp++)
- ;
- envp++;
-
- for(auxv=(uint32*)envp; auxv[0] != AT_NULL; auxv += 2) {
- switch(auxv[0]) {
- case AT_RANDOM: // kernel provided 16-byte worth of random data
- if(auxv[1]) {
- rnd = (byte*)auxv[1];
- runtime·randomNumber = rnd[4] | rnd[5]<<8 | rnd[6]<<16 | rnd[7]<<24;
- }
- break;
- case AT_PLATFORM: // v5l, v6l, v7l
- if(auxv[1]) {
- t = *(uint8*)(auxv[1]+1);
- if(t >= '5' && t <= '7')
- runtime·armArch = t - '0';
- }
- break;
- case AT_HWCAP: // CPU capability bit flags
- runtime·hwcap = auxv[1];
- break;
- }
- }
-}
-
-#pragma textflag 7
-int64
-runtime·cputicks(void)
-{
- // Currently cputicks() is used in blocking profiler and to seed runtime·fastrand1().
- // runtime·nanotime() is a poor approximation of CPU ticks that is enough for the profiler.
- // runtime·randomNumber provides better seeding of fastrand1.
- return runtime·nanotime() + runtime·randomNumber;
-}
diff --git a/src/pkg/runtime/signal_linux_arm.h b/src/pkg/runtime/signal_linux_arm.h
new file mode 100644
index 000000000..a674c0d57
--- /dev/null
+++ b/src/pkg/runtime/signal_linux_arm.h
@@ -0,0 +1,28 @@
+// 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.
+
+#define SIG_REGS(ctxt) (*((Sigcontext*)&((Ucontext*)(ctxt))->uc_mcontext))
+
+#define SIG_R0(info, ctxt) (SIG_REGS(ctxt).arm_r0)
+#define SIG_R1(info, ctxt) (SIG_REGS(ctxt).arm_r1)
+#define SIG_R2(info, ctxt) (SIG_REGS(ctxt).arm_r2)
+#define SIG_R3(info, ctxt) (SIG_REGS(ctxt).arm_r3)
+#define SIG_R4(info, ctxt) (SIG_REGS(ctxt).arm_r4)
+#define SIG_R5(info, ctxt) (SIG_REGS(ctxt).arm_r5)
+#define SIG_R6(info, ctxt) (SIG_REGS(ctxt).arm_r6)
+#define SIG_R7(info, ctxt) (SIG_REGS(ctxt).arm_r7)
+#define SIG_R8(info, ctxt) (SIG_REGS(ctxt).arm_r8)
+#define SIG_R9(info, ctxt) (SIG_REGS(ctxt).arm_r9)
+#define SIG_R10(info, ctxt) (SIG_REGS(ctxt).arm_r10)
+#define SIG_FP(info, ctxt) (SIG_REGS(ctxt).arm_fp)
+#define SIG_IP(info, ctxt) (SIG_REGS(ctxt).arm_ip)
+#define SIG_SP(info, ctxt) (SIG_REGS(ctxt).arm_sp)
+#define SIG_LR(info, ctxt) (SIG_REGS(ctxt).arm_lr)
+#define SIG_PC(info, ctxt) (SIG_REGS(ctxt).arm_pc)
+#define SIG_CPSR(info, ctxt) (SIG_REGS(ctxt).arm_cpsr)
+#define SIG_FAULT(info, ctxt) (SIG_REGS(ctxt).fault_address)
+#define SIG_TRAP(info, ctxt) (SIG_REGS(ctxt).trap_no)
+#define SIG_ERROR(info, ctxt) (SIG_REGS(ctxt).error_code)
+#define SIG_OLDMASK(info, ctxt) (SIG_REGS(ctxt).oldmask)
+#define SIG_CODE0(info, ctxt) ((uintptr)(info)->si_code)
diff --git a/src/pkg/runtime/signal_netbsd_386.c b/src/pkg/runtime/signal_netbsd_386.c
deleted file mode 100644
index 08744c425..000000000
--- a/src/pkg/runtime/signal_netbsd_386.c
+++ /dev/null
@@ -1,164 +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 "runtime.h"
-#include "defs_GOOS_GOARCH.h"
-#include "signals_GOOS.h"
-#include "os_GOOS.h"
-
-extern void runtime·lwp_tramp(void);
-extern void runtime·sigtramp(void);
-
-typedef struct sigaction {
- union {
- void (*_sa_handler)(int32);
- void (*_sa_sigaction)(int32, Siginfo*, void *);
- } _sa_u; /* signal handler */
- uint32 sa_mask[4]; /* signal mask to apply */
- int32 sa_flags; /* see signal options below */
-} Sigaction;
-
-void
-runtime·dumpregs(McontextT *mc)
-{
- runtime·printf("eax %x\n", mc->__gregs[REG_EAX]);
- runtime·printf("ebx %x\n", mc->__gregs[REG_EBX]);
- runtime·printf("ecx %x\n", mc->__gregs[REG_ECX]);
- runtime·printf("edx %x\n", mc->__gregs[REG_EDX]);
- runtime·printf("edi %x\n", mc->__gregs[REG_EDI]);
- runtime·printf("esi %x\n", mc->__gregs[REG_ESI]);
- runtime·printf("ebp %x\n", mc->__gregs[REG_EBP]);
- runtime·printf("esp %x\n", mc->__gregs[REG_UESP]);
- runtime·printf("eip %x\n", mc->__gregs[REG_EIP]);
- runtime·printf("eflags %x\n", mc->__gregs[REG_EFL]);
- runtime·printf("cs %x\n", mc->__gregs[REG_CS]);
- runtime·printf("fs %x\n", mc->__gregs[REG_FS]);
- runtime·printf("gs %x\n", mc->__gregs[REG_GS]);
-}
-
-void
-runtime·sighandler(int32 sig, Siginfo *info, void *context, G *gp)
-{
- UcontextT *uc = context;
- McontextT *mc = &uc->uc_mcontext;
- uintptr *sp;
- SigTab *t;
-
- if(sig == SIGPROF) {
- runtime·sigprof((uint8*)mc->__gregs[REG_EIP],
- (uint8*)mc->__gregs[REG_UESP], nil, gp);
- return;
- }
-
- t = &runtime·sigtab[sig];
- if(info->_code != SI_USER && (t->flags & SigPanic)) {
- if(gp == nil || gp == m->g0)
- goto Throw;
- // Make it look like a call to the signal func.
- // We need to pass arguments out of band since
- // augmenting the stack frame would break
- // the unwinding code.
- gp->sig = sig;
- gp->sigcode0 = info->_code;
- gp->sigcode1 = *(uintptr*)&info->_reason[0]; /* _addr */
- gp->sigpc = mc->__gregs[REG_EIP];
-
- // Only push runtime·sigpanic if __gregs[REG_EIP] != 0.
- // If __gregs[REG_EIP] == 0, probably panicked because of a
- // call to a nil func. Not pushing that onto sp will make the
- // trace look like a call to runtime·sigpanic instead.
- // (Otherwise the trace will end at runtime·sigpanic
- // and we won't get to see who faulted.)
- if(mc->__gregs[REG_EIP] != 0) {
- sp = (uintptr*)mc->__gregs[REG_UESP];
- *--sp = mc->__gregs[REG_EIP];
- mc->__gregs[REG_UESP] = (uintptr)sp;
- }
- mc->__gregs[REG_EIP] = (uintptr)runtime·sigpanic;
- return;
- }
-
- if(info->_code == SI_USER || (t->flags & SigNotify))
- if(runtime·sigsend(sig))
- return;
- if(t->flags & SigKill)
- runtime·exit(2);
- if(!(t->flags & SigThrow))
- return;
-
-Throw:
- runtime·startpanic();
-
- if(sig < 0 || sig >= NSIG)
- runtime·printf("Signal %d\n", sig);
- else
- runtime·printf("%s\n", runtime·sigtab[sig].name);
-
- runtime·printf("PC=%X\n", mc->__gregs[REG_EIP]);
- if(m->lockedg != nil && m->ncgo > 0 && gp == m->g0) {
- runtime·printf("signal arrived during cgo execution\n");
- gp = m->lockedg;
- }
- runtime·printf("\n");
-
- if(runtime·gotraceback()){
- runtime·traceback((void*)mc->__gregs[REG_EIP],
- (void*)mc->__gregs[REG_UESP], 0, gp);
- runtime·tracebackothers(gp);
- runtime·dumpregs(mc);
- }
-
- runtime·exit(2);
-}
-
-void
-runtime·signalstack(byte *p, int32 n)
-{
- Sigaltstack st;
-
- st.ss_sp = p;
- st.ss_size = n;
- st.ss_flags = 0;
- if(p == nil)
- st.ss_flags = SS_DISABLE;
- runtime·sigaltstack(&st, nil);
-}
-
-void
-runtime·setsig(int32 i, void (*fn)(int32, Siginfo*, void*, G*), bool restart)
-{
- Sigaction sa;
-
- // If SIGHUP handler is SIG_IGN, assume running
- // under nohup and do not set explicit handler.
- if(i == SIGHUP) {
- runtime·memclr((byte*)&sa, sizeof sa);
- runtime·sigaction(i, nil, &sa);
- if(sa._sa_u._sa_sigaction == SIG_IGN)
- return;
- }
-
- runtime·memclr((byte*)&sa, sizeof sa);
- sa.sa_flags = SA_SIGINFO|SA_ONSTACK;
- if(restart)
- sa.sa_flags |= SA_RESTART;
- sa.sa_mask[0] = ~0U;
- sa.sa_mask[1] = ~0U;
- sa.sa_mask[2] = ~0U;
- sa.sa_mask[3] = ~0U;
- if (fn == runtime·sighandler)
- fn = (void*)runtime·sigtramp;
- sa._sa_u._sa_sigaction = (void*)fn;
- runtime·sigaction(i, &sa, nil);
-}
-
-void
-runtime·lwp_mcontext_init(McontextT *mc, void *stack, M *mp, G *gp, void (*fn)(void))
-{
- mc->__gregs[REG_EIP] = (uint32)runtime·lwp_tramp;
- mc->__gregs[REG_UESP] = (uint32)stack;
- mc->__gregs[REG_EBX] = (uint32)mp;
- mc->__gregs[REG_EDX] = (uint32)gp;
- mc->__gregs[REG_ESI] = (uint32)fn;
-}
diff --git a/src/pkg/runtime/signal_netbsd_386.h b/src/pkg/runtime/signal_netbsd_386.h
new file mode 100644
index 000000000..d5a8a0c4b
--- /dev/null
+++ b/src/pkg/runtime/signal_netbsd_386.h
@@ -0,0 +1,23 @@
+// 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.
+
+#define SIG_REGS(ctxt) (((UcontextT*)(ctxt))->uc_mcontext)
+
+#define SIG_EAX(info, ctxt) (SIG_REGS(ctxt).__gregs[REG_EAX])
+#define SIG_EBX(info, ctxt) (SIG_REGS(ctxt).__gregs[REG_EBX])
+#define SIG_ECX(info, ctxt) (SIG_REGS(ctxt).__gregs[REG_ECX])
+#define SIG_EDX(info, ctxt) (SIG_REGS(ctxt).__gregs[REG_EDX])
+#define SIG_EDI(info, ctxt) (SIG_REGS(ctxt).__gregs[REG_EDI])
+#define SIG_ESI(info, ctxt) (SIG_REGS(ctxt).__gregs[REG_ESI])
+#define SIG_EBP(info, ctxt) (SIG_REGS(ctxt).__gregs[REG_EBP])
+#define SIG_ESP(info, ctxt) (SIG_REGS(ctxt).__gregs[REG_UESP])
+#define SIG_EIP(info, ctxt) (SIG_REGS(ctxt).__gregs[REG_EIP])
+#define SIG_EFLAGS(info, ctxt) (SIG_REGS(ctxt).__gregs[REG_EFL])
+
+#define SIG_CS(info, ctxt) (SIG_REGS(ctxt).__gregs[REG_CS])
+#define SIG_FS(info, ctxt) (SIG_REGS(ctxt).__gregs[REG_FS])
+#define SIG_GS(info, ctxt) (SIG_REGS(ctxt).__gregs[REG_GS])
+
+#define SIG_CODE0(info, ctxt) ((info)->_code)
+#define SIG_CODE1(info, ctxt) (*(uintptr*)&(info)->_reason[0])
diff --git a/src/pkg/runtime/signal_netbsd_amd64.c b/src/pkg/runtime/signal_netbsd_amd64.c
deleted file mode 100644
index 46afb682b..000000000
--- a/src/pkg/runtime/signal_netbsd_amd64.c
+++ /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.
-
-#include "runtime.h"
-#include "defs_GOOS_GOARCH.h"
-#include "signals_GOOS.h"
-#include "os_GOOS.h"
-
-extern void runtime·lwp_tramp(void);
-extern void runtime·sigtramp(void);
-
-typedef struct sigaction {
- union {
- void (*_sa_handler)(int32);
- void (*_sa_sigaction)(int32, Siginfo*, void *);
- } _sa_u; /* signal handler */
- uint32 sa_mask[4]; /* signal mask to apply */
- int32 sa_flags; /* see signal options below */
-} Sigaction;
-
-void
-runtime·dumpregs(McontextT *mc)
-{
- runtime·printf("rax %X\n", mc->__gregs[REG_RAX]);
- runtime·printf("rbx %X\n", mc->__gregs[REG_RBX]);
- runtime·printf("rcx %X\n", mc->__gregs[REG_RCX]);
- runtime·printf("rdx %X\n", mc->__gregs[REG_RDX]);
- runtime·printf("rdi %X\n", mc->__gregs[REG_RDI]);
- runtime·printf("rsi %X\n", mc->__gregs[REG_RSI]);
- runtime·printf("rbp %X\n", mc->__gregs[REG_RBP]);
- runtime·printf("rsp %X\n", mc->__gregs[REG_RSP]);
- runtime·printf("r8 %X\n", mc->__gregs[REG_R8]);
- runtime·printf("r9 %X\n", mc->__gregs[REG_R9]);
- runtime·printf("r10 %X\n", mc->__gregs[REG_R10]);
- runtime·printf("r11 %X\n", mc->__gregs[REG_R11]);
- runtime·printf("r12 %X\n", mc->__gregs[REG_R12]);
- runtime·printf("r13 %X\n", mc->__gregs[REG_R13]);
- runtime·printf("r14 %X\n", mc->__gregs[REG_R14]);
- runtime·printf("r15 %X\n", mc->__gregs[REG_R15]);
- runtime·printf("rip %X\n", mc->__gregs[REG_RIP]);
- runtime·printf("rflags %X\n", mc->__gregs[REG_RFLAGS]);
- runtime·printf("cs %X\n", mc->__gregs[REG_CS]);
- runtime·printf("fs %X\n", mc->__gregs[REG_FS]);
- runtime·printf("gs %X\n", mc->__gregs[REG_GS]);
-}
-
-void
-runtime·sighandler(int32 sig, Siginfo *info, void *context, G *gp)
-{
- UcontextT *uc = context;
- McontextT *mc = &uc->uc_mcontext;
- uintptr *sp;
- SigTab *t;
-
- if(sig == SIGPROF) {
- runtime·sigprof((uint8*)mc->__gregs[REG_RIP],
- (uint8*)mc->__gregs[REG_RSP], nil, gp);
- return;
- }
-
- t = &runtime·sigtab[sig];
- if(info->_code != SI_USER && (t->flags & SigPanic)) {
- if(gp == nil || gp == m->g0)
- goto Throw;
- // Make it look like a call to the signal func.
- // We need to pass arguments out of band since augmenting the
- // stack frame would break the unwinding code.
- gp->sig = sig;
- gp->sigcode0 = info->_code;
- gp->sigcode1 = *(uintptr*)&info->_reason[0]; /* _addr */
- gp->sigpc = mc->__gregs[REG_RIP];
-
- // Only push runtime·sigpanic if __gregs[REG_RIP] != 0.
- // If __gregs[REG_RIP] == 0, probably panicked because of a
- // call to a nil func. Not pushing that onto sp will make the
- // trace look like a call to runtime·sigpanic instead.
- // (Otherwise the trace will end at runtime·sigpanic
- // and we won't get to see who faulted.)
- if(mc->__gregs[REG_RIP] != 0) {
- sp = (uintptr*)mc->__gregs[REG_RSP];
- *--sp = mc->__gregs[REG_RIP];
- mc->__gregs[REG_RSP] = (uintptr)sp;
- }
- mc->__gregs[REG_RIP] = (uintptr)runtime·sigpanic;
- return;
- }
-
- if(info->_code == SI_USER || (t->flags & SigNotify))
- if(runtime·sigsend(sig))
- return;
- if(t->flags & SigKill)
- runtime·exit(2);
- if(!(t->flags & SigThrow))
- return;
-
-Throw:
- runtime·startpanic();
-
- if(sig < 0 || sig >= NSIG)
- runtime·printf("Signal %d\n", sig);
- else
- runtime·printf("%s\n", runtime·sigtab[sig].name);
-
- runtime·printf("PC=%X\n", mc->__gregs[REG_RIP]);
- if(m->lockedg != nil && m->ncgo > 0 && gp == m->g0) {
- runtime·printf("signal arrived during cgo execution\n");
- gp = m->lockedg;
- }
- runtime·printf("\n");
-
- if(runtime·gotraceback()){
- runtime·traceback((void*)mc->__gregs[REG_RIP],
- (void*)mc->__gregs[REG_RSP], 0, gp);
- runtime·tracebackothers(gp);
- runtime·dumpregs(mc);
- }
-
- runtime·exit(2);
-}
-
-void
-runtime·signalstack(byte *p, int32 n)
-{
- Sigaltstack st;
-
- st.ss_sp = p;
- st.ss_size = n;
- st.ss_flags = 0;
- if(p == nil)
- st.ss_flags = SS_DISABLE;
- runtime·sigaltstack(&st, nil);
-}
-
-void
-runtime·setsig(int32 i, void (*fn)(int32, Siginfo*, void*, G*), bool restart)
-{
- Sigaction sa;
-
- // If SIGHUP handler is SIG_IGN, assume running
- // under nohup and do not set explicit handler.
- if(i == SIGHUP) {
- runtime·memclr((byte*)&sa, sizeof sa);
- runtime·sigaction(i, nil, &sa);
- if(sa._sa_u._sa_sigaction == SIG_IGN)
- return;
- }
-
- runtime·memclr((byte*)&sa, sizeof sa);
- sa.sa_flags = SA_SIGINFO|SA_ONSTACK;
- if(restart)
- sa.sa_flags |= SA_RESTART;
- sa.sa_mask[0] = ~0U;
- sa.sa_mask[1] = ~0U;
- sa.sa_mask[2] = ~0U;
- sa.sa_mask[3] = ~0U;
- if (fn == runtime·sighandler)
- fn = (void*)runtime·sigtramp;
- sa._sa_u._sa_sigaction = (void*)fn;
- runtime·sigaction(i, &sa, nil);
-}
-
-void
-runtime·lwp_mcontext_init(McontextT *mc, void *stack, M *mp, G *gp, void (*fn)(void))
-{
- // Machine dependent mcontext initialisation for LWP.
- mc->__gregs[REG_RIP] = (uint64)runtime·lwp_tramp;
- mc->__gregs[REG_RSP] = (uint64)stack;
- mc->__gregs[REG_R8] = (uint64)mp;
- mc->__gregs[REG_R9] = (uint64)gp;
- mc->__gregs[REG_R12] = (uint64)fn;
-}
diff --git a/src/pkg/runtime/signal_netbsd_amd64.h b/src/pkg/runtime/signal_netbsd_amd64.h
new file mode 100644
index 000000000..7ec4cd98c
--- /dev/null
+++ b/src/pkg/runtime/signal_netbsd_amd64.h
@@ -0,0 +1,31 @@
+// 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.
+
+#define SIG_REGS(ctxt) (((UcontextT*)(ctxt))->uc_mcontext)
+
+#define SIG_RAX(info, ctxt) (SIG_REGS(ctxt).__gregs[REG_RAX])
+#define SIG_RBX(info, ctxt) (SIG_REGS(ctxt).__gregs[REG_RBX])
+#define SIG_RCX(info, ctxt) (SIG_REGS(ctxt).__gregs[REG_RCX])
+#define SIG_RDX(info, ctxt) (SIG_REGS(ctxt).__gregs[REG_RDX])
+#define SIG_RDI(info, ctxt) (SIG_REGS(ctxt).__gregs[REG_RDI])
+#define SIG_RSI(info, ctxt) (SIG_REGS(ctxt).__gregs[REG_RSI])
+#define SIG_RBP(info, ctxt) (SIG_REGS(ctxt).__gregs[REG_RBP])
+#define SIG_RSP(info, ctxt) (SIG_REGS(ctxt).__gregs[REG_RSP])
+#define SIG_R8(info, ctxt) (SIG_REGS(ctxt).__gregs[REG_R8])
+#define SIG_R9(info, ctxt) (SIG_REGS(ctxt).__gregs[REG_R9])
+#define SIG_R10(info, ctxt) (SIG_REGS(ctxt).__gregs[REG_R10])
+#define SIG_R11(info, ctxt) (SIG_REGS(ctxt).__gregs[REG_R11])
+#define SIG_R12(info, ctxt) (SIG_REGS(ctxt).__gregs[REG_R12])
+#define SIG_R13(info, ctxt) (SIG_REGS(ctxt).__gregs[REG_R13])
+#define SIG_R14(info, ctxt) (SIG_REGS(ctxt).__gregs[REG_R14])
+#define SIG_R15(info, ctxt) (SIG_REGS(ctxt).__gregs[REG_R15])
+#define SIG_RIP(info, ctxt) (SIG_REGS(ctxt).__gregs[REG_RIP])
+#define SIG_RFLAGS(info, ctxt) (SIG_REGS(ctxt).__gregs[REG_RFLAGS])
+
+#define SIG_CS(info, ctxt) (SIG_REGS(ctxt).__gregs[REG_CS])
+#define SIG_FS(info, ctxt) (SIG_REGS(ctxt).__gregs[REG_FS])
+#define SIG_GS(info, ctxt) (SIG_REGS(ctxt).__gregs[REG_GS])
+
+#define SIG_CODE0(info, ctxt) ((info)->_code)
+#define SIG_CODE1(info, ctxt) (*(uintptr*)&(info)->_reason[0])
diff --git a/src/pkg/runtime/signal_netbsd_arm.c b/src/pkg/runtime/signal_netbsd_arm.c
deleted file mode 100644
index 97f62687b..000000000
--- a/src/pkg/runtime/signal_netbsd_arm.c
+++ /dev/null
@@ -1,208 +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 "runtime.h"
-#include "defs_GOOS_GOARCH.h"
-#include "signals_GOOS.h"
-#include "os_GOOS.h"
-
-#define r0 __gregs[0]
-#define r1 __gregs[1]
-#define r2 __gregs[2]
-#define r3 __gregs[3]
-#define r4 __gregs[4]
-#define r5 __gregs[5]
-#define r6 __gregs[6]
-#define r7 __gregs[7]
-#define r8 __gregs[8]
-#define r9 __gregs[9]
-#define r10 __gregs[10]
-#define r11 __gregs[11]
-#define r12 __gregs[12]
-#define r13 __gregs[13]
-#define r14 __gregs[14]
-#define r15 __gregs[15]
-#define cpsr __gregs[16]
-
-void
-runtime·dumpregs(McontextT *r)
-{
- runtime·printf("r0 %x\n", r->r0);
- runtime·printf("r1 %x\n", r->r1);
- runtime·printf("r2 %x\n", r->r2);
- runtime·printf("r3 %x\n", r->r3);
- runtime·printf("r4 %x\n", r->r4);
- runtime·printf("r5 %x\n", r->r5);
- runtime·printf("r6 %x\n", r->r6);
- runtime·printf("r7 %x\n", r->r7);
- runtime·printf("r8 %x\n", r->r8);
- runtime·printf("r9 %x\n", r->r9);
- runtime·printf("r10 %x\n", r->r10);
- runtime·printf("fp %x\n", r->r11);
- runtime·printf("ip %x\n", r->r12);
- runtime·printf("sp %x\n", r->r13);
- runtime·printf("lr %x\n", r->r14);
- runtime·printf("pc %x\n", r->r15);
- runtime·printf("cpsr %x\n", r->cpsr);
-}
-
-extern void runtime·lwp_tramp(void);
-extern void runtime·sigtramp(void);
-
-typedef struct sigaction {
- union {
- void (*_sa_handler)(int32);
- void (*_sa_sigaction)(int32, Siginfo*, void *);
- } _sa_u; /* signal handler */
- uint32 sa_mask[4]; /* signal mask to apply */
- int32 sa_flags; /* see signal options below */
-} Sigaction;
-
-void
-runtime·sighandler(int32 sig, Siginfo *info, void *context, G *gp)
-{
- UcontextT *uc;
- McontextT *r;
- SigTab *t;
-
- uc = context;
- r = &uc->uc_mcontext;
-
- if(sig == SIGPROF) {
- runtime·sigprof((uint8*)r->r15, (uint8*)r->r13, (uint8*)r->r14, gp);
- return;
- }
-
- t = &runtime·sigtab[sig];
- if(info->_code != SI_USER && (t->flags & SigPanic)) {
- if(gp == nil || gp == m->g0)
- goto Throw;
- // Make it look like a call to the signal func.
- // We have to pass arguments out of band since
- // augmenting the stack frame would break
- // the unwinding code.
- gp->sig = sig;
- gp->sigcode0 = info->_code;
- gp->sigcode1 = *(uintptr*)&info->_reason[0]; /* _addr */
- gp->sigpc = r->r15;
-
- // We arrange lr, and pc to pretend the panicking
- // function calls sigpanic directly.
- // Always save LR to stack so that panics in leaf
- // functions are correctly handled. This smashes
- // the stack frame but we're not going back there
- // anyway.
- r->r13 -= 4;
- *(uint32 *)r->r13 = r->r14;
- // 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(r->r15 != 0)
- r->r14 = r->r15;
- // In case we are panicking from external C code
- r->r10 = (uintptr)gp;
- r->r9 = (uintptr)m;
- r->r15 = (uintptr)runtime·sigpanic;
- return;
- }
-
- if(info->_code == SI_USER || (t->flags & SigNotify))
- if(runtime·sigsend(sig))
- return;
- if(t->flags & SigKill)
- runtime·exit(2);
- if(!(t->flags & SigThrow))
- return;
-
-Throw:
- runtime·startpanic();
-
- if(sig < 0 || sig >= NSIG)
- runtime·printf("Signal %d\n", sig);
- else
- runtime·printf("%s\n", runtime·sigtab[sig].name);
-
- runtime·printf("PC=%x\n", r->r15);
- if(m->lockedg != nil && m->ncgo > 0 && gp == m->g0) {
- runtime·printf("signal arrived during cgo execution\n");
- gp = m->lockedg;
- }
- runtime·printf("\n");
-
- if(runtime·gotraceback()){
- runtime·traceback((void*)r->r15, (void*)r->r13, (void*)r->r14, gp);
- runtime·tracebackothers(gp);
- runtime·printf("\n");
- runtime·dumpregs(r);
- }
-
-// breakpoint();
- runtime·exit(2);
-}
-
-void
-runtime·signalstack(byte *p, int32 n)
-{
- Sigaltstack st;
-
- st.ss_sp = (uint8*)p;
- st.ss_size = n;
- st.ss_flags = 0;
- if(p == nil)
- st.ss_flags = SS_DISABLE;
- runtime·sigaltstack(&st, nil);
-}
-
-void
-runtime·setsig(int32 i, void (*fn)(int32, Siginfo*, void*, G*), bool restart)
-{
- Sigaction sa;
-
- // If SIGHUP handler is SIG_IGN, assume running
- // under nohup and do not set explicit handler.
- if(i == SIGHUP) {
- runtime·memclr((byte*)&sa, sizeof sa);
- runtime·sigaction(i, nil, &sa);
- if(sa._sa_u._sa_sigaction == SIG_IGN)
- return;
- }
-
- runtime·memclr((byte*)&sa, sizeof sa);
- sa.sa_flags = SA_SIGINFO|SA_ONSTACK;
- if(restart)
- sa.sa_flags |= SA_RESTART;
- sa.sa_mask[0] = ~0U;
- sa.sa_mask[1] = ~0U;
- sa.sa_mask[2] = ~0U;
- sa.sa_mask[3] = ~0U;
- if (fn == runtime·sighandler)
- fn = (void*)runtime·sigtramp;
- sa._sa_u._sa_sigaction = (void*)fn;
- runtime·sigaction(i, &sa, nil);
-}
-
-void
-runtime·lwp_mcontext_init(McontextT *mc, void *stack, M *mp, G *gp, void (*fn)(void))
-{
- mc->r15 = (uint32)runtime·lwp_tramp;
- mc->r13 = (uint32)stack;
- mc->r0 = (uint32)mp;
- mc->r1 = (uint32)gp;
- mc->r2 = (uint32)fn;
-}
-
-void
-runtime·checkgoarm(void)
-{
- // TODO(minux)
-}
-
-#pragma textflag 7
-int64
-runtime·cputicks() {
- // Currently cputicks() is used in blocking profiler and to seed runtime·fastrand1().
- // runtime·nanotime() is a poor approximation of CPU ticks that is enough for the profiler.
- // TODO: need more entropy to better seed fastrand1.
- return runtime·nanotime();
-}
diff --git a/src/pkg/runtime/signal_netbsd_arm.h b/src/pkg/runtime/signal_netbsd_arm.h
new file mode 100644
index 000000000..12f5827a6
--- /dev/null
+++ b/src/pkg/runtime/signal_netbsd_arm.h
@@ -0,0 +1,30 @@
+// 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.
+
+#define SIG_REGS(ctxt) (((UcontextT*)(ctxt))->uc_mcontext)
+
+#define SIG_R0(info, ctxt) (SIG_REGS(ctxt).__gregs[REG_R0])
+#define SIG_R1(info, ctxt) (SIG_REGS(ctxt).__gregs[REG_R1])
+#define SIG_R2(info, ctxt) (SIG_REGS(ctxt).__gregs[REG_R2])
+#define SIG_R3(info, ctxt) (SIG_REGS(ctxt).__gregs[REG_R3])
+#define SIG_R4(info, ctxt) (SIG_REGS(ctxt).__gregs[REG_R4])
+#define SIG_R5(info, ctxt) (SIG_REGS(ctxt).__gregs[REG_R5])
+#define SIG_R6(info, ctxt) (SIG_REGS(ctxt).__gregs[REG_R6])
+#define SIG_R7(info, ctxt) (SIG_REGS(ctxt).__gregs[REG_R7])
+#define SIG_R8(info, ctxt) (SIG_REGS(ctxt).__gregs[REG_R8])
+#define SIG_R9(info, ctxt) (SIG_REGS(ctxt).__gregs[REG_R9])
+#define SIG_R10(info, ctxt) (SIG_REGS(ctxt).__gregs[REG_R10])
+#define SIG_FP(info, ctxt) (SIG_REGS(ctxt).__gregs[REG_R11])
+#define SIG_IP(info, ctxt) (SIG_REGS(ctxt).__gregs[REG_R12])
+#define SIG_SP(info, ctxt) (SIG_REGS(ctxt).__gregs[REG_R13])
+#define SIG_LR(info, ctxt) (SIG_REGS(ctxt).__gregs[REG_R14])
+#define SIG_PC(info, ctxt) (SIG_REGS(ctxt).__gregs[REG_R15])
+#define SIG_CPSR(info, ctxt) (SIG_REGS(ctxt).__gregs[REG_CPSR])
+#define SIG_FAULT(info, ctxt) (*(uintptr*)&(info)->_reason[0])
+#define SIG_TRAP(info, ctxt) (0)
+#define SIG_ERROR(info, ctxt) (0)
+#define SIG_OLDMASK(info, ctxt) (0)
+
+#define SIG_CODE0(info, ctxt) ((info)->_code)
+#define SIG_CODE1(info, ctxt) (*(uintptr*)&(info)->_reason[0])
diff --git a/src/pkg/runtime/signal_openbsd_386.c b/src/pkg/runtime/signal_openbsd_386.c
deleted file mode 100644
index 516797c8d..000000000
--- a/src/pkg/runtime/signal_openbsd_386.c
+++ /dev/null
@@ -1,147 +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 "runtime.h"
-#include "defs_GOOS_GOARCH.h"
-#include "signals_GOOS.h"
-#include "os_GOOS.h"
-
-extern void runtime·sigtramp(void);
-
-typedef struct sigaction {
- union {
- void (*__sa_handler)(int32);
- void (*__sa_sigaction)(int32, Siginfo*, void *);
- } __sigaction_u; /* signal handler */
- uint32 sa_mask; /* signal mask to apply */
- int32 sa_flags; /* see signal options below */
-} Sigaction;
-
-void
-runtime·dumpregs(Sigcontext *r)
-{
- runtime·printf("eax %x\n", r->sc_eax);
- runtime·printf("ebx %x\n", r->sc_ebx);
- runtime·printf("ecx %x\n", r->sc_ecx);
- runtime·printf("edx %x\n", r->sc_edx);
- runtime·printf("edi %x\n", r->sc_edi);
- runtime·printf("esi %x\n", r->sc_esi);
- runtime·printf("ebp %x\n", r->sc_ebp);
- runtime·printf("esp %x\n", r->sc_esp);
- runtime·printf("eip %x\n", r->sc_eip);
- runtime·printf("eflags %x\n", r->sc_eflags);
- runtime·printf("cs %x\n", r->sc_cs);
- runtime·printf("fs %x\n", r->sc_fs);
- runtime·printf("gs %x\n", r->sc_gs);
-}
-
-void
-runtime·sighandler(int32 sig, Siginfo *info, void *context, G *gp)
-{
- Sigcontext *r = context;
- uintptr *sp;
- SigTab *t;
-
- if(sig == SIGPROF) {
- runtime·sigprof((uint8*)r->sc_eip, (uint8*)r->sc_esp, nil, gp);
- return;
- }
-
- t = &runtime·sigtab[sig];
- if(info->si_code != SI_USER && (t->flags & SigPanic)) {
- if(gp == nil || gp == m->g0)
- goto Throw;
- // 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 = info->si_code;
- gp->sigcode1 = *(uintptr*)((byte*)info + 12); /* si_addr */
- gp->sigpc = r->sc_eip;
-
- // Only push runtime·sigpanic if r->sc_eip != 0.
- // If r->sc_eip == 0, probably panicked because of a
- // call to a nil func. Not pushing that onto sp will
- // make the trace look like a call to runtime·sigpanic instead.
- // (Otherwise the trace will end at runtime·sigpanic and we
- // won't get to see who faulted.)
- if(r->sc_eip != 0) {
- sp = (uintptr*)r->sc_esp;
- *--sp = r->sc_eip;
- r->sc_esp = (uintptr)sp;
- }
- r->sc_eip = (uintptr)runtime·sigpanic;
- return;
- }
-
- if(info->si_code == SI_USER || (t->flags & SigNotify))
- if(runtime·sigsend(sig))
- return;
- if(t->flags & SigKill)
- runtime·exit(2);
- if(!(t->flags & SigThrow))
- return;
-
-Throw:
- runtime·startpanic();
-
- if(sig < 0 || sig >= NSIG)
- runtime·printf("Signal %d\n", sig);
- else
- runtime·printf("%s\n", runtime·sigtab[sig].name);
-
- runtime·printf("PC=%X\n", r->sc_eip);
- if(m->lockedg != nil && m->ncgo > 0 && gp == m->g0) {
- runtime·printf("signal arrived during cgo execution\n");
- gp = m->lockedg;
- }
- runtime·printf("\n");
-
- if(runtime·gotraceback()){
- runtime·traceback((void*)r->sc_eip, (void*)r->sc_esp, 0, gp);
- runtime·tracebackothers(gp);
- runtime·dumpregs(r);
- }
-
- runtime·exit(2);
-}
-
-void
-runtime·signalstack(byte *p, int32 n)
-{
- Sigaltstack st;
-
- st.ss_sp = p;
- st.ss_size = n;
- st.ss_flags = 0;
- if(p == nil)
- st.ss_flags = SS_DISABLE;
- runtime·sigaltstack(&st, nil);
-}
-
-void
-runtime·setsig(int32 i, void (*fn)(int32, Siginfo*, void*, G*), bool restart)
-{
- Sigaction sa;
-
- // If SIGHUP handler is SIG_IGN, assume running
- // under nohup and do not set explicit handler.
- if(i == SIGHUP) {
- runtime·memclr((byte*)&sa, sizeof sa);
- runtime·sigaction(i, nil, &sa);
- if(sa.__sigaction_u.__sa_sigaction == SIG_IGN)
- return;
- }
-
- runtime·memclr((byte*)&sa, sizeof sa);
- sa.sa_flags = SA_SIGINFO|SA_ONSTACK;
- if(restart)
- sa.sa_flags |= SA_RESTART;
- sa.sa_mask = ~0ULL;
- if (fn == runtime·sighandler)
- fn = (void*)runtime·sigtramp;
- sa.__sigaction_u.__sa_sigaction = (void*)fn;
- runtime·sigaction(i, &sa, nil);
-}
diff --git a/src/pkg/runtime/signal_openbsd_386.h b/src/pkg/runtime/signal_openbsd_386.h
new file mode 100644
index 000000000..6742db8d4
--- /dev/null
+++ b/src/pkg/runtime/signal_openbsd_386.h
@@ -0,0 +1,23 @@
+// 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.
+
+#define SIG_REGS(ctxt) (*(Sigcontext*)(ctxt))
+
+#define SIG_EAX(info, ctxt) (SIG_REGS(ctxt).sc_eax)
+#define SIG_EBX(info, ctxt) (SIG_REGS(ctxt).sc_ebx)
+#define SIG_ECX(info, ctxt) (SIG_REGS(ctxt).sc_ecx)
+#define SIG_EDX(info, ctxt) (SIG_REGS(ctxt).sc_edx)
+#define SIG_EDI(info, ctxt) (SIG_REGS(ctxt).sc_edi)
+#define SIG_ESI(info, ctxt) (SIG_REGS(ctxt).sc_esi)
+#define SIG_EBP(info, ctxt) (SIG_REGS(ctxt).sc_ebp)
+#define SIG_ESP(info, ctxt) (SIG_REGS(ctxt).sc_esp)
+#define SIG_EIP(info, ctxt) (SIG_REGS(ctxt).sc_eip)
+#define SIG_EFLAGS(info, ctxt) (SIG_REGS(ctxt).sc_eflags)
+
+#define SIG_CS(info, ctxt) (SIG_REGS(ctxt).sc_cs)
+#define SIG_FS(info, ctxt) (SIG_REGS(ctxt).sc_fs)
+#define SIG_GS(info, ctxt) (SIG_REGS(ctxt).sc_gs)
+
+#define SIG_CODE0(info, ctxt) ((info)->si_code)
+#define SIG_CODE1(info, ctxt) (*(uintptr*)((byte*)info + 12))
diff --git a/src/pkg/runtime/signal_openbsd_amd64.c b/src/pkg/runtime/signal_openbsd_amd64.c
deleted file mode 100644
index 0d0db770b..000000000
--- a/src/pkg/runtime/signal_openbsd_amd64.c
+++ /dev/null
@@ -1,156 +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 "runtime.h"
-#include "defs_GOOS_GOARCH.h"
-#include "signals_GOOS.h"
-#include "os_GOOS.h"
-
-extern void runtime·sigtramp(void);
-
-typedef struct sigaction {
- union {
- void (*__sa_handler)(int32);
- void (*__sa_sigaction)(int32, Siginfo*, void *);
- } __sigaction_u; /* signal handler */
- uint32 sa_mask; /* signal mask to apply */
- int32 sa_flags; /* see signal options below */
-} Sigaction;
-
-void
-runtime·dumpregs(Sigcontext *r)
-{
- runtime·printf("rax %X\n", r->sc_rax);
- runtime·printf("rbx %X\n", r->sc_rbx);
- runtime·printf("rcx %X\n", r->sc_rcx);
- runtime·printf("rdx %X\n", r->sc_rdx);
- runtime·printf("rdi %X\n", r->sc_rdi);
- runtime·printf("rsi %X\n", r->sc_rsi);
- runtime·printf("rbp %X\n", r->sc_rbp);
- runtime·printf("rsp %X\n", r->sc_rsp);
- runtime·printf("r8 %X\n", r->sc_r8);
- runtime·printf("r9 %X\n", r->sc_r9);
- runtime·printf("r10 %X\n", r->sc_r10);
- runtime·printf("r11 %X\n", r->sc_r11);
- runtime·printf("r12 %X\n", r->sc_r12);
- runtime·printf("r13 %X\n", r->sc_r13);
- runtime·printf("r14 %X\n", r->sc_r14);
- runtime·printf("r15 %X\n", r->sc_r15);
- runtime·printf("rip %X\n", r->sc_rip);
- runtime·printf("rflags %X\n", r->sc_rflags);
- runtime·printf("cs %X\n", r->sc_cs);
- runtime·printf("fs %X\n", r->sc_fs);
- runtime·printf("gs %X\n", r->sc_gs);
-}
-
-void
-runtime·sighandler(int32 sig, Siginfo *info, void *context, G *gp)
-{
- Sigcontext *r = context;
- uintptr *sp;
- SigTab *t;
-
- if(sig == SIGPROF) {
- runtime·sigprof((uint8*)r->sc_rip,
- (uint8*)r->sc_rsp, nil, gp);
- return;
- }
-
- t = &runtime·sigtab[sig];
- if(info->si_code != SI_USER && (t->flags & SigPanic)) {
- if(gp == nil || gp == m->g0)
- goto Throw;
- // 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 = info->si_code;
- gp->sigcode1 = *(uintptr*)((byte*)info + 16); /* si_addr */
- gp->sigpc = r->sc_rip;
-
- // Only push runtime·sigpanic if r->sc_rip != 0.
- // If r->sc_rip == 0, probably panicked because of a
- // call to a nil func. Not pushing that onto sp will
- // make the trace look like a call to runtime·sigpanic instead.
- // (Otherwise the trace will end at runtime·sigpanic and we
- // won't get to see who faulted.)
- if(r->sc_rip != 0) {
- sp = (uintptr*)r->sc_rsp;
- *--sp = r->sc_rip;
- r->sc_rsp = (uintptr)sp;
- }
- r->sc_rip = (uintptr)runtime·sigpanic;
- return;
- }
-
- if(info->si_code == SI_USER || (t->flags & SigNotify))
- if(runtime·sigsend(sig))
- return;
- if(t->flags & SigKill)
- runtime·exit(2);
- if(!(t->flags & SigThrow))
- return;
-
-Throw:
- runtime·startpanic();
-
- if(sig < 0 || sig >= NSIG)
- runtime·printf("Signal %d\n", sig);
- else
- runtime·printf("%s\n", runtime·sigtab[sig].name);
-
- runtime·printf("PC=%X\n", r->sc_rip);
- if(m->lockedg != nil && m->ncgo > 0 && gp == m->g0) {
- runtime·printf("signal arrived during cgo execution\n");
- gp = m->lockedg;
- }
- runtime·printf("\n");
-
- if(runtime·gotraceback()){
- runtime·traceback((void*)r->sc_rip, (void*)r->sc_rsp, 0, gp);
- runtime·tracebackothers(gp);
- runtime·dumpregs(r);
- }
-
- runtime·exit(2);
-}
-
-void
-runtime·signalstack(byte *p, int32 n)
-{
- Sigaltstack st;
-
- st.ss_sp = p;
- st.ss_size = n;
- st.ss_flags = 0;
- if(p == nil)
- st.ss_flags = SS_DISABLE;
- runtime·sigaltstack(&st, nil);
-}
-
-void
-runtime·setsig(int32 i, void (*fn)(int32, Siginfo*, void*, G*), bool restart)
-{
- Sigaction sa;
-
- // If SIGHUP handler is SIG_IGN, assume running
- // under nohup and do not set explicit handler.
- if(i == SIGHUP) {
- runtime·memclr((byte*)&sa, sizeof sa);
- runtime·sigaction(i, nil, &sa);
- if(sa.__sigaction_u.__sa_sigaction == SIG_IGN)
- return;
- }
-
- runtime·memclr((byte*)&sa, sizeof sa);
- sa.sa_flags = SA_SIGINFO|SA_ONSTACK;
- if(restart)
- sa.sa_flags |= SA_RESTART;
- sa.sa_mask = ~0U;
- if(fn == runtime·sighandler)
- fn = (void*)runtime·sigtramp;
- sa.__sigaction_u.__sa_sigaction = (void*)fn;
- runtime·sigaction(i, &sa, nil);
-}
diff --git a/src/pkg/runtime/signal_openbsd_amd64.h b/src/pkg/runtime/signal_openbsd_amd64.h
new file mode 100644
index 000000000..b46a5dfa6
--- /dev/null
+++ b/src/pkg/runtime/signal_openbsd_amd64.h
@@ -0,0 +1,31 @@
+// 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.
+
+#define SIG_REGS(ctxt) (*(Sigcontext*)(ctxt))
+
+#define SIG_RAX(info, ctxt) (SIG_REGS(ctxt).sc_rax)
+#define SIG_RBX(info, ctxt) (SIG_REGS(ctxt).sc_rbx)
+#define SIG_RCX(info, ctxt) (SIG_REGS(ctxt).sc_rcx)
+#define SIG_RDX(info, ctxt) (SIG_REGS(ctxt).sc_rdx)
+#define SIG_RDI(info, ctxt) (SIG_REGS(ctxt).sc_rdi)
+#define SIG_RSI(info, ctxt) (SIG_REGS(ctxt).sc_rsi)
+#define SIG_RBP(info, ctxt) (SIG_REGS(ctxt).sc_rbp)
+#define SIG_RSP(info, ctxt) (SIG_REGS(ctxt).sc_rsp)
+#define SIG_R8(info, ctxt) (SIG_REGS(ctxt).sc_r8)
+#define SIG_R9(info, ctxt) (SIG_REGS(ctxt).sc_r9)
+#define SIG_R10(info, ctxt) (SIG_REGS(ctxt).sc_r10)
+#define SIG_R11(info, ctxt) (SIG_REGS(ctxt).sc_r11)
+#define SIG_R12(info, ctxt) (SIG_REGS(ctxt).sc_r12)
+#define SIG_R13(info, ctxt) (SIG_REGS(ctxt).sc_r13)
+#define SIG_R14(info, ctxt) (SIG_REGS(ctxt).sc_r14)
+#define SIG_R15(info, ctxt) (SIG_REGS(ctxt).sc_r15)
+#define SIG_RIP(info, ctxt) (SIG_REGS(ctxt).sc_rip)
+#define SIG_RFLAGS(info, ctxt) (SIG_REGS(ctxt).sc_rflags)
+
+#define SIG_CS(info, ctxt) (SIG_REGS(ctxt).sc_cs)
+#define SIG_FS(info, ctxt) (SIG_REGS(ctxt).sc_fs)
+#define SIG_GS(info, ctxt) (SIG_REGS(ctxt).sc_gs)
+
+#define SIG_CODE0(info, ctxt) ((info)->si_code)
+#define SIG_CODE1(info, ctxt) (*(uintptr*)((byte*)(info) + 16))
diff --git a/src/pkg/runtime/signal_unix.c b/src/pkg/runtime/signal_unix.c
index 9b7e8b03a..54e461f99 100644
--- a/src/pkg/runtime/signal_unix.c
+++ b/src/pkg/runtime/signal_unix.c
@@ -7,6 +7,7 @@
#include "runtime.h"
#include "defs_GOOS_GOARCH.h"
#include "os_GOOS.h"
+#include "signal_unix.h"
extern SigTab runtime·sigtab[];
@@ -21,6 +22,20 @@ runtime·initsig(void)
t = &runtime·sigtab[i];
if((t->flags == 0) || (t->flags & SigDefault))
continue;
+
+ // 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(i) {
+ case SIGHUP:
+ case SIGINT:
+ if(runtime·getsig(i) == SIG_IGN) {
+ t->flags = SigNotify | SigIgnored;
+ continue;
+ }
+ }
+
+ t->flags |= SigHandling;
runtime·setsig(i, runtime·sighandler, true);
}
}
@@ -28,18 +43,35 @@ runtime·initsig(void)
void
runtime·sigenable(uint32 sig)
{
- int32 i;
SigTab *t;
- for(i = 0; i<NSIG; i++) {
- // ~0 means all signals.
- if(~sig == 0 || i == sig) {
- t = &runtime·sigtab[i];
- if(t->flags & SigDefault) {
- runtime·setsig(i, runtime·sighandler, true);
- t->flags &= ~SigDefault; // make this idempotent
- }
- }
+ if(sig >= NSIG)
+ return;
+
+ t = &runtime·sigtab[sig];
+ if((t->flags & SigNotify) && !(t->flags & SigHandling)) {
+ t->flags |= SigHandling;
+ if(runtime·getsig(sig) == SIG_IGN)
+ t->flags |= SigIgnored;
+ runtime·setsig(sig, runtime·sighandler, true);
+ }
+}
+
+void
+runtime·sigdisable(uint32 sig)
+{
+ SigTab *t;
+
+ if(sig >= NSIG)
+ return;
+
+ t = &runtime·sigtab[sig];
+ if((t->flags & SigNotify) && (t->flags & SigHandling)) {
+ t->flags &= ~SigHandling;
+ if(t->flags & SigIgnored)
+ runtime·setsig(sig, SIG_IGN, true);
+ else
+ runtime·setsig(sig, SIG_DFL, true);
}
}
@@ -66,5 +98,23 @@ void
os·sigpipe(void)
{
runtime·setsig(SIGPIPE, SIG_DFL, false);
- runtime·raisesigpipe();
+ runtime·raise(SIGPIPE);
+}
+
+void
+runtime·crash(void)
+{
+#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·setsig(SIGABRT, SIG_DFL, false);
+ runtime·raise(SIGABRT);
}
diff --git a/src/pkg/runtime/signal_unix.h b/src/pkg/runtime/signal_unix.h
new file mode 100644
index 000000000..2d84a0186
--- /dev/null
+++ b/src/pkg/runtime/signal_unix.h
@@ -0,0 +1,14 @@
+// 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.
+
+#define SIG_DFL ((void*)0)
+#define SIG_IGN ((void*)1)
+
+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/src/pkg/runtime/signals_plan9.h b/src/pkg/runtime/signals_plan9.h
index 0f1165e2a..f9bec65fc 100644
--- a/src/pkg/runtime/signals_plan9.h
+++ b/src/pkg/runtime/signals_plan9.h
@@ -1,3 +1,7 @@
+// 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.
+
#define N SigNotify
#define T SigThrow
#define P SigPanic
diff --git a/src/pkg/runtime/sigqueue.goc b/src/pkg/runtime/sigqueue.goc
index ab5f312e4..7e083685d 100644
--- a/src/pkg/runtime/sigqueue.goc
+++ b/src/pkg/runtime/sigqueue.goc
@@ -133,8 +133,6 @@ done:;
// Must only be called from a single goroutine at a time.
func signal_enable(s uint32) {
- int32 i;
-
if(!sig.inuse) {
// The first call to signal_enable is for us
// to use for initialization. It does not pass
@@ -144,16 +142,16 @@ func signal_enable(s uint32) {
return;
}
- if(~s == 0) {
- // Special case: want everything.
- for(i=0; i<nelem(sig.wanted); i++)
- sig.wanted[i] = ~(uint32)0;
- runtime·sigenable(s);
- 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);
+}
diff --git a/src/pkg/runtime/stack_test.go b/src/pkg/runtime/stack_test.go
index 759f7c46e..da0181a66 100644
--- a/src/pkg/runtime/stack_test.go
+++ b/src/pkg/runtime/stack_test.go
@@ -1533,7 +1533,7 @@ func stack5000() (uintptr, uintptr) { var buf [5000]byte; use(buf[:]); return St
func TestStackMem(t *testing.T) {
const (
BatchSize = 32
- BatchCount = 512
+ BatchCount = 256
ArraySize = 1024
RecursionDepth = 128
)
@@ -1562,6 +1562,11 @@ func TestStackMem(t *testing.T) {
for i := 0; i < BatchSize; i++ {
<-c
}
+
+ // The goroutines have signaled via c that they are ready to exit.
+ // Give them a chance to exit by sleeping. If we don't wait, we
+ // might not reuse them on the next batch.
+ time.Sleep(10 * time.Millisecond)
}
s1 := new(MemStats)
ReadMemStats(s1)
@@ -1571,7 +1576,9 @@ func TestStackMem(t *testing.T) {
if consumed > estimate {
t.Fatalf("Stack mem: want %v, got %v", estimate, consumed)
}
- if s1.StackInuse > 4<<20 {
- t.Fatalf("Stack inuse: want %v, got %v", 4<<20, s1.StackInuse)
+ inuse := s1.StackInuse - s0.StackInuse
+ t.Logf("Inuse %vMB for stack mem", inuse>>20)
+ if inuse > 4<<20 {
+ t.Fatalf("Stack inuse: want %v, got %v", 4<<20, inuse)
}
}
diff --git a/src/pkg/runtime/string.goc b/src/pkg/runtime/string.goc
index c0d3f2bde..49bf1148b 100644
--- a/src/pkg/runtime/string.goc
+++ b/src/pkg/runtime/string.goc
@@ -206,8 +206,6 @@ func cmpstring(s1 String, s2 String) (v int) {
}
func eqstring(s1 String, s2 String) (v bool) {
- uintgo i, l;
-
if(s1.len != s2.len) {
v = false;
return;
@@ -216,13 +214,7 @@ func eqstring(s1 String, s2 String) (v bool) {
v = true;
return;
}
- l = s1.len;
- for(i=0; i<l; i++)
- if(s1.str[i] != s2.str[i]) {
- v = false;
- return;
- }
- v = true;
+ v = runtime·memeq(s1.str, s2.str, s1.len);
}
int32
diff --git a/src/pkg/runtime/string_test.go b/src/pkg/runtime/string_test.go
index 8f13f0f42..df3ff06a7 100644
--- a/src/pkg/runtime/string_test.go
+++ b/src/pkg/runtime/string_test.go
@@ -1,3 +1,7 @@
+// 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_test
import (
@@ -43,3 +47,31 @@ func BenchmarkCompareStringDifferentLength(b *testing.B) {
}
}
}
+
+func BenchmarkCompareStringBigUnaligned(b *testing.B) {
+ bytes := make([]byte, 0, 1<<20)
+ for len(bytes) < 1<<20 {
+ bytes = append(bytes, "Hello Gophers!"...)
+ }
+ s1, s2 := string(bytes), "hello"+string(bytes)
+ for i := 0; i < b.N; i++ {
+ if s1 != s2[len("hello"):] {
+ b.Fatal("s1 != s2")
+ }
+ }
+ b.SetBytes(int64(len(s1)))
+}
+
+func BenchmarkCompareStringBig(b *testing.B) {
+ bytes := make([]byte, 0, 1<<20)
+ for len(bytes) < 1<<20 {
+ bytes = append(bytes, "Hello Gophers!"...)
+ }
+ s1, s2 := string(bytes), string(bytes)
+ for i := 0; i < b.N; i++ {
+ if s1 != s2 {
+ b.Fatal("s1 != s2")
+ }
+ }
+ b.SetBytes(int64(len(s1)))
+}
diff --git a/src/pkg/runtime/symtab.c b/src/pkg/runtime/symtab.c
index d7221c476..578406247 100644
--- a/src/pkg/runtime/symtab.c
+++ b/src/pkg/runtime/symtab.c
@@ -670,6 +670,6 @@ runtime·showframe(Func *f, bool current)
if(current && m->throwing > 0)
return 1;
if(traceback < 0)
- traceback = runtime·gotraceback();
+ traceback = runtime·gotraceback(nil);
return traceback > 1 || f != nil && contains(f->name, ".") && !hasprefix(f->name, "runtime.");
}
diff --git a/src/pkg/runtime/sys_darwin_386.s b/src/pkg/runtime/sys_darwin_386.s
index 8a938f9f4..59bb9d80d 100644
--- a/src/pkg/runtime/sys_darwin_386.s
+++ b/src/pkg/runtime/sys_darwin_386.s
@@ -24,18 +24,34 @@ TEXT runtime·exit1(SB),7,$0
MOVL $0xf1, 0xf1 // crash
RET
+TEXT runtime·open(SB),7,$0
+ MOVL $5, AX
+ INT $0x80
+ RET
+
+TEXT runtime·close(SB),7,$0
+ MOVL $6, AX
+ INT $0x80
+ RET
+
+TEXT runtime·read(SB),7,$0
+ MOVL $3, AX
+ INT $0x80
+ RET
+
TEXT runtime·write(SB),7,$0
MOVL $4, AX
INT $0x80
RET
-TEXT runtime·raisesigpipe(SB),7,$8
- get_tls(CX)
- MOVL m(CX), DX
- MOVL m_procid(DX), DX
- MOVL DX, 0(SP) // thread_port
- MOVL $13, 4(SP) // signal: SIGPIPE
- MOVL $328, AX // __pthread_kill
+TEXT runtime·raise(SB),7,$16
+ MOVL $20, AX // getpid
+ INT $0x80
+ MOVL AX, 4(SP) // pid
+ MOVL sig+0(FP), AX
+ MOVL AX, 8(SP) // signal
+ MOVL $1, 12(SP) // posix
+ MOVL $37, AX // kill
INT $0x80
RET
@@ -473,3 +489,32 @@ TEXT runtime·sysctl(SB),7,$0
RET
MOVL $0, AX
RET
+
+// int32 runtime·kqueue(void);
+TEXT runtime·kqueue(SB),7,$0
+ MOVL $362, AX
+ INT $0x80
+ JAE 2(PC)
+ NEGL AX
+ RET
+
+// int32 runtime·kevent(int kq, Kevent *changelist, int nchanges, Kevent *eventlist, int nevents, Timespec *timeout);
+TEXT runtime·kevent(SB),7,$0
+ MOVL $363, AX
+ INT $0x80
+ JAE 2(PC)
+ NEGL AX
+ RET
+
+// int32 runtime·closeonexec(int32 fd);
+TEXT runtime·closeonexec(SB),7,$32
+ MOVL $92, AX // fcntl
+ // 0(SP) is where the caller PC would be; kernel skips it
+ MOVL fd+0(FP), BX
+ MOVL BX, 4(SP) // fd
+ MOVL $2, 8(SP) // F_SETFD
+ MOVL $1, 12(SP) // FD_CLOEXEC
+ INT $0x80
+ JAE 2(PC)
+ NEGL AX
+ RET
diff --git a/src/pkg/runtime/sys_darwin_amd64.s b/src/pkg/runtime/sys_darwin_amd64.s
index 4e43a76c3..b324a0424 100644
--- a/src/pkg/runtime/sys_darwin_amd64.s
+++ b/src/pkg/runtime/sys_darwin_amd64.s
@@ -30,6 +30,28 @@ TEXT runtime·exit1(SB),7,$0
MOVL $0xf1, 0xf1 // crash
RET
+TEXT runtime·open(SB),7,$0
+ MOVQ 8(SP), DI // arg 1 pathname
+ MOVL 16(SP), SI // arg 2 flags
+ MOVL 20(SP), DX // arg 3 mode
+ MOVL $(0x2000000+5), AX // syscall entry
+ SYSCALL
+ RET
+
+TEXT runtime·close(SB),7,$0
+ MOVL 8(SP), DI // arg 1 fd
+ MOVL $(0x2000000+6), AX // syscall entry
+ SYSCALL
+ RET
+
+TEXT runtime·read(SB),7,$0
+ MOVL 8(SP), DI // arg 1 fd
+ MOVQ 16(SP), SI // arg 2 buf
+ MOVL 24(SP), DX // arg 3 count
+ MOVL $(0x2000000+3), AX // syscall entry
+ SYSCALL
+ RET
+
TEXT runtime·write(SB),7,$0
MOVL 8(SP), DI // arg 1 fd
MOVQ 16(SP), SI // arg 2 buf
@@ -38,12 +60,13 @@ TEXT runtime·write(SB),7,$0
SYSCALL
RET
-TEXT runtime·raisesigpipe(SB),7,$24
- get_tls(CX)
- MOVQ m(CX), DX
- MOVL $13, DI // arg 1 SIGPIPE
- MOVQ m_procid(DX), SI // arg 2 thread_port
- MOVL $(0x2000000+328), AX // syscall entry __pthread_kill
+TEXT runtime·raise(SB),7,$24
+ MOVL $(0x2000000+20), AX // getpid
+ SYSCALL
+ MOVQ AX, DI // arg 1 - pid
+ MOVL sig+0(FP), SI // arg 2 - signal
+ MOVL $1, DX // arg 3 - posix
+ MOVL $(0x2000000+37), AX // kill
SYSCALL
RET
@@ -267,7 +290,7 @@ TEXT runtime·bsdthread_create(SB),7,$0
MOVQ $(0x2000000+360), AX // bsdthread_create
SYSCALL
JCC 3(PC)
- NEGL AX
+ NEGQ AX
RET
MOVL $0, AX
RET
@@ -320,7 +343,7 @@ TEXT runtime·bsdthread_register(SB),7,$0
MOVQ $(0x2000000+366), AX // bsdthread_register
SYSCALL
JCC 3(PC)
- NEGL AX
+ NEGQ AX
RET
MOVL $0, AX
RET
@@ -413,7 +436,41 @@ TEXT runtime·sysctl(SB),7,$0
MOVL $(0x2000000+202), AX // syscall entry
SYSCALL
JCC 3(PC)
- NEGL AX
+ NEGQ AX
RET
MOVL $0, AX
RET
+
+// int32 runtime·kqueue(void);
+TEXT runtime·kqueue(SB),7,$0
+ MOVQ $0, DI
+ MOVQ $0, SI
+ MOVQ $0, DX
+ MOVL $(0x2000000+362), AX
+ SYSCALL
+ JCC 2(PC)
+ NEGQ AX
+ RET
+
+// int32 runtime·kevent(int kq, Kevent *changelist, int nchanges, Kevent *eventlist, int nevents, Timespec *timeout);
+TEXT runtime·kevent(SB),7,$0
+ MOVL 8(SP), DI
+ MOVQ 16(SP), SI
+ MOVL 24(SP), DX
+ MOVQ 32(SP), R10
+ MOVL 40(SP), R8
+ MOVQ 48(SP), R9
+ MOVL $(0x2000000+363), AX
+ SYSCALL
+ JCC 2(PC)
+ NEGQ AX
+ RET
+
+// void runtime·closeonexec(int32 fd);
+TEXT runtime·closeonexec(SB),7,$0
+ MOVL 8(SP), DI // fd
+ MOVQ $2, SI // F_SETFD
+ MOVQ $1, DX // FD_CLOEXEC
+ MOVL $(0x2000000+92), AX // fcntl
+ SYSCALL
+ RET
diff --git a/src/pkg/runtime/sys_freebsd_386.s b/src/pkg/runtime/sys_freebsd_386.s
index d5370267a..d960663cb 100644
--- a/src/pkg/runtime/sys_freebsd_386.s
+++ b/src/pkg/runtime/sys_freebsd_386.s
@@ -56,6 +56,21 @@ TEXT runtime·exit1(SB),7,$-4
MOVL $0xf1, 0xf1 // crash
RET
+TEXT runtime·open(SB),7,$-4
+ MOVL $5, AX
+ INT $0x80
+ RET
+
+TEXT runtime·close(SB),7,$-4
+ MOVL $6, AX
+ INT $0x80
+ RET
+
+TEXT runtime·read(SB),7,$-4
+ MOVL $3, AX
+ INT $0x80
+ RET
+
TEXT runtime·write(SB),7,$-4
MOVL $4, AX
INT $0x80
@@ -66,16 +81,17 @@ TEXT runtime·getrlimit(SB),7,$-4
INT $0x80
RET
-TEXT runtime·raisesigpipe(SB),7,$12
+TEXT runtime·raise(SB),7,$16
// thr_self(&8(SP))
LEAL 8(SP), AX
- MOVL AX, 0(SP)
+ MOVL AX, 4(SP)
MOVL $432, AX
INT $0x80
// thr_kill(self, SIGPIPE)
MOVL 8(SP), AX
- MOVL AX, 0(SP)
- MOVL $13, 4(SP)
+ MOVL AX, 4(SP)
+ MOVL sig+0(FP), AX
+ MOVL AX, 8(SP)
MOVL $433, AX
INT $0x80
RET
diff --git a/src/pkg/runtime/sys_freebsd_amd64.s b/src/pkg/runtime/sys_freebsd_amd64.s
index 40c6237e2..cfa33d4fb 100644
--- a/src/pkg/runtime/sys_freebsd_amd64.s
+++ b/src/pkg/runtime/sys_freebsd_amd64.s
@@ -58,6 +58,28 @@ TEXT runtime·exit1(SB),7,$-8
MOVL $0xf1, 0xf1 // crash
RET
+TEXT runtime·open(SB),7,$-8
+ MOVQ 8(SP), DI // arg 1 pathname
+ MOVL 16(SP), SI // arg 2 flags
+ MOVL 20(SP), DX // arg 3 mode
+ MOVL $5, AX
+ SYSCALL
+ RET
+
+TEXT runtime·close(SB),7,$-8
+ MOVL 8(SP), DI // arg 1 fd
+ MOVL $6, AX
+ SYSCALL
+ RET
+
+TEXT runtime·read(SB),7,$-8
+ MOVL 8(SP), DI // arg 1 fd
+ MOVQ 16(SP), SI // arg 2 buf
+ MOVL 24(SP), DX // arg 3 count
+ MOVL $3, AX
+ SYSCALL
+ RET
+
TEXT runtime·write(SB),7,$-8
MOVL 8(SP), DI // arg 1 fd
MOVQ 16(SP), SI // arg 2 buf
@@ -73,14 +95,14 @@ TEXT runtime·getrlimit(SB),7,$-8
SYSCALL
RET
-TEXT runtime·raisesigpipe(SB),7,$16
+TEXT runtime·raise(SB),7,$16
// thr_self(&8(SP))
LEAQ 8(SP), DI // arg 1 &8(SP)
MOVL $432, AX
SYSCALL
// thr_kill(self, SIGPIPE)
MOVQ 8(SP), DI // arg 1 id
- MOVQ $13, SI // arg 2 SIGPIPE
+ MOVL sig+0(FP), SI // arg 2
MOVL $433, AX
SYSCALL
RET
@@ -239,7 +261,7 @@ TEXT runtime·sysctl(SB),7,$0
MOVQ $202, AX // sys___sysctl
SYSCALL
JCC 3(PC)
- NEGL AX
+ NEGQ AX
RET
MOVL $0, AX
RET
diff --git a/src/pkg/runtime/sys_freebsd_arm.s b/src/pkg/runtime/sys_freebsd_arm.s
index 77050e8d0..5531936ff 100644
--- a/src/pkg/runtime/sys_freebsd_arm.s
+++ b/src/pkg/runtime/sys_freebsd_arm.s
@@ -54,6 +54,20 @@ TEXT runtime·exit1(SB),7,$-8
MOVW.CS R9, (R9)
RET
+TEXT runtime·open(SB),7,$-8
+ MOVW 0(FP), R0 // arg 1 name
+ MOVW 4(FP), R1 // arg 2 mode
+ MOVW 8(FP), R2 // arg 3 perm
+ SWI $5
+ RET
+
+TEXT runtime·read(SB),7,$-8
+ MOVW 0(FP), R0 // arg 1 fd
+ MOVW 4(FP), R1 // arg 2 buf
+ MOVW 8(FP), R2 // arg 3 count
+ SWI $3
+ RET
+
TEXT runtime·write(SB),7,$-8
MOVW 0(FP), R0 // arg 1 fd
MOVW 4(FP), R1 // arg 2 buf
@@ -61,6 +75,11 @@ TEXT runtime·write(SB),7,$-8
SWI $4
RET
+TEXT runtime·close(SB),7,$-8
+ MOVW 0(FP), R0 // arg 1 fd
+ SWI $6
+ RET
+
TEXT runtime·getrlimit(SB),7,$-8
MOVW 0(FP), R0
MOVW 4(FP), R1
@@ -68,13 +87,13 @@ TEXT runtime·getrlimit(SB),7,$-8
SWI $194
RET
-TEXT runtime·raisesigpipe(SB),7,$8
+TEXT runtime·raise(SB),7,$8
// thr_self(&4(R13))
MOVW $4(R13), R0 // arg 1 &4(R13)
SWI $432
// thr_kill(self, SIGPIPE)
MOVW 4(R13), R0 // arg 1 id
- MOVW $13, R1 // arg 2 SIGPIPE
+ MOVW sig+0(FP), R1 // arg 2 - signal
SWI $433
RET
diff --git a/src/pkg/runtime/sys_linux_386.s b/src/pkg/runtime/sys_linux_386.s
index f27fd4713..76ebe3dcf 100644
--- a/src/pkg/runtime/sys_linux_386.s
+++ b/src/pkg/runtime/sys_linux_386.s
@@ -77,11 +77,11 @@ TEXT runtime·usleep(SB),7,$8
CALL *runtime·_vdso(SB)
RET
-TEXT runtime·raisesigpipe(SB),7,$12
+TEXT runtime·raise(SB),7,$12
MOVL $224, AX // syscall - gettid
CALL *runtime·_vdso(SB)
- MOVL AX, 0(SP) // arg 1 tid
- MOVL $13, 4(SP) // arg 2 SIGPIPE
+ MOVL AX, BX // arg 1 tid
+ MOVL sig+0(FP), CX // arg 2 signal
MOVL $238, AX // syscall - tkill
CALL *runtime·_vdso(SB)
RET
@@ -430,3 +430,46 @@ TEXT runtime·sched_getaffinity(SB),7,$0
MOVL 12(SP), DX
CALL *runtime·_vdso(SB)
RET
+
+// int32 runtime·epollcreate(int32 size);
+TEXT runtime·epollcreate(SB),7,$0
+ MOVL $254, AX
+ MOVL 4(SP), BX
+ CALL *runtime·_vdso(SB)
+ RET
+
+// int32 runtime·epollcreate1(int32 flags);
+TEXT runtime·epollcreate1(SB),7,$0
+ MOVL $329, AX
+ MOVL 4(SP), BX
+ CALL *runtime·_vdso(SB)
+ RET
+
+// int32 runtime·epollctl(int32 epfd, int32 op, int32 fd, EpollEvent *ev);
+TEXT runtime·epollctl(SB),7,$0
+ MOVL $255, AX
+ MOVL 4(SP), BX
+ MOVL 8(SP), CX
+ MOVL 12(SP), DX
+ MOVL 16(SP), SI
+ CALL *runtime·_vdso(SB)
+ RET
+
+// int32 runtime·epollwait(int32 epfd, EpollEvent *ev, int32 nev, int32 timeout);
+TEXT runtime·epollwait(SB),7,$0
+ MOVL $256, AX
+ MOVL 4(SP), BX
+ MOVL 8(SP), CX
+ MOVL 12(SP), DX
+ MOVL 16(SP), SI
+ CALL *runtime·_vdso(SB)
+ RET
+
+// void runtime·closeonexec(int32 fd);
+TEXT runtime·closeonexec(SB),7,$0
+ MOVL $55, AX // fcntl
+ MOVL 4(SP), BX // fd
+ MOVL $2, CX // F_SETFD
+ MOVL $1, DX // FD_CLOEXEC
+ CALL *runtime·_vdso(SB)
+ RET
diff --git a/src/pkg/runtime/sys_linux_amd64.s b/src/pkg/runtime/sys_linux_amd64.s
index e45943758..2d802abb6 100644
--- a/src/pkg/runtime/sys_linux_amd64.s
+++ b/src/pkg/runtime/sys_linux_amd64.s
@@ -75,11 +75,11 @@ TEXT runtime·usleep(SB),7,$16
SYSCALL
RET
-TEXT runtime·raisesigpipe(SB),7,$12
+TEXT runtime·raise(SB),7,$12
MOVL $186, AX // syscall - gettid
SYSCALL
MOVL AX, DI // arg 1 tid
- MOVL $13, SI // arg 2 SIGPIPE
+ MOVL sig+0(FP), SI // arg 2
MOVL $200, AX // syscall - tkill
SYSCALL
RET
@@ -347,3 +347,46 @@ TEXT runtime·sched_getaffinity(SB),7,$0
MOVL $204, AX // syscall entry
SYSCALL
RET
+
+// int32 runtime·epollcreate(int32 size);
+TEXT runtime·epollcreate(SB),7,$0
+ MOVL 8(SP), DI
+ MOVL $213, AX // syscall entry
+ SYSCALL
+ RET
+
+// int32 runtime·epollcreate1(int32 flags);
+TEXT runtime·epollcreate1(SB),7,$0
+ MOVL 8(SP), DI
+ MOVL $291, AX // syscall entry
+ SYSCALL
+ RET
+
+// int32 runtime·epollctl(int32 epfd, int32 op, int32 fd, EpollEvent *ev);
+TEXT runtime·epollctl(SB),7,$0
+ MOVL 8(SP), DI
+ MOVL 12(SP), SI
+ MOVL 16(SP), DX
+ MOVQ 24(SP), R10
+ MOVL $233, AX // syscall entry
+ SYSCALL
+ RET
+
+// int32 runtime·epollwait(int32 epfd, EpollEvent *ev, int32 nev, int32 timeout);
+TEXT runtime·epollwait(SB),7,$0
+ MOVL 8(SP), DI
+ MOVQ 16(SP), SI
+ MOVL 24(SP), DX
+ MOVL 28(SP), R10
+ MOVL $232, AX // syscall entry
+ SYSCALL
+ RET
+
+// void runtime·closeonexec(int32 fd);
+TEXT runtime·closeonexec(SB),7,$0
+ MOVL 8(SP), DI // fd
+ MOVQ $2, SI // F_SETFD
+ MOVQ $1, DX // FD_CLOEXEC
+ MOVL $72, AX // fcntl
+ SYSCALL
+ RET
diff --git a/src/pkg/runtime/sys_linux_arm.s b/src/pkg/runtime/sys_linux_arm.s
index 8bae2933f..7f813482d 100644
--- a/src/pkg/runtime/sys_linux_arm.s
+++ b/src/pkg/runtime/sys_linux_arm.s
@@ -36,6 +36,11 @@
#define SYS_ugetrlimit (SYS_BASE + 191)
#define SYS_sched_getaffinity (SYS_BASE + 242)
#define SYS_clock_gettime (SYS_BASE + 263)
+#define SYS_epoll_create (SYS_BASE + 250)
+#define SYS_epoll_ctl (SYS_BASE + 251)
+#define SYS_epoll_wait (SYS_BASE + 252)
+#define SYS_epoll_create1 (SYS_BASE + 357)
+#define SYS_fcntl (SYS_BASE + 55)
#define ARM_BASE (SYS_BASE + 0x0f0000)
@@ -92,11 +97,11 @@ TEXT runtime·exit1(SB),7,$-4
MOVW $1003, R1
MOVW R0, (R1) // fail hard
-TEXT runtime·raisesigpipe(SB),7,$-4
+TEXT runtime·raise(SB),7,$-4
MOVW $SYS_gettid, R7
SWI $0
// arg 1 tid already in R0 from gettid
- MOVW $13, R1 // arg 2 SIGPIPE
+ MOVW sig+0(FP), R1 // arg 2 - signal
MOVW $SYS_tkill, R7
SWI $0
RET
@@ -371,7 +376,6 @@ cascheck:
MOVW $0, R0
RET
-
TEXT runtime·casp(SB),7,$0
B runtime·cas(SB)
@@ -387,3 +391,46 @@ TEXT runtime·sched_getaffinity(SB),7,$0
MOVW $SYS_sched_getaffinity, R7
SWI $0
RET
+
+// int32 runtime·epollcreate(int32 size)
+TEXT runtime·epollcreate(SB),7,$0
+ MOVW 0(FP), R0
+ MOVW $SYS_epoll_create, R7
+ SWI $0
+ RET
+
+// int32 runtime·epollcreate1(int32 flags)
+TEXT runtime·epollcreate1(SB),7,$0
+ MOVW 0(FP), R0
+ MOVW $SYS_epoll_create1, R7
+ SWI $0
+ RET
+
+// int32 runtime·epollctl(int32 epfd, int32 op, int32 fd, EpollEvent *ev)
+TEXT runtime·epollctl(SB),7,$0
+ MOVW 0(FP), R0
+ MOVW 4(FP), R1
+ MOVW 8(FP), R2
+ MOVW 12(FP), R3
+ MOVW $SYS_epoll_ctl, R7
+ SWI $0
+ RET
+
+// int32 runtime·epollwait(int32 epfd, EpollEvent *ev, int32 nev, int32 timeout)
+TEXT runtime·epollwait(SB),7,$0
+ MOVW 0(FP), R0
+ MOVW 4(FP), R1
+ MOVW 8(FP), R2
+ MOVW 12(FP), R3
+ MOVW $SYS_epoll_wait, R7
+ SWI $0
+ RET
+
+// void runtime·closeonexec(int32 fd)
+TEXT runtime·closeonexec(SB),7,$0
+ MOVW 0(FP), R0 // fd
+ MOVW $2, R1 // F_SETFD
+ MOVW $1, R2 // FD_CLOEXEC
+ MOVW $SYS_fcntl, R7
+ SWI $0
+ RET
diff --git a/src/pkg/runtime/sys_netbsd_386.s b/src/pkg/runtime/sys_netbsd_386.s
index 3d3d31273..992eba77d 100644
--- a/src/pkg/runtime/sys_netbsd_386.s
+++ b/src/pkg/runtime/sys_netbsd_386.s
@@ -22,6 +22,21 @@ TEXT runtime·exit1(SB),7,$-4
MOVL $0xf1, 0xf1 // crash
RET
+TEXT runtime·open(SB),7,$-4
+ MOVL $5, AX
+ INT $0x80
+ RET
+
+TEXT runtime·close(SB),7,$-4
+ MOVL $6, AX
+ INT $0x80
+ RET
+
+TEXT runtime·read(SB),7,$-4
+ MOVL $3, AX
+ INT $0x80
+ RET
+
TEXT runtime·write(SB),7,$-4
MOVL $4, AX // sys_write
INT $0x80
@@ -46,12 +61,13 @@ TEXT runtime·usleep(SB),7,$24
INT $0x80
RET
-TEXT runtime·raisesigpipe(SB),7,$12
+TEXT runtime·raise(SB),7,$12
MOVL $311, AX // sys__lwp_self
INT $0x80
MOVL $0, 0(SP)
MOVL AX, 4(SP) // arg 1 - target
- MOVL $13, 8(SP) // arg 2 - signo == SIGPIPE
+ MOVL sig+0(FP), AX
+ MOVL AX, 8(SP) // arg 2 - signo
MOVL $318, AX // sys__lwp_kill
INT $0x80
RET
@@ -72,8 +88,6 @@ TEXT runtime·mmap(SB),7,$36
STOSL
MOVL $197, AX // sys_mmap
INT $0x80
- JCC 2(PC)
- NEGL AX
RET
TEXT runtime·munmap(SB),7,$-4
diff --git a/src/pkg/runtime/sys_netbsd_amd64.s b/src/pkg/runtime/sys_netbsd_amd64.s
index e73e83ded..574d8a91b 100644
--- a/src/pkg/runtime/sys_netbsd_amd64.s
+++ b/src/pkg/runtime/sys_netbsd_amd64.s
@@ -16,7 +16,7 @@ TEXT runtime·lwp_create(SB),7,$0
MOVL $309, AX // sys__lwp_create
SYSCALL
JCC 2(PC)
- NEGL AX
+ NEGQ AX
RET
TEXT runtime·lwp_tramp(SB),7,$0
@@ -79,6 +79,28 @@ TEXT runtime·exit1(SB),7,$-8
MOVL $0xf1, 0xf1 // crash
RET
+TEXT runtime·open(SB),7,$-8
+ MOVQ 8(SP), DI // arg 1 pathname
+ MOVL 16(SP), SI // arg 2 flags
+ MOVL 20(SP), DX // arg 3 mode
+ MOVL $5, AX
+ SYSCALL
+ RET
+
+TEXT runtime·close(SB),7,$-8
+ MOVL 8(SP), DI // arg 1 fd
+ MOVL $6, AX
+ SYSCALL
+ RET
+
+TEXT runtime·read(SB),7,$-8
+ MOVL 8(SP), DI // arg 1 fd
+ MOVQ 16(SP), SI // arg 2 buf
+ MOVL 24(SP), DX // arg 3 count
+ MOVL $3, AX
+ SYSCALL
+ RET
+
TEXT runtime·write(SB),7,$-8
MOVL 8(SP), DI // arg 1 - fd
MOVQ 16(SP), SI // arg 2 - buf
@@ -103,11 +125,11 @@ TEXT runtime·usleep(SB),7,$16
SYSCALL
RET
-TEXT runtime·raisesigpipe(SB),7,$16
+TEXT runtime·raise(SB),7,$16
MOVL $311, AX // sys__lwp_self
SYSCALL
MOVQ AX, DI // arg 1 - target
- MOVQ $13, SI // arg 2 - signo == SIGPIPE
+ MOVL sig+0(FP), SI // arg 2 - signo
MOVL $318, AX // sys__lwp_kill
SYSCALL
RET
@@ -231,8 +253,6 @@ TEXT runtime·mmap(SB),7,$0
MOVQ $0, R9 // arg 6 - pad
MOVL $197, AX // sys_mmap
SYSCALL
- JCC 2(PC)
- NEGL AX
ADDQ $16, SP
RET
@@ -284,7 +304,7 @@ TEXT runtime·sysctl(SB),7,$0
MOVQ $202, AX // sys___sysctl
SYSCALL
JCC 3(PC)
- NEGL AX
+ NEGQ AX
RET
MOVL $0, AX
RET
diff --git a/src/pkg/runtime/sys_netbsd_arm.s b/src/pkg/runtime/sys_netbsd_arm.s
index 4a119c5de..3ff335f4d 100644
--- a/src/pkg/runtime/sys_netbsd_arm.s
+++ b/src/pkg/runtime/sys_netbsd_arm.s
@@ -21,6 +21,25 @@ TEXT runtime·exit1(SB),7,$-4
MOVW $1, R9 // crash
MOVW R9, (R9)
RET
+
+TEXT runtime·open(SB),7,$-8
+ MOVW 0(FP), R0
+ MOVW 4(FP), R1
+ MOVW 8(FP), R2
+ SWI $0xa00005
+ RET
+
+TEXT runtime·close(SB),7,$-8
+ MOVW 0(FP), R0
+ SWI $0xa00006
+ RET
+
+TEXT runtime·read(SB),7,$-8
+ MOVW 0(FP), R0
+ MOVW 4(FP), R1
+ MOVW 8(FP), R2
+ SWI $0xa00003
+ RET
TEXT runtime·write(SB),7,$-4
MOVW 0(FP), R0 // arg 1 - fd
@@ -88,9 +107,9 @@ TEXT runtime·usleep(SB),7,$16
SWI $0xa001ae // sys_nanosleep
RET
-TEXT runtime·raisesigpipe(SB),7,$16
+TEXT runtime·raise(SB),7,$16
SWI $0xa00137 // sys__lwp_self, the returned R0 is arg 1
- MOVW $13, R1 // arg 2 - signo == SIGPIPE
+ MOVW sig+0(FP), R1 // arg 2 - signal
SWI $0xa0013e // sys__lwp_kill
RET
diff --git a/src/pkg/runtime/sys_openbsd_386.s b/src/pkg/runtime/sys_openbsd_386.s
index c62e0f949..37b6ff215 100644
--- a/src/pkg/runtime/sys_openbsd_386.s
+++ b/src/pkg/runtime/sys_openbsd_386.s
@@ -24,6 +24,21 @@ TEXT runtime·exit1(SB),7,$8
MOVL $0xf1, 0xf1 // crash
RET
+TEXT runtime·open(SB),7,$-4
+ MOVL $5, AX
+ INT $0x80
+ RET
+
+TEXT runtime·close(SB),7,$-4
+ MOVL $6, AX
+ INT $0x80
+ RET
+
+TEXT runtime·read(SB),7,$-4
+ MOVL $3, AX
+ INT $0x80
+ RET
+
TEXT runtime·write(SB),7,$-4
MOVL $4, AX // sys_write
INT $0x80
@@ -47,12 +62,13 @@ TEXT runtime·usleep(SB),7,$20
INT $0x80
RET
-TEXT runtime·raisesigpipe(SB),7,$12
+TEXT runtime·raise(SB),7,$12
MOVL $299, AX // sys_getthrid
INT $0x80
MOVL $0, 0(SP)
MOVL AX, 4(SP) // arg 1 - pid
- MOVL $13, 8(SP) // arg 2 - signum == SIGPIPE
+ MOVL sig+0(FP), AX
+ MOVL AX, 8(SP) // arg 2 - signum
MOVL $37, AX // sys_kill
INT $0x80
RET
@@ -73,8 +89,6 @@ TEXT runtime·mmap(SB),7,$36
STOSL
MOVL $197, AX // sys_mmap
INT $0x80
- JCC 2(PC)
- NEGL AX
RET
TEXT runtime·munmap(SB),7,$-4
diff --git a/src/pkg/runtime/sys_openbsd_amd64.s b/src/pkg/runtime/sys_openbsd_amd64.s
index 8a736507f..cbd2c2f76 100644
--- a/src/pkg/runtime/sys_openbsd_amd64.s
+++ b/src/pkg/runtime/sys_openbsd_amd64.s
@@ -23,7 +23,7 @@ TEXT runtime·tfork(SB),7,$32
// Return if tfork syscall failed.
JCC 3(PC)
- NEGL AX
+ NEGQ AX
RET
// In parent, return.
@@ -87,6 +87,28 @@ TEXT runtime·exit1(SB),7,$-8
MOVL $0xf1, 0xf1 // crash
RET
+TEXT runtime·open(SB),7,$-8
+ MOVQ 8(SP), DI // arg 1 pathname
+ MOVL 16(SP), SI // arg 2 flags
+ MOVL 20(SP), DX // arg 3 mode
+ MOVL $5, AX
+ SYSCALL
+ RET
+
+TEXT runtime·close(SB),7,$-8
+ MOVL 8(SP), DI // arg 1 fd
+ MOVL $6, AX
+ SYSCALL
+ RET
+
+TEXT runtime·read(SB),7,$-8
+ MOVL 8(SP), DI // arg 1 fd
+ MOVQ 16(SP), SI // arg 2 buf
+ MOVL 24(SP), DX // arg 3 count
+ MOVL $3, AX
+ SYSCALL
+ RET
+
TEXT runtime·write(SB),7,$-8
MOVL 8(SP), DI // arg 1 - fd
MOVQ 16(SP), SI // arg 2 - buf
@@ -111,11 +133,11 @@ TEXT runtime·usleep(SB),7,$16
SYSCALL
RET
-TEXT runtime·raisesigpipe(SB),7,$16
+TEXT runtime·raise(SB),7,$16
MOVL $299, AX // sys_getthrid
SYSCALL
MOVQ AX, DI // arg 1 - pid
- MOVQ $13, SI // arg 2 - signum == SIGPIPE
+ MOVL sig+0(FP), SI // arg 2 - signum
MOVL $37, AX // sys_kill
SYSCALL
RET
@@ -220,8 +242,6 @@ TEXT runtime·mmap(SB),7,$0
MOVQ $0, R9 // arg 6 - pad
MOVL $197, AX
SYSCALL
- JCC 2(PC)
- NEGL AX
ADDQ $16, SP
RET
@@ -272,7 +292,7 @@ TEXT runtime·sysctl(SB),7,$0
MOVQ $202, AX // sys___sysctl
SYSCALL
JCC 3(PC)
- NEGL AX
+ NEGQ AX
RET
MOVL $0, AX
RET
diff --git a/src/pkg/runtime/sys_plan9_386.s b/src/pkg/runtime/sys_plan9_386.s
index 3385b083a..1f860a961 100644
--- a/src/pkg/runtime/sys_plan9_386.s
+++ b/src/pkg/runtime/sys_plan9_386.s
@@ -170,3 +170,30 @@ TEXT runtime·sigtramp(SB),7,$0
// Only used by the 64-bit runtime.
TEXT runtime·setfpmasks(SB),7,$0
RET
+
+#define ERRMAX 128 /* from os_plan9.h */
+
+// func errstr() String
+// Only used by package syscall.
+// Grab error string due to a syscall made
+// in entersyscall mode, without going
+// through the allocator (issue 4994).
+// See ../syscall/asm_plan9_386.s:/·Syscall/
+TEXT runtime·errstr(SB),7,$0
+ get_tls(AX)
+ MOVL m(AX), BX
+ MOVL m_errstr(BX), CX
+ MOVL CX, 4(SP)
+ MOVL $ERRMAX, 8(SP)
+ MOVL $41, AX
+ INT $64
+
+ // syscall requires caller-save
+ MOVL 4(SP), CX
+
+ // push the argument
+ PUSHL CX
+ CALL runtime·findnull(SB)
+ POPL CX
+ MOVL AX, 8(SP)
+ RET
diff --git a/src/pkg/runtime/sys_plan9_amd64.s b/src/pkg/runtime/sys_plan9_amd64.s
index b34f98a68..c0c896ebc 100644
--- a/src/pkg/runtime/sys_plan9_amd64.s
+++ b/src/pkg/runtime/sys_plan9_amd64.s
@@ -206,3 +206,31 @@ TEXT runtime·setfpmasks(SB),7,$8
MOVL AX, 0(SP)
LDMXCSR 0(SP)
RET
+
+#define ERRMAX 128 /* from os_plan9.h */
+
+// func errstr() String
+// Only used by package syscall.
+// Grab error string due to a syscall made
+// in entersyscall mode, without going
+// through the allocator (issue 4994).
+// See ../syscall/asm_plan9_386.s:/·Syscall/
+TEXT runtime·errstr(SB),7,$0
+ get_tls(AX)
+ MOVQ m(AX), BX
+ MOVQ m_errstr(BX), CX
+ MOVQ CX, 8(SP)
+ MOVQ $ERRMAX, 16(SP)
+ MOVQ $0x8000, AX
+ MOVQ $41, BP
+ SYSCALL
+
+ // syscall requires caller-save
+ MOVQ 8(SP), CX
+
+ // push the argument
+ PUSHQ CX
+ CALL runtime·findnull(SB)
+ POPQ CX
+ MOVQ AX, 16(SP)
+ RET
diff --git a/src/pkg/runtime/sys_windows_386.s b/src/pkg/runtime/sys_windows_386.s
index ca59f0a1d..206cdccc4 100644
--- a/src/pkg/runtime/sys_windows_386.s
+++ b/src/pkg/runtime/sys_windows_386.s
@@ -314,3 +314,46 @@ TEXT runtime·remove_exception_handler(SB),7,$0
MOVL AX, 0(FS)
RET
+
+TEXT runtime·osyield(SB),7,$20
+ // Tried NtYieldExecution but it doesn't yield hard enough.
+ // NtWaitForSingleObject being used here as Sleep(0).
+ MOVL runtime·NtWaitForSingleObject(SB), AX
+ MOVL $-1, hi-4(SP)
+ MOVL $-1, lo-8(SP)
+ LEAL lo-8(SP), BX
+ MOVL BX, ptime-12(SP)
+ MOVL $0, alertable-16(SP)
+ MOVL $-1, handle-20(SP)
+ MOVL SP, BP
+ CALL checkstack4<>(SB)
+ CALL AX
+ MOVL BP, SP
+ RET
+
+TEXT runtime·usleep(SB),7,$20
+ MOVL runtime·NtWaitForSingleObject(SB), AX
+ // Have 1us units; need negative 100ns units.
+ // Assume multiply by 10 will not overflow 32-bit word.
+ MOVL usec+0(FP), BX
+ IMULL $10, BX
+ NEGL BX
+ MOVL $-1, hi-4(SP)
+ MOVL BX, lo-8(SP)
+ LEAL lo-8(SP), BX
+ MOVL BX, ptime-12(SP)
+ MOVL $0, alertable-16(SP)
+ MOVL $-1, handle-20(SP)
+ MOVL SP, BP
+ CALL checkstack4<>(SB)
+ CALL AX
+ MOVL BP, SP
+ RET
+
+// This function requires 4 bytes of stack,
+// to simulate what calling NtWaitForSingleObject will use.
+// (It is just a CALL to the system call dispatch.)
+// If the linker okays the call to checkstack4 (a NOSPLIT function)
+// then the call to NtWaitForSingleObject is okay too.
+TEXT checkstack4<>(SB),7,$4
+ RET
diff --git a/src/pkg/runtime/sys_windows_amd64.s b/src/pkg/runtime/sys_windows_amd64.s
index fe88f3b75..c20a268b1 100644
--- a/src/pkg/runtime/sys_windows_amd64.s
+++ b/src/pkg/runtime/sys_windows_amd64.s
@@ -346,3 +346,35 @@ TEXT runtime·install_exception_handler(SB),7,$0
TEXT runtime·remove_exception_handler(SB),7,$0
RET
+
+TEXT runtime·osyield(SB),7,$8
+ // Tried NtYieldExecution but it doesn't yield hard enough.
+ // NtWaitForSingleObject being used here as Sleep(0).
+ // The CALL is safe because NtXxx is a system call wrapper:
+ // it puts the right system call number in AX, then does
+ // a SYSENTER and a RET.
+ MOVQ runtime·NtWaitForSingleObject(SB), AX
+ MOVQ $1, BX
+ NEGQ BX
+ MOVQ SP, R8 // ptime
+ MOVQ BX, (R8)
+ MOVQ $-1, CX // handle
+ MOVQ $0, DX // alertable
+ CALL AX
+ RET
+
+TEXT runtime·usleep(SB),7,$8
+ // The CALL is safe because NtXxx is a system call wrapper:
+ // it puts the right system call number in AX, then does
+ // a SYSENTER and a RET.
+ MOVQ runtime·NtWaitForSingleObject(SB), AX
+ // Have 1us units; want negative 100ns units.
+ MOVL usec+0(FP), BX
+ IMULQ $10, BX
+ NEGQ BX
+ MOVQ SP, R8 // ptime
+ MOVQ BX, (R8)
+ MOVQ $-1, CX // handle
+ MOVQ $0, DX // alertable
+ CALL AX
+ RET
diff --git a/src/pkg/runtime/time.goc b/src/pkg/runtime/time.goc
index 2babb173d..6de989f51 100644
--- a/src/pkg/runtime/time.goc
+++ b/src/pkg/runtime/time.goc
@@ -15,7 +15,6 @@ package time
static Timers timers;
static void addtimer(Timer*);
-static bool deltimer(Timer*);
// Package time APIs.
// Godoc uses the comments in package time, not these.
@@ -31,15 +30,13 @@ func Sleep(ns int64) {
func startTimer(t *Timer) {
if(raceenabled)
runtime·racerelease(t);
- runtime·lock(&timers);
- addtimer(t);
- runtime·unlock(&timers);
+ 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 = deltimer(t);
+ stopped = runtime·deltimer(t);
}
// C runtime.
@@ -79,6 +76,14 @@ runtime·tsleep(int64 ns, int8 *reason)
static FuncVal timerprocv = {timerproc};
+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
@@ -121,8 +126,8 @@ addtimer(Timer *t)
// Delete timer t from the heap.
// Do not need to update the timerproc:
// if it wakes up early, no big deal.
-static bool
-deltimer(Timer *t)
+bool
+runtime·deltimer(Timer *t)
{
int32 i;
diff --git a/src/pkg/runtime/time_plan9_386.c b/src/pkg/runtime/time_plan9_386.c
index a29d45715..fc08a90d6 100644
--- a/src/pkg/runtime/time_plan9_386.c
+++ b/src/pkg/runtime/time_plan9_386.c
@@ -24,7 +24,7 @@ runtime·nanotime(void)
// file descriptor) is roughly four times slower
// in 9vx on a 2.16 GHz Intel Core 2 Duo.
- if(fd < 0 && (fd = runtime·open((byte*)"/dev/bintime", OREAD|OCEXEC)) < 0)
+ if(fd < 0 && (fd = runtime·open("/dev/bintime", OREAD|OCEXEC, 0)) < 0)
return 0;
if(runtime·pread(fd, b, sizeof b, 0) != sizeof b)
return 0;
diff --git a/src/pkg/runtime/traceback_arm.c b/src/pkg/runtime/traceback_arm.c
index dd85cc02c..ae2d3241f 100644
--- a/src/pkg/runtime/traceback_arm.c
+++ b/src/pkg/runtime/traceback_arm.c
@@ -17,9 +17,9 @@ void _divu(void);
void _modu(void);
int32
-runtime·gentraceback(byte *pc0, byte *sp, byte *lr0, G *gp, int32 skip, uintptr *pcbuf, int32 max)
+runtime·gentraceback(byte *pc0, byte *sp, byte *lr0, G *gp, int32 skip, uintptr *pcbuf, int32 max, void (*fn)(Func*, byte*, byte*, void*), void *arg)
{
- int32 i, n, iter;
+ int32 i, n;
uintptr pc, lr, tracepc, x;
byte *fp;
bool waspanic;
@@ -46,7 +46,7 @@ runtime·gentraceback(byte *pc0, byte *sp, byte *lr0, G *gp, int32 skip, uintptr
n = 0;
stk = (Stktop*)gp->stackbase;
- for(iter = 0; iter < 100 && n < max; iter++) { // iter avoids looping forever
+ while(n < max) {
// Typically:
// pc is the PC of the running function.
// sp is the stack pointer at that program counter.
@@ -60,28 +60,34 @@ runtime·gentraceback(byte *pc0, byte *sp, byte *lr0, G *gp, int32 skip, uintptr
sp = (byte*)stk->gobuf.sp;
lr = 0;
fp = nil;
- if(pcbuf == nil && runtime·showframe(nil, gp == m->curg))
+ if(pcbuf == nil && fn == nil && runtime·showframe(nil, gp == m->curg))
runtime·printf("----- stack segment boundary -----\n");
stk = (Stktop*)stk->stackbase;
continue;
}
- if(pc <= 0x1000 || (f = runtime·findfunc(pc)) == nil)
+ if(pc <= 0x1000 || (f = runtime·findfunc(pc)) == nil) {
+ if(fn != nil)
+ runtime·throw("unknown pc");
break;
+ }
// Found an actual function.
if(lr == 0)
lr = *(uintptr*)sp;
if(fp == nil) {
fp = sp;
- if(pc > f->entry && f->frame >= 0)
- fp += f->frame;
+ if(pc > f->entry && f->frame >= sizeof(uintptr))
+ fp += f->frame - sizeof(uintptr);
+ fp += sizeof(uintptr);
}
if(skip > 0)
skip--;
else if(pcbuf != nil)
pcbuf[n++] = pc;
+ else if(fn != nil)
+ (*fn)(f, (byte*)pc, sp, arg);
else {
if(runtime·showframe(f, gp == m->curg)) {
// Print during crash.
@@ -113,7 +119,7 @@ runtime·gentraceback(byte *pc0, byte *sp, byte *lr0, G *gp, int32 skip, uintptr
waspanic = f->entry == (uintptr)runtime·sigpanic;
- if(pcbuf == nil && f->entry == (uintptr)runtime·newstack && gp == m->g0) {
+ if(pcbuf == nil && fn == nil && f->entry == (uintptr)runtime·newstack && gp == m->g0) {
runtime·printf("----- newstack called from goroutine %D -----\n", m->curg->goid);
pc = (uintptr)m->morepc;
sp = (byte*)m->moreargp - sizeof(void*);
@@ -124,7 +130,7 @@ runtime·gentraceback(byte *pc0, byte *sp, byte *lr0, G *gp, int32 skip, uintptr
continue;
}
- if(pcbuf == nil && f->entry == (uintptr)runtime·lessstack && gp == m->g0) {
+ if(pcbuf == nil && fn == nil && f->entry == (uintptr)runtime·lessstack && gp == m->g0) {
runtime·printf("----- lessstack called from goroutine %D -----\n", m->curg->goid);
gp = m->curg;
stk = (Stktop*)gp->stackbase;
@@ -135,6 +141,10 @@ runtime·gentraceback(byte *pc0, byte *sp, byte *lr0, G *gp, int32 skip, uintptr
continue;
}
+ // Do not unwind past the bottom of the stack.
+ if(pc == (uintptr)runtime·goexit)
+ break;
+
// Unwind to next frame.
pc = lr;
lr = 0;
@@ -162,7 +172,7 @@ runtime·gentraceback(byte *pc0, byte *sp, byte *lr0, G *gp, int32 skip, uintptr
}
}
- if(pcbuf == nil && (pc = gp->gopc) != 0 && (f = runtime·findfunc(pc)) != nil
+ if(pcbuf == nil && fn == nil && (pc = gp->gopc) != 0 && (f = runtime·findfunc(pc)) != nil
&& runtime·showframe(f, gp == m->curg) && gp->goid != 1) {
runtime·printf("created by %S\n", f->name);
tracepc = pc; // back up to CALL instruction for funcline.
@@ -186,7 +196,7 @@ runtime·traceback(byte *pc0, byte *sp, byte *lr, G *gp)
sp = (byte*)gp->sched.sp;
lr = nil;
}
- runtime·gentraceback(pc0, sp, lr, gp, 0, nil, 100);
+ runtime·gentraceback(pc0, sp, lr, gp, 0, nil, 100, nil, nil);
}
// func caller(n int) (pc uintptr, file string, line int, ok bool)
@@ -198,5 +208,5 @@ runtime·callers(int32 skip, uintptr *pcbuf, int32 m)
sp = runtime·getcallersp(&skip);
pc = runtime·getcallerpc(&skip);
- return runtime·gentraceback(pc, sp, 0, g, skip, pcbuf, m);
+ return runtime·gentraceback(pc, sp, 0, g, skip, pcbuf, m, nil, nil);
}
diff --git a/src/pkg/runtime/traceback_x86.c b/src/pkg/runtime/traceback_x86.c
index 72603ae8e..ce52df870 100644
--- a/src/pkg/runtime/traceback_x86.c
+++ b/src/pkg/runtime/traceback_x86.c
@@ -17,14 +17,14 @@ void runtime·sigpanic(void);
// This code is also used for the 386 tracebacks.
// Use uintptr for an appropriate word-sized integer.
-// Generic traceback. Handles runtime stack prints (pcbuf == nil)
-// as well as the runtime.Callers function (pcbuf != nil).
-// A little clunky to merge the two but avoids duplicating
-// the code and all its subtlety.
+// Generic traceback. Handles runtime stack prints (pcbuf == nil),
+// the runtime.Callers function (pcbuf != nil), as well as the garbage
+// collector (fn != nil). A little clunky to merge the two but avoids
+// duplicating the code and all its subtlety.
int32
-runtime·gentraceback(byte *pc0, byte *sp, byte *lr0, G *gp, int32 skip, uintptr *pcbuf, int32 max)
+runtime·gentraceback(byte *pc0, byte *sp, byte *lr0, G *gp, int32 skip, uintptr *pcbuf, int32 max, void (*fn)(Func*, byte*, byte*, void*), void *arg)
{
- int32 i, n, iter, sawnewstack;
+ int32 i, n, sawnewstack;
uintptr pc, lr, tracepc;
byte *fp;
Stktop *stk;
@@ -54,7 +54,7 @@ runtime·gentraceback(byte *pc0, byte *sp, byte *lr0, G *gp, int32 skip, uintptr
n = 0;
sawnewstack = 0;
stk = (Stktop*)gp->stackbase;
- for(iter = 0; iter < 100 && n < max; iter++) { // iter avoids looping forever
+ while(n < max) {
// Typically:
// pc is the PC of the running function.
// sp is the stack pointer at that program counter.
@@ -68,13 +68,16 @@ runtime·gentraceback(byte *pc0, byte *sp, byte *lr0, G *gp, int32 skip, uintptr
sp = (byte*)stk->gobuf.sp;
lr = 0;
fp = nil;
- if(pcbuf == nil && runtime·showframe(nil, gp == m->curg))
+ if(pcbuf == nil && fn == nil && runtime·showframe(nil, gp == m->curg))
runtime·printf("----- stack segment boundary -----\n");
stk = (Stktop*)stk->stackbase;
continue;
}
- if(pc <= 0x1000 || (f = runtime·findfunc(pc)) == nil)
+ if(pc <= 0x1000 || (f = runtime·findfunc(pc)) == nil) {
+ if(fn != nil)
+ runtime·throw("unknown pc");
break;
+ }
// Found an actual function.
if(fp == nil) {
@@ -91,6 +94,8 @@ runtime·gentraceback(byte *pc0, byte *sp, byte *lr0, G *gp, int32 skip, uintptr
skip--;
else if(pcbuf != nil)
pcbuf[n++] = pc;
+ else if(fn != nil)
+ (*fn)(f, (byte*)pc, sp, arg);
else {
if(runtime·showframe(f, gp == m->curg)) {
// Print during crash.
@@ -129,7 +134,7 @@ runtime·gentraceback(byte *pc0, byte *sp, byte *lr0, G *gp, int32 skip, uintptr
if(f->entry == (uintptr)runtime·newstack)
sawnewstack = 1;
- if(pcbuf == nil && f->entry == (uintptr)runtime·morestack && gp == m->g0 && sawnewstack) {
+ if(pcbuf == nil && fn == nil && f->entry == (uintptr)runtime·morestack && gp == m->g0 && sawnewstack) {
// The fact that we saw newstack means that morestack
// has managed to record its information in m, so we can
// use it to keep unwinding the stack.
@@ -144,7 +149,7 @@ runtime·gentraceback(byte *pc0, byte *sp, byte *lr0, G *gp, int32 skip, uintptr
continue;
}
- if(pcbuf == nil && f->entry == (uintptr)runtime·lessstack && gp == m->g0) {
+ if(pcbuf == nil && fn == nil && f->entry == (uintptr)runtime·lessstack && gp == m->g0) {
// Lessstack is running on scheduler stack. Switch to original goroutine.
runtime·printf("----- lessstack called from goroutine %D -----\n", m->curg->goid);
gp = m->curg;
@@ -156,6 +161,10 @@ runtime·gentraceback(byte *pc0, byte *sp, byte *lr0, G *gp, int32 skip, uintptr
continue;
}
+ // Do not unwind past the bottom of the stack.
+ if(pc == (uintptr)runtime·goexit)
+ break;
+
// Unwind to next frame.
pc = lr;
lr = 0;
@@ -164,7 +173,7 @@ runtime·gentraceback(byte *pc0, byte *sp, byte *lr0, G *gp, int32 skip, uintptr
}
// Show what created goroutine, except main goroutine (goid 1).
- if(pcbuf == nil && (pc = gp->gopc) != 0 && (f = runtime·findfunc(pc)) != nil
+ if(pcbuf == nil && fn == nil && (pc = gp->gopc) != 0 && (f = runtime·findfunc(pc)) != nil
&& runtime·showframe(f, gp == m->curg) && gp->goid != 1) {
runtime·printf("created by %S\n", f->name);
tracepc = pc; // back up to CALL instruction for funcline.
@@ -187,7 +196,7 @@ runtime·traceback(byte *pc0, byte *sp, byte*, G *gp)
pc0 = gp->sched.pc;
sp = (byte*)gp->sched.sp;
}
- runtime·gentraceback(pc0, sp, nil, gp, 0, nil, 100);
+ runtime·gentraceback(pc0, sp, nil, gp, 0, nil, 100, nil, nil);
}
int32
@@ -199,5 +208,5 @@ runtime·callers(int32 skip, uintptr *pcbuf, int32 m)
sp = (byte*)&skip;
pc = runtime·getcallerpc(&skip);
- return runtime·gentraceback(pc, sp, nil, g, skip, pcbuf, m);
+ return runtime·gentraceback(pc, sp, nil, g, skip, pcbuf, m, nil, nil);
}
diff --git a/src/pkg/runtime/vdso_linux_amd64.c b/src/pkg/runtime/vdso_linux_amd64.c
index ab68c23c3..f55d312a0 100644
--- a/src/pkg/runtime/vdso_linux_amd64.c
+++ b/src/pkg/runtime/vdso_linux_amd64.c
@@ -4,6 +4,7 @@
#include "runtime.h"
+#define AT_RANDOM 25
#define AT_SYSINFO_EHDR 33
#define AT_NULL 0 /* End of vector */
#define PT_LOAD 1 /* Loadable program segment */
@@ -319,11 +320,16 @@ runtime·linux_setup_vdso(int32 argc, uint8** argv)
if(elf_auxv[i].a_type == AT_SYSINFO_EHDR) {
if(elf_auxv[i].a_un.a_val == 0) {
// Something went wrong
- return;
+ continue;
}
vdso_init_from_sysinfo_ehdr(&vdso_info, (Elf64_Ehdr*)elf_auxv[i].a_un.a_val);
vdso_parse_symbols(&vdso_info, vdso_find_version(&vdso_info, &linux26));
- return;
+ continue;
+ }
+ if(elf_auxv[i].a_type == AT_RANDOM) {
+ runtime·startup_random_data = (byte*)elf_auxv[i].a_un.a_val;
+ runtime·startup_random_data_len = 16;
+ continue;
}
}
}
diff --git a/src/pkg/sort/example_multi_test.go b/src/pkg/sort/example_multi_test.go
new file mode 100644
index 000000000..d0a9e7dc3
--- /dev/null
+++ b/src/pkg/sort/example_multi_test.go
@@ -0,0 +1,132 @@
+// 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 sort_test
+
+import (
+ "fmt"
+ "sort"
+)
+
+// A Change is a record of source code changes, recording user, language, and delta size.
+type Change struct {
+ user string
+ language string
+ lines int
+}
+
+type lessFunc func(p1, p2 *Change) bool
+
+// multiSorter implements the Sort interface, sorting the changes within.
+type multiSorter struct {
+ changes []Change
+ less []lessFunc
+}
+
+// Sort sorts the argument slice according to the less functions passed to OrderedBy.
+func (ms *multiSorter) Sort(changes []Change) {
+ sort.Sort(ms)
+}
+
+// OrderedBy returns a Sorter that sorts using the less functions, in order.
+// Call its Sort method to sort the data.
+func OrderedBy(less ...lessFunc) *multiSorter {
+ return &multiSorter{
+ changes: changes,
+ less: less,
+ }
+}
+
+// Len is part of sort.Interface.
+func (ms *multiSorter) Len() int {
+ return len(ms.changes)
+}
+
+// Swap is part of sort.Interface.
+func (ms *multiSorter) Swap(i, j int) {
+ ms.changes[i], ms.changes[j] = ms.changes[j], ms.changes[i]
+}
+
+// Less is part of sort.Interface. It is implemented by looping along the
+// less functions until it finds a comparison that is either Less or
+// !Less. Note that it can call the less functions twice per call. We
+// could change the functions to return -1, 0, 1 and reduce the
+// number of calls for greater efficiency: an exercise for the reader.
+func (ms *multiSorter) Less(i, j int) bool {
+ p, q := &ms.changes[i], &ms.changes[j]
+ // Try all but the last comparison.
+ var k int
+ for k = 0; k < len(ms.less)-1; k++ {
+ less := ms.less[k]
+ switch {
+ case less(p, q):
+ // p < q, so we have a decision.
+ return true
+ case less(q, p):
+ // p > q, so we have a decision.
+ return false
+ }
+ // p == q; try the next comparison.
+ }
+ // All comparisons to here said "equal", so just return whatever
+ // the final comparison reports.
+ return ms.less[k](p, q)
+}
+
+var changes = []Change{
+ {"gri", "Go", 100},
+ {"ken", "C", 150},
+ {"glenda", "Go", 200},
+ {"rsc", "Go", 200},
+ {"r", "Go", 100},
+ {"ken", "Go", 200},
+ {"dmr", "C", 100},
+ {"r", "C", 150},
+ {"gri", "Smalltalk", 80},
+}
+
+// ExampleMultiKeys demonstrates a technique for sorting a struct type using different
+// sets of multiple fields in the comparison. We chain together "Less" functions, each of
+// which compares a single field.
+func Example_sortMultiKeys() {
+ // Closures that order the Change structure.
+ user := func(c1, c2 *Change) bool {
+ return c1.user < c2.user
+ }
+ language := func(c1, c2 *Change) bool {
+ return c1.language < c2.language
+ }
+ increasingLines := func(c1, c2 *Change) bool {
+ return c1.lines < c2.lines
+ }
+ decreasingLines := func(c1, c2 *Change) bool {
+ return c1.lines > c2.lines // Note: > orders downwards.
+ }
+
+ // Simple use: Sort by user.
+ OrderedBy(user).Sort(changes)
+ fmt.Println("By user:", changes)
+
+ // multiSorter implements the Sort interface, so we can also do this.
+ sort.Sort(OrderedBy(user, increasingLines))
+ fmt.Println("By user,<lines:", changes)
+
+ // More examples.
+ OrderedBy(user, decreasingLines).Sort(changes)
+ fmt.Println("By user,>lines:", changes)
+
+ OrderedBy(language, increasingLines).Sort(changes)
+ fmt.Println("By language,<lines:", changes)
+
+ OrderedBy(language, increasingLines, user).Sort(changes)
+ fmt.Println("By language,<lines,user:", changes)
+
+ // Output:
+ //By user: [{dmr C 100} {glenda Go 200} {gri Smalltalk 80} {gri Go 100} {ken Go 200} {ken C 150} {r Go 100} {r C 150} {rsc Go 200}]
+ //By user,<lines: [{dmr C 100} {glenda Go 200} {gri Smalltalk 80} {gri Go 100} {ken C 150} {ken Go 200} {r Go 100} {r C 150} {rsc Go 200}]
+ //By user,>lines: [{dmr C 100} {glenda Go 200} {gri Go 100} {gri Smalltalk 80} {ken Go 200} {ken C 150} {r C 150} {r Go 100} {rsc Go 200}]
+ //By language,<lines: [{dmr C 100} {ken C 150} {r C 150} {gri Go 100} {r Go 100} {ken Go 200} {glenda Go 200} {rsc Go 200} {gri Smalltalk 80}]
+ //By language,<lines,user: [{dmr C 100} {ken C 150} {r C 150} {gri Go 100} {r Go 100} {glenda Go 200} {ken Go 200} {rsc Go 200} {gri Smalltalk 80}]
+
+}
diff --git a/src/pkg/sort/search_test.go b/src/pkg/sort/search_test.go
index 4d8d6d930..ee95c663c 100644
--- a/src/pkg/sort/search_test.go
+++ b/src/pkg/sort/search_test.go
@@ -5,6 +5,7 @@
package sort_test
import (
+ "runtime"
. "sort"
"testing"
)
@@ -127,6 +128,9 @@ func runSearchWrappers() {
}
func TestSearchWrappersDontAlloc(t *testing.T) {
+ if runtime.GOMAXPROCS(0) > 1 {
+ t.Skip("skipping; GOMAXPROCS>1")
+ }
allocs := testing.AllocsPerRun(100, runSearchWrappers)
if allocs != 0 {
t.Errorf("expected no allocs for runSearchWrappers, got %v", allocs)
diff --git a/src/pkg/sort/sort.go b/src/pkg/sort/sort.go
index e10961992..d3092e801 100644
--- a/src/pkg/sort/sort.go
+++ b/src/pkg/sort/sort.go
@@ -6,8 +6,6 @@
// collections.
package sort
-import "math"
-
// A type, typically a collection, that satisfies sort.Interface can be
// sorted by the routines in this package. The methods require that the
// elements of the collection be enumerated by an integer index.
@@ -245,9 +243,14 @@ func (p IntSlice) Sort() { Sort(p) }
type Float64Slice []float64
func (p Float64Slice) Len() int { return len(p) }
-func (p Float64Slice) Less(i, j int) bool { return p[i] < p[j] || math.IsNaN(p[i]) && !math.IsNaN(p[j]) }
+func (p Float64Slice) Less(i, j int) bool { return p[i] < p[j] || isNaN(p[i]) && !isNaN(p[j]) }
func (p Float64Slice) Swap(i, j int) { p[i], p[j] = p[j], p[i] }
+// isNaN is a copy of math.IsNaN to avoid a dependency on the math package.
+func isNaN(f float64) bool {
+ return f != f
+}
+
// Sort is a convenience method.
func (p Float64Slice) Sort() { Sort(p) }
diff --git a/src/pkg/strconv/extfloat.go b/src/pkg/strconv/extfloat.go
index b7eaaa61b..bed8b16bd 100644
--- a/src/pkg/strconv/extfloat.go
+++ b/src/pkg/strconv/extfloat.go
@@ -636,7 +636,6 @@ func (f *extFloat) ShortestDecimal(d *decimalSlice, lower, upper *extFloat) bool
1<<shift, multiplier*2)
}
}
- return false
}
// adjustLastDigit modifies d = x-currentDiff*ε, to get closest to
diff --git a/src/pkg/strconv/strconv_test.go b/src/pkg/strconv/strconv_test.go
index c3c538926..40ab4ce6a 100644
--- a/src/pkg/strconv/strconv_test.go
+++ b/src/pkg/strconv/strconv_test.go
@@ -5,6 +5,7 @@
package strconv_test
import (
+ "runtime"
. "strconv"
"strings"
"testing"
@@ -19,14 +20,12 @@ var (
desc string
fn func()
}{
- // TODO(bradfitz): this might be 0, once escape analysis is better
- {1, `AppendInt(localBuf[:0], 123, 10)`, func() {
+ {0, `AppendInt(localBuf[:0], 123, 10)`, func() {
var localBuf [64]byte
AppendInt(localBuf[:0], 123, 10)
}},
{0, `AppendInt(globalBuf[:0], 123, 10)`, func() { AppendInt(globalBuf[:0], 123, 10) }},
- // TODO(bradfitz): this might be 0, once escape analysis is better
- {1, `AppendFloat(localBuf[:0], 1.23, 'g', 5, 64)`, func() {
+ {0, `AppendFloat(localBuf[:0], 1.23, 'g', 5, 64)`, func() {
var localBuf [64]byte
AppendFloat(localBuf[:0], 1.23, 'g', 5, 64)
}},
@@ -43,6 +42,9 @@ var (
)
func TestCountMallocs(t *testing.T) {
+ if runtime.GOMAXPROCS(0) > 1 {
+ t.Skip("skipping; GOMAXPROCS>1")
+ }
for _, mt := range mallocTest {
allocs := testing.AllocsPerRun(100, mt.fn)
if max := float64(mt.count); allocs > max {
diff --git a/src/pkg/strings/strings.go b/src/pkg/strings/strings.go
index ccf415e69..986f6d61e 100644
--- a/src/pkg/strings/strings.go
+++ b/src/pkg/strings/strings.go
@@ -26,7 +26,11 @@ func explode(s string, n int) []string {
i, cur := 0, 0
for ; i+1 < n; i++ {
ch, size = utf8.DecodeRuneInString(s[cur:])
- a[i] = string(ch)
+ 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
@@ -488,10 +492,10 @@ func isSeparator(r rune) bool {
return unicode.IsSpace(r)
}
-// BUG(r): The rule Title uses for word boundaries does not handle Unicode punctuation properly.
-
// Title returns a copy of the string s with all Unicode letters that begin words
// mapped to their title case.
+//
+// BUG: The rule Title uses for word boundaries does not handle Unicode punctuation properly.
func Title(s string) string {
// Use a closure here to remember state.
// Hackish but effective. Depends on Map scanning in order and calling
diff --git a/src/pkg/strings/strings_test.go b/src/pkg/strings/strings_test.go
index 09de49e5f..68b658ca4 100644
--- a/src/pkg/strings/strings_test.go
+++ b/src/pkg/strings/strings_test.go
@@ -1095,3 +1095,21 @@ func BenchmarkFieldsFunc(b *testing.B) {
FieldsFunc(fieldsInput, unicode.IsSpace)
}
}
+
+func BenchmarkSplit1(b *testing.B) {
+ for i := 0; i < b.N; i++ {
+ Split(benchInputHard, "")
+ }
+}
+
+func BenchmarkSplit2(b *testing.B) {
+ for i := 0; i < b.N; i++ {
+ Split(benchInputHard, "/")
+ }
+}
+
+func BenchmarkSplit3(b *testing.B) {
+ for i := 0; i < b.N; i++ {
+ Split(benchInputHard, "hello")
+ }
+}
diff --git a/src/pkg/sync/atomic/asm_386.s b/src/pkg/sync/atomic/asm_386.s
index 7a98a61d8..8c02f106f 100644
--- a/src/pkg/sync/atomic/asm_386.s
+++ b/src/pkg/sync/atomic/asm_386.s
@@ -28,10 +28,13 @@ TEXT ·CompareAndSwapInt64(SB),7,$0
TEXT ·CompareAndSwapUint64(SB),7,$0
MOVL addr+0(FP), BP
- MOVL old+4(FP), AX
- MOVL old+8(FP), DX
- MOVL new+12(FP), BX
- MOVL new+16(FP), CX
+ TESTL $7, BP
+ JZ 2(PC)
+ MOVL 0, AX // crash with nil ptr deref
+ MOVL old_lo+4(FP), AX
+ MOVL old_hi+8(FP), DX
+ MOVL new_lo+12(FP), BX
+ MOVL new_hi+16(FP), CX
// CMPXCHG8B was introduced on the Pentium.
LOCK
CMPXCHG8B 0(BP)
@@ -61,9 +64,12 @@ TEXT ·AddInt64(SB),7,$0
TEXT ·AddUint64(SB),7,$0
// no XADDQ so use CMPXCHG8B loop
MOVL addr+0(FP), BP
+ TESTL $7, BP
+ JZ 2(PC)
+ MOVL 0, AX // crash with nil ptr deref
// DI:SI = delta
- MOVL delta+4(FP), SI
- MOVL delta+8(FP), DI
+ MOVL delta_lo+4(FP), SI
+ MOVL delta_hi+8(FP), DI
// DX:AX = *addr
MOVL 0(BP), AX
MOVL 4(BP), DX
@@ -87,8 +93,8 @@ addloop:
// success
// return CX:BX
- MOVL BX, new+12(FP)
- MOVL CX, new+16(FP)
+ MOVL BX, new_lo+12(FP)
+ MOVL CX, new_hi+16(FP)
RET
TEXT ·LoadInt32(SB),7,$0
@@ -105,6 +111,9 @@ TEXT ·LoadInt64(SB),7,$0
TEXT ·LoadUint64(SB),7,$0
MOVL addr+0(FP), AX
+ TESTL $7, AX
+ JZ 2(PC)
+ MOVL 0, AX // crash with nil ptr deref
// MOVQ and EMMS were introduced on the Pentium MMX.
// MOVQ (%EAX), %MM0
BYTE $0x0f; BYTE $0x6f; BYTE $0x00
@@ -133,6 +142,9 @@ TEXT ·StoreInt64(SB),7,$0
TEXT ·StoreUint64(SB),7,$0
MOVL addr+0(FP), AX
+ TESTL $7, AX
+ JZ 2(PC)
+ MOVL 0, AX // crash with nil ptr deref
// MOVQ and EMMS were introduced on the Pentium MMX.
// MOVQ 0x8(%ESP), %MM0
BYTE $0x0f; BYTE $0x6f; BYTE $0x44; BYTE $0x24; BYTE $0x08
diff --git a/src/pkg/sync/atomic/asm_arm.s b/src/pkg/sync/atomic/asm_arm.s
index 4faf5b5d9..a0525881e 100644
--- a/src/pkg/sync/atomic/asm_arm.s
+++ b/src/pkg/sync/atomic/asm_arm.s
@@ -29,6 +29,10 @@ casfail:
TEXT ·armCompareAndSwapUint64(SB),7,$0
BL fastCheck64<>(SB)
MOVW addr+0(FP), R1
+ // make unaligned atomic access panic
+ AND.S $7, R1, R2
+ BEQ 2(PC)
+ MOVW R2, (R2)
MOVW oldlo+4(FP), R2
MOVW oldhi+8(FP), R3
MOVW newlo+12(FP), R4
@@ -67,6 +71,10 @@ addloop:
TEXT ·armAddUint64(SB),7,$0
BL fastCheck64<>(SB)
MOVW addr+0(FP), R1
+ // make unaligned atomic access panic
+ AND.S $7, R1, R2
+ BEQ 2(PC)
+ MOVW R2, (R2)
MOVW deltalo+4(FP), R2
MOVW deltahi+8(FP), R3
add64loop:
@@ -84,6 +92,10 @@ add64loop:
TEXT ·armLoadUint64(SB),7,$0
BL fastCheck64<>(SB)
MOVW addr+0(FP), R1
+ // make unaligned atomic access panic
+ AND.S $7, R1, R2
+ BEQ 2(PC)
+ MOVW R2, (R2)
load64loop:
LDREXD (R1), R2 // loads R2 and R3
STREXD R2, (R1), R0 // stores R2 and R3
@@ -96,6 +108,10 @@ load64loop:
TEXT ·armStoreUint64(SB),7,$0
BL fastCheck64<>(SB)
MOVW addr+0(FP), R1
+ // make unaligned atomic access panic
+ AND.S $7, R1, R2
+ BEQ 2(PC)
+ MOVW R2, (R2)
MOVW vallo+4(FP), R2
MOVW valhi+8(FP), R3
store64loop:
diff --git a/src/pkg/sync/atomic/asm_linux_arm.s b/src/pkg/sync/atomic/asm_linux_arm.s
index 098acf35b..5b16894b9 100644
--- a/src/pkg/sync/atomic/asm_linux_arm.s
+++ b/src/pkg/sync/atomic/asm_linux_arm.s
@@ -80,6 +80,10 @@ TEXT cas64<>(SB),7,$0
TEXT kernelCAS64<>(SB),7,$0
// int (*__kuser_cmpxchg64_t)(const int64_t *oldval, const int64_t *newval, volatile int64_t *ptr);
MOVW addr+0(FP), R2 // ptr
+ // make unaligned atomic access panic
+ AND.S $7, R2, R1
+ BEQ 2(PC)
+ MOVW R1, (R1)
MOVW $4(FP), R0 // oldval
MOVW $12(FP), R1 // newval
BL cas64<>(SB)
@@ -91,6 +95,10 @@ TEXT kernelCAS64<>(SB),7,$0
TEXT generalCAS64<>(SB),7,$20
// bool runtime·cas64(uint64 volatile *addr, uint64 *old, uint64 new)
MOVW addr+0(FP), R0
+ // make unaligned atomic access panic
+ AND.S $7, R0, R1
+ BEQ 2(PC)
+ MOVW R1, (R1)
MOVW R0, 4(R13)
MOVW $4(FP), R1 // oldval
MOVW R1, 8(R13)
diff --git a/src/pkg/sync/atomic/atomic_test.go b/src/pkg/sync/atomic/atomic_test.go
index 3e105561c..b392df595 100644
--- a/src/pkg/sync/atomic/atomic_test.go
+++ b/src/pkg/sync/atomic/atomic_test.go
@@ -1177,3 +1177,29 @@ func TestStoreLoadRelAcq64(t *testing.T) {
<-c
<-c
}
+
+func shouldPanic(t *testing.T, name string, f func()) {
+ defer func() {
+ if recover() == nil {
+ t.Errorf("%s did not panic", name)
+ }
+ }()
+ f()
+}
+
+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")
+ }
+
+ x := make([]uint32, 4)
+ p := (*uint64)(unsafe.Pointer(&x[1])) // misaligned
+
+ shouldPanic(t, "LoadUint64", func() { LoadUint64(p) })
+ shouldPanic(t, "StoreUint64", func() { StoreUint64(p, 1) })
+ shouldPanic(t, "CompareAndSwapUint64", func() { CompareAndSwapUint64(p, 1, 2) })
+ shouldPanic(t, "AddUint64", func() { AddUint64(p, 3) })
+}
diff --git a/src/pkg/sync/atomic/race.go b/src/pkg/sync/atomic/race.go
index 242bbf298..2320b5707 100644
--- a/src/pkg/sync/atomic/race.go
+++ b/src/pkg/sync/atomic/race.go
@@ -25,6 +25,7 @@ func CompareAndSwapInt32(val *int32, old, new int32) bool {
}
func CompareAndSwapUint32(val *uint32, old, new uint32) (swapped bool) {
+ _ = *val
swapped = false
runtime.RaceSemacquire(&mtx)
runtime.RaceRead(unsafe.Pointer(val))
@@ -43,6 +44,7 @@ func CompareAndSwapInt64(val *int64, old, new int64) bool {
}
func CompareAndSwapUint64(val *uint64, old, new uint64) (swapped bool) {
+ _ = *val
swapped = false
runtime.RaceSemacquire(&mtx)
runtime.RaceRead(unsafe.Pointer(val))
@@ -57,6 +59,7 @@ func CompareAndSwapUint64(val *uint64, old, new uint64) (swapped bool) {
}
func CompareAndSwapPointer(val *unsafe.Pointer, old, new unsafe.Pointer) (swapped bool) {
+ _ = *val
swapped = false
runtime.RaceSemacquire(&mtx)
runtime.RaceRead(unsafe.Pointer(val))
@@ -71,6 +74,7 @@ func CompareAndSwapPointer(val *unsafe.Pointer, old, new unsafe.Pointer) (swappe
}
func CompareAndSwapUintptr(val *uintptr, old, new uintptr) (swapped bool) {
+ _ = *val
swapped = false
runtime.RaceSemacquire(&mtx)
runtime.RaceRead(unsafe.Pointer(val))
@@ -89,6 +93,7 @@ func AddInt32(val *int32, delta int32) int32 {
}
func AddUint32(val *uint32, delta uint32) (new uint32) {
+ _ = *val
runtime.RaceSemacquire(&mtx)
runtime.RaceRead(unsafe.Pointer(val))
runtime.RaceAcquire(unsafe.Pointer(val))
@@ -105,6 +110,7 @@ func AddInt64(val *int64, delta int64) int64 {
}
func AddUint64(val *uint64, delta uint64) (new uint64) {
+ _ = *val
runtime.RaceSemacquire(&mtx)
runtime.RaceRead(unsafe.Pointer(val))
runtime.RaceAcquire(unsafe.Pointer(val))
@@ -117,6 +123,7 @@ func AddUint64(val *uint64, delta uint64) (new uint64) {
}
func AddUintptr(val *uintptr, delta uintptr) (new uintptr) {
+ _ = *val
runtime.RaceSemacquire(&mtx)
runtime.RaceRead(unsafe.Pointer(val))
runtime.RaceAcquire(unsafe.Pointer(val))
@@ -133,6 +140,7 @@ func LoadInt32(addr *int32) int32 {
}
func LoadUint32(addr *uint32) (val uint32) {
+ _ = *addr
runtime.RaceSemacquire(&mtx)
runtime.RaceRead(unsafe.Pointer(addr))
runtime.RaceAcquire(unsafe.Pointer(addr))
@@ -146,6 +154,7 @@ func LoadInt64(addr *int64) int64 {
}
func LoadUint64(addr *uint64) (val uint64) {
+ _ = *addr
runtime.RaceSemacquire(&mtx)
runtime.RaceRead(unsafe.Pointer(addr))
runtime.RaceAcquire(unsafe.Pointer(addr))
@@ -155,6 +164,7 @@ func LoadUint64(addr *uint64) (val uint64) {
}
func LoadPointer(addr *unsafe.Pointer) (val unsafe.Pointer) {
+ _ = *addr
runtime.RaceSemacquire(&mtx)
runtime.RaceRead(unsafe.Pointer(addr))
runtime.RaceAcquire(unsafe.Pointer(addr))
@@ -164,6 +174,7 @@ func LoadPointer(addr *unsafe.Pointer) (val unsafe.Pointer) {
}
func LoadUintptr(addr *uintptr) (val uintptr) {
+ _ = *addr
runtime.RaceSemacquire(&mtx)
runtime.RaceRead(unsafe.Pointer(addr))
runtime.RaceAcquire(unsafe.Pointer(addr))
@@ -177,6 +188,7 @@ func StoreInt32(addr *int32, val int32) {
}
func StoreUint32(addr *uint32, val uint32) {
+ _ = *addr
runtime.RaceSemacquire(&mtx)
runtime.RaceRead(unsafe.Pointer(addr))
*addr = val
@@ -189,6 +201,7 @@ func StoreInt64(addr *int64, val int64) {
}
func StoreUint64(addr *uint64, val uint64) {
+ _ = *addr
runtime.RaceSemacquire(&mtx)
runtime.RaceRead(unsafe.Pointer(addr))
*addr = val
@@ -197,6 +210,7 @@ func StoreUint64(addr *uint64, val uint64) {
}
func StorePointer(addr *unsafe.Pointer, val unsafe.Pointer) {
+ _ = *addr
runtime.RaceSemacquire(&mtx)
runtime.RaceRead(unsafe.Pointer(addr))
*addr = val
@@ -205,6 +219,7 @@ func StorePointer(addr *unsafe.Pointer, val unsafe.Pointer) {
}
func StoreUintptr(addr *uintptr, val uintptr) {
+ _ = *addr
runtime.RaceSemacquire(&mtx)
runtime.RaceRead(unsafe.Pointer(addr))
*addr = val
diff --git a/src/pkg/sync/cond.go b/src/pkg/sync/cond.go
index 491b98569..13547a8a1 100644
--- a/src/pkg/sync/cond.go
+++ b/src/pkg/sync/cond.go
@@ -57,6 +57,7 @@ func NewCond(l Locker) *Cond {
//
func (c *Cond) Wait() {
if raceenabled {
+ _ = c.m.state
raceDisable()
}
c.m.Lock()
@@ -80,6 +81,7 @@ func (c *Cond) Wait() {
// during the call.
func (c *Cond) Signal() {
if raceenabled {
+ _ = c.m.state
raceDisable()
}
c.m.Lock()
@@ -106,6 +108,7 @@ func (c *Cond) Signal() {
// during the call.
func (c *Cond) Broadcast() {
if raceenabled {
+ _ = c.m.state
raceDisable()
}
c.m.Lock()
diff --git a/src/pkg/sync/mutex.go b/src/pkg/sync/mutex.go
index b4629ebca..73b337702 100644
--- a/src/pkg/sync/mutex.go
+++ b/src/pkg/sync/mutex.go
@@ -81,6 +81,7 @@ func (m *Mutex) Lock() {
// arrange for another goroutine to unlock it.
func (m *Mutex) Unlock() {
if raceenabled {
+ _ = m.state
raceRelease(unsafe.Pointer(m))
}
diff --git a/src/pkg/sync/rwmutex.go b/src/pkg/sync/rwmutex.go
index b494c6435..3db541995 100644
--- a/src/pkg/sync/rwmutex.go
+++ b/src/pkg/sync/rwmutex.go
@@ -28,6 +28,7 @@ const rwmutexMaxReaders = 1 << 30
// RLock locks rw for reading.
func (rw *RWMutex) RLock() {
if raceenabled {
+ _ = rw.w.state
raceDisable()
}
if atomic.AddInt32(&rw.readerCount, 1) < 0 {
@@ -46,6 +47,7 @@ func (rw *RWMutex) RLock() {
// on entry to RUnlock.
func (rw *RWMutex) RUnlock() {
if raceenabled {
+ _ = rw.w.state
raceReleaseMerge(unsafe.Pointer(&rw.writerSem))
raceDisable()
}
@@ -69,6 +71,7 @@ func (rw *RWMutex) RUnlock() {
// the lock.
func (rw *RWMutex) Lock() {
if raceenabled {
+ _ = rw.w.state
raceDisable()
}
// First, resolve competition with other writers.
@@ -94,6 +97,7 @@ func (rw *RWMutex) Lock() {
// arrange for another goroutine to RUnlock (Unlock) it.
func (rw *RWMutex) Unlock() {
if raceenabled {
+ _ = rw.w.state
raceRelease(unsafe.Pointer(&rw.readerSem))
raceRelease(unsafe.Pointer(&rw.writerSem))
raceDisable()
diff --git a/src/pkg/sync/waitgroup.go b/src/pkg/sync/waitgroup.go
index 1277f1c6d..ca3883783 100644
--- a/src/pkg/sync/waitgroup.go
+++ b/src/pkg/sync/waitgroup.go
@@ -43,6 +43,7 @@ type WaitGroup struct {
// other event to be waited for. See the WaitGroup example.
func (wg *WaitGroup) Add(delta int) {
if raceenabled {
+ _ = wg.m.state
raceReleaseMerge(unsafe.Pointer(wg))
raceDisable()
defer raceEnable()
@@ -71,6 +72,7 @@ func (wg *WaitGroup) Done() {
// Wait blocks until the WaitGroup counter is zero.
func (wg *WaitGroup) Wait() {
if raceenabled {
+ _ = wg.m.state
raceDisable()
}
if atomic.LoadInt32(&wg.counter) == 0 {
diff --git a/src/pkg/syscall/asm_plan9_386.s b/src/pkg/syscall/asm_plan9_386.s
index 2ba137608..0ae20f568 100644
--- a/src/pkg/syscall/asm_plan9_386.s
+++ b/src/pkg/syscall/asm_plan9_386.s
@@ -29,7 +29,7 @@ TEXT ·Syscall(SB),7,$0
JNE ok3
SUBL $8, SP
- CALL syscall·errstr(SB)
+ CALL runtime·errstr(SB)
MOVL SP, SI
ADDL $8, SP
JMP copyresult3
@@ -67,7 +67,7 @@ TEXT ·Syscall6(SB),7,$0
JNE ok4
SUBL $8, SP
- CALL syscall·errstr(SB)
+ CALL runtime·errstr(SB)
MOVL SP, SI
ADDL $8, SP
JMP copyresult4
diff --git a/src/pkg/syscall/asm_plan9_amd64.s b/src/pkg/syscall/asm_plan9_amd64.s
index e363b743c..40cc12642 100644
--- a/src/pkg/syscall/asm_plan9_amd64.s
+++ b/src/pkg/syscall/asm_plan9_amd64.s
@@ -32,7 +32,7 @@ TEXT ·Syscall(SB),7,$0
JNE ok3
SUBQ $16, SP
- CALL syscall·errstr(SB)
+ CALL runtime·errstr(SB)
MOVQ SP, SI
ADDQ $16, SP
JMP copyresult3
@@ -71,7 +71,7 @@ TEXT ·Syscall6(SB),7,$0
JNE ok4
SUBQ $16, SP
- CALL syscall·errstr(SB)
+ CALL runtime·errstr(SB)
MOVQ SP, SI
ADDQ $16, SP
JMP copyresult4
diff --git a/src/pkg/syscall/exec_bsd.go b/src/pkg/syscall/exec_bsd.go
index 318cbc060..5d3d57813 100644
--- a/src/pkg/syscall/exec_bsd.go
+++ b/src/pkg/syscall/exec_bsd.go
@@ -39,10 +39,18 @@ func forkAndExecInChild(argv0 *byte, argv, envv []*byte, chroot, dir *byte, attr
i int
)
+ // guard against side effects of shuffling fds below.
+ // Make sure that nextfd is beyond any currently open files so
+ // that we can't run the risk of overwriting any of them.
fd := make([]int, len(attr.Files))
+ nextfd = len(attr.Files)
for i, ufd := range attr.Files {
+ if nextfd < int(ufd) {
+ nextfd = int(ufd)
+ }
fd[i] = int(ufd)
}
+ nextfd++
darwin := runtime.GOOS == "darwin"
@@ -131,7 +139,6 @@ func forkAndExecInChild(argv0 *byte, argv, envv []*byte, chroot, dir *byte, attr
// Pass 1: look for fd[i] < i and move those up above len(fd)
// so that pass 2 won't stomp on an fd it needs later.
- nextfd = int(len(fd))
if pipe < nextfd {
_, _, err1 = RawSyscall(SYS_DUP2, uintptr(pipe), uintptr(nextfd), 0)
if err1 != 0 {
@@ -215,11 +222,6 @@ childerror:
for {
RawSyscall(SYS_EXIT, 253, 0, 0)
}
-
- // Calling panic is not actually safe,
- // but the for loop above won't break
- // and this shuts up the compiler.
- panic("unreached")
}
// Try to open a pipe with O_CLOEXEC set on both file descriptors.
diff --git a/src/pkg/syscall/exec_linux.go b/src/pkg/syscall/exec_linux.go
index a8dc672b8..ddd946ed2 100644
--- a/src/pkg/syscall/exec_linux.go
+++ b/src/pkg/syscall/exec_linux.go
@@ -40,11 +40,18 @@ func forkAndExecInChild(argv0 *byte, argv, envv []*byte, chroot, dir *byte, attr
i int
)
- // guard against side effects of shuffling fds below.
+ // Guard against side effects of shuffling fds below.
+ // Make sure that nextfd is beyond any currently open files so
+ // that we can't run the risk of overwriting any of them.
fd := make([]int, len(attr.Files))
+ nextfd = len(attr.Files)
for i, ufd := range attr.Files {
+ if nextfd < int(ufd) {
+ nextfd = int(ufd)
+ }
fd[i] = int(ufd)
}
+ nextfd++
// About to call fork.
// No more allocation or calls of non-assembly functions.
@@ -143,7 +150,6 @@ func forkAndExecInChild(argv0 *byte, argv, envv []*byte, chroot, dir *byte, attr
// Pass 1: look for fd[i] < i and move those up above len(fd)
// so that pass 2 won't stomp on an fd it needs later.
- nextfd = int(len(fd))
if pipe < nextfd {
_, _, err1 = RawSyscall(SYS_DUP2, uintptr(pipe), uintptr(nextfd), 0)
if err1 != 0 {
diff --git a/src/pkg/syscall/exec_plan9.go b/src/pkg/syscall/exec_plan9.go
index ebd57f3e3..99ad2f158 100644
--- a/src/pkg/syscall/exec_plan9.go
+++ b/src/pkg/syscall/exec_plan9.go
@@ -183,11 +183,18 @@ func forkAndExecInChild(argv0 *byte, argv []*byte, envv []envItem, dir *byte, at
errbuf [ERRMAX]byte
)
- // guard against side effects of shuffling fds below.
+ // Guard against side effects of shuffling fds below.
+ // Make sure that nextfd is beyond any currently open files so
+ // that we can't run the risk of overwriting any of them.
fd := make([]int, len(attr.Files))
+ nextfd = len(attr.Files)
for i, ufd := range attr.Files {
+ if nextfd < int(ufd) {
+ nextfd = int(ufd)
+ }
fd[i] = int(ufd)
}
+ nextfd++
if envv != nil {
clearenv = RFCENVG
@@ -251,7 +258,6 @@ func forkAndExecInChild(argv0 *byte, argv []*byte, envv []envItem, dir *byte, at
// Pass 1: look for fd[i] < i and move those up above len(fd)
// so that pass 2 won't stomp on an fd it needs later.
- nextfd = int(len(fd))
if pipe < nextfd {
r1, _, _ = RawSyscall(SYS_DUP, uintptr(pipe), uintptr(nextfd), 0)
if int32(r1) == -1 {
diff --git a/src/pkg/syscall/mkerrors.sh b/src/pkg/syscall/mkerrors.sh
index e8abb6774..5a39d707b 100755
--- a/src/pkg/syscall/mkerrors.sh
+++ b/src/pkg/syscall/mkerrors.sh
@@ -43,6 +43,7 @@ includes_FreeBSD='
#include <sys/socket.h>
#include <sys/sockio.h>
#include <sys/sysctl.h>
+#include <sys/mman.h>
#include <sys/wait.h>
#include <sys/ioctl.h>
#include <net/bpf.h>
diff --git a/src/pkg/syscall/passfd_test.go b/src/pkg/syscall/passfd_test.go
index 079c9303b..e16debae1 100644
--- a/src/pkg/syscall/passfd_test.go
+++ b/src/pkg/syscall/passfd_test.go
@@ -13,7 +13,6 @@ import (
"net"
"os"
"os/exec"
- "runtime"
"syscall"
"testing"
"time"
@@ -27,9 +26,6 @@ import (
// "-test.run=^TestPassFD$" and an environment variable used to signal
// that the test should become the child process instead.
func TestPassFD(t *testing.T) {
- if runtime.GOOS == "openbsd" {
- t.Skip("issue 4956")
- }
if os.Getenv("GO_WANT_HELPER_PROCESS") == "1" {
passFDChild()
return
@@ -53,7 +49,7 @@ func TestPassFD(t *testing.T) {
defer readFile.Close()
cmd := exec.Command(os.Args[0], "-test.run=^TestPassFD$", "--", tempDir)
- cmd.Env = append([]string{"GO_WANT_HELPER_PROCESS=1"}, os.Environ()...)
+ cmd.Env = []string{"GO_WANT_HELPER_PROCESS=1"}
cmd.ExtraFiles = []*os.File{writeFile}
out, err := cmd.CombinedOutput()
diff --git a/src/pkg/syscall/syscall_bsd.go b/src/pkg/syscall/syscall_bsd.go
index a1e0d153f..560409a26 100644
--- a/src/pkg/syscall/syscall_bsd.go
+++ b/src/pkg/syscall/syscall_bsd.go
@@ -327,6 +327,11 @@ func Getsockname(fd int) (sa Sockaddr, err error) {
if err = getsockname(fd, &rsa, &len); err != nil {
return
}
+ // TODO(jsing): Remove after OpenBSD 5.4 is released (see issue 3349).
+ if runtime.GOOS == "openbsd" && rsa.Addr.Family == AF_UNSPEC && rsa.Addr.Len == 0 {
+ rsa.Addr.Family = AF_UNIX
+ rsa.Addr.Len = SizeofSockaddrUnix
+ }
return anyToSockaddr(&rsa)
}
diff --git a/src/pkg/syscall/syscall_darwin.go b/src/pkg/syscall/syscall_darwin.go
index 7fe406aaa..75ef8f0a9 100644
--- a/src/pkg/syscall/syscall_darwin.go
+++ b/src/pkg/syscall/syscall_darwin.go
@@ -125,7 +125,7 @@ func Kill(pid int, signum Signal) (err error) { return kill(pid, int(signum), 1)
//sys Exchangedata(path1 string, path2 string, options int) (err error)
//sys Exit(code int)
//sys Fchdir(fd int) (err error)
-//sys Fchflags(path string, flags int) (err error)
+//sys Fchflags(fd int, flags int) (err error)
//sys Fchmod(fd int, mode uint32) (err error)
//sys Fchown(fd int, uid int, gid int) (err error)
//sys Flock(fd int, how int) (err error)
diff --git a/src/pkg/syscall/syscall_freebsd.go b/src/pkg/syscall/syscall_freebsd.go
index c7ffe223e..9fbcc48c6 100644
--- a/src/pkg/syscall/syscall_freebsd.go
+++ b/src/pkg/syscall/syscall_freebsd.go
@@ -118,7 +118,7 @@ func SetsockoptIPMreqn(fd, level, opt int, mreq *IPMreqn) (err error) {
//sysnb Dup2(from int, to int) (err error)
//sys Exit(code int)
//sys Fchdir(fd int) (err error)
-//sys Fchflags(path string, flags int) (err error)
+//sys Fchflags(fd int, flags int) (err error)
//sys Fchmod(fd int, mode uint32) (err error)
//sys Fchown(fd int, uid int, gid int) (err error)
//sys Flock(fd int, how int) (err error)
diff --git a/src/pkg/syscall/syscall_netbsd.go b/src/pkg/syscall/syscall_netbsd.go
index b0fa1112d..97812717f 100644
--- a/src/pkg/syscall/syscall_netbsd.go
+++ b/src/pkg/syscall/syscall_netbsd.go
@@ -152,7 +152,7 @@ func sendfile(outfd int, infd int, offset *int64, count int) (written int, err e
//sysnb Dup2(from int, to int) (err error)
//sys Exit(code int)
//sys Fchdir(fd int) (err error)
-//sys Fchflags(path string, flags int) (err error)
+//sys Fchflags(fd int, flags int) (err error)
//sys Fchmod(fd int, mode uint32) (err error)
//sys Fchown(fd int, uid int, gid int) (err error)
//sys Flock(fd int, how int) (err error)
diff --git a/src/pkg/syscall/syscall_openbsd.go b/src/pkg/syscall/syscall_openbsd.go
index a146dca2c..89c73215a 100644
--- a/src/pkg/syscall/syscall_openbsd.go
+++ b/src/pkg/syscall/syscall_openbsd.go
@@ -110,7 +110,7 @@ func sendfile(outfd int, infd int, offset *int64, count int) (written int, err e
//sysnb Dup2(from int, to int) (err error)
//sys Exit(code int)
//sys Fchdir(fd int) (err error)
-//sys Fchflags(path string, flags int) (err error)
+//sys Fchflags(fd int, flags int) (err error)
//sys Fchmod(fd int, mode uint32) (err error)
//sys Fchown(fd int, uid int, gid int) (err error)
//sys Flock(fd int, how int) (err error)
diff --git a/src/pkg/syscall/zerrors_freebsd_386.go b/src/pkg/syscall/zerrors_freebsd_386.go
index 9cf82f90e..048687361 100644
--- a/src/pkg/syscall/zerrors_freebsd_386.go
+++ b/src/pkg/syscall/zerrors_freebsd_386.go
@@ -92,6 +92,31 @@ const (
AF_VENDOR45 = 0x81
AF_VENDOR46 = 0x83
AF_VENDOR47 = 0x85
+ B0 = 0x0
+ B110 = 0x6e
+ B115200 = 0x1c200
+ B1200 = 0x4b0
+ B134 = 0x86
+ B14400 = 0x3840
+ B150 = 0x96
+ B1800 = 0x708
+ B19200 = 0x4b00
+ B200 = 0xc8
+ B230400 = 0x38400
+ B2400 = 0x960
+ B28800 = 0x7080
+ B300 = 0x12c
+ B38400 = 0x9600
+ B460800 = 0x70800
+ B4800 = 0x12c0
+ B50 = 0x32
+ B57600 = 0xe100
+ B600 = 0x258
+ B7200 = 0x1c20
+ B75 = 0x4b
+ B76800 = 0x12c00
+ B921600 = 0xe1000
+ B9600 = 0x2580
BIOCFEEDBACK = 0x8004427c
BIOCFLUSH = 0x20004268
BIOCGBLEN = 0x40044266
@@ -106,6 +131,7 @@ const (
BIOCGRTIMEOUT = 0x4008426e
BIOCGSEESENT = 0x40044276
BIOCGSTATS = 0x4008426f
+ BIOCGTSTAMP = 0x40044283
BIOCIMMEDIATE = 0x80044270
BIOCLOCK = 0x2000427a
BIOCPROMISC = 0x20004269
@@ -123,6 +149,7 @@ const (
BIOCSRSIG = 0x80044273
BIOCSRTIMEOUT = 0x8008426d
BIOCSSEESENT = 0x80044277
+ BIOCSTSTAMP = 0x80044284
BIOCVERSION = 0x40044271
BPF_A = 0x10
BPF_ABS = 0x20
@@ -168,13 +195,47 @@ const (
BPF_SUB = 0x10
BPF_TAX = 0x0
BPF_TXA = 0x80
+ BPF_T_BINTIME = 0x2
+ BPF_T_BINTIME_FAST = 0x102
+ BPF_T_BINTIME_MONOTONIC = 0x202
+ BPF_T_BINTIME_MONOTONIC_FAST = 0x302
+ BPF_T_FAST = 0x100
+ BPF_T_FLAG_MASK = 0x300
+ BPF_T_FORMAT_MASK = 0x3
+ BPF_T_MICROTIME = 0x0
+ BPF_T_MICROTIME_FAST = 0x100
+ BPF_T_MICROTIME_MONOTONIC = 0x200
+ BPF_T_MICROTIME_MONOTONIC_FAST = 0x300
+ BPF_T_MONOTONIC = 0x200
+ BPF_T_MONOTONIC_FAST = 0x300
+ BPF_T_NANOTIME = 0x1
+ BPF_T_NANOTIME_FAST = 0x101
+ BPF_T_NANOTIME_MONOTONIC = 0x201
+ BPF_T_NANOTIME_MONOTONIC_FAST = 0x301
+ BPF_T_NONE = 0x3
+ BPF_T_NORMAL = 0x0
BPF_W = 0x0
BPF_X = 0x8
+ BRKINT = 0x2
+ CFLUSH = 0xf
+ CLOCAL = 0x8000
+ CREAD = 0x800
+ CS5 = 0x0
+ CS6 = 0x100
+ CS7 = 0x200
+ CS8 = 0x300
+ CSIZE = 0x300
+ CSTART = 0x11
+ CSTATUS = 0x14
+ CSTOP = 0x13
+ CSTOPB = 0x400
+ CSUSP = 0x1a
CTL_MAXNAME = 0x18
CTL_NET = 0x4
DLT_A429 = 0xb8
DLT_A653_ICM = 0xb9
DLT_AIRONET_HEADER = 0x78
+ DLT_AOS = 0xde
DLT_APPLE_IP_OVER_IEEE1394 = 0x8a
DLT_ARCNET = 0x7
DLT_ARCNET_LINUX = 0x81
@@ -187,12 +248,16 @@ const (
DLT_BLUETOOTH_HCI_H4 = 0xbb
DLT_BLUETOOTH_HCI_H4_WITH_PHDR = 0xc9
DLT_CAN20B = 0xbe
+ DLT_CAN_SOCKETCAN = 0xe3
DLT_CHAOS = 0x5
DLT_CHDLC = 0x68
DLT_CISCO_IOS = 0x76
DLT_C_HDLC = 0x68
DLT_C_HDLC_WITH_DIR = 0xcd
+ DLT_DBUS = 0xe7
+ DLT_DECT = 0xdd
DLT_DOCSIS = 0x8f
+ DLT_DVB_CI = 0xeb
DLT_ECONET = 0x73
DLT_EN10MB = 0x1
DLT_EN3MB = 0x2
@@ -200,6 +265,8 @@ const (
DLT_ERF = 0xc5
DLT_ERF_ETH = 0xaf
DLT_ERF_POS = 0xb0
+ DLT_FC_2 = 0xe0
+ DLT_FC_2_WITH_FRAME_DELIMS = 0xe1
DLT_FDDI = 0xa
DLT_FLEXRAY = 0xd2
DLT_FRELAY = 0x6b
@@ -209,6 +276,8 @@ const (
DLT_GPF_F = 0xab
DLT_GPF_T = 0xaa
DLT_GPRS_LLC = 0xa9
+ DLT_GSMTAP_ABIS = 0xda
+ DLT_GSMTAP_UM = 0xd9
DLT_HHDLC = 0x79
DLT_IBM_SN = 0x92
DLT_IBM_SP = 0x91
@@ -218,18 +287,25 @@ const (
DLT_IEEE802_11_RADIO_AVS = 0xa3
DLT_IEEE802_15_4 = 0xc3
DLT_IEEE802_15_4_LINUX = 0xbf
+ DLT_IEEE802_15_4_NOFCS = 0xe6
DLT_IEEE802_15_4_NONASK_PHY = 0xd7
DLT_IEEE802_16_MAC_CPS = 0xbc
DLT_IEEE802_16_MAC_CPS_RADIO = 0xc1
DLT_IPFILTER = 0x74
DLT_IPMB = 0xc7
DLT_IPMB_LINUX = 0xd1
+ DLT_IPNET = 0xe2
+ DLT_IPOIB = 0xf2
+ DLT_IPV4 = 0xe4
+ DLT_IPV6 = 0xe5
DLT_IP_OVER_FC = 0x7a
DLT_JUNIPER_ATM1 = 0x89
DLT_JUNIPER_ATM2 = 0x87
+ DLT_JUNIPER_ATM_CEMIC = 0xee
DLT_JUNIPER_CHDLC = 0xb5
DLT_JUNIPER_ES = 0x84
DLT_JUNIPER_ETHER = 0xb2
+ DLT_JUNIPER_FIBRECHANNEL = 0xea
DLT_JUNIPER_FRELAY = 0xb4
DLT_JUNIPER_GGSN = 0x85
DLT_JUNIPER_ISM = 0xc2
@@ -242,22 +318,32 @@ const (
DLT_JUNIPER_PPPOE = 0xa7
DLT_JUNIPER_PPPOE_ATM = 0xa8
DLT_JUNIPER_SERVICES = 0x88
+ DLT_JUNIPER_SRX_E2E = 0xe9
DLT_JUNIPER_ST = 0xc8
DLT_JUNIPER_VP = 0xb7
+ DLT_JUNIPER_VS = 0xe8
DLT_LAPB_WITH_DIR = 0xcf
DLT_LAPD = 0xcb
DLT_LIN = 0xd4
+ DLT_LINUX_EVDEV = 0xd8
DLT_LINUX_IRDA = 0x90
DLT_LINUX_LAPD = 0xb1
DLT_LINUX_PPP_WITHDIRECTION = 0xa6
DLT_LINUX_SLL = 0x71
DLT_LOOP = 0x6c
DLT_LTALK = 0x72
+ DLT_MATCHING_MAX = 0xf2
+ DLT_MATCHING_MIN = 0x68
DLT_MFR = 0xb6
DLT_MOST = 0xd3
+ DLT_MPLS = 0xdb
DLT_MTP2 = 0x8c
DLT_MTP2_WITH_PHDR = 0x8b
DLT_MTP3 = 0x8d
+ DLT_MUX27010 = 0xec
+ DLT_NETANALYZER = 0xf0
+ DLT_NETANALYZER_TRANSPARENT = 0xf1
+ DLT_NFLOG = 0xef
DLT_NULL = 0x0
DLT_PCI_EXP = 0x7d
DLT_PFLOG = 0x75
@@ -279,11 +365,13 @@ const (
DLT_SITA = 0xc4
DLT_SLIP = 0x8
DLT_SLIP_BSDOS = 0xf
+ DLT_STANAG_5066_D_PDU = 0xed
DLT_SUNATM = 0x7b
DLT_SYMANTEC_FIREWALL = 0x63
DLT_TZSP = 0x80
DLT_USB = 0xba
DLT_USB_LINUX = 0xbd
+ DLT_USB_LINUX_MMAPPED = 0xdc
DLT_USER0 = 0x93
DLT_USER1 = 0x94
DLT_USER10 = 0x9d
@@ -300,6 +388,7 @@ const (
DLT_USER7 = 0x9a
DLT_USER8 = 0x9b
DLT_USER9 = 0x9c
+ DLT_WIHART = 0xdf
DLT_X2E_SERIAL = 0xd5
DLT_X2E_XORAYA = 0xd6
DT_BLK = 0x6
@@ -346,6 +435,7 @@ const (
EXTPROC = 0x800
FD_CLOEXEC = 0x1
FD_SETSIZE = 0x400
+ FLUSHO = 0x800000
F_CANCEL = 0x5
F_DUP2FD = 0xa
F_DUPFD = 0x0
@@ -369,12 +459,17 @@ const (
F_UNLCK = 0x2
F_UNLCKSYS = 0x4
F_WRLCK = 0x3
+ HUPCL = 0x4000
+ ICANON = 0x100
+ ICRNL = 0x100
+ IEXTEN = 0x400
IFAN_ARRIVAL = 0x0
IFAN_DEPARTURE = 0x1
IFF_ALLMULTI = 0x200
IFF_ALTPHYS = 0x4000
IFF_BROADCAST = 0x2
- IFF_CANTCHANGE = 0x208f72
+ IFF_CANTCHANGE = 0x218f72
+ IFF_CANTCONFIG = 0x10000
IFF_DEBUG = 0x4
IFF_DRV_OACTIVE = 0x400
IFF_DRV_RUNNING = 0x40
@@ -488,6 +583,7 @@ const (
IFT_IEEE8023ADLAG = 0xa1
IFT_IFGSN = 0x91
IFT_IMT = 0xbe
+ IFT_INFINIBAND = 0xc7
IFT_INTERLEAVE = 0x7c
IFT_IP = 0x7e
IFT_IPFORWARD = 0x8e
@@ -603,6 +699,12 @@ const (
IFT_X25MLP = 0x79
IFT_X25PLE = 0x28
IFT_XETHER = 0x1a
+ IGNBRK = 0x1
+ IGNCR = 0x80
+ IGNPAR = 0x4
+ IMAXBEL = 0x2000
+ INLCR = 0x40
+ INPCK = 0x10
IN_CLASSA_HOST = 0xffffff
IN_CLASSA_MAX = 0x80
IN_CLASSA_NET = 0xff000000
@@ -618,6 +720,7 @@ const (
IN_CLASSD_NET = 0xf0000000
IN_CLASSD_NSHIFT = 0x1c
IN_LOOPBACKNET = 0x7f
+ IN_RFC3021_MASK = 0xfffffffe
IPPROTO_3PC = 0x22
IPPROTO_ADFS = 0x44
IPPROTO_AH = 0x33
@@ -679,6 +782,7 @@ const (
IPPROTO_MAX = 0x100
IPPROTO_MAXID = 0x34
IPPROTO_MEAS = 0x13
+ IPPROTO_MH = 0x87
IPPROTO_MHRP = 0x30
IPPROTO_MICP = 0x5f
IPPROTO_MOBILE = 0x37
@@ -709,6 +813,7 @@ const (
IPPROTO_SCCSP = 0x60
IPPROTO_SCTP = 0x84
IPPROTO_SDRP = 0x2a
+ IPPROTO_SEND = 0x103
IPPROTO_SEP = 0x21
IPPROTO_SKIP = 0x39
IPPROTO_SPACER = 0x7fff
@@ -856,6 +961,7 @@ const (
IP_RECVIF = 0x14
IP_RECVOPTS = 0x5
IP_RECVRETOPTS = 0x6
+ IP_RECVTOS = 0x44
IP_RECVTTL = 0x41
IP_RETOPTS = 0x8
IP_RF = 0x8000
@@ -867,10 +973,44 @@ const (
IP_TOS = 0x3
IP_TTL = 0x4
IP_UNBLOCK_SOURCE = 0x49
+ ISIG = 0x80
+ ISTRIP = 0x20
+ IXANY = 0x800
+ IXOFF = 0x400
+ IXON = 0x200
LOCK_EX = 0x2
LOCK_NB = 0x4
LOCK_SH = 0x1
LOCK_UN = 0x8
+ MADV_AUTOSYNC = 0x7
+ MADV_CORE = 0x9
+ MADV_DONTNEED = 0x4
+ MADV_FREE = 0x5
+ MADV_NOCORE = 0x8
+ MADV_NORMAL = 0x0
+ MADV_NOSYNC = 0x6
+ MADV_PROTECT = 0xa
+ MADV_RANDOM = 0x1
+ MADV_SEQUENTIAL = 0x2
+ MADV_WILLNEED = 0x3
+ MAP_ANON = 0x1000
+ MAP_ANONYMOUS = 0x1000
+ MAP_COPY = 0x2
+ MAP_FILE = 0x0
+ MAP_FIXED = 0x10
+ MAP_HASSEMAPHORE = 0x200
+ MAP_NOCORE = 0x20000
+ MAP_NORESERVE = 0x40
+ MAP_NOSYNC = 0x800
+ MAP_PREFAULT_READ = 0x40000
+ MAP_PRIVATE = 0x2
+ MAP_RENAME = 0x20
+ MAP_RESERVED0080 = 0x80
+ MAP_RESERVED0100 = 0x100
+ MAP_SHARED = 0x1
+ MAP_STACK = 0x400
+ MCL_CURRENT = 0x1
+ MCL_FUTURE = 0x2
MSG_COMPAT = 0x8000
MSG_CTRUNC = 0x20
MSG_DONTROUTE = 0x4
@@ -884,11 +1024,16 @@ const (
MSG_PEEK = 0x2
MSG_TRUNC = 0x10
MSG_WAITALL = 0x40
+ MS_ASYNC = 0x1
+ MS_INVALIDATE = 0x2
+ MS_SYNC = 0x0
NET_RT_DUMP = 0x1
NET_RT_FLAGS = 0x2
NET_RT_IFLIST = 0x3
+ NET_RT_IFLISTL = 0x5
NET_RT_IFMALIST = 0x4
- NET_RT_MAXID = 0x5
+ NET_RT_MAXID = 0x6
+ NOFLSH = 0x80000000
NOTE_ATTRIB = 0x8
NOTE_CHILD = 0x4
NOTE_DELETE = 0x1
@@ -912,6 +1057,12 @@ const (
NOTE_TRACKERR = 0x2
NOTE_TRIGGER = 0x1000000
NOTE_WRITE = 0x2
+ OCRNL = 0x10
+ ONLCR = 0x2
+ ONLRET = 0x40
+ ONOCR = 0x20
+ ONOEOT = 0x8
+ OPOST = 0x1
O_ACCMODE = 0x3
O_APPEND = 0x8
O_ASYNC = 0x40
@@ -933,6 +1084,14 @@ const (
O_TRUNC = 0x400
O_TTY_INIT = 0x80000
O_WRONLY = 0x1
+ PARENB = 0x1000
+ PARMRK = 0x8
+ PARODD = 0x2000
+ PENDIN = 0x20000000
+ PROT_EXEC = 0x4
+ PROT_NONE = 0x0
+ PROT_READ = 0x1
+ PROT_WRITE = 0x2
RLIMIT_AS = 0xa
RLIMIT_CORE = 0x4
RLIMIT_CPU = 0x0
@@ -1010,6 +1169,8 @@ const (
RTV_SPIPE = 0x10
RTV_SSTHRESH = 0x20
RTV_WEIGHT = 0x100
+ RT_CACHING_CONTEXT = 0x1
+ RT_DEFAULT_FIB = 0x0
RUSAGE_CHILDREN = -0x1
RUSAGE_SELF = 0x0
RUSAGE_THREAD = 0x1
@@ -1042,6 +1203,7 @@ const (
SIOCGIFCONF = 0xc0086924
SIOCGIFDESCR = 0xc020692a
SIOCGIFDSTADDR = 0xc0206922
+ SIOCGIFFIB = 0xc020695c
SIOCGIFFLAGS = 0xc0206911
SIOCGIFGENERIC = 0xc020693a
SIOCGIFGMEMB = 0xc024698a
@@ -1073,6 +1235,7 @@ const (
SIOCSIFCAP = 0x8020691e
SIOCSIFDESCR = 0x80206929
SIOCSIFDSTADDR = 0x8020690e
+ SIOCSIFFIB = 0x8020695d
SIOCSIFFLAGS = 0x80206910
SIOCSIFGENERIC = 0x80206939
SIOCSIFLLADDR = 0x8020693c
@@ -1115,6 +1278,8 @@ const (
SO_NO_OFFLOAD = 0x4000
SO_OOBINLINE = 0x100
SO_PEERLABEL = 0x1010
+ SO_PROTOCOL = 0x1016
+ SO_PROTOTYPE = 0x1016
SO_RCVBUF = 0x1002
SO_RCVLOWAT = 0x1004
SO_RCVTIMEO = 0x1006
@@ -1127,9 +1292,17 @@ const (
SO_TIMESTAMP = 0x400
SO_TYPE = 0x1008
SO_USELOOPBACK = 0x40
+ SO_USER_COOKIE = 0x1015
+ TCIFLUSH = 0x1
+ TCIOFLUSH = 0x3
+ TCOFLUSH = 0x2
TCP_CA_NAME_MAX = 0x10
TCP_CONGESTION = 0x40
TCP_INFO = 0x20
+ TCP_KEEPCNT = 0x400
+ TCP_KEEPIDLE = 0x100
+ TCP_KEEPINIT = 0x80
+ TCP_KEEPINTVL = 0x200
TCP_MAXBURST = 0x4
TCP_MAXHLEN = 0x3c
TCP_MAXOLEN = 0x28
@@ -1139,10 +1312,11 @@ const (
TCP_MAX_WINSHIFT = 0xe
TCP_MD5SIG = 0x10
TCP_MINMSS = 0xd8
- TCP_MSS = 0x200
+ TCP_MSS = 0x218
TCP_NODELAY = 0x1
TCP_NOOPT = 0x8
TCP_NOPUSH = 0x4
+ TCSAFLUSH = 0x2
TIOCCBRK = 0x2000747a
TIOCCDTR = 0x20007478
TIOCCONS = 0x80047462
@@ -1205,6 +1379,26 @@ const (
TIOCSWINSZ = 0x80087467
TIOCTIMESTAMP = 0x40087459
TIOCUCNTL = 0x80047466
+ TOSTOP = 0x400000
+ VDISCARD = 0xf
+ VDSUSP = 0xb
+ VEOF = 0x0
+ VEOL = 0x1
+ VEOL2 = 0x2
+ VERASE = 0x3
+ VERASE2 = 0x7
+ VINTR = 0x8
+ VKILL = 0x5
+ VLNEXT = 0xe
+ VMIN = 0x10
+ VQUIT = 0x9
+ VREPRINT = 0x6
+ VSTART = 0xc
+ VSTATUS = 0x12
+ VSTOP = 0xd
+ VSUSP = 0xa
+ VTIME = 0x11
+ VWERASE = 0x4
WCONTINUED = 0x4
WCOREFLAG = 0x80
WLINUXCLONE = 0x80000000
@@ -1229,6 +1423,7 @@ const (
EBADRPC = Errno(0x48)
EBUSY = Errno(0x10)
ECANCELED = Errno(0x55)
+ ECAPMODE = Errno(0x5e)
ECHILD = Errno(0xa)
ECONNABORTED = Errno(0x35)
ECONNREFUSED = Errno(0x3d)
@@ -1252,7 +1447,7 @@ const (
EIO = Errno(0x5)
EISCONN = Errno(0x38)
EISDIR = Errno(0x15)
- ELAST = Errno(0x5d)
+ ELAST = Errno(0x5e)
ELOOP = Errno(0x3e)
EMFILE = Errno(0x18)
EMLINK = Errno(0x1f)
@@ -1447,6 +1642,7 @@ var errors = [...]string{
91: "link has been severed",
92: "protocol error",
93: "capabilities insufficient",
+ 94: "not permitted in capability mode",
}
// Signal table
diff --git a/src/pkg/syscall/zerrors_freebsd_amd64.go b/src/pkg/syscall/zerrors_freebsd_amd64.go
index 732570659..a45d7f495 100644
--- a/src/pkg/syscall/zerrors_freebsd_amd64.go
+++ b/src/pkg/syscall/zerrors_freebsd_amd64.go
@@ -92,6 +92,31 @@ const (
AF_VENDOR45 = 0x81
AF_VENDOR46 = 0x83
AF_VENDOR47 = 0x85
+ B0 = 0x0
+ B110 = 0x6e
+ B115200 = 0x1c200
+ B1200 = 0x4b0
+ B134 = 0x86
+ B14400 = 0x3840
+ B150 = 0x96
+ B1800 = 0x708
+ B19200 = 0x4b00
+ B200 = 0xc8
+ B230400 = 0x38400
+ B2400 = 0x960
+ B28800 = 0x7080
+ B300 = 0x12c
+ B38400 = 0x9600
+ B460800 = 0x70800
+ B4800 = 0x12c0
+ B50 = 0x32
+ B57600 = 0xe100
+ B600 = 0x258
+ B7200 = 0x1c20
+ B75 = 0x4b
+ B76800 = 0x12c00
+ B921600 = 0xe1000
+ B9600 = 0x2580
BIOCFEEDBACK = 0x8004427c
BIOCFLUSH = 0x20004268
BIOCGBLEN = 0x40044266
@@ -106,6 +131,7 @@ const (
BIOCGRTIMEOUT = 0x4010426e
BIOCGSEESENT = 0x40044276
BIOCGSTATS = 0x4008426f
+ BIOCGTSTAMP = 0x40044283
BIOCIMMEDIATE = 0x80044270
BIOCLOCK = 0x2000427a
BIOCPROMISC = 0x20004269
@@ -123,6 +149,7 @@ const (
BIOCSRSIG = 0x80044273
BIOCSRTIMEOUT = 0x8010426d
BIOCSSEESENT = 0x80044277
+ BIOCSTSTAMP = 0x80044284
BIOCVERSION = 0x40044271
BPF_A = 0x10
BPF_ABS = 0x20
@@ -168,13 +195,47 @@ const (
BPF_SUB = 0x10
BPF_TAX = 0x0
BPF_TXA = 0x80
+ BPF_T_BINTIME = 0x2
+ BPF_T_BINTIME_FAST = 0x102
+ BPF_T_BINTIME_MONOTONIC = 0x202
+ BPF_T_BINTIME_MONOTONIC_FAST = 0x302
+ BPF_T_FAST = 0x100
+ BPF_T_FLAG_MASK = 0x300
+ BPF_T_FORMAT_MASK = 0x3
+ BPF_T_MICROTIME = 0x0
+ BPF_T_MICROTIME_FAST = 0x100
+ BPF_T_MICROTIME_MONOTONIC = 0x200
+ BPF_T_MICROTIME_MONOTONIC_FAST = 0x300
+ BPF_T_MONOTONIC = 0x200
+ BPF_T_MONOTONIC_FAST = 0x300
+ BPF_T_NANOTIME = 0x1
+ BPF_T_NANOTIME_FAST = 0x101
+ BPF_T_NANOTIME_MONOTONIC = 0x201
+ BPF_T_NANOTIME_MONOTONIC_FAST = 0x301
+ BPF_T_NONE = 0x3
+ BPF_T_NORMAL = 0x0
BPF_W = 0x0
BPF_X = 0x8
+ BRKINT = 0x2
+ CFLUSH = 0xf
+ CLOCAL = 0x8000
+ CREAD = 0x800
+ CS5 = 0x0
+ CS6 = 0x100
+ CS7 = 0x200
+ CS8 = 0x300
+ CSIZE = 0x300
+ CSTART = 0x11
+ CSTATUS = 0x14
+ CSTOP = 0x13
+ CSTOPB = 0x400
+ CSUSP = 0x1a
CTL_MAXNAME = 0x18
CTL_NET = 0x4
DLT_A429 = 0xb8
DLT_A653_ICM = 0xb9
DLT_AIRONET_HEADER = 0x78
+ DLT_AOS = 0xde
DLT_APPLE_IP_OVER_IEEE1394 = 0x8a
DLT_ARCNET = 0x7
DLT_ARCNET_LINUX = 0x81
@@ -187,12 +248,16 @@ const (
DLT_BLUETOOTH_HCI_H4 = 0xbb
DLT_BLUETOOTH_HCI_H4_WITH_PHDR = 0xc9
DLT_CAN20B = 0xbe
+ DLT_CAN_SOCKETCAN = 0xe3
DLT_CHAOS = 0x5
DLT_CHDLC = 0x68
DLT_CISCO_IOS = 0x76
DLT_C_HDLC = 0x68
DLT_C_HDLC_WITH_DIR = 0xcd
+ DLT_DBUS = 0xe7
+ DLT_DECT = 0xdd
DLT_DOCSIS = 0x8f
+ DLT_DVB_CI = 0xeb
DLT_ECONET = 0x73
DLT_EN10MB = 0x1
DLT_EN3MB = 0x2
@@ -200,6 +265,8 @@ const (
DLT_ERF = 0xc5
DLT_ERF_ETH = 0xaf
DLT_ERF_POS = 0xb0
+ DLT_FC_2 = 0xe0
+ DLT_FC_2_WITH_FRAME_DELIMS = 0xe1
DLT_FDDI = 0xa
DLT_FLEXRAY = 0xd2
DLT_FRELAY = 0x6b
@@ -209,6 +276,8 @@ const (
DLT_GPF_F = 0xab
DLT_GPF_T = 0xaa
DLT_GPRS_LLC = 0xa9
+ DLT_GSMTAP_ABIS = 0xda
+ DLT_GSMTAP_UM = 0xd9
DLT_HHDLC = 0x79
DLT_IBM_SN = 0x92
DLT_IBM_SP = 0x91
@@ -218,18 +287,25 @@ const (
DLT_IEEE802_11_RADIO_AVS = 0xa3
DLT_IEEE802_15_4 = 0xc3
DLT_IEEE802_15_4_LINUX = 0xbf
+ DLT_IEEE802_15_4_NOFCS = 0xe6
DLT_IEEE802_15_4_NONASK_PHY = 0xd7
DLT_IEEE802_16_MAC_CPS = 0xbc
DLT_IEEE802_16_MAC_CPS_RADIO = 0xc1
DLT_IPFILTER = 0x74
DLT_IPMB = 0xc7
DLT_IPMB_LINUX = 0xd1
+ DLT_IPNET = 0xe2
+ DLT_IPOIB = 0xf2
+ DLT_IPV4 = 0xe4
+ DLT_IPV6 = 0xe5
DLT_IP_OVER_FC = 0x7a
DLT_JUNIPER_ATM1 = 0x89
DLT_JUNIPER_ATM2 = 0x87
+ DLT_JUNIPER_ATM_CEMIC = 0xee
DLT_JUNIPER_CHDLC = 0xb5
DLT_JUNIPER_ES = 0x84
DLT_JUNIPER_ETHER = 0xb2
+ DLT_JUNIPER_FIBRECHANNEL = 0xea
DLT_JUNIPER_FRELAY = 0xb4
DLT_JUNIPER_GGSN = 0x85
DLT_JUNIPER_ISM = 0xc2
@@ -242,22 +318,32 @@ const (
DLT_JUNIPER_PPPOE = 0xa7
DLT_JUNIPER_PPPOE_ATM = 0xa8
DLT_JUNIPER_SERVICES = 0x88
+ DLT_JUNIPER_SRX_E2E = 0xe9
DLT_JUNIPER_ST = 0xc8
DLT_JUNIPER_VP = 0xb7
+ DLT_JUNIPER_VS = 0xe8
DLT_LAPB_WITH_DIR = 0xcf
DLT_LAPD = 0xcb
DLT_LIN = 0xd4
+ DLT_LINUX_EVDEV = 0xd8
DLT_LINUX_IRDA = 0x90
DLT_LINUX_LAPD = 0xb1
DLT_LINUX_PPP_WITHDIRECTION = 0xa6
DLT_LINUX_SLL = 0x71
DLT_LOOP = 0x6c
DLT_LTALK = 0x72
+ DLT_MATCHING_MAX = 0xf2
+ DLT_MATCHING_MIN = 0x68
DLT_MFR = 0xb6
DLT_MOST = 0xd3
+ DLT_MPLS = 0xdb
DLT_MTP2 = 0x8c
DLT_MTP2_WITH_PHDR = 0x8b
DLT_MTP3 = 0x8d
+ DLT_MUX27010 = 0xec
+ DLT_NETANALYZER = 0xf0
+ DLT_NETANALYZER_TRANSPARENT = 0xf1
+ DLT_NFLOG = 0xef
DLT_NULL = 0x0
DLT_PCI_EXP = 0x7d
DLT_PFLOG = 0x75
@@ -279,11 +365,13 @@ const (
DLT_SITA = 0xc4
DLT_SLIP = 0x8
DLT_SLIP_BSDOS = 0xf
+ DLT_STANAG_5066_D_PDU = 0xed
DLT_SUNATM = 0x7b
DLT_SYMANTEC_FIREWALL = 0x63
DLT_TZSP = 0x80
DLT_USB = 0xba
DLT_USB_LINUX = 0xbd
+ DLT_USB_LINUX_MMAPPED = 0xdc
DLT_USER0 = 0x93
DLT_USER1 = 0x94
DLT_USER10 = 0x9d
@@ -300,6 +388,7 @@ const (
DLT_USER7 = 0x9a
DLT_USER8 = 0x9b
DLT_USER9 = 0x9c
+ DLT_WIHART = 0xdf
DLT_X2E_SERIAL = 0xd5
DLT_X2E_XORAYA = 0xd6
DT_BLK = 0x6
@@ -346,6 +435,7 @@ const (
EXTPROC = 0x800
FD_CLOEXEC = 0x1
FD_SETSIZE = 0x400
+ FLUSHO = 0x800000
F_CANCEL = 0x5
F_DUP2FD = 0xa
F_DUPFD = 0x0
@@ -369,12 +459,17 @@ const (
F_UNLCK = 0x2
F_UNLCKSYS = 0x4
F_WRLCK = 0x3
+ HUPCL = 0x4000
+ ICANON = 0x100
+ ICRNL = 0x100
+ IEXTEN = 0x400
IFAN_ARRIVAL = 0x0
IFAN_DEPARTURE = 0x1
IFF_ALLMULTI = 0x200
IFF_ALTPHYS = 0x4000
IFF_BROADCAST = 0x2
- IFF_CANTCHANGE = 0x208f72
+ IFF_CANTCHANGE = 0x218f72
+ IFF_CANTCONFIG = 0x10000
IFF_DEBUG = 0x4
IFF_DRV_OACTIVE = 0x400
IFF_DRV_RUNNING = 0x40
@@ -488,6 +583,7 @@ const (
IFT_IEEE8023ADLAG = 0xa1
IFT_IFGSN = 0x91
IFT_IMT = 0xbe
+ IFT_INFINIBAND = 0xc7
IFT_INTERLEAVE = 0x7c
IFT_IP = 0x7e
IFT_IPFORWARD = 0x8e
@@ -603,6 +699,12 @@ const (
IFT_X25MLP = 0x79
IFT_X25PLE = 0x28
IFT_XETHER = 0x1a
+ IGNBRK = 0x1
+ IGNCR = 0x80
+ IGNPAR = 0x4
+ IMAXBEL = 0x2000
+ INLCR = 0x40
+ INPCK = 0x10
IN_CLASSA_HOST = 0xffffff
IN_CLASSA_MAX = 0x80
IN_CLASSA_NET = 0xff000000
@@ -618,6 +720,7 @@ const (
IN_CLASSD_NET = 0xf0000000
IN_CLASSD_NSHIFT = 0x1c
IN_LOOPBACKNET = 0x7f
+ IN_RFC3021_MASK = 0xfffffffe
IPPROTO_3PC = 0x22
IPPROTO_ADFS = 0x44
IPPROTO_AH = 0x33
@@ -679,6 +782,7 @@ const (
IPPROTO_MAX = 0x100
IPPROTO_MAXID = 0x34
IPPROTO_MEAS = 0x13
+ IPPROTO_MH = 0x87
IPPROTO_MHRP = 0x30
IPPROTO_MICP = 0x5f
IPPROTO_MOBILE = 0x37
@@ -709,6 +813,7 @@ const (
IPPROTO_SCCSP = 0x60
IPPROTO_SCTP = 0x84
IPPROTO_SDRP = 0x2a
+ IPPROTO_SEND = 0x103
IPPROTO_SEP = 0x21
IPPROTO_SKIP = 0x39
IPPROTO_SPACER = 0x7fff
@@ -856,6 +961,7 @@ const (
IP_RECVIF = 0x14
IP_RECVOPTS = 0x5
IP_RECVRETOPTS = 0x6
+ IP_RECVTOS = 0x44
IP_RECVTTL = 0x41
IP_RETOPTS = 0x8
IP_RF = 0x8000
@@ -867,10 +973,44 @@ const (
IP_TOS = 0x3
IP_TTL = 0x4
IP_UNBLOCK_SOURCE = 0x49
+ ISIG = 0x80
+ ISTRIP = 0x20
+ IXANY = 0x800
+ IXOFF = 0x400
+ IXON = 0x200
LOCK_EX = 0x2
LOCK_NB = 0x4
LOCK_SH = 0x1
LOCK_UN = 0x8
+ MADV_AUTOSYNC = 0x7
+ MADV_CORE = 0x9
+ MADV_DONTNEED = 0x4
+ MADV_FREE = 0x5
+ MADV_NOCORE = 0x8
+ MADV_NORMAL = 0x0
+ MADV_NOSYNC = 0x6
+ MADV_PROTECT = 0xa
+ MADV_RANDOM = 0x1
+ MADV_SEQUENTIAL = 0x2
+ MADV_WILLNEED = 0x3
+ MAP_ANON = 0x1000
+ MAP_ANONYMOUS = 0x1000
+ MAP_COPY = 0x2
+ MAP_FILE = 0x0
+ MAP_FIXED = 0x10
+ MAP_HASSEMAPHORE = 0x200
+ MAP_NOCORE = 0x20000
+ MAP_NORESERVE = 0x40
+ MAP_NOSYNC = 0x800
+ MAP_PREFAULT_READ = 0x40000
+ MAP_PRIVATE = 0x2
+ MAP_RENAME = 0x20
+ MAP_RESERVED0080 = 0x80
+ MAP_RESERVED0100 = 0x100
+ MAP_SHARED = 0x1
+ MAP_STACK = 0x400
+ MCL_CURRENT = 0x1
+ MCL_FUTURE = 0x2
MSG_COMPAT = 0x8000
MSG_CTRUNC = 0x20
MSG_DONTROUTE = 0x4
@@ -884,11 +1024,16 @@ const (
MSG_PEEK = 0x2
MSG_TRUNC = 0x10
MSG_WAITALL = 0x40
+ MS_ASYNC = 0x1
+ MS_INVALIDATE = 0x2
+ MS_SYNC = 0x0
NET_RT_DUMP = 0x1
NET_RT_FLAGS = 0x2
NET_RT_IFLIST = 0x3
+ NET_RT_IFLISTL = 0x5
NET_RT_IFMALIST = 0x4
- NET_RT_MAXID = 0x5
+ NET_RT_MAXID = 0x6
+ NOFLSH = 0x80000000
NOTE_ATTRIB = 0x8
NOTE_CHILD = 0x4
NOTE_DELETE = 0x1
@@ -912,6 +1057,12 @@ const (
NOTE_TRACKERR = 0x2
NOTE_TRIGGER = 0x1000000
NOTE_WRITE = 0x2
+ OCRNL = 0x10
+ ONLCR = 0x2
+ ONLRET = 0x40
+ ONOCR = 0x20
+ ONOEOT = 0x8
+ OPOST = 0x1
O_ACCMODE = 0x3
O_APPEND = 0x8
O_ASYNC = 0x40
@@ -933,6 +1084,14 @@ const (
O_TRUNC = 0x400
O_TTY_INIT = 0x80000
O_WRONLY = 0x1
+ PARENB = 0x1000
+ PARMRK = 0x8
+ PARODD = 0x2000
+ PENDIN = 0x20000000
+ PROT_EXEC = 0x4
+ PROT_NONE = 0x0
+ PROT_READ = 0x1
+ PROT_WRITE = 0x2
RLIMIT_AS = 0xa
RLIMIT_CORE = 0x4
RLIMIT_CPU = 0x0
@@ -1010,6 +1169,8 @@ const (
RTV_SPIPE = 0x10
RTV_SSTHRESH = 0x20
RTV_WEIGHT = 0x100
+ RT_CACHING_CONTEXT = 0x1
+ RT_DEFAULT_FIB = 0x0
RUSAGE_CHILDREN = -0x1
RUSAGE_SELF = 0x0
RUSAGE_THREAD = 0x1
@@ -1042,6 +1203,7 @@ const (
SIOCGIFCONF = 0xc0106924
SIOCGIFDESCR = 0xc020692a
SIOCGIFDSTADDR = 0xc0206922
+ SIOCGIFFIB = 0xc020695c
SIOCGIFFLAGS = 0xc0206911
SIOCGIFGENERIC = 0xc020693a
SIOCGIFGMEMB = 0xc028698a
@@ -1073,6 +1235,7 @@ const (
SIOCSIFCAP = 0x8020691e
SIOCSIFDESCR = 0x80206929
SIOCSIFDSTADDR = 0x8020690e
+ SIOCSIFFIB = 0x8020695d
SIOCSIFFLAGS = 0x80206910
SIOCSIFGENERIC = 0x80206939
SIOCSIFLLADDR = 0x8020693c
@@ -1115,6 +1278,8 @@ const (
SO_NO_OFFLOAD = 0x4000
SO_OOBINLINE = 0x100
SO_PEERLABEL = 0x1010
+ SO_PROTOCOL = 0x1016
+ SO_PROTOTYPE = 0x1016
SO_RCVBUF = 0x1002
SO_RCVLOWAT = 0x1004
SO_RCVTIMEO = 0x1006
@@ -1127,9 +1292,17 @@ const (
SO_TIMESTAMP = 0x400
SO_TYPE = 0x1008
SO_USELOOPBACK = 0x40
+ SO_USER_COOKIE = 0x1015
+ TCIFLUSH = 0x1
+ TCIOFLUSH = 0x3
+ TCOFLUSH = 0x2
TCP_CA_NAME_MAX = 0x10
TCP_CONGESTION = 0x40
TCP_INFO = 0x20
+ TCP_KEEPCNT = 0x400
+ TCP_KEEPIDLE = 0x100
+ TCP_KEEPINIT = 0x80
+ TCP_KEEPINTVL = 0x200
TCP_MAXBURST = 0x4
TCP_MAXHLEN = 0x3c
TCP_MAXOLEN = 0x28
@@ -1139,10 +1312,11 @@ const (
TCP_MAX_WINSHIFT = 0xe
TCP_MD5SIG = 0x10
TCP_MINMSS = 0xd8
- TCP_MSS = 0x200
+ TCP_MSS = 0x218
TCP_NODELAY = 0x1
TCP_NOOPT = 0x8
TCP_NOPUSH = 0x4
+ TCSAFLUSH = 0x2
TIOCCBRK = 0x2000747a
TIOCCDTR = 0x20007478
TIOCCONS = 0x80047462
@@ -1205,6 +1379,26 @@ const (
TIOCSWINSZ = 0x80087467
TIOCTIMESTAMP = 0x40107459
TIOCUCNTL = 0x80047466
+ TOSTOP = 0x400000
+ VDISCARD = 0xf
+ VDSUSP = 0xb
+ VEOF = 0x0
+ VEOL = 0x1
+ VEOL2 = 0x2
+ VERASE = 0x3
+ VERASE2 = 0x7
+ VINTR = 0x8
+ VKILL = 0x5
+ VLNEXT = 0xe
+ VMIN = 0x10
+ VQUIT = 0x9
+ VREPRINT = 0x6
+ VSTART = 0xc
+ VSTATUS = 0x12
+ VSTOP = 0xd
+ VSUSP = 0xa
+ VTIME = 0x11
+ VWERASE = 0x4
WCONTINUED = 0x4
WCOREFLAG = 0x80
WLINUXCLONE = 0x80000000
@@ -1229,6 +1423,7 @@ const (
EBADRPC = Errno(0x48)
EBUSY = Errno(0x10)
ECANCELED = Errno(0x55)
+ ECAPMODE = Errno(0x5e)
ECHILD = Errno(0xa)
ECONNABORTED = Errno(0x35)
ECONNREFUSED = Errno(0x3d)
@@ -1252,7 +1447,7 @@ const (
EIO = Errno(0x5)
EISCONN = Errno(0x38)
EISDIR = Errno(0x15)
- ELAST = Errno(0x5d)
+ ELAST = Errno(0x5e)
ELOOP = Errno(0x3e)
EMFILE = Errno(0x18)
EMLINK = Errno(0x1f)
@@ -1447,6 +1642,7 @@ var errors = [...]string{
91: "link has been severed",
92: "protocol error",
93: "capabilities insufficient",
+ 94: "not permitted in capability mode",
}
// Signal table
diff --git a/src/pkg/syscall/zerrors_freebsd_arm.go b/src/pkg/syscall/zerrors_freebsd_arm.go
index 92cade265..82f30abc5 100644
--- a/src/pkg/syscall/zerrors_freebsd_arm.go
+++ b/src/pkg/syscall/zerrors_freebsd_arm.go
@@ -7,7 +7,6 @@
package syscall
const (
- //O_CLOEXEC = 0x100000
AF_APPLETALK = 0x10
AF_ARP = 0x23
AF_ATM = 0x1e
@@ -333,10 +332,11 @@ const (
DLT_LINUX_SLL = 0x71
DLT_LOOP = 0x6c
DLT_LTALK = 0x72
- DLT_MATCHING_MAX = 0xf2
+ DLT_MATCHING_MAX = 0xf6
DLT_MATCHING_MIN = 0x68
DLT_MFR = 0xb6
DLT_MOST = 0xd3
+ DLT_MPEG_2_TS = 0xf3
DLT_MPLS = 0xdb
DLT_MTP2 = 0x8c
DLT_MTP2_WITH_PHDR = 0x8b
@@ -344,7 +344,9 @@ const (
DLT_MUX27010 = 0xec
DLT_NETANALYZER = 0xf0
DLT_NETANALYZER_TRANSPARENT = 0xf1
+ DLT_NFC_LLCP = 0xf5
DLT_NFLOG = 0xef
+ DLT_NG40 = 0xf4
DLT_NULL = 0x0
DLT_PCI_EXP = 0x7d
DLT_PFLOG = 0x75
@@ -985,6 +987,35 @@ const (
LOCK_NB = 0x4
LOCK_SH = 0x1
LOCK_UN = 0x8
+ MADV_AUTOSYNC = 0x7
+ MADV_CORE = 0x9
+ MADV_DONTNEED = 0x4
+ MADV_FREE = 0x5
+ MADV_NOCORE = 0x8
+ MADV_NORMAL = 0x0
+ MADV_NOSYNC = 0x6
+ MADV_PROTECT = 0xa
+ MADV_RANDOM = 0x1
+ MADV_SEQUENTIAL = 0x2
+ MADV_WILLNEED = 0x3
+ MAP_ANON = 0x1000
+ MAP_ANONYMOUS = 0x1000
+ MAP_COPY = 0x2
+ MAP_FILE = 0x0
+ MAP_FIXED = 0x10
+ MAP_HASSEMAPHORE = 0x200
+ MAP_NOCORE = 0x20000
+ MAP_NORESERVE = 0x40
+ MAP_NOSYNC = 0x800
+ MAP_PREFAULT_READ = 0x40000
+ MAP_PRIVATE = 0x2
+ MAP_RENAME = 0x20
+ MAP_RESERVED0080 = 0x80
+ MAP_RESERVED0100 = 0x100
+ MAP_SHARED = 0x1
+ MAP_STACK = 0x400
+ MCL_CURRENT = 0x1
+ MCL_FUTURE = 0x2
MSG_COMPAT = 0x8000
MSG_CTRUNC = 0x20
MSG_DONTROUTE = 0x4
@@ -998,6 +1029,9 @@ const (
MSG_PEEK = 0x2
MSG_TRUNC = 0x10
MSG_WAITALL = 0x40
+ MS_ASYNC = 0x1
+ MS_INVALIDATE = 0x2
+ MS_SYNC = 0x0
NET_RT_DUMP = 0x1
NET_RT_FLAGS = 0x2
NET_RT_IFLIST = 0x3
@@ -1059,6 +1093,10 @@ const (
PARMRK = 0x8
PARODD = 0x2000
PENDIN = 0x20000000
+ PROT_EXEC = 0x4
+ PROT_NONE = 0x0
+ PROT_READ = 0x1
+ PROT_WRITE = 0x2
RLIMIT_AS = 0xa
RLIMIT_CORE = 0x4
RLIMIT_CPU = 0x0
@@ -1369,10 +1407,12 @@ const (
VWERASE = 0x4
WCONTINUED = 0x4
WCOREFLAG = 0x80
+ WEXITED = 0x10
WLINUXCLONE = 0x80000000
WNOHANG = 0x1
WNOWAIT = 0x8
WSTOPPED = 0x2
+ WTRAPPED = 0x20
WUNTRACED = 0x2
)
diff --git a/src/pkg/syscall/zsyscall_darwin_386.go b/src/pkg/syscall/zsyscall_darwin_386.go
index 2f99b7f6c..98500792d 100644
--- a/src/pkg/syscall/zsyscall_darwin_386.go
+++ b/src/pkg/syscall/zsyscall_darwin_386.go
@@ -458,13 +458,8 @@ func Fchdir(fd int) (err error) {
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Fchflags(path string, flags int) (err error) {
- var _p0 *byte
- _p0, err = BytePtrFromString(path)
- if err != nil {
- return
- }
- _, _, e1 := Syscall(SYS_FCHFLAGS, uintptr(unsafe.Pointer(_p0)), uintptr(flags), 0)
+func Fchflags(fd int, flags int) (err error) {
+ _, _, e1 := Syscall(SYS_FCHFLAGS, uintptr(fd), uintptr(flags), 0)
if e1 != 0 {
err = e1
}
diff --git a/src/pkg/syscall/zsyscall_darwin_amd64.go b/src/pkg/syscall/zsyscall_darwin_amd64.go
index 0f08df4c5..ee810e076 100644
--- a/src/pkg/syscall/zsyscall_darwin_amd64.go
+++ b/src/pkg/syscall/zsyscall_darwin_amd64.go
@@ -458,13 +458,8 @@ func Fchdir(fd int) (err error) {
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Fchflags(path string, flags int) (err error) {
- var _p0 *byte
- _p0, err = BytePtrFromString(path)
- if err != nil {
- return
- }
- _, _, e1 := Syscall(SYS_FCHFLAGS, uintptr(unsafe.Pointer(_p0)), uintptr(flags), 0)
+func Fchflags(fd int, flags int) (err error) {
+ _, _, e1 := Syscall(SYS_FCHFLAGS, uintptr(fd), uintptr(flags), 0)
if e1 != 0 {
err = e1
}
diff --git a/src/pkg/syscall/zsyscall_freebsd_386.go b/src/pkg/syscall/zsyscall_freebsd_386.go
index 5ca0bcb16..631994fba 100644
--- a/src/pkg/syscall/zsyscall_freebsd_386.go
+++ b/src/pkg/syscall/zsyscall_freebsd_386.go
@@ -418,13 +418,8 @@ func Fchdir(fd int) (err error) {
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Fchflags(path string, flags int) (err error) {
- var _p0 *byte
- _p0, err = BytePtrFromString(path)
- if err != nil {
- return
- }
- _, _, e1 := Syscall(SYS_FCHFLAGS, uintptr(unsafe.Pointer(_p0)), uintptr(flags), 0)
+func Fchflags(fd int, flags int) (err error) {
+ _, _, e1 := Syscall(SYS_FCHFLAGS, uintptr(fd), uintptr(flags), 0)
if e1 != 0 {
err = e1
}
diff --git a/src/pkg/syscall/zsyscall_freebsd_amd64.go b/src/pkg/syscall/zsyscall_freebsd_amd64.go
index 260677473..1d5180853 100644
--- a/src/pkg/syscall/zsyscall_freebsd_amd64.go
+++ b/src/pkg/syscall/zsyscall_freebsd_amd64.go
@@ -418,13 +418,8 @@ func Fchdir(fd int) (err error) {
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Fchflags(path string, flags int) (err error) {
- var _p0 *byte
- _p0, err = BytePtrFromString(path)
- if err != nil {
- return
- }
- _, _, e1 := Syscall(SYS_FCHFLAGS, uintptr(unsafe.Pointer(_p0)), uintptr(flags), 0)
+func Fchflags(fd int, flags int) (err error) {
+ _, _, e1 := Syscall(SYS_FCHFLAGS, uintptr(fd), uintptr(flags), 0)
if e1 != 0 {
err = e1
}
diff --git a/src/pkg/syscall/zsyscall_netbsd_386.go b/src/pkg/syscall/zsyscall_netbsd_386.go
index 10ac072db..0ee19bee1 100644
--- a/src/pkg/syscall/zsyscall_netbsd_386.go
+++ b/src/pkg/syscall/zsyscall_netbsd_386.go
@@ -435,13 +435,8 @@ func Fchdir(fd int) (err error) {
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Fchflags(path string, flags int) (err error) {
- var _p0 *byte
- _p0, err = BytePtrFromString(path)
- if err != nil {
- return
- }
- _, _, e1 := Syscall(SYS_FCHFLAGS, uintptr(unsafe.Pointer(_p0)), uintptr(flags), 0)
+func Fchflags(fd int, flags int) (err error) {
+ _, _, e1 := Syscall(SYS_FCHFLAGS, uintptr(fd), uintptr(flags), 0)
if e1 != 0 {
err = e1
}
diff --git a/src/pkg/syscall/zsyscall_netbsd_amd64.go b/src/pkg/syscall/zsyscall_netbsd_amd64.go
index f10dc0bf4..b9d272144 100644
--- a/src/pkg/syscall/zsyscall_netbsd_amd64.go
+++ b/src/pkg/syscall/zsyscall_netbsd_amd64.go
@@ -435,13 +435,8 @@ func Fchdir(fd int) (err error) {
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Fchflags(path string, flags int) (err error) {
- var _p0 *byte
- _p0, err = BytePtrFromString(path)
- if err != nil {
- return
- }
- _, _, e1 := Syscall(SYS_FCHFLAGS, uintptr(unsafe.Pointer(_p0)), uintptr(flags), 0)
+func Fchflags(fd int, flags int) (err error) {
+ _, _, e1 := Syscall(SYS_FCHFLAGS, uintptr(fd), uintptr(flags), 0)
if e1 != 0 {
err = e1
}
diff --git a/src/pkg/syscall/zsyscall_openbsd_386.go b/src/pkg/syscall/zsyscall_openbsd_386.go
index 60e907bd2..2c2a56732 100644
--- a/src/pkg/syscall/zsyscall_openbsd_386.go
+++ b/src/pkg/syscall/zsyscall_openbsd_386.go
@@ -416,13 +416,8 @@ func Fchdir(fd int) (err error) {
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Fchflags(path string, flags int) (err error) {
- var _p0 *byte
- _p0, err = BytePtrFromString(path)
- if err != nil {
- return
- }
- _, _, e1 := Syscall(SYS_FCHFLAGS, uintptr(unsafe.Pointer(_p0)), uintptr(flags), 0)
+func Fchflags(fd int, flags int) (err error) {
+ _, _, e1 := Syscall(SYS_FCHFLAGS, uintptr(fd), uintptr(flags), 0)
if e1 != 0 {
err = e1
}
diff --git a/src/pkg/syscall/zsyscall_openbsd_amd64.go b/src/pkg/syscall/zsyscall_openbsd_amd64.go
index 1403dd7e7..4e1470696 100644
--- a/src/pkg/syscall/zsyscall_openbsd_amd64.go
+++ b/src/pkg/syscall/zsyscall_openbsd_amd64.go
@@ -416,13 +416,8 @@ func Fchdir(fd int) (err error) {
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Fchflags(path string, flags int) (err error) {
- var _p0 *byte
- _p0, err = BytePtrFromString(path)
- if err != nil {
- return
- }
- _, _, e1 := Syscall(SYS_FCHFLAGS, uintptr(unsafe.Pointer(_p0)), uintptr(flags), 0)
+func Fchflags(fd int, flags int) (err error) {
+ _, _, e1 := Syscall(SYS_FCHFLAGS, uintptr(fd), uintptr(flags), 0)
if e1 != 0 {
err = e1
}
diff --git a/src/pkg/syscall/zsysnum_freebsd_386.go b/src/pkg/syscall/zsysnum_freebsd_386.go
index 5a2bfd119..74400b6f6 100644
--- a/src/pkg/syscall/zsysnum_freebsd_386.go
+++ b/src/pkg/syscall/zsysnum_freebsd_386.go
@@ -149,6 +149,7 @@ const (
SYS_FFCLOCK_GETCOUNTER = 241 // { int ffclock_getcounter(ffcounter *ffcount); }
SYS_FFCLOCK_SETESTIMATE = 242 // { int ffclock_setestimate( \
SYS_FFCLOCK_GETESTIMATE = 243 // { int ffclock_getestimate( \
+ SYS_CLOCK_GETCPUCLOCKID2 = 247 // { int clock_getcpuclockid2(id_t id,\
SYS_NTP_GETTIME = 248 // { int ntp_gettime(struct ntptimeval *ntvp); }
SYS_MINHERIT = 250 // { int minherit(void *addr, size_t len, \
SYS_RFORK = 251 // { int rfork(int flags); }
@@ -320,7 +321,7 @@ const (
SYS_JAIL_REMOVE = 508 // { int jail_remove(int jid); }
SYS_CLOSEFROM = 509 // { int closefrom(int lowfd); }
SYS_LPATHCONF = 513 // { int lpathconf(char *path, int name); }
- SYS_CAP_NEW = 514 // { int cap_new(int fd, u_int64_t rights); }
+ SYS_CAP_NEW = 514 // { int cap_new(int fd, uint64_t rights); }
SYS_CAP_GETRIGHTS = 515 // { int cap_getrights(int fd, \
SYS_CAP_ENTER = 516 // { int cap_enter(void); }
SYS_CAP_GETMODE = 517 // { int cap_getmode(u_int *modep); }
@@ -337,4 +338,5 @@ const (
SYS_RCTL_REMOVE_RULE = 529 // { int rctl_remove_rule(const void *inbufp, \
SYS_POSIX_FALLOCATE = 530 // { int posix_fallocate(int fd, \
SYS_POSIX_FADVISE = 531 // { int posix_fadvise(int fd, off_t offset, \
+ SYS_WAIT6 = 532 // { int wait6(int idtype, int id, \
)
diff --git a/src/pkg/syscall/zsysnum_freebsd_amd64.go b/src/pkg/syscall/zsysnum_freebsd_amd64.go
index 5a2bfd119..74400b6f6 100644
--- a/src/pkg/syscall/zsysnum_freebsd_amd64.go
+++ b/src/pkg/syscall/zsysnum_freebsd_amd64.go
@@ -149,6 +149,7 @@ const (
SYS_FFCLOCK_GETCOUNTER = 241 // { int ffclock_getcounter(ffcounter *ffcount); }
SYS_FFCLOCK_SETESTIMATE = 242 // { int ffclock_setestimate( \
SYS_FFCLOCK_GETESTIMATE = 243 // { int ffclock_getestimate( \
+ SYS_CLOCK_GETCPUCLOCKID2 = 247 // { int clock_getcpuclockid2(id_t id,\
SYS_NTP_GETTIME = 248 // { int ntp_gettime(struct ntptimeval *ntvp); }
SYS_MINHERIT = 250 // { int minherit(void *addr, size_t len, \
SYS_RFORK = 251 // { int rfork(int flags); }
@@ -320,7 +321,7 @@ const (
SYS_JAIL_REMOVE = 508 // { int jail_remove(int jid); }
SYS_CLOSEFROM = 509 // { int closefrom(int lowfd); }
SYS_LPATHCONF = 513 // { int lpathconf(char *path, int name); }
- SYS_CAP_NEW = 514 // { int cap_new(int fd, u_int64_t rights); }
+ SYS_CAP_NEW = 514 // { int cap_new(int fd, uint64_t rights); }
SYS_CAP_GETRIGHTS = 515 // { int cap_getrights(int fd, \
SYS_CAP_ENTER = 516 // { int cap_enter(void); }
SYS_CAP_GETMODE = 517 // { int cap_getmode(u_int *modep); }
@@ -337,4 +338,5 @@ const (
SYS_RCTL_REMOVE_RULE = 529 // { int rctl_remove_rule(const void *inbufp, \
SYS_POSIX_FALLOCATE = 530 // { int posix_fallocate(int fd, \
SYS_POSIX_FADVISE = 531 // { int posix_fadvise(int fd, off_t offset, \
+ SYS_WAIT6 = 532 // { int wait6(int idtype, int id, \
)
diff --git a/src/pkg/syscall/zsysnum_freebsd_arm.go b/src/pkg/syscall/zsysnum_freebsd_arm.go
index 5a2bfd119..61a6a3295 100644
--- a/src/pkg/syscall/zsysnum_freebsd_arm.go
+++ b/src/pkg/syscall/zsysnum_freebsd_arm.go
@@ -149,6 +149,7 @@ const (
SYS_FFCLOCK_GETCOUNTER = 241 // { int ffclock_getcounter(ffcounter *ffcount); }
SYS_FFCLOCK_SETESTIMATE = 242 // { int ffclock_setestimate( \
SYS_FFCLOCK_GETESTIMATE = 243 // { int ffclock_getestimate( \
+ SYS_CLOCK_GETCPUCLOCKID2 = 247 // { int clock_getcpuclockid2(id_t id,\
SYS_NTP_GETTIME = 248 // { int ntp_gettime(struct ntptimeval *ntvp); }
SYS_MINHERIT = 250 // { int minherit(void *addr, size_t len, \
SYS_RFORK = 251 // { int rfork(int flags); }
@@ -320,8 +321,8 @@ const (
SYS_JAIL_REMOVE = 508 // { int jail_remove(int jid); }
SYS_CLOSEFROM = 509 // { int closefrom(int lowfd); }
SYS_LPATHCONF = 513 // { int lpathconf(char *path, int name); }
- SYS_CAP_NEW = 514 // { int cap_new(int fd, u_int64_t rights); }
- SYS_CAP_GETRIGHTS = 515 // { int cap_getrights(int fd, \
+ SYS_CAP_NEW = 514 // { int cap_new(int fd, uint64_t rights); }
+ SYS_CAP_RIGHTS_GET = 515 // { int cap_rights_get(int fd, \
SYS_CAP_ENTER = 516 // { int cap_enter(void); }
SYS_CAP_GETMODE = 517 // { int cap_getmode(u_int *modep); }
SYS_PDFORK = 518 // { int pdfork(int *fdp, int flags); }
@@ -337,4 +338,10 @@ const (
SYS_RCTL_REMOVE_RULE = 529 // { int rctl_remove_rule(const void *inbufp, \
SYS_POSIX_FALLOCATE = 530 // { int posix_fallocate(int fd, \
SYS_POSIX_FADVISE = 531 // { int posix_fadvise(int fd, off_t offset, \
+ SYS_WAIT6 = 532 // { int wait6(int idtype, int id, \
+ SYS_CAP_RIGHTS_LIMIT = 533 // { int cap_rights_limit(int fd, \
+ SYS_CAP_IOCTLS_LIMIT = 534 // { int cap_ioctls_limit(int fd, \
+ SYS_CAP_IOCTLS_GET = 535 // { ssize_t cap_ioctls_get(int fd, \
+ SYS_CAP_FCNTLS_LIMIT = 536 // { int cap_fcntls_limit(int fd, \
+ SYS_CAP_FCNTLS_GET = 537 // { int cap_fcntls_get(int fd, \
)
diff --git a/src/pkg/testing/iotest/reader.go b/src/pkg/testing/iotest/reader.go
index 441b9102d..a5bccca90 100644
--- a/src/pkg/testing/iotest/reader.go
+++ b/src/pkg/testing/iotest/reader.go
@@ -37,9 +37,11 @@ func (r *halfReader) Read(p []byte) (int, error) {
return r.r.Read(p[0 : (len(p)+1)/2])
}
-// DataErrReader returns a Reader that returns the final
-// error with the last data read, instead of by itself with
-// zero bytes of data.
+// DataErrReader changes the way errors are handled by a Reader. Normally, a
+// Reader returns an error (typically EOF) from the first Read call after the
+// last piece of data is read. DataErrReader wraps a Reader and changes its
+// behavior so the final error is returned along with the final data, instead
+// of in the first call after the final data.
func DataErrReader(r io.Reader) io.Reader { return &dataErrReader{r, nil, make([]byte, 1024)} }
type dataErrReader struct {
diff --git a/src/pkg/testing/quick/quick.go b/src/pkg/testing/quick/quick.go
index 242709822..761a6471b 100644
--- a/src/pkg/testing/quick/quick.go
+++ b/src/pkg/testing/quick/quick.go
@@ -140,8 +140,6 @@ func Value(t reflect.Type, rand *rand.Rand) (value reflect.Value, ok bool) {
default:
return reflect.Value{}, false
}
-
- return
}
// A Config structure contains options for running a test.
diff --git a/src/pkg/testing/testing.go b/src/pkg/testing/testing.go
index 86cd46c29..312d28732 100644
--- a/src/pkg/testing/testing.go
+++ b/src/pkg/testing/testing.go
@@ -18,6 +18,8 @@
// ...
// }
//
+// Benchmarks
+//
// Functions of the form
// func BenchmarkXxx(*testing.B)
// are considered benchmarks, and are executed by the "go test" command when
@@ -49,6 +51,8 @@
// }
// }
//
+// Examples
+//
// The package also runs and verifies example code. Example functions may
// include a concluding line comment that begins with "Output:" and is compared with
// the standard output of the function when the tests are run. (The comparison
@@ -246,11 +250,13 @@ func (c *common) log(s string) {
}
// Log formats its arguments using default formatting, analogous to Println,
-// and records the text in the error log.
+// and records the text in the error log. The text will be printed only if
+// the test fails or the -test.v flag is set.
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.
+// and records the text in the error log. The text will be printed only if
+// the test fails or the -test.v flag is set.
func (c *common) Logf(format string, args ...interface{}) { c.log(fmt.Sprintf(format, args...)) }
// Error is equivalent to Log followed by Fail.
@@ -337,6 +343,7 @@ func tRunner(t *T, test *InternalTest) {
t.duration = time.Now().Sub(t.start)
// If the test panicked, print any test output before dying.
if err := recover(); err != nil {
+ t.Fail()
t.report()
panic(err)
}
diff --git a/src/pkg/text/template/exec.go b/src/pkg/text/template/exec.go
index b9c03d8f0..8ec8174a1 100644
--- a/src/pkg/text/template/exec.go
+++ b/src/pkg/text/template/exec.go
@@ -5,6 +5,7 @@
package template
import (
+ "bytes"
"fmt"
"io"
"reflect"
@@ -125,8 +126,23 @@ func (t *Template) Execute(wr io.Writer, data interface{}) (err error) {
wr: wr,
vars: []variable{{"$", value}},
}
+ t.init()
if t.Tree == nil || t.Root == nil {
- state.errorf("%q is an incomplete or empty template", t.name)
+ var b bytes.Buffer
+ for name, tmpl := range t.tmpl {
+ if tmpl.Tree == nil || tmpl.Root == nil {
+ continue
+ }
+ if b.Len() > 0 {
+ b.WriteString(", ")
+ }
+ fmt.Fprintf(&b, "%q", name)
+ }
+ var s string
+ if b.Len() > 0 {
+ s = "; defined templates are: " + b.String()
+ }
+ state.errorf("%q is an incomplete or empty template%s", t.Name(), s)
}
state.walk(value, t.Root)
return
@@ -603,6 +619,8 @@ func (s *state) evalArg(dot reflect.Value, typ reflect.Type, n parse.Node) refle
return s.validateType(s.evalVariableNode(dot, arg, nil, zero), typ)
case *parse.PipeNode:
return s.validateType(s.evalPipeline(dot, arg), typ)
+ case *parse.IdentifierNode:
+ return s.evalFunction(dot, arg, arg, nil, zero)
}
switch typ.Kind() {
case reflect.Bool:
diff --git a/src/pkg/text/template/exec_test.go b/src/pkg/text/template/exec_test.go
index 683e9ac76..0ab20acc9 100644
--- a/src/pkg/text/template/exec_test.go
+++ b/src/pkg/text/template/exec_test.go
@@ -499,6 +499,8 @@ var execTests = []execTest{
{"bug8b", "{{4|dddArg 3}}", "", tVal, false},
// A bug was introduced that broke map lookups for lower-case names.
{"bug9", "{{.cause}}", "neglect", map[string]string{"cause": "neglect"}, true},
+ // Field chain starting with function did not work.
+ {"bug10", "{{mapOfThree.three}}-{{(mapOfThree).three}}", "3-3", 0, true},
}
func zeroArgs() string {
@@ -560,19 +562,24 @@ func stringer(s fmt.Stringer) string {
return s.String()
}
+func mapOfThree() interface{} {
+ return map[string]int{"three": 3}
+}
+
func testExecute(execTests []execTest, template *Template, t *testing.T) {
b := new(bytes.Buffer)
funcs := FuncMap{
- "add": add,
- "count": count,
- "dddArg": dddArg,
- "echo": echo,
- "makemap": makemap,
- "oneArg": oneArg,
- "typeOf": typeOf,
- "vfunc": vfunc,
- "zeroArgs": zeroArgs,
- "stringer": stringer,
+ "add": add,
+ "count": count,
+ "dddArg": dddArg,
+ "echo": echo,
+ "makemap": makemap,
+ "mapOfThree": mapOfThree,
+ "oneArg": oneArg,
+ "stringer": stringer,
+ "typeOf": typeOf,
+ "vfunc": vfunc,
+ "zeroArgs": zeroArgs,
}
for _, test := range execTests {
var tmpl *Template
@@ -816,3 +823,40 @@ func TestExecuteOnNewTemplate(t *testing.T) {
// This is issue 3872.
_ = New("Name").Templates()
}
+
+const testTemplates = `{{define "one"}}one{{end}}{{define "two"}}two{{end}}`
+
+func TestMessageForExecuteEmpty(t *testing.T) {
+ // Test a truly empty template.
+ tmpl := New("empty")
+ var b bytes.Buffer
+ err := tmpl.Execute(&b, 0)
+ if err == nil {
+ t.Fatal("expected initial error")
+ }
+ got := err.Error()
+ want := `template: empty: "empty" is an incomplete or empty template`
+ if got != want {
+ t.Errorf("expected error %s got %s", want, got)
+ }
+ // Add a non-empty template to check that the error is helpful.
+ tests, err := New("").Parse(testTemplates)
+ if err != nil {
+ t.Fatal(err)
+ }
+ tmpl.AddParseTree("secondary", tests.Tree)
+ err = tmpl.Execute(&b, 0)
+ if err == nil {
+ t.Fatal("expected second error")
+ }
+ got = err.Error()
+ want = `template: empty: "empty" is an incomplete or empty template; defined templates are: "secondary"`
+ if got != want {
+ t.Errorf("expected error %s got %s", want, got)
+ }
+ // Make sure we can execute the secondary.
+ err = tmpl.ExecuteTemplate(&b, "secondary", 0)
+ if err != nil {
+ t.Fatal(err)
+ }
+}
diff --git a/src/pkg/text/template/funcs.go b/src/pkg/text/template/funcs.go
index 31549dc45..818766364 100644
--- a/src/pkg/text/template/funcs.go
+++ b/src/pkg/text/template/funcs.go
@@ -18,7 +18,7 @@ import (
// FuncMap is the type of the map defining the mapping from names to functions.
// Each function must have either a single return value, or two return values of
// which the second has type error. In that case, if the second (error)
-// argument evaluates to non-nil during execution, execution terminates and
+// return value evaluates to non-nil during execution, execution terminates and
// Execute returns that error.
type FuncMap map[string]interface{}
diff --git a/src/pkg/text/template/parse/parse.go b/src/pkg/text/template/parse/parse.go
index c0fb9274a..802e298c2 100644
--- a/src/pkg/text/template/parse/parse.go
+++ b/src/pkg/text/template/parse/parse.go
@@ -429,7 +429,6 @@ func (t *Tree) pipeline(context string) (pipe *PipeNode) {
t.unexpected(token, context)
}
}
- return
}
func (t *Tree) parseControl(context string) (pos Pos, line int, pipe *PipeNode, list, elseList *ListNode) {
@@ -445,7 +444,6 @@ func (t *Tree) parseControl(context string) (pos Pos, line int, pipe *PipeNode,
if next.Type() != nodeEnd {
t.errorf("expected end; found %s", next)
}
- elseList = elseList
}
return pipe.Position(), line, pipe, list, elseList
}
diff --git a/src/pkg/time/example_test.go b/src/pkg/time/example_test.go
index 8928caaba..cfa5b38c5 100644
--- a/src/pkg/time/example_test.go
+++ b/src/pkg/time/example_test.go
@@ -58,20 +58,25 @@ func ExampleDate() {
}
func ExampleTime_Format() {
- const format = "Jan 2, 2006 at 3:04pm (MST)"
+ // layout shows by example how the reference time should be represented.
+ const layout = "Jan 2, 2006 at 3:04pm (MST)"
t := time.Date(2009, time.November, 10, 15, 0, 0, 0, time.Local)
- fmt.Println(t.Format(format))
- fmt.Println(t.UTC().Format(format))
+ fmt.Println(t.Format(layout))
+ fmt.Println(t.UTC().Format(layout))
// Output:
// Nov 10, 2009 at 3:00pm (PST)
// Nov 10, 2009 at 11:00pm (UTC)
}
func ExampleParse() {
+ // longForm shows by example how the reference time would be represented in
+ // the desired layout.
const longForm = "Jan 2, 2006 at 3:04pm (MST)"
t, _ := time.Parse(longForm, "Feb 3, 2013 at 7:54pm (PST)")
fmt.Println(t)
+ // shortForm is another way the reference time would be represented
+ // in the desired layout; it has no time zone present.
// Note: without explicit zone, returns time in UTC.
const shortForm = "2006-Jan-02"
t, _ = time.Parse(shortForm, "2013-Feb-03")
diff --git a/src/pkg/time/format.go b/src/pkg/time/format.go
index 817c79a80..7fe040231 100644
--- a/src/pkg/time/format.go
+++ b/src/pkg/time/format.go
@@ -6,15 +6,17 @@ package time
import "errors"
-// These are predefined layouts for use in Time.Format.
-// The standard time used in the layouts is:
+// These are predefined layouts for use in Time.Format and Time.Parse.
+// The reference time used in the layouts is:
// Mon Jan 2 15:04:05 MST 2006
// which is Unix time 1136239445. Since MST is GMT-0700,
-// the standard time can be thought of as
+// the reference time can be thought of as
// 01/02 03:04:05PM '06 -0700
-// To define your own format, write down what the standard time would look
+// To define your own format, write down what the reference time would look
// like formatted your way; see the values of constants like ANSIC,
-// StampMicro or Kitchen for examples.
+// StampMicro or Kitchen for examples. The model is to demonstrate what the
+// reference time looks like so that the Format and Parse methods can apply
+// the same transformation to a general time value.
//
// Within the format string, an underscore _ represents a space that may be
// replaced by a digit if the following number (a day) has two digits; for
@@ -367,13 +369,16 @@ func (t Time) String() string {
}
// Format returns a textual representation of the time value formatted
-// according to layout. The layout defines the format by showing the
-// representation of the standard time,
+// according to layout, which defines the format by showing how the reference
+// time,
// Mon Jan 2 15:04:05 -0700 MST 2006
-// which is then used to describe the time to be formatted. Predefined
-// layouts ANSIC, UnixDate, RFC3339 and others describe standard
-// representations. For more information about the formats and the
-// definition of the standard time, see the documentation for ANSIC.
+// would be displayed if it were the value; it serves as an example of the
+// desired output. The same display rules will then be applied to the time
+// value.
+// Predefined layouts ANSIC, UnixDate, RFC3339 and others describe standard
+// and convenient representations of the reference time. For more information
+// about the formats and the definition of the reference time, see the
+// documentation for ANSIC and the other constants defined by this package.
func (t Time) Format(layout string) string {
var (
name, offset, abs = t.locabs()
@@ -627,13 +632,15 @@ func skip(value, prefix string) (string, error) {
}
// Parse parses a formatted string and returns the time value it represents.
-// The layout defines the format by showing the representation of the
-// standard time,
+// The layout defines the format by showing how the reference time,
// Mon Jan 2 15:04:05 -0700 MST 2006
-// which is then used to describe the string to be parsed. Predefined layouts
-// ANSIC, UnixDate, RFC3339 and others describe standard representations. For
-// more information about the formats and the definition of the standard
-// time, see the documentation for ANSIC.
+// would be interpreted if it were the value; it serves as an example of
+// the input format. The same interpretation will then be made to the
+// input string.
+// Predefined layouts ANSIC, UnixDate, RFC3339 and others describe standard
+// and convenient representations of the reference time. For more information
+// about the formats and the definition of the reference time, see the
+// documentation for ANSIC and the other constants defined by this package.
//
// Elements omitted from the value are assumed to be zero or, when
// zero is impossible, one, so parsing "3:04pm" returns the time
diff --git a/src/pkg/time/sleep_test.go b/src/pkg/time/sleep_test.go
index 9908e220f..1322f0611 100644
--- a/src/pkg/time/sleep_test.go
+++ b/src/pkg/time/sleep_test.go
@@ -60,10 +60,11 @@ func TestAfterStress(t *testing.T) {
Sleep(Nanosecond)
}
}()
- c := Tick(1)
+ ticker := NewTicker(1)
for i := 0; i < 100; i++ {
- <-c
+ <-ticker.C
}
+ ticker.Stop()
atomic.StoreUint32(&stop, 1)
}
diff --git a/src/pkg/time/time_test.go b/src/pkg/time/time_test.go
index 4b268f73d..a0ee37ae3 100644
--- a/src/pkg/time/time_test.go
+++ b/src/pkg/time/time_test.go
@@ -11,6 +11,7 @@ import (
"fmt"
"math/big"
"math/rand"
+ "runtime"
"strconv"
"strings"
"testing"
@@ -1299,6 +1300,9 @@ var mallocTest = []struct {
}
func TestCountMallocs(t *testing.T) {
+ if runtime.GOMAXPROCS(0) > 1 {
+ t.Skip("skipping; GOMAXPROCS>1")
+ }
for _, mt := range mallocTest {
allocs := int(testing.AllocsPerRun(100, mt.fn))
if allocs > mt.count {
diff --git a/src/pkg/unicode/letter.go b/src/pkg/unicode/letter.go
index 8d56363df..fadaa57d8 100644
--- a/src/pkg/unicode/letter.go
+++ b/src/pkg/unicode/letter.go
@@ -151,7 +151,7 @@ func is32(ranges []Range32, r uint32) bool {
return false
}
-// Is tests whether rune is in the specified table of ranges.
+// Is reports whether the rune is in the specified table of ranges.
func Is(rangeTab *RangeTable, r rune) bool {
r16 := rangeTab.R16
if len(r16) > 0 && r <= rune(r16[len(r16)-1].Hi) {
diff --git a/src/pkg/unicode/maketables.go b/src/pkg/unicode/maketables.go
index 53d8b967e..e5ed08b23 100644
--- a/src/pkg/unicode/maketables.go
+++ b/src/pkg/unicode/maketables.go
@@ -440,7 +440,7 @@ func printCategories() {
varDecl = "\tLetter = _L; // Letter/L is the set of Unicode letters, category L.\n"
varDecl += "\tL = _L\n"
case "M":
- varDecl = "\tMark = _M; // Mark/M is the set of Unicode mark characters, category M.\n"
+ varDecl = "\tMark = _M; // Mark/M is the set of Unicode mark characters, category M.\n"
varDecl += "\tM = _M\n"
case "N":
varDecl = "\tNumber = _N; // Number/N is the set of Unicode number characters, category N.\n"
diff --git a/src/pkg/unicode/tables.go b/src/pkg/unicode/tables.go
index 36b5a3115..939c41dc5 100644
--- a/src/pkg/unicode/tables.go
+++ b/src/pkg/unicode/tables.go
@@ -2864,7 +2864,7 @@ var (
Lo = _Lo // Lo is the set of Unicode characters in category Lo.
Lower = _Ll // Lower is the set of Unicode lower case letters.
Ll = _Ll // Ll is the set of Unicode characters in category Ll.
- Mark = _M // Mark/M is the set of Unicode mark characters, category M.
+ Mark = _M // Mark/M is the set of Unicode mark characters, category M.
M = _M
Mc = _Mc // Mc is the set of Unicode characters in category Mc.
Me = _Me // Me is the set of Unicode characters in category Me.
diff --git a/src/pkg/unicode/utf8/utf8_test.go b/src/pkg/unicode/utf8/utf8_test.go
index c516871c9..758d7a0f8 100644
--- a/src/pkg/unicode/utf8/utf8_test.go
+++ b/src/pkg/unicode/utf8/utf8_test.go
@@ -124,7 +124,7 @@ func TestDecodeRune(t *testing.T) {
s := m.str
r, size = DecodeRuneInString(s)
if r != m.r || size != len(b) {
- t.Errorf("DecodeRune(%q) = %#04x, %d want %#04x, %d", s, r, size, m.r, len(b))
+ t.Errorf("DecodeRuneInString(%q) = %#04x, %d want %#04x, %d", s, r, size, m.r, len(b))
}
// there's an extra byte that bytes left behind - make sure trailing byte works
@@ -164,7 +164,7 @@ func TestDecodeRune(t *testing.T) {
t.Errorf("DecodeRune(%q) = %#04x, %d want %#04x, %d", b, r, size, RuneError, 1)
}
s = string(b)
- r, size = DecodeRune(b)
+ r, size = DecodeRuneInString(s)
if r != RuneError || size != 1 {
t.Errorf("DecodeRuneInString(%q) = %#04x, %d want %#04x, %d", s, r, size, RuneError, 1)
}
@@ -182,7 +182,7 @@ func TestDecodeSurrogateRune(t *testing.T) {
s := m.str
r, size = DecodeRuneInString(s)
if r != RuneError || size != 1 {
- t.Errorf("DecodeRune(%q) = %x, %d want %x, %d", b, r, size, RuneError, 1)
+ t.Errorf("DecodeRuneInString(%q) = %x, %d want %x, %d", b, r, size, RuneError, 1)
}
}
}