aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRobert Griesemer <gri@golang.org>2016-03-11 14:58:26 -0800
committerMatthew Dempsky <mdempsky@google.com>2016-08-16 10:48:20 -0700
commitd5bb1db3ec256ea65713baeaa3b2cb1b0b151792 (patch)
treeb53dcf6f1130ab93358e1333c78218a719bc24c0
parentc7cc983097d21f1ed3ad07672052f37a431a1192 (diff)
downloadgo-d5bb1db3ec256ea65713baeaa3b2cb1b0b151792.tar.gz
go-d5bb1db3ec256ea65713baeaa3b2cb1b0b151792.zip
cmd/compile/internal/syntax: don't allocate a string for each keyword
$ go test -run StdLib -fast parsed 1074061 lines (2828 files) in 571.1019ms (1880681 lines/s) allocated 263.676Mb (461.696Mb/s) PASS
-rw-r--r--src/cmd/compile/internal/syntax/scanner.go32
-rw-r--r--src/cmd/compile/internal/syntax/source.go4
2 files changed, 24 insertions, 12 deletions
diff --git a/src/cmd/compile/internal/syntax/scanner.go b/src/cmd/compile/internal/syntax/scanner.go
index 35e9b2cd1a..7df5e381ab 100644
--- a/src/cmd/compile/internal/syntax/scanner.go
+++ b/src/cmd/compile/internal/syntax/scanner.go
@@ -320,7 +320,7 @@ func (s *scanner) ident() {
// possibly a keyword
if len(lit) >= 2 {
- if tok := keywordMap[hash(lit)]; tok != 0 && tokstrings[tok] == lit {
+ if tok := keywordMap[hash(lit)]; tok != 0 && strbyteseql(tokstrings[tok], lit) {
s.nlsemi = contains(1<<_Break|1<<_Continue|1<<_Fallthrough|1<<_Return, tok)
s.tok = tok
return
@@ -329,21 +329,33 @@ func (s *scanner) ident() {
s.nlsemi = true
s.tok = _Name
- s.lit = lit
+ s.lit = string(lit)
}
// hash is a perfect hash function for keywords.
// It assumes that s has at least length 2.
-func hash(s string) uint {
+func hash(s []byte) uint {
return (uint(s[0])<<4 ^ uint(s[1]) + uint(len(s))) & uint(len(keywordMap)-1)
}
+func strbyteseql(s string, b []byte) bool {
+ if len(s) == len(b) {
+ for i, b := range b {
+ if s[i] != b {
+ return false
+ }
+ }
+ return true
+ }
+ return false
+}
+
var keywordMap [1 << 6]token // size must be power of two
func init() {
// populate keywordMap
for tok := _Break; tok <= _Var; tok++ {
- h := hash(tokstrings[tok])
+ h := hash([]byte(tokstrings[tok]))
if keywordMap[h] != 0 {
panic("imperfect hash")
}
@@ -369,7 +381,7 @@ func (s *scanner) number(c rune) {
panic("malformed hex constant")
}
s.ungetr()
- s.lit = s.stopLit()
+ s.lit = string(s.stopLit())
return
}
@@ -387,7 +399,7 @@ func (s *scanner) number(c rune) {
panic("malformed octal constant")
}
s.ungetr()
- s.lit = s.stopLit()
+ s.lit = string(s.stopLit())
return
}
@@ -426,7 +438,7 @@ func (s *scanner) number(c rune) {
s.ungetr() // not complex
}
- s.lit = s.stopLit()
+ s.lit = string(s.stopLit())
}
func (s *scanner) stdString() {
@@ -443,7 +455,7 @@ func (s *scanner) stdString() {
panic("string not terminated")
}
}
- s.lit = s.stopLit()
+ s.lit = string(s.stopLit())
}
func (s *scanner) rawString() {
@@ -458,7 +470,7 @@ func (s *scanner) rawString() {
}
// TODO(gri) deal with CRs (or don't?)
}
- s.lit = s.stopLit()
+ s.lit = string(s.stopLit())
}
func (s *scanner) rune() {
@@ -471,7 +483,7 @@ func (s *scanner) rune() {
if c != '\'' {
panic(c)
}
- s.lit = s.stopLit()
+ s.lit = string(s.stopLit())
}
func (s *scanner) match(r rune, prefix string) rune {
diff --git a/src/cmd/compile/internal/syntax/source.go b/src/cmd/compile/internal/syntax/source.go
index 07b59ab298..9f00f1e87e 100644
--- a/src/cmd/compile/internal/syntax/source.go
+++ b/src/cmd/compile/internal/syntax/source.go
@@ -139,11 +139,11 @@ func (s *source) startLit() {
s.lit = s.lit[:0] // reuse lit
}
-func (s *source) stopLit() string {
+func (s *source) stopLit() []byte {
lit := s.buf[s.suf:s.r]
if len(s.lit) > 0 {
lit = append(s.lit, lit...)
}
s.suf = -1 // no pending literal
- return string(lit)
+ return lit
}