]> Cypherpunks repositories - gostls13.git/commitdiff
unicode/utf8: remove some bounds checks from DecodeRune
authorJosh Bleecher Snyder <josharian@gmail.com>
Wed, 24 Apr 2019 22:31:24 +0000 (15:31 -0700)
committerJosh Bleecher Snyder <josharian@gmail.com>
Thu, 25 Apr 2019 00:01:23 +0000 (00:01 +0000)
The compiler couldn't quite see that reading p[2] and p[3] was safe.
This change provides a few hints to help it.
First, make sz an int throughout, rather than just when checking the input length.
Second, use <= instead of == in later comparisons.

name                  old time/op  new time/op  delta
DecodeASCIIRune-8     2.62ns ± 3%  2.60ns ± 5%     ~     (p=0.126 n=18+19)
DecodeJapaneseRune-8  4.46ns ±10%  4.01ns ± 5%  -10.00%  (p=0.000 n=19+20)

Change-Id: I2f78a17e38156fbf8b0f5dd6c07c20d6a47e9209
Reviewed-on: https://go-review.googlesource.com/c/go/+/173662
Run-TryBot: Josh Bleecher Snyder <josharian@gmail.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Brad Fitzpatrick <bradfitz@golang.org>
src/unicode/utf8/utf8.go

index 2d4a48625659a991da91eb181ac673a1f0f07187..eae4ead0dae09e446879c6418ad4a02809247523 100644 (file)
@@ -161,23 +161,23 @@ func DecodeRune(p []byte) (r rune, size int) {
                mask := rune(x) << 31 >> 31 // Create 0x0000 or 0xFFFF.
                return rune(p[0])&^mask | RuneError&mask, 1
        }
-       sz := x & 7
+       sz := int(x & 7)
        accept := acceptRanges[x>>4]
-       if n < int(sz) {
+       if n < sz {
                return RuneError, 1
        }
        b1 := p[1]
        if b1 < accept.lo || accept.hi < b1 {
                return RuneError, 1
        }
-       if sz == 2 {
+       if sz <= 2 { // <= instead of == to help the compiler eliminate some bounds checks
                return rune(p0&mask2)<<6 | rune(b1&maskx), 2
        }
        b2 := p[2]
        if b2 < locb || hicb < b2 {
                return RuneError, 1
        }
-       if sz == 3 {
+       if sz <= 3 {
                return rune(p0&mask3)<<12 | rune(b1&maskx)<<6 | rune(b2&maskx), 3
        }
        b3 := p[3]
@@ -209,23 +209,23 @@ func DecodeRuneInString(s string) (r rune, size int) {
                mask := rune(x) << 31 >> 31 // Create 0x0000 or 0xFFFF.
                return rune(s[0])&^mask | RuneError&mask, 1
        }
-       sz := x & 7
+       sz := int(x & 7)
        accept := acceptRanges[x>>4]
-       if n < int(sz) {
+       if n < sz {
                return RuneError, 1
        }
        s1 := s[1]
        if s1 < accept.lo || accept.hi < s1 {
                return RuneError, 1
        }
-       if sz == 2 {
+       if sz <= 2 { // <= instead of == to help the compiler eliminate some bounds checks
                return rune(s0&mask2)<<6 | rune(s1&maskx), 2
        }
        s2 := s[2]
        if s2 < locb || hicb < s2 {
                return RuneError, 1
        }
-       if sz == 3 {
+       if sz <= 3 {
                return rune(s0&mask3)<<12 | rune(s1&maskx)<<6 | rune(s2&maskx), 3
        }
        s3 := s[3]