From 2f9c9e552d7cdcbf6aecbd4aee900cce39bcd2d9 Mon Sep 17 00:00:00 2001 From: David Crawshaw Date: Fri, 20 Feb 2015 11:05:36 -0500 Subject: cmd/go: link cgo into tests on darwin/arm We currently have only one supported darwin/arm device, a locked iOS machine. It requires cgo binaries. Change-Id: If36a152e6a743e4a58ea3470e62cccb742630a5d Reviewed-on: https://go-review.googlesource.com/5443 Reviewed-by: Russ Cox --- src/cmd/go/test.go | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/cmd/go/test.go b/src/cmd/go/test.go index a8110f385d..c44a2199dc 100644 --- a/src/cmd/go/test.go +++ b/src/cmd/go/test.go @@ -772,6 +772,10 @@ func (b *builder) test(p *Package) (buildAction, runAction, printAction *action, recompileForTest(pmain, p, ptest, testDir) } + if buildContext.GOOS == "darwin" && buildContext.GOARCH == "arm" { + t.NeedCgo = true + } + for _, cp := range pmain.imports { if len(cp.coverVars) > 0 { t.Cover = append(t.Cover, coverInfo{cp, cp.coverVars}) @@ -1207,6 +1211,7 @@ type testFuncs struct { NeedTest bool ImportXtest bool NeedXtest bool + NeedCgo bool Cover []coverInfo } @@ -1310,6 +1315,10 @@ import ( {{range $i, $p := .Cover}} _cover{{$i}} {{$p.Package.ImportPath | printf "%q"}} {{end}} + +{{if .NeedCgo}} + _ "runtime/cgo" +{{end}} ) var tests = []testing.InternalTest{ -- cgit v1.2.3-54-g00ecf From 828129fdbc2d95ab8d8dfa637e0f7251924c8b8b Mon Sep 17 00:00:00 2001 From: Alexandre Cesaro Date: Tue, 23 Dec 2014 20:29:13 +0100 Subject: net/mail: move RFC 2047 code to internal/mime The code concerning quoted-printable encoding (RFC 2045) and its variant for MIME headers (RFC 2047) is currently spread in mime/multipart and net/mail. It is also not exported. This commit is the second step to fix that issue. It moves the RFC 2047 encoding and decoding functions from net/mail to internal/mime. The exported API is unchanged. Updates #4943 Change-Id: I5f58aa58e74bbe4ec91b2e9b8c81921338053b00 Reviewed-on: https://go-review.googlesource.com/2101 Reviewed-by: Brad Fitzpatrick --- src/go/build/deps_test.go | 2 +- src/internal/mime/header.go | 122 ++++++++++++++++++++++++++++++++++++++++++++ src/net/mail/message.go | 103 ++----------------------------------- 3 files changed, 126 insertions(+), 101 deletions(-) create mode 100644 src/internal/mime/header.go diff --git a/src/go/build/deps_test.go b/src/go/build/deps_test.go index 98201a5d96..d186a17e0e 100644 --- a/src/go/build/deps_test.go +++ b/src/go/build/deps_test.go @@ -252,7 +252,7 @@ var pkgDeps = map[string][]string{ // Uses of networking. "log/syslog": {"L4", "OS", "net"}, - "net/mail": {"L4", "NET", "OS"}, + "net/mail": {"L4", "NET", "OS", "internal/mime"}, "net/textproto": {"L4", "OS", "net"}, // Core crypto. diff --git a/src/internal/mime/header.go b/src/internal/mime/header.go new file mode 100644 index 0000000000..9bc3e5e576 --- /dev/null +++ b/src/internal/mime/header.go @@ -0,0 +1,122 @@ +// Copyright 2015 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package mime + +import ( + "bytes" + "encoding/base64" + "errors" + "fmt" + "io" + "io/ioutil" + "strconv" + "strings" + "unicode" +) + +// EncodeWord encodes a string into an RFC 2047 encoded-word. +func EncodeWord(s string) string { + // UTF-8 "Q" encoding + b := bytes.NewBufferString("=?utf-8?q?") + for i := 0; i < len(s); i++ { + switch c := s[i]; { + case c == ' ': + b.WriteByte('_') + case isVchar(c) && c != '=' && c != '?' && c != '_': + b.WriteByte(c) + default: + fmt.Fprintf(b, "=%02X", c) + } + } + b.WriteString("?=") + return b.String() +} + +// DecodeWord decodes an RFC 2047 encoded-word. +func DecodeWord(s string) (string, error) { + fields := strings.Split(s, "?") + if len(fields) != 5 || fields[0] != "=" || fields[4] != "=" { + return "", errors.New("address not RFC 2047 encoded") + } + charset, enc := strings.ToLower(fields[1]), strings.ToLower(fields[2]) + if charset != "us-ascii" && charset != "iso-8859-1" && charset != "utf-8" { + return "", fmt.Errorf("charset not supported: %q", charset) + } + + in := bytes.NewBufferString(fields[3]) + var r io.Reader + switch enc { + case "b": + r = base64.NewDecoder(base64.StdEncoding, in) + case "q": + r = qDecoder{r: in} + default: + return "", fmt.Errorf("RFC 2047 encoding not supported: %q", enc) + } + + dec, err := ioutil.ReadAll(r) + if err != nil { + return "", err + } + + switch charset { + case "us-ascii": + b := new(bytes.Buffer) + for _, c := range dec { + if c >= 0x80 { + b.WriteRune(unicode.ReplacementChar) + } else { + b.WriteRune(rune(c)) + } + } + return b.String(), nil + case "iso-8859-1": + b := new(bytes.Buffer) + for _, c := range dec { + b.WriteRune(rune(c)) + } + return b.String(), nil + case "utf-8": + return string(dec), nil + } + panic("unreachable") +} + +type qDecoder struct { + r io.Reader + scratch [2]byte +} + +func (qd qDecoder) Read(p []byte) (n int, err error) { + // This method writes at most one byte into p. + if len(p) == 0 { + return 0, nil + } + if _, err := qd.r.Read(qd.scratch[:1]); err != nil { + return 0, err + } + switch c := qd.scratch[0]; { + case c == '=': + if _, err := io.ReadFull(qd.r, qd.scratch[:2]); err != nil { + return 0, err + } + x, err := strconv.ParseInt(string(qd.scratch[:2]), 16, 64) + if err != nil { + return 0, fmt.Errorf("mime: invalid RFC 2047 encoding: %q", qd.scratch[:2]) + } + p[0] = byte(x) + case c == '_': + p[0] = ' ' + default: + p[0] = c + } + return 1, nil +} + +// isVchar returns true if c is an RFC 5322 VCHAR character. +func isVchar(c byte) bool { + // Visible (printing) characters. + return '!' <= c && c <= '~' +} diff --git a/src/net/mail/message.go b/src/net/mail/message.go index 19aa888d87..71fe74b9ca 100644 --- a/src/net/mail/message.go +++ b/src/net/mail/message.go @@ -18,17 +18,14 @@ package mail import ( "bufio" "bytes" - "encoding/base64" "errors" "fmt" + "internal/mime" "io" - "io/ioutil" "log" "net/textproto" - "strconv" "strings" "time" - "unicode" ) var debug = debugT(false) @@ -180,21 +177,7 @@ func (a *Address) String() string { return b.String() } - // UTF-8 "Q" encoding - b := bytes.NewBufferString("=?utf-8?q?") - for i := 0; i < len(a.Name); i++ { - switch c := a.Name[i]; { - case c == ' ': - b.WriteByte('_') - case isVchar(c) && c != '=' && c != '?' && c != '_': - b.WriteByte(c) - default: - fmt.Fprintf(b, "=%02X", c) - } - } - b.WriteString("?= ") - b.WriteString(s) - return b.String() + return mime.EncodeWord(a.Name) + " " + s } type addrParser []byte @@ -352,7 +335,7 @@ func (p *addrParser) consumePhrase() (phrase string, err error) { // RFC 2047 encoded-word starts with =?, ends with ?=, and has two other ?s. if err == nil && strings.HasPrefix(word, "=?") && strings.HasSuffix(word, "?=") && strings.Count(word, "?") == 4 { - word, err = decodeRFC2047Word(word) + word, err = mime.DecodeWord(word) } if err != nil { @@ -440,86 +423,6 @@ func (p *addrParser) len() int { return len(*p) } -func decodeRFC2047Word(s string) (string, error) { - fields := strings.Split(s, "?") - if len(fields) != 5 || fields[0] != "=" || fields[4] != "=" { - return "", errors.New("address not RFC 2047 encoded") - } - charset, enc := strings.ToLower(fields[1]), strings.ToLower(fields[2]) - if charset != "us-ascii" && charset != "iso-8859-1" && charset != "utf-8" { - return "", fmt.Errorf("charset not supported: %q", charset) - } - - in := bytes.NewBufferString(fields[3]) - var r io.Reader - switch enc { - case "b": - r = base64.NewDecoder(base64.StdEncoding, in) - case "q": - r = qDecoder{r: in} - default: - return "", fmt.Errorf("RFC 2047 encoding not supported: %q", enc) - } - - dec, err := ioutil.ReadAll(r) - if err != nil { - return "", err - } - - switch charset { - case "us-ascii": - b := new(bytes.Buffer) - for _, c := range dec { - if c >= 0x80 { - b.WriteRune(unicode.ReplacementChar) - } else { - b.WriteRune(rune(c)) - } - } - return b.String(), nil - case "iso-8859-1": - b := new(bytes.Buffer) - for _, c := range dec { - b.WriteRune(rune(c)) - } - return b.String(), nil - case "utf-8": - return string(dec), nil - } - panic("unreachable") -} - -type qDecoder struct { - r io.Reader - scratch [2]byte -} - -func (qd qDecoder) Read(p []byte) (n int, err error) { - // This method writes at most one byte into p. - if len(p) == 0 { - return 0, nil - } - if _, err := qd.r.Read(qd.scratch[:1]); err != nil { - return 0, err - } - switch c := qd.scratch[0]; { - case c == '=': - if _, err := io.ReadFull(qd.r, qd.scratch[:2]); err != nil { - return 0, err - } - x, err := strconv.ParseInt(string(qd.scratch[:2]), 16, 64) - if err != nil { - return 0, fmt.Errorf("mail: invalid RFC 2047 encoding: %q", qd.scratch[:2]) - } - p[0] = byte(x) - case c == '_': - p[0] = ' ' - default: - p[0] = c - } - return 1, nil -} - var atextChars = []byte("ABCDEFGHIJKLMNOPQRSTUVWXYZ" + "abcdefghijklmnopqrstuvwxyz" + "0123456789" + -- cgit v1.2.3-54-g00ecf From 2b0213d569dcfdd3f82fa7c98fd5fea26b6e3038 Mon Sep 17 00:00:00 2001 From: Robert Griesemer Date: Mon, 23 Feb 2015 10:05:02 -0800 Subject: math/big: incorporated feedback from prior TBR reviews Change-Id: Ida847365223ef09b4a3846e240b4bb6919cb0fe9 Reviewed-on: https://go-review.googlesource.com/5610 Reviewed-by: Alan Donovan --- src/math/big/float.go | 58 +++++++++++++++++++++++++--------------------- src/math/big/float_test.go | 2 ++ src/math/big/int.go | 2 +- src/math/big/natconv.go | 2 +- 4 files changed, 36 insertions(+), 28 deletions(-) diff --git a/src/math/big/float.go b/src/math/big/float.go index 877379c901..47755f2719 100644 --- a/src/math/big/float.go +++ b/src/math/big/float.go @@ -39,10 +39,10 @@ const debugFloat = true // enable for debugging // and according to its rounding mode, unless specified otherwise. If the // result precision is 0 (see below), it is set to the precision of the // argument with the largest precision value before any rounding takes -// place. The rounding mode remains unchanged, thus uninitialized Floats -// provided as result arguments will "inherit" a reasonble precision from -// the incoming arguments and their mode is the zero value for RoundingMode -// (ToNearestEven). +// place, and the rounding mode remains unchanged. Thus, uninitialized Floats +// provided as result arguments will have their precision set to a reasonable +// value determined by the operands and their mode is the zero value for +// RoundingMode (ToNearestEven). // // By setting the desired precision to 24 or 53 and using ToNearestEven // rounding, Float operations produce the same results as the corresponding @@ -62,6 +62,9 @@ type Float struct { prec uint // TODO(gri) make this a 32bit field } +// TODO(gri) provide a couple of Example tests showing typical Float intialization +// and use. + // Internal representation: The mantissa bits x.mant of a Float x are stored // in a nat slice long enough to hold up to x.prec bits; the slice may (but // doesn't have to) be shorter if the mantissa contains trailing 0 bits. @@ -158,7 +161,7 @@ func (z *Float) SetPrec(prec uint) *Float { // SetMode sets z's rounding mode to mode and returns an exact z. // z remains unchanged otherwise. func (z *Float) SetMode(mode RoundingMode) *Float { - z.acc = Exact + z.acc = Exact // TODO(gri) should we not do this? what's the general rule for setting accuracy? z.mode = mode return z } @@ -274,23 +277,21 @@ func (z *Float) setExp(e int64) { } // debugging support -func validate(args ...*Float) { - for i, x := range args { - const msb = 1 << (_W - 1) - m := len(x.mant) - if m == 0 { - // 0.0 or Inf - if x.exp != 0 && x.exp != infExp { - panic(fmt.Sprintf("#%d: %empty matissa with invalid exponent %d", i, x.exp)) - } - continue - } - if x.mant[m-1]&msb == 0 { - panic(fmt.Sprintf("#%d: msb not set in last word %#x of %s", i, x.mant[m-1], x.Format('p', 0))) - } - if x.prec <= 0 { - panic(fmt.Sprintf("#%d: invalid precision %d", i, x.prec)) +func validate(x *Float) { + const msb = 1 << (_W - 1) + m := len(x.mant) + if m == 0 { + // 0.0 or Inf + if x.exp != 0 && x.exp != infExp { + panic(fmt.Sprintf("%empty matissa with invalid exponent %d", x.exp)) } + return + } + if x.mant[m-1]&msb == 0 { + panic(fmt.Sprintf("msb not set in last word %#x of %s", x.mant[m-1], x.Format('p', 0))) + } + if x.prec <= 0 { + panic(fmt.Sprintf("invalid precision %d", x.prec)) } } @@ -1064,7 +1065,8 @@ func (x *Float) ucmp(y *Float) int { // result. func (z *Float) Add(x, y *Float) *Float { if debugFloat { - validate(x, y) + validate(x) + validate(y) } if z.prec == 0 { @@ -1104,7 +1106,8 @@ func (z *Float) Add(x, y *Float) *Float { // Precision, rounding, and accuracy reporting are as for Add. func (z *Float) Sub(x, y *Float) *Float { if debugFloat { - validate(x, y) + validate(x) + validate(y) } if z.prec == 0 { @@ -1143,7 +1146,8 @@ func (z *Float) Sub(x, y *Float) *Float { // Precision, rounding, and accuracy reporting are as for Add. func (z *Float) Mul(x, y *Float) *Float { if debugFloat { - validate(x, y) + validate(x) + validate(y) } if z.prec == 0 { @@ -1171,7 +1175,8 @@ func (z *Float) Mul(x, y *Float) *Float { // Precision, rounding, and accuracy reporting are as for Add. func (z *Float) Quo(x, y *Float) *Float { if debugFloat { - validate(x, y) + validate(x) + validate(y) } if z.prec == 0 { @@ -1251,7 +1256,8 @@ func (z *Float) Rsh(x *Float, s uint) *Float { // Infinities with matching sign are equal. func (x *Float) Cmp(y *Float) int { if debugFloat { - validate(x, y) + validate(x) + validate(y) } mx := x.ord() diff --git a/src/math/big/float_test.go b/src/math/big/float_test.go index 17247b1eb2..2789cfb9f3 100644 --- a/src/math/big/float_test.go +++ b/src/math/big/float_test.go @@ -1077,6 +1077,8 @@ func TestFloatQuoSmoke(t *testing.T) { } } +// TODO(gri) Add tests that check correctness in the presence of aliasing. + // For rounding modes ToNegativeInf and ToPositiveInf, rounding is affected // by the sign of the value to be rounded. Test that rounding happens after // the sign of a result has been set. diff --git a/src/math/big/int.go b/src/math/big/int.go index 5c1b2cd765..0695d78973 100644 --- a/src/math/big/int.go +++ b/src/math/big/int.go @@ -361,7 +361,7 @@ func (x *Int) Uint64() uint64 { // and returns z and a boolean indicating success. If SetString fails, // the value of z is undefined but the returned value is nil. // -// The base argument must be 0 or a value from 2 through MaxBase. If the base +// The base argument must be 0 or a value between 2 and MaxBase. If the base // is 0, the string prefix determines the actual conversion base. A prefix of // ``0x'' or ``0X'' selects base 16; the ``0'' prefix selects base 8, and a // ``0b'' or ``0B'' prefix selects base 2. Otherwise the selected base is 10. diff --git a/src/math/big/natconv.go b/src/math/big/natconv.go index b5c37731fa..022dcfe38c 100644 --- a/src/math/big/natconv.go +++ b/src/math/big/natconv.go @@ -60,7 +60,7 @@ func pow(x Word, n int) (p Word) { // digit = "0" ... "9" | "a" ... "z" | "A" ... "Z" . // // Unless fracOk is set, the base argument must be 0 or a value between -// 2 through MaxBase. If fracOk is set, the base argument must be one of +// 2 and MaxBase. If fracOk is set, the base argument must be one of // 0, 2, 10, or 16. Providing an invalid base argument leads to a run- // time panic. // -- cgit v1.2.3-54-g00ecf From 96333a7e4841c37d4c70cdab8748f9e69012cf29 Mon Sep 17 00:00:00 2001 From: Robert Griesemer Date: Mon, 23 Feb 2015 10:20:20 -0800 Subject: go/token: document that column positions and file offsets are in bytes Fixes #9948. Change-Id: I7b354fccd5e933eeeb2253a66acec050ebff6e41 Reviewed-on: https://go-review.googlesource.com/5611 Reviewed-by: Alan Donovan --- src/go/token/position.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/go/token/position.go b/src/go/token/position.go index 82d90eeb72..17452bb3d5 100644 --- a/src/go/token/position.go +++ b/src/go/token/position.go @@ -21,7 +21,7 @@ type Position struct { Filename string // filename, if any Offset int // offset, starting at 0 Line int // line number, starting at 1 - Column int // column number, starting at 1 (character count) + Column int // column number, starting at 1 (byte count) } // IsValid returns true if the position is valid. @@ -56,8 +56,8 @@ func (pos Position) String() string { // where base and size are specified when adding the file to the file set via // AddFile. // -// To create the Pos value for a specific source offset, first add -// the respective file to the current file set (via FileSet.AddFile) +// To create the Pos value for a specific source offset (measured in bytes), +// first add the respective file to the current file set using FileSet.AddFile // and then call File.Pos(offset) for that file. Given a Pos value p // for a specific file set fset, the corresponding Position value is // obtained by calling fset.Position(p). -- cgit v1.2.3-54-g00ecf From 99482f2f9e7710206386ff45869cb76a53e0ac76 Mon Sep 17 00:00:00 2001 From: Rick Hudson Date: Thu, 19 Feb 2015 18:11:24 -0500 Subject: runtime: Add prefetch to allocation code The routine mallocgc retrieves objects from freelists. Prefetch the object that will be returned in the next call to mallocgc. Experiments indicate that this produces a 1% improvement when using prefetchnta and less when using prefetcht0, prefetcht1, or prefetcht2. Benchmark numbers indicate a 1% improvement over no prefetch, much less over prefetcht0, prefetcht1, and prefetcht2. These numbers were for the garbage benchmark with MAXPROCS=4 no prefetch >> 5.96 / 5.77 / 5.89 prefetcht0(uintptr(v.ptr().next)) >> 5.88 / 6.17 / 5.84 prefetcht1(uintptr(v.ptr().next)) >> 5.88 / 5.89 / 5.91 prefetcht2(uintptr(v.ptr().next)) >> 5.87 / 6.47 / 5.92 prefetchnta(uintptr(v.ptr().next)) >> 5.72 / 5.84 / 5.85 Change-Id: I54e07172081cccb097d5b5ce8789d74daa055ed9 Reviewed-on: https://go-review.googlesource.com/5350 Reviewed-by: Dmitry Vyukov Reviewed-by: Austin Clements --- src/runtime/malloc.go | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/runtime/malloc.go b/src/runtime/malloc.go index 475f97fd05..fac5ca49ce 100644 --- a/src/runtime/malloc.go +++ b/src/runtime/malloc.go @@ -553,7 +553,8 @@ func mallocgc(size uintptr, typ *_type, flags uint32) unsafe.Pointer { } s.freelist = v.ptr().next s.ref++ - //TODO: prefetch v.next + // prefetchnta offers best performance, see change list message. + prefetchnta(uintptr(v.ptr().next)) x = unsafe.Pointer(v) (*[2]uint64)(x)[0] = 0 (*[2]uint64)(x)[1] = 0 @@ -584,7 +585,8 @@ func mallocgc(size uintptr, typ *_type, flags uint32) unsafe.Pointer { } s.freelist = v.ptr().next s.ref++ - //TODO: prefetch + // prefetchnta offers best performance, see change list message. + prefetchnta(uintptr(v.ptr().next)) x = unsafe.Pointer(v) if flags&flagNoZero == 0 { v.ptr().next = 0 -- cgit v1.2.3-54-g00ecf From 6a10f720f2f3bd48f37c5d357c41e02c8722033a Mon Sep 17 00:00:00 2001 From: Robert Griesemer Date: Mon, 23 Feb 2015 10:57:21 -0800 Subject: math/big: don't return io.EOF on successful call of ParseFloat Fixes $9938. Change-Id: Ie8680a875225748abd660fb26b4c25546e7b92d3 Reviewed-on: https://go-review.googlesource.com/5620 Reviewed-by: Alan Donovan --- src/math/big/floatconv.go | 17 +++++++---------- src/math/big/floatconv_test.go | 6 ++---- 2 files changed, 9 insertions(+), 14 deletions(-) diff --git a/src/math/big/floatconv.go b/src/math/big/floatconv.go index a857fa6513..e41d447db0 100644 --- a/src/math/big/floatconv.go +++ b/src/math/big/floatconv.go @@ -126,11 +126,9 @@ func (z *Float) Scan(r io.ByteScanner, base int) (f *Float, b int, err error) { } // Parse is like z.Scan(r, base), but instead of reading from an -// io.ByteScanner, it parses the string s. An error is returned if the -// string contains invalid or trailing characters not belonging to the -// number. -// -// TODO(gri) define possible errors more precisely +// io.ByteScanner, it parses the string s. An error is returned if +// the string contains invalid or trailing bytes not belonging to +// the number. func (z *Float) Parse(s string, base int) (f *Float, b int, err error) { r := strings.NewReader(s) @@ -139,11 +137,10 @@ func (z *Float) Parse(s string, base int) (f *Float, b int, err error) { } // entire string must have been consumed - var ch byte - if ch, err = r.ReadByte(); err != io.EOF { - if err == nil { - err = fmt.Errorf("expected end of string, found %q", ch) - } + if ch, err2 := r.ReadByte(); err2 == nil { + err = fmt.Errorf("expected end of string, found %q", ch) + } else if err2 != io.EOF { + err = err2 } return diff --git a/src/math/big/floatconv_test.go b/src/math/big/floatconv_test.go index 11e5df448a..a22a1f7ddf 100644 --- a/src/math/big/floatconv_test.go +++ b/src/math/big/floatconv_test.go @@ -5,7 +5,6 @@ package big import ( - "io" "math" "strconv" "testing" @@ -59,7 +58,7 @@ func TestFloatSetFloat64String(t *testing.T) { {"+10000000000000000000000000000000000000000e-0", 1e40}, } { var x Float - x.prec = 53 // TODO(gri) find better solution + x.SetPrec(53) _, ok := x.SetString(test.s) if !ok { t.Errorf("%s: parse error", test.s) @@ -313,8 +312,7 @@ func TestFloatFormat(t *testing.T) { {"3.14", 'x', 0, "%x"}, } { f, _, err := ParseFloat(test.x, 0, 1000, ToNearestEven) - // TODO(gri) should we return io.EOF at the end? - if err != nil && err != io.EOF { + if err != nil { t.Errorf("%v: %s", test, err) continue } -- cgit v1.2.3-54-g00ecf