diff options
author | Robert Griesemer <gri@golang.org> | 2016-03-11 14:58:26 -0800 |
---|---|---|
committer | Matthew Dempsky <mdempsky@google.com> | 2016-08-16 10:48:20 -0700 |
commit | d5bb1db3ec256ea65713baeaa3b2cb1b0b151792 (patch) | |
tree | b53dcf6f1130ab93358e1333c78218a719bc24c0 | |
parent | c7cc983097d21f1ed3ad07672052f37a431a1192 (diff) | |
download | go-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.go | 32 | ||||
-rw-r--r-- | src/cmd/compile/internal/syntax/source.go | 4 |
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 } |