}
type instanceLookup struct {
- m map[*Named][]*Named
+ // buf is used to avoid allocating the map m in the common case of a small
+ // number of instances.
+ buf [3]*Named
+ m map[*Named][]*Named
}
func (l *instanceLookup) lookup(inst *Named) *Named {
+ for _, t := range l.buf {
+ if t != nil && Identical(inst, t) {
+ return t
+ }
+ }
for _, t := range l.m[inst.Origin()] {
if Identical(inst, t) {
return t
}
func (l *instanceLookup) add(inst *Named) {
+ for i, t := range l.buf {
+ if t == nil {
+ l.buf[i] = inst
+ return
+ }
+ }
if l.m == nil {
l.m = make(map[*Named][]*Named)
}
--- /dev/null
+// Copyright 2022 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 types2_test
+
+import (
+ "path/filepath"
+ "runtime"
+ "testing"
+
+ . "cmd/compile/internal/types2"
+)
+
+// BenchmarkLookupFieldOrMethod measures types.LookupFieldOrMethod performance.
+// LookupFieldOrMethod is a performance hotspot for both type-checking and
+// external API calls.
+func BenchmarkLookupFieldOrMethod(b *testing.B) {
+ // Choose an arbitrary, large package.
+ path := filepath.Join(runtime.GOROOT(), "src", "net", "http")
+
+ files, err := pkgFiles(path)
+ if err != nil {
+ b.Fatal(err)
+ }
+
+ conf := Config{
+ Importer: defaultImporter(),
+ }
+
+ pkg, err := conf.Check("http", files, nil)
+ if err != nil {
+ b.Fatal(err)
+ }
+
+ scope := pkg.Scope()
+ names := scope.Names()
+
+ // Look up an arbitrary name for each type referenced in the package scope.
+ lookup := func() {
+ for _, name := range names {
+ typ := scope.Lookup(name).Type()
+ LookupFieldOrMethod(typ, true, pkg, "m")
+ }
+ }
+
+ // Perform a lookup once, to ensure that any lazily-evaluated state is
+ // complete.
+ lookup()
+
+ b.ResetTimer()
+ for i := 0; i < b.N; i++ {
+ lookup()
+ }
+}
}
type instanceLookup struct {
- m map[*Named][]*Named
+ // buf is used to avoid allocating the map m in the common case of a small
+ // number of instances.
+ buf [3]*Named
+ m map[*Named][]*Named
}
func (l *instanceLookup) lookup(inst *Named) *Named {
+ for _, t := range l.buf {
+ if t != nil && Identical(inst, t) {
+ return t
+ }
+ }
for _, t := range l.m[inst.Origin()] {
if Identical(inst, t) {
return t
}
func (l *instanceLookup) add(inst *Named) {
+ for i, t := range l.buf {
+ if t == nil {
+ l.buf[i] = inst
+ return
+ }
+ }
if l.m == nil {
l.m = make(map[*Named][]*Named)
}
--- /dev/null
+// Copyright 2022 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 types_test
+
+import (
+ "go/importer"
+ "go/token"
+ "path/filepath"
+ "runtime"
+ "testing"
+
+ . "go/types"
+)
+
+// BenchmarkLookupFieldOrMethod measures types.LookupFieldOrMethod performance.
+// LookupFieldOrMethod is a performance hotspot for both type-checking and
+// external API calls.
+func BenchmarkLookupFieldOrMethod(b *testing.B) {
+ // Choose an arbitrary, large package.
+ path := filepath.Join(runtime.GOROOT(), "src", "net", "http")
+
+ fset := token.NewFileSet()
+ files, err := pkgFiles(fset, path, 0)
+ if err != nil {
+ b.Fatal(err)
+ }
+
+ conf := Config{
+ Importer: importer.Default(),
+ }
+
+ pkg, err := conf.Check("http", fset, files, nil)
+ if err != nil {
+ b.Fatal(err)
+ }
+
+ scope := pkg.Scope()
+ names := scope.Names()
+
+ // Look up an arbitrary name for each type referenced in the package scope.
+ lookup := func() {
+ for _, name := range names {
+ typ := scope.Lookup(name).Type()
+ LookupFieldOrMethod(typ, true, pkg, "m")
+ }
+ }
+
+ // Perform a lookup once, to ensure that any lazily-evaluated state is
+ // complete.
+ lookup()
+
+ b.ResetTimer()
+ for i := 0; i < b.N; i++ {
+ lookup()
+ }
+}