diff options
Diffstat (limited to 'src/pkg')
473 files changed, 12764 insertions, 28304 deletions
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..d94f7f9ad 100644 --- a/src/pkg/bufio/scan.go +++ b/src/pkg/bufio/scan.go @@ -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. @@ -169,7 +167,6 @@ func (s *Scanner) Scan() bool { } s.end += n } - panic("not reached") } // advance consumes n bytes of the buffer. It reports whether the advance was legal. diff --git a/src/pkg/bytes/asm_386.s b/src/pkg/bytes/asm_386.s index c444b55e1..997738fe2 100644 --- a/src/pkg/bytes/asm_386.s +++ b/src/pkg/bytes/asm_386.s @@ -4,21 +4,21 @@ 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) + MOVL DI, ret+16(FP) RET TEXT ·Equal(SB),7,$0 - MOVL a+4(FP), BX - MOVL b+16(FP), CX + MOVL a_len+4(FP), BX + MOVL b_len+16(FP), CX MOVL $0, AX CMPL BX, CX JNE eqret @@ -29,5 +29,5 @@ TEXT ·Equal(SB),7,$0 JNE eqret MOVL $1, AX eqret: - MOVB AX, r+24(FP) + MOVB AX, ret+24(FP) RET diff --git a/src/pkg/bytes/asm_amd64.s b/src/pkg/bytes/asm_amd64.s index 482422642..b8f9f1b81 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,18 +81,18 @@ 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 + MOVQ a_len+8(FP), BX + MOVQ b_len+32(FP), CX MOVL $0, AX CMPQ BX, CX JNE eqret @@ -103,6 +103,6 @@ TEXT ·Equal(SB),7,$0 MOVL $1, DX CMOVLEQ DX, AX eqret: - MOVB AX, r+48(FP) + MOVB AX, ret+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/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/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/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/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..21608dbac 100644 --- a/src/pkg/crypto/rand/util.go +++ b/src/pkg/crypto/rand/util.go @@ -98,8 +98,6 @@ func Prime(rand io.Reader, bits int) (p *big.Int, err error) { return } } - - return } // Int returns a uniform random value in [0, max). @@ -130,6 +128,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/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..5530a5d90 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) } @@ -116,6 +122,12 @@ func convertAssign(dest, src interface{}) error { } *d = s return nil + case *RawBytes: + if d == nil { + return errNilPtr + } + *d = s + return nil } case nil: switch d := dest.(type) { @@ -125,6 +137,12 @@ func convertAssign(dest, src interface{}) error { } *d = nil return nil + case *RawBytes: + if d == nil { + return errNilPtr + } + *d = nil + return nil } } @@ -141,6 +159,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 { diff --git a/src/pkg/database/sql/convert_test.go b/src/pkg/database/sql/convert_test.go index 9c362d732..6aedeb0a4 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`}, diff --git a/src/pkg/database/sql/sql.go b/src/pkg/database/sql/sql.go index 4faaa11b1..bc92ecd8e 100644 --- a/src/pkg/database/sql/sql.go +++ b/src/pkg/database/sql/sql.go @@ -177,26 +177,49 @@ 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 + outConn map[*driverConn]bool // whether the conn is in use + freeConn []*driverConn 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 + onConnPut map[*driverConn][]func() // code (with mu held) run when conn is next returned + 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 { + sync.Mutex + ci driver.Conn +} + +// 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 @@ -258,30 +281,48 @@ func (db *DB) removeDep(x finalCloser, dep interface{}) error { // // Most users will open a database via a driver-specific connection // helper function that returns a *DB. +// +// 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()), + outConn: make(map[*driverConn]bool), + lastPut: make(map[*driverConn]string), + onConnPut: make(map[*driverConn][]func()), } 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 { + dc.Lock() + err1 := dc.ci.Close() + dc.Unlock() if err1 != nil { err = err1 } @@ -291,15 +332,49 @@ 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 + } +} + +// 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 func() { + dc.Lock() + dc.ci.Close() + dc.Unlock() + }() + } } -// conn returns a newly-opened or cached driver.Conn -func (db *DB) conn() (driver.Conn, error) { +// conn returns a newly-opened or cached *driverConn +func (db *DB) conn() (*driverConn, error) { db.mu.Lock() if db.closed { db.mu.Unlock() @@ -313,13 +388,16 @@ func (db *DB) conn() (driver.Conn, error) { 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 } - return conn, err + dc := &driverConn{ci: ci} + db.mu.Lock() + db.outConn[dc] = true + db.mu.Unlock() + return dc, nil } // connIfFree returns (wanted, true) if wanted is still a valid conn and @@ -327,7 +405,7 @@ func (db *DB) conn() (driver.Conn, error) { // // 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) { +func (db *DB) connIfFree(wanted *driverConn) (conn *driverConn, ok bool) { db.mu.Lock() defer db.mu.Unlock() if db.outConn[wanted] { @@ -346,12 +424,12 @@ func (db *DB) connIfFree(wanted driver.Conn) (conn driver.Conn, ok bool) { } // 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] { @@ -369,24 +447,24 @@ 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 !db.outConn[dc] { 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) + delete(db.outConn, dc) - if fns, ok := db.onConnPut[c]; ok { + if fns, ok := db.onConnPut[dc]; ok { for _, fn := range fns { fn() } - delete(db.onConnPut, c) + delete(db.onConnPut, dc) } if err == driver.ErrBadConn { @@ -395,17 +473,20 @@ 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.Lock() + dc.ci.Close() + dc.Unlock() } // Prepare creates a prepared statement for later queries or executions. @@ -430,21 +511,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.ci.Prepare(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 +547,39 @@ 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() + 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. @@ -521,24 +609,26 @@ 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,16 +636,21 @@ 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 } @@ -563,10 +658,10 @@ func (db *DB) queryConn(ci driver.Conn, releaseConn func(error), query string, a // with releaseConn. rows := &Rows{ db: db, - ci: ci, + dc: dc, releaseConn: releaseConn, rowsi: rowsi, - closeStmt: sti, + closeStmt: si, } return rows, nil } @@ -594,18 +689,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 +721,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 +739,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 +757,8 @@ func (tx *Tx) Commit() error { return ErrTxDone } defer tx.close() + tx.dc.Lock() + defer tx.dc.Unlock() return tx.txi.Commit() } @@ -678,6 +768,8 @@ func (tx *Tx) Rollback() error { return ErrTxDone } defer tx.close() + tx.dc.Lock() + defer tx.dc.Unlock() return tx.txi.Rollback() } @@ -701,21 +793,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 +835,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 +857,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 +909,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 +924,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 +941,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,8 +998,8 @@ 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 @@ -900,7 +1007,7 @@ func (s *Stmt) connStmt() (ci driver.Conn, releaseConn func(error), si driver.St 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 { + if _, match = s.db.connIfFree(v.dc); match { cs = v break } @@ -911,11 +1018,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.ci.Prepare(s.query) + dc.Unlock() if err == driver.ErrBadConn && i < 10 { continue } @@ -923,14 +1032,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 +1050,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 @@ -956,7 +1066,7 @@ func (s *Stmt) Query(args ...interface{}) (*Rows, error) { // with releaseConn. rows := &Rows{ db: s.db, - ci: ci, + dc: dc, rowsi: rowsi, // releaseConn set below } @@ -968,20 +1078,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 +1148,7 @@ 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) } s.css = nil return nil @@ -1053,7 +1169,7 @@ func (s *Stmt) finalClose() error { // ... 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 @@ -1226,11 +1342,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 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..2a9592e10 100644 --- a/src/pkg/database/sql/sql_test.go +++ b/src/pkg/database/sql/sql_test.go @@ -5,7 +5,6 @@ package sql import ( - "database/sql/driver" "fmt" "reflect" "strings" @@ -16,10 +15,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 @@ -78,7 +77,7 @@ 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 TestQuery(t *testing.T) { @@ -576,7 +575,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 +707,86 @@ 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) + } +} 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..037c5b236 100644 --- a/src/pkg/encoding/json/decode_test.go +++ b/src/pkg/encoding/json/decode_test.go @@ -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/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("	") esc_nl = []byte("
") esc_cr = []byte("
") + 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/fmt_test.go b/src/pkg/fmt/fmt_test.go index af4b5c8f8..552f76931 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" @@ -601,6 +602,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/go/build/build.go b/src/pkg/go/build/build.go index 16c3da458..dc3669c1d 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,6 +284,17 @@ 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 @@ -397,11 +425,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 +486,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 +998,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 +1017,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 +1039,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/doc/doc.go b/src/pkg/go/doc/doc.go index 65b1b83eb..96d867cae 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 marked comments 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 token.Pos // position 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/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..7e1422d0c 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,54 @@ 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(), + 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 +516,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 +527,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 +558,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 +789,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/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/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/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/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, ©) - } - } 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..a035ef1ea --- /dev/null +++ b/src/pkg/image/gif/reader_test.go @@ -0,0 +1,135 @@ +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 the bounds too big, just by one. + testGIF[32] = 2 + want := "gif: frame bounds larger than image bounds" + try(t, testGIF, want) + + // Make the bounds too small; does not trigger bounds + // check, but now there's too much data. + testGIF[32] = 0 + want = "gif: too much image data" + try(t, testGIF, want) + testGIF[32] = 1 + + // Make the bounds really big, expect an error. + want = "gif: frame bounds larger than image bounds" + for i := 0; i < 4; i++ { + testGIF[32+i] = 0xff + } + try(t, testGIF, 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/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..fd7f005c2 100644 --- a/src/pkg/math/big/int.go +++ b/src/pkg/math/big/int.go @@ -795,8 +795,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/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_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/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/mime/multipart/multipart.go b/src/pkg/mime/multipart/multipart.go index 77e969b41..a6204d7bd 100644 --- a/src/pkg/mime/multipart/multipart.go +++ b/src/pkg/mime/multipart/multipart.go @@ -265,11 +265,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/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..da5f7e302 100644 --- a/src/pkg/net/dial.go +++ b/src/pkg/net/dial.go @@ -11,7 +11,27 @@ import ( // A DialOption modifies a DialOpt call. type DialOption interface { - dialOption() + setDialOpt(*dialOpts) +} + +var noLocalAddr Addr // nil + +// dialOpts holds all the dial options, populated by a DialOption's +// setDialOpt. +// +// All fields may be their zero value. +type dialOpts struct { + deadline time.Time + localAddr Addr + network string // if empty, "tcp" + deferredConnect bool +} + +func (o *dialOpts) net() string { + if o.network == "" { + return "tcp" + } + return o.network } var ( @@ -38,7 +58,9 @@ func Network(net string) DialOption { type dialNetwork string -func (dialNetwork) dialOption() {} +func (s dialNetwork) setDialOpt(o *dialOpts) { + o.network = string(s) +} // Deadline returns a DialOption to fail a dial that doesn't // complete before t. @@ -46,19 +68,29 @@ func Deadline(t time.Time) DialOption { return dialDeadline(t) } +type dialDeadline time.Time + +func (t dialDeadline) setDialOpt(o *dialOpts) { + o.deadline = time.Time(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)) + return dialTimeoutOpt(d) } -type dialDeadline time.Time +type dialTimeoutOpt time.Duration -func (dialDeadline) dialOption() {} +func (d dialTimeoutOpt) setDialOpt(o *dialOpts) { + o.deadline = time.Now().Add(time.Duration(d)) +} type tcpFastOpen struct{} -func (tcpFastOpen) dialOption() {} +func (tcpFastOpen) setDialOpt(o *dialOpts) { + o.deferredConnect = true +} // TODO(bradfitz): implement this (golang.org/issue/4842) and unexport this. // @@ -74,7 +106,9 @@ type localAddrOption struct { la Addr } -func (localAddrOption) dialOption() {} +func (a localAddrOption) setDialOpt(o *dialOpts) { + o.localAddr = a.la +} // LocalAddress returns a dial option to perform a dial with the // provided local address. The address must be of a compatible type @@ -135,67 +169,44 @@ 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 net 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") // +// For Unix networks, the addr must be a file system path. func Dial(net, addr string) (Conn, error) { return DialOpt(addr, dialNetwork(net)) } -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 -} - // 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) + var o dialOpts + for _, opt := range opts { + opt.setDialOpt(&o) + } + ra, err := resolveAddr("dial", o.net(), addr, o.deadline) if err != nil { return nil, err } - return dial(net, addr, la, ra, deadline) + return dial(o.net(), addr, o.localAddr, ra, o.deadline) } func dial(net, addr string, la, ra Addr, deadline time.Time) (c Conn, err error) { @@ -274,7 +285,6 @@ func dialTimeoutRace(net, addr string, timeout time.Duration) (Conn, error) { case p := <-ch: return p.Conn, p.error } - panic("unreachable") } type stringAddr struct { @@ -285,8 +295,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 +313,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_test.go b/src/pkg/net/dial_test.go index 2303e8fa4..098df738b 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. 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/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_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..2b418a868 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,255 +37,8 @@ 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) - } - } -} - -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] + pd pollDesc } func dialTimeout(net, addr string, timeout time.Duration) (Conn, error) { @@ -307,9 +57,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 } @@ -331,25 +81,28 @@ func (fd *netFD) name() string { } 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 + 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() @@ -371,6 +124,9 @@ func (fd *netFD) decref() { fd.sysmu.Lock() fd.sysref-- if fd.closing && fd.sysref == 0 && fd.sysfile != nil { + // Poller may want to unregister fd in readiness notification mechanism, + // so this must be executed before sysfile.Close(). + fd.pd.Close() fd.sysfile.Close() fd.sysfile = nil fd.sysfd = -1 @@ -379,21 +135,21 @@ func (fd *netFD) decref() { } 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 +181,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 +210,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 +239,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 +275,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 +288,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 +314,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 +341,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 +363,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 +372,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/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..d7d2c1879 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} @@ -182,7 +181,7 @@ func TestPostFormRequestFormat(t *testing.T) { } func TestRedirects(t *testing.T) { - defer checkLeakedTransports(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/example_test.go b/src/pkg/net/http/example_test.go index 22073eaf7..eed3beeea 100644 --- a/src/pkg/net/http/example_test.go +++ b/src/pkg/net/http/example_test.go @@ -54,3 +54,8 @@ func ExampleFileServer() { // we use StripPrefix so that /tmpfiles/somefile will access /tmp/somefile http.Handle("/tmpfiles/", http.StripPrefix("/tmpfiles/", http.FileServer(http.Dir("/tmp")))) } + +func ExampleStripPrefix() { + // we use StripPrefix so that /tmpfiles/somefile will access /tmp/somefile + 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/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..dabb169d1 100644 --- a/src/pkg/net/http/request.go +++ b/src/pkg/net/http/request.go @@ -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: 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..49836ce2c 100644 --- a/src/pkg/net/http/response_test.go +++ b/src/pkg/net/http/response_test.go @@ -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..5adde545f 100644 --- a/src/pkg/net/http/serve_test.go +++ b/src/pkg/net/http/serve_test.go @@ -184,7 +184,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 +257,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 +333,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 +392,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 +468,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 +539,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 +560,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 +591,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 +621,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 +656,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 +676,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 +759,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 +897,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 +972,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 +1023,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 +1089,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 +1105,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 +1132,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 +1176,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 +1213,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 +1268,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 +1311,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) @@ -1620,3 +1620,34 @@ 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{ + closec: make(chan bool), + } + 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 + } +} diff --git a/src/pkg/net/http/server.go b/src/pkg/net/http/server.go index b6ab78228..aee3229d3 100644 --- a/src/pkg/net/http/server.go +++ b/src/pkg/net/http/server.go @@ -109,9 +109,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 @@ -180,12 +182,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() @@ -362,14 +378,87 @@ 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 := newBufioWriter(c.rwc) 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) + bufioWriterCache = make(chan bufioWriterPair, 4) +) + +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 newBufioWriter(w io.Writer) (*bufio.Writer, *switchWriter) { + select { + case p := <-bufioWriterCache: + p.sw.Writer = w + return p.bw, p.sw + default: + sw := &switchWriter{w} + return bufio.NewWriter(sw), 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 <- 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. @@ -655,7 +744,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 @@ -742,6 +831,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 +1046,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) }) } @@ -1337,7 +1438,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/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/transport.go b/src/pkg/net/http/transport.go index 685d7d56c..08ced2c3d 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 @@ -68,7 +64,18 @@ type Transport struct { // 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,13 +683,6 @@ 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) @@ -636,7 +701,7 @@ 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} @@ -648,8 +713,14 @@ func (pc *persistConn) readLoop() { 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 +737,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 +930,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 +972,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 +992,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..4bb711b17 100644 --- a/src/pkg/net/http/transport_test.go +++ b/src/pkg/net/http/transport_test.go @@ -102,7 +102,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 +135,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 +186,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 +237,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 +270,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 +339,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 +396,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 +452,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 +481,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 +523,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 +580,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 +673,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 +702,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 +729,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 +795,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 +834,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 +864,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 +892,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 +917,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,15 +940,18 @@ 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{} + defer tr.CloseIdleConnections() c := &Client{Transport: tr} reqs := make(chan string) defer close(reqs) @@ -973,8 +976,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 +988,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 +1049,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 +1117,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 +1164,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 +1217,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 +1294,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 +1313,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 +1327,64 @@ 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 +} + 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..a80fb01d0 100644 --- a/src/pkg/net/http/z_last_test.go +++ b/src/pkg/net/http/z_last_test.go @@ -7,27 +7,60 @@ 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(") { + 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 @@ -40,6 +73,7 @@ func checkLeakedTransports(t *testing.T) { ").writeLoop(": "a Transport", "created by net/http/httptest.(*Server).Start": "an httptest.Server", "timeoutHandler": "a TimeoutHandler", + "net.(*netFD).connect(": "a timing out dial", } for i := 0; i < 4; i++ { bad = "" @@ -56,5 +90,6 @@ func checkLeakedTransports(t *testing.T) { // shutting down, so give it some time. time.Sleep(250 * time.Millisecond) } - t.Errorf("Test appears to have leaked %s:\n%s", bad, stacks) + gs := interestingGoroutines() + t.Errorf("Test appears to have leaked %s:\n%s", bad, strings.Join(gs, "\n\n")) } 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/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..841b57ab4 100644 --- a/src/pkg/net/ipraw_test.go +++ b/src/pkg/net/ipraw_test.go @@ -2,13 +2,12 @@ // 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" @@ -29,6 +28,11 @@ var resolveIPAddrTests = []struct { {"ip6", "::1", &IPAddr{IP: ParseIP("::1")}, nil}, {"ip6: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}, + {"ip6", "fe80::1", &IPAddr{IP: ParseIP("fe80::1"), Zone: "name"}, nil}, + {"ip6", "fe80::1", &IPAddr{IP: ParseIP("fe80::1"), Zone: "index"}, 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 @@ -39,6 +43,21 @@ var resolveIPAddrTests = []struct { func TestResolveIPAddr(t *testing.T) { for _, tt := range resolveIPAddrTests { + if tt.addr != nil && (tt.addr.Zone == "name" || tt.addr.Zone == "index") { + ifi := loopbackInterface() + if ifi == nil { + continue + } + switch tt.addr.Zone { + case "name": + tt.litAddr += "%" + ifi.Name + tt.addr.Zone = zoneToString(ifi.Index) + case "index": + index := fmt.Sprintf("%v", ifi.Index) + tt.litAddr += "%" + index + tt.addr.Zone = index + } + } addr, err := ResolveIPAddr(tt.net, tt.litAddr) if err != tt.err { t.Fatalf("ResolveIPAddr(%v, %v) failed: %v", tt.net, tt.litAddr, err) @@ -339,3 +358,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..9d99e7591 100644 --- a/src/pkg/net/iprawsock.go +++ b/src/pkg/net/iprawsock.go @@ -19,12 +19,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..43a5eab41 100644 --- a/src/pkg/net/iprawsock_plan9.go +++ b/src/pkg/net/iprawsock_plan9.go @@ -34,7 +34,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) { diff --git a/src/pkg/net/iprawsock_posix.go b/src/pkg/net/iprawsock_posix.go index 2ef4db19c..1bcaef9f2 100644 --- a/src/pkg/net/iprawsock_posix.go +++ b/src/pkg/net/iprawsock_posix.go @@ -98,7 +98,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) { 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..1eb6a420d --- /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", "windows": + 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..c101ffecd 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}, } 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..2ebde8799 100644 --- a/src/pkg/net/sock_posix.go +++ b/src/pkg/net/sock_posix.go @@ -49,13 +49,17 @@ func socket(net string, f, t, p int, ipv6only bool, ulsa, ursa syscall.Sockaddr, } if ursa != nil { - fd.wdeadline.setTime(deadline) + if !deadline.IsZero() { + setWriteDeadline(fd, deadline) + } if err = fd.connect(ursa); err != nil { closesocket(s) return nil, err } fd.isConnected = true - fd.wdeadline.set(0) + if !deadline.IsZero() { + setWriteDeadline(fd, time.Time{}) + } } lsa, _ := syscall.Getsockname(s) @@ -63,5 +67,8 @@ func socket(net string, f, t, p int, ipv6only bool, ulsa, ursa syscall.Sockaddr, rsa, _ := syscall.Getpeername(s) raddr := toAddr(rsa) fd.setAddr(laddr, raddr) + if fd.raddr == nil { + fd.raddr = toAddr(ursa) + } 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..add8e4823 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" @@ -158,6 +159,11 @@ var resolveTCPAddrTests = []struct { {"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}, + {"tcp6", "[fe80::1]:3", &TCPAddr{IP: ParseIP("fe80::1"), Port: 3, Zone: "name"}, nil}, + {"tcp6", "[fe80::1]:4", &TCPAddr{IP: ParseIP("fe80::1"), Port: 4, Zone: "index"}, 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 @@ -166,6 +172,24 @@ var resolveTCPAddrTests = []struct { func TestResolveTCPAddr(t *testing.T) { for _, tt := range resolveTCPAddrTests { + if tt.addr != nil && (tt.addr.Zone == "name" || tt.addr.Zone == "index") { + ifi := loopbackInterface() + if ifi == nil { + continue + } + i := last(tt.litAddr, ']') + if i > 0 { + switch tt.addr.Zone { + case "name": + tt.litAddr = tt.litAddr[:i] + "%" + ifi.Name + tt.litAddr[i:] + tt.addr.Zone = zoneToString(ifi.Index) + case "index": + index := fmt.Sprintf("%v", ifi.Index) + tt.litAddr = tt.litAddr[:i] + "%" + index + tt.litAddr[i:] + tt.addr.Zone = index + } + } + } addr, err := ResolveTCPAddr(tt.net, tt.litAddr) if err != tt.err { t.Fatalf("ResolveTCPAddr(%v, %v) failed: %v", tt.net, tt.litAddr, err) @@ -204,3 +228,79 @@ func TestTCPListenerName(t *testing.T) { } } } + +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..27db11568 100644 --- a/src/pkg/net/tcpsock.go +++ b/src/pkg/net/tcpsock.go @@ -20,14 +20,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/textproto/reader.go b/src/pkg/net/textproto/reader.go index b61bea862..35e27acb5 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 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..b3cafb096 100644 --- a/src/pkg/net/udp_test.go +++ b/src/pkg/net/udp_test.go @@ -5,6 +5,7 @@ package net import ( + "fmt" "reflect" "runtime" "testing" @@ -22,6 +23,11 @@ var resolveUDPAddrTests = []struct { {"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}, + {"udp6", "[fe80::1]:3", &UDPAddr{IP: ParseIP("fe80::1"), Port: 3, Zone: "name"}, nil}, + {"udp6", "[fe80::1]:4", &UDPAddr{IP: ParseIP("fe80::1"), Port: 4, Zone: "index"}, 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 @@ -30,6 +36,24 @@ var resolveUDPAddrTests = []struct { func TestResolveUDPAddr(t *testing.T) { for _, tt := range resolveUDPAddrTests { + if tt.addr != nil && (tt.addr.Zone == "name" || tt.addr.Zone == "index") { + ifi := loopbackInterface() + if ifi == nil { + continue + } + i := last(tt.litAddr, ']') + if i > 0 { + switch tt.addr.Zone { + case "name": + tt.litAddr = tt.litAddr[:i] + "%" + ifi.Name + tt.litAddr[i:] + tt.addr.Zone = zoneToString(ifi.Index) + case "index": + index := fmt.Sprintf("%v", ifi.Index) + tt.litAddr = tt.litAddr[:i] + "%" + index + tt.litAddr[i:] + tt.addr.Zone = index + } + } + } addr, err := ResolveUDPAddr(tt.net, tt.litAddr) if err != tt.err { t.Fatalf("ResolveUDPAddr(%v, %v) failed: %v", tt.net, tt.litAddr, err) @@ -146,3 +170,78 @@ func TestUDPConnLocalName(t *testing.T) { } } } + +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..277050606 100644 --- a/src/pkg/net/udpsock.go +++ b/src/pkg/net/udpsock.go @@ -24,14 +24,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..66dcbab7c 100644 --- a/src/pkg/net/udpsock_plan9.go +++ b/src/pkg/net/udpsock_plan9.go @@ -58,7 +58,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. diff --git a/src/pkg/net/udpsock_posix.go b/src/pkg/net/udpsock_posix.go index 385cd902e..9aafb7083 100644 --- a/src/pkg/net/udpsock_posix.go +++ b/src/pkg/net/udpsock_posix.go @@ -89,7 +89,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. diff --git a/src/pkg/net/unixsock.go b/src/pkg/net/unixsock.go index ae0956958..977ff9103 100644 --- a/src/pkg/net/unixsock.go +++ b/src/pkg/net/unixsock.go @@ -12,7 +12,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 +37,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_posix.go b/src/pkg/net/unixsock_posix.go index 6d6ce3f5e..8d57dacbd 100644 --- a/src/pkg/net/unixsock_posix.go +++ b/src/pkg/net/unixsock_posix.go @@ -99,7 +99,6 @@ func sotypeToNet(sotype int) string { default: panic("sotypeToNet unknown socket type") } - return "" } // UnixConn is an implementation of the Conn interface for connections diff --git a/src/pkg/net/url/url.go b/src/pkg/net/url/url.go index a39964ea1..c1864036c 100644 --- a/src/pkg/net/url/url.go +++ b/src/pkg/net/url/url.go @@ -362,7 +362,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 } @@ -583,43 +583,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 +635,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..dfcf4be23 100644 --- a/src/pkg/os/exec/exec_test.go +++ b/src/pkg/os/exec/exec_test.go @@ -151,6 +151,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 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..9a4dd6c31 100644 --- a/src/pkg/reflect/all_test.go +++ b/src/pkg/reflect/all_test.go @@ -13,6 +13,7 @@ import ( "math/rand" "os" . "reflect" + "runtime" "sync" "testing" "time" @@ -1457,7 +1458,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 +1474,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 +1499,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 +1574,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 +1584,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,18 +1611,201 @@ 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) { @@ -2011,6 +2262,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) 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..5ec94f576 100644 --- a/src/pkg/reflect/type.go +++ b/src/pkg/reflect/type.go @@ -1246,7 +1246,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. diff --git a/src/pkg/reflect/value.go b/src/pkg/reflect/value.go index c87812c46..5a3720489 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 @@ -2030,7 +2094,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 +2128,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..6f6908a74 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 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..2dc821256 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; @@ -467,6 +473,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..bb65d3faf 100644 --- a/src/pkg/runtime/arch_arm.h +++ b/src/pkg/runtime/arch_arm.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 = '5', BigEndian = 0, diff --git a/src/pkg/runtime/asm_386.s b/src/pkg/runtime/asm_386.s index 96f04e0ae..6bcacf4cc 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,25 @@ 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 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 +82,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 @@ -706,7 +717,261 @@ 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 + diff --git a/src/pkg/runtime/asm_amd64.s b/src/pkg/runtime/asm_amd64.s index 987958498..f4cfa576e 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,6 +20,17 @@ 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 @@ -65,6 +76,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 +454,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: @@ -719,7 +737,165 @@ 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 diff --git a/src/pkg/runtime/asm_arm.s b/src/pkg/runtime/asm_arm.s index 45b53541b..6b2d6afda 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 @@ -489,3 +490,17 @@ TEXT runtime·stackguard(SB),7,$0 MOVW R1, sp+0(FP) MOVW R2, limit+4(FP) RET + +// 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 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..9193d599d 100644 --- a/src/pkg/runtime/atomic_arm.c +++ b/src/pkg/runtime/atomic_arm.c @@ -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..19f6115a6 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 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_openbsd_386.c b/src/pkg/runtime/cgo/gcc_openbsd_386.c index 86c1365ad..80be31b9c 100644 --- a/src/pkg/runtime/cgo/gcc_openbsd_386.c +++ b/src/pkg/runtime/cgo/gcc_openbsd_386.c @@ -48,9 +48,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 * diff --git a/src/pkg/runtime/cgo/gcc_openbsd_amd64.c b/src/pkg/runtime/cgo/gcc_openbsd_amd64.c index d3a5e36b0..e9cc8184b 100644 --- a/src/pkg/runtime/cgo/gcc_openbsd_amd64.c +++ b/src/pkg/runtime/cgo/gcc_openbsd_amd64.c @@ -48,9 +48,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 * diff --git a/src/pkg/runtime/cgocall.c b/src/pkg/runtime/cgocall.c index 590bf9b67..0c9618749 100644 --- a/src/pkg/runtime/cgocall.c +++ b/src/pkg/runtime/cgocall.c @@ -95,7 +95,8 @@ static void unwindm(void); // Call from Go to C. -static FuncVal unlockOSThread = { runtime·unlockOSThread }; +static void endcgo(void); +static FuncVal endcgoV = { endcgo }; void runtime·cgocall(void (*fn)(void*), void *arg) @@ -123,7 +124,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 @@ -148,6 +149,16 @@ runtime·cgocall(void (*fn)(void*), void *arg) 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 +167,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 +286,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/crash_test.go b/src/pkg/runtime/crash_test.go index 5f84cb5a2..80549a505 100644 --- a/src/pkg/runtime/crash_test.go +++ b/src/pkg/runtime/crash_test.go @@ -91,6 +91,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 +183,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/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_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..3475339bf 100644 --- a/src/pkg/runtime/gc_test.go +++ b/src/pkg/runtime/gc_test.go @@ -7,6 +7,7 @@ package runtime_test import ( "os" "runtime" + "runtime/debug" "testing" ) @@ -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..0f92becab 100644 --- a/src/pkg/runtime/hashmap.c +++ b/src/pkg/runtime/hashmap.c @@ -9,703 +9,831 @@ #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) + uint8 B; // log_2 of # of buckets (can hold up to LOAD * 2^B items) + uint8 flags; + 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 + 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 +}; +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; - } else { - *init_power = 12; + 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. + 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) { + 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) { + 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. + new_buckets = runtime·mallocgc(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; + Bucket *b; + uint8 top; + uintptr i; bool eq; + byte *k, *k2, *v; + key = *keyp; + 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; - } - 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); - } - 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); + 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) { + 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 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 QUICKEQ(x) true +#include "hashmap_fast.c" + +#undef HASH_LOOKUP1 +#undef HASH_LOOKUP2 +#undef KEYTYPE +#undef HASHFUNC +#undef EQFUNC +#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 QUICKEQ(x) true +#include "hashmap_fast.c" + +#undef HASH_LOOKUP1 +#undef HASH_LOOKUP2 +#undef KEYTYPE +#undef HASHFUNC +#undef EQFUNC +#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·mcmp((x).str, (y).str, (x).len) == 0)) +#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); + 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; - } - 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); + if(b->overflow == nil) + break; + b = b->overflow; } - 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); + + // 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 } - USED(e_hash); - return (0); -} -static int32 -hash_insert_internal (MapType *t, struct hash_subtable **pst, int32 flags, hash_hash_t hash, - Hmap *h, void *data, void **pres) -{ - int32 elemsize = h->datasize + offsetof (struct hash_entry, data[0]); - bool eq; + if(inserti == nil) { + // all current buckets are full, allocate a new one. + newb = runtime·mallocgc(h->bucketsize, 0, 1, 0); + clearbucket(newb); + b->overflow = newb; + inserti = newb->tophash; + insertk = newb->data; + insertv = insertk + h->keysize * BUCKETSIZE; + } - if ((flags & HASH_REHASH) == 0) { - hash += HASH_ADJUST (hash); - hash &= ~HASH_MASK; + // store new key/value at insert position + if((h->flags & IndirectKey) != 0) { + kmem = runtime·mallocgc(t->key->size, 0, 1, 0); + *(byte**)insertk = kmem; + insertk = kmem; } - 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; - } - } - /* 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 (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); - } - } - 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); - } + if((h->flags & IndirectValue) != 0) { + vmem = runtime·mallocgc(t->elem->size, 0, 1, 0); + *(byte**)insertv = vmem; + insertv = vmem; } + 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 (MapType *t, Hmap *h, void *data, void **pres) +static void +hash_remove(MapType *t, Hmap *h, void *key) { uintptr hash; - int32 rc; - + uintptr bucket; + Bucket *b; + uint8 top; + uintptr i; + byte *k, *v; + bool eq; + + if(docheck) + check(t, h); hash = h->hash0; - (*t->key->alg->hash) (&hash, t->key->size, data); - rc = hash_insert_internal (t, &h->st, 0, hash, h, data, pres); + 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; + } + if((h->flags & IndirectValue) != 0) { + v = *(byte**)v; + } - h->count += (rc == 0); /* increment count if element didn't previously exist */ - return (rc); + 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; + } + b = b->overflow; + } while(b != nil); } -static uint32 -hash_count (Hmap *h) -{ - return (h->count); -} +// TODO: shrink the map, the same way we grow it. -static void -iter_restart (struct hash_iter *it, struct hash_subtable *st, int32 used) +// If you modify hash_iter, also change cmd/gc/range.c to indicate +// the size of this structure. +struct hash_iter { - 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) { - 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); - } - sub->e = e; -} + uint8* key; // Must be in first position. Write nil to indicate iteration end (see cmd/gc/range.c). + uint8* value; -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); - } - } + MapType *t; + Hmap *h; - for (;;) { - while (e <= last && (e_hash = e->hash) == HASH_NIL) { - e = HASH_OFFSET (e, elemsize); - } - 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); - } else { - it->i--; - sub = &it->subtable_state[it->i]; - e = sub->e; - last = sub->last; - } - } 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; - } - } -} + // end point for iteration + uintptr endbucket; + bool wrapped; + // state of table at time iterator is initialized + uint8 B; + byte *buckets; + + // iter state + uintptr bucket; + struct Bucket *bptr; + uintptr i; +}; + +// 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 -hash_iter_init (MapType *t, Hmap *h, struct hash_iter *it) +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); -} + it->h = h; -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); - } - e = HASH_OFFSET (e, elemsize); - } - if (h->flag & CanFreeTable) - free (st); - *slots += lslots; - *used += lused; -} + // grab snapshot of bucket state + it->B = h->B; + it->buckets = h->buckets; -static void -hash_destroy (Hmap *h) -{ - int32 slots = 0; - int32 used = 0; + // iterator state + it->bucket = it->endbucket = runtime·fastrand1() & (((uintptr)1 << h->B) - 1); + it->wrapped = false; + it->bptr = nil; - clean_st (h, h->st, &slots, &used); - free (h); + // Remember we have an iterator at this level. + h->flags |= Iterator; } +// 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_visit_internal (struct hash_subtable *st, - int32 used, int32 level, - void (*data_visit) (void *arg, int32 level, void *data), - void *arg) +hash_next(struct hash_iter *it) { - 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); + Hmap *h; + MapType *t; + uintptr bucket; + Bucket *b; + uintptr i; + bool eq; + byte *k, *v; + byte *rk, *rv; + + h = it->h; + t = it->t; + bucket = it->bucket; + b = it->bptr; + i = it->i; + +next: + if(b == nil) { + if(bucket == it->endbucket && it->wrapped) { + // end of iteration + it->key = nil; + it->value = nil; + return; + } + if(h->oldbuckets != nil && it->B == h->B) { + // Iterator was started in the middle of a grow, and the grow isn't done yet. + // Make sure the bucket we're about to read is valid. + grow_work(t, h, bucket); } - if (e->hash != HASH_NIL) { - assert (i < index + st->max_probes); - assert (index <= i); + b = (Bucket*)(it->buckets + bucket * h->bucketsize); + bucket++; + if(bucket == ((uintptr)1 << it->B)) { + bucket = 0; + it->wrapped = true; + } + i = 0; + } + 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(!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; + 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). @@ -713,73 +841,141 @@ bool hash_gciter_init (Hmap *h, struct hash_gciter *it) { // GC during map initialization - if(h->st == nil) + 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; + } + } + 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; } - 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); + 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 +983,13 @@ 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) -{ - if(h->flag & IndirectKey) - p = *(void**)p; - return p; -} - -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 +998,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 +1006,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 +1043,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 +1052,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 +1069,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 +1077,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 +1091,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 +1117,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 +1156,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 +1164,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 +1175,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 +1252,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 +1275,18 @@ runtime·mapiterinit(MapType *t, Hmap *h, struct hash_iter *it) void reflect·mapiterinit(MapType *t, Hmap *h, struct hash_iter *it) { - uint8 flag; + uint8 flags; 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; + // eagerly anymore. + flags = h->flags; + if(flags & IndirectKey) + flags &= ~CanFreeKey; else - flag &= ~CanFreeTable; - h->flag = flag; + flags &= ~CanFreeBucket; + h->flags = flags; } it = runtime·mal(sizeof *it); @@ -1165,12 +1303,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 +1326,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 +1353,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 +1373,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 +1411,6 @@ reflect·maplen(Hmap *h, intgo len) void runtime·mapiter2(struct hash_iter *it, ...) { - Hmap *h; byte *ak, *av, *res; MapType *t; @@ -1284,19 +1418,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..2169f4c30 --- /dev/null +++ b/src/pkg/runtime/hashmap_fast.c @@ -0,0 +1,149 @@ +// 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; + Bucket *b; + uint8 top; + uintptr i; + KEYTYPE *k; + byte *v; + + 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 && (h->count == 1 || QUICKEQ(key))) { + // One-bucket table. Don't hash, just check each bucket entry. + 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 && EQFUNC(key, *k)) { + value = v; + FLUSH(&value); + return; + } + } + } else { + hash = h->hash0; + HASHFUNC(&hash, sizeof(KEYTYPE), &key); + bucket = hash & (((uintptr)1 << h->B) - 1); + if(h->oldbuckets != nil) + grow_work(t, h, bucket); + b = (Bucket*)(h->buckets + bucket * (offsetof(Bucket, data[0]) + BUCKETSIZE * sizeof(KEYTYPE) + BUCKETSIZE * h->valuesize)); + 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; + Bucket *b; + uint8 top; + uintptr i; + KEYTYPE *k; + byte *v; + + 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 && (h->count == 1 || QUICKEQ(key))) { + // One-bucket table. Don't hash, just check each bucket entry. + 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 && EQFUNC(key, *k)) { + value = v; + res = true; + FLUSH(&value); + FLUSH(&res); + return; + } + } + } else { + hash = h->hash0; + HASHFUNC(&hash, sizeof(KEYTYPE), &key); + bucket = hash & (((uintptr)1 << h->B) - 1); + if(h->oldbuckets != nil) + grow_work(t, h, bucket); + b = (Bucket*)(h->buckets + bucket * (offsetof(Bucket, data[0]) + BUCKETSIZE * sizeof(KEYTYPE) + BUCKETSIZE * h->valuesize)); + 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/malloc.goc b/src/pkg/runtime/malloc.goc index ac131b3af..fa28e2b73 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"); @@ -516,7 +516,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 +554,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/map_test.go b/src/pkg/runtime/map_test.go new file mode 100644 index 000000000..29e19db2c --- /dev/null +++ b/src/pkg/runtime/map_test.go @@ -0,0 +1,282 @@ +// 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" + "runtime" + "sort" + "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 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") + } +} diff --git a/src/pkg/runtime/mapspeed_test.go b/src/pkg/runtime/mapspeed_test.go new file mode 100644 index 000000000..a37974060 --- /dev/null +++ b/src/pkg/runtime/mapspeed_test.go @@ -0,0 +1,150 @@ +// 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 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 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] + } +} 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..aa499f476 100644 --- a/src/pkg/runtime/mgc0.c +++ b/src/pkg/runtime/mgc0.c @@ -140,6 +140,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 +192,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 +255,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 +283,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 +304,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 +311,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 +325,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 +358,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 +435,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 +460,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) { @@ -575,20 +568,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 +598,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 +617,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; @@ -703,7 +683,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 +692,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: @@ -759,17 +740,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 +778,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 +792,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 +805,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 +819,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 +886,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 +912,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 +960,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 +999,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 +1012,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 +1021,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 +1047,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. @@ -1339,7 +1356,7 @@ addstackroots(G *gp) 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, 0}); + addroot((Obj){sp, (byte*)stk - sp, (uintptr)defaultProg | PRECISE | LOOP}); sp = (byte*)stk->gobuf.sp; guard = stk->stackguard; stk = (Stktop*)stk->stackbase; @@ -1381,14 +1398,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; } } @@ -1655,6 +1675,8 @@ runtime·memorydump(void) void runtime·gchelper(void) { + gchelperstart(); + // parallel mark for over gc roots runtime·parfordo(work.markfor); @@ -1668,6 +1690,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 +1780,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 +1882,7 @@ gc(struct gc_args *args) t1 = runtime·nanotime(); + gchelperstart(); runtime·parfordo(work.markfor); scanblock(nil, nil, 0, true); @@ -1868,6 +1894,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 +2036,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..18f3654b4 100644 --- a/src/pkg/runtime/mgc0.h +++ b/src/pkg/runtime/mgc0.h @@ -24,6 +24,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..177f40659 100644 --- a/src/pkg/runtime/mheap.c +++ b/src/pkg/runtime/mheap.c @@ -409,6 +409,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/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..d6ef0d144 --- /dev/null +++ b/src/pkg/runtime/netpoll_epoll.c @@ -0,0 +1,92 @@ +// 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) +{ + 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) + runtime·printf("epollwait failed with %d\n", -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..ad721e293 --- /dev/null +++ b/src/pkg/runtime/netpoll_kqueue.c @@ -0,0 +1,105 @@ +// 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) +{ + 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) + runtime·printf("kqueue failed with %d\n", -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..6216e3a3c 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,6 +70,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(); @@ -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) @@ -530,3 +552,41 @@ runtime·badsignal(int32 sig) 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..68c0f4750 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,11 +46,16 @@ 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; } @@ -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(); @@ -241,3 +264,58 @@ runtime·badsignal(int32 sig) 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..e4ae1a5d8 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: @@ -290,3 +312,60 @@ runtime·badsignal(int32 sig) 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..936334cac 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(); @@ -286,3 +304,58 @@ runtime·badsignal(int32 sig) 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..4ce64f9f2 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(); @@ -263,3 +286,55 @@ runtime·badsignal(int32 sig) 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..8d05730e4 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); @@ -782,8 +794,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; } @@ -970,7 +982,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 +1007,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 +1068,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 @@ -1164,6 +1227,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 +1319,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 +1351,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; @@ -1885,7 +1953,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 +1973,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 +1999,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/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..26cd3a4e4 100644 --- a/src/pkg/runtime/race/testdata/mop_test.go +++ b/src/pkg/runtime/race/testdata/mop_test.go @@ -306,6 +306,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 int + ch := make(chan int, 2) + + go func() { + x = y / 3 + 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 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..1fe051b12 100644 --- a/src/pkg/runtime/race/testdata/slice_test.go +++ b/src/pkg/runtime/race/testdata/slice_test.go @@ -463,3 +463,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/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.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..46c77e3fd 100644 --- a/src/pkg/runtime/runtime.h +++ b/src/pkg/runtime/runtime.h @@ -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. @@ -235,8 +236,9 @@ 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 + int8 raceignore; // ignore race detection events M* m; // for debuggers, but offset not hard-coded M* lockedm; int32 sig; @@ -320,6 +322,7 @@ struct M #endif #ifdef GOOS_plan9 int8* notesig; + byte* errstr; #endif SEH* seh; uintptr end[]; @@ -381,6 +384,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 +487,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; @@ -555,11 +561,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*); @@ -578,7 +598,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 +654,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 +687,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 +698,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 +716,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); @@ -761,6 +787,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 +963,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/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..0ba66ab9f --- /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)(info)->si_addr) 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_test.go b/src/pkg/runtime/string_test.go index 8f13f0f42..6ba3c1d29 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 ( 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/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/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/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..3cd7835cc 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" @@ -43,6 +44,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/atomic_test.go b/src/pkg/sync/atomic/atomic_test.go index 3e105561c..72f303040 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 386 they crash + // instead of failing silently. + if runtime.GOARCH != "386" { + t.Skip("test only runs on 386") + } + + 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/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..bc644d97a 100644 --- a/src/pkg/syscall/exec_bsd.go +++ b/src/pkg/syscall/exec_bsd.go @@ -215,11 +215,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/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..a0e590950 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 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/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/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/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/text/template/exec.go b/src/pkg/text/template/exec.go index b9c03d8f0..12c40b70f 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 diff --git a/src/pkg/text/template/exec_test.go b/src/pkg/text/template/exec_test.go index 683e9ac76..0f8beec5e 100644 --- a/src/pkg/text/template/exec_test.go +++ b/src/pkg/text/template/exec_test.go @@ -816,3 +816,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/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/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) } } } |