mirror of https://github.com/golang/go.git
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
This commit is contained in:
parent
c7cc983097
commit
d5bb1db3ec
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue