-
-
Notifications
You must be signed in to change notification settings - Fork 378
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
unused: use more efficient types.Implements implementation
The standard types.Implements implementation produces a lot of garbage in lookupFieldOrMethod. By using MethodSetCache and method sets, we can avoid a lot of this garbage. This directly translates to lower runtimes and lower peak memory usage. Compared with 442643a, for std and cockroachdb, we get the following numbers: Total allocations std: 6268 MB -> 4702 MB cdb: 28398 MB -> 19048 MB Peak rss std: 4,556,404 -> 3,253,004 cdb: 17,403,616 -> 12,546,948 Time std: 0:25.18 -> 0:21.84 cdb: 1:45.70 -> 1:30.74 Updates gh-394
- Loading branch information
Showing
2 changed files
with
82 additions
and
2 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,79 @@ | ||
package unused | ||
|
||
import "go/types" | ||
|
||
// lookupMethod returns the index of and method with matching package and name, or (-1, nil). | ||
func lookupMethod(T *types.Interface, pkg *types.Package, name string) (int, *types.Func) { | ||
if name != "_" { | ||
for i := 0; i < T.NumMethods(); i++ { | ||
m := T.Method(i) | ||
if sameId(m, pkg, name) { | ||
return i, m | ||
} | ||
} | ||
} | ||
return -1, nil | ||
} | ||
|
||
func sameId(obj types.Object, pkg *types.Package, name string) bool { | ||
// spec: | ||
// "Two identifiers are different if they are spelled differently, | ||
// or if they appear in different packages and are not exported. | ||
// Otherwise, they are the same." | ||
if name != obj.Name() { | ||
return false | ||
} | ||
// obj.Name == name | ||
if obj.Exported() { | ||
return true | ||
} | ||
// not exported, so packages must be the same (pkg == nil for | ||
// fields in Universe scope; this can only happen for types | ||
// introduced via Eval) | ||
if pkg == nil || obj.Pkg() == nil { | ||
return pkg == obj.Pkg() | ||
} | ||
// pkg != nil && obj.pkg != nil | ||
return pkg.Path() == obj.Pkg().Path() | ||
} | ||
|
||
func (c *Checker) implements(V types.Type, T *types.Interface) bool { | ||
// fast path for common case | ||
if T.Empty() { | ||
return true | ||
} | ||
|
||
if ityp, _ := V.Underlying().(*types.Interface); ityp != nil { | ||
for i := 0; i < T.NumMethods(); i++ { | ||
m := T.Method(i) | ||
_, obj := lookupMethod(ityp, m.Pkg(), m.Name()) | ||
switch { | ||
case obj == nil: | ||
return false | ||
case !types.Identical(obj.Type(), m.Type()): | ||
return false | ||
} | ||
} | ||
return true | ||
} | ||
|
||
// A concrete type implements T if it implements all methods of T. | ||
ms := c.msCache.MethodSet(V) | ||
for i := 0; i < T.NumMethods(); i++ { | ||
m := T.Method(i) | ||
sel := ms.Lookup(m.Pkg(), m.Name()) | ||
if sel == nil { | ||
return false | ||
} | ||
|
||
f, _ := sel.Obj().(*types.Func) | ||
if f == nil { | ||
return false | ||
} | ||
|
||
if !types.Identical(f.Type(), m.Type()) { | ||
return false | ||
} | ||
} | ||
return true | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters