1
0
mirror of https://github.com/golang/go synced 2024-11-18 23:05:06 -07:00

cmd/compile: sort method sets earlier

By sorting method sets earlier, we can change the interface
satisfaction problem from taking O(NM) time to O(N+M). This is the
same algorithm already used by runtime and reflect for dynamic
interface satisfaction testing.

For #22075.

Change-Id: I3d889f0227f37704535739bbde11f5107b4eea17
Reviewed-on: https://go-review.googlesource.com/100845
Run-TryBot: Matthew Dempsky <mdempsky@google.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Robert Griesemer <gri@golang.org>
This commit is contained in:
Matthew Dempsky 2018-03-15 13:14:41 -07:00
parent dfaed7ff19
commit 91bbe5388d
2 changed files with 33 additions and 27 deletions

View File

@ -454,7 +454,6 @@ func methods(t *types.Type) []*Sig {
} }
} }
obj.SortSlice(ms, func(i, j int) bool { return siglt(ms[i], ms[j]) })
return ms return ms
} }

View File

@ -1628,6 +1628,7 @@ func expandmeth(t *types.Type) {
} }
ms = append(ms, t.Methods().Slice()...) ms = append(ms, t.Methods().Slice()...)
sort.Sort(methcmp(ms))
t.AllMethods().Set(ms) t.AllMethods().Set(ms)
} }
@ -1847,18 +1848,21 @@ func implements(t, iface *types.Type, m, samename **types.Field, ptr *int) bool
return false return false
} }
// if this is too slow,
// could sort these first
// and then do one loop.
if t.IsInterface() { if t.IsInterface() {
Outer: i := 0
tms := t.Fields().Slice()
for _, im := range iface.Fields().Slice() { for _, im := range iface.Fields().Slice() {
for _, tm := range t.Fields().Slice() { for i < len(tms) && tms[i].Sym != im.Sym {
if tm.Sym == im.Sym { i++
if eqtype(tm.Type, im.Type) {
continue Outer
} }
if i == len(tms) {
*m = im
*samename = nil
*ptr = 0
return false
}
tm := tms[i]
if !eqtype(tm.Type, im.Type) {
*m = im *m = im
*samename = tm *samename = tm
*ptr = 0 *ptr = 0
@ -1866,38 +1870,41 @@ func implements(t, iface *types.Type, m, samename **types.Field, ptr *int) bool
} }
} }
*m = im
*samename = nil
*ptr = 0
return false
}
return true return true
} }
t = methtype(t) t = methtype(t)
var tms []*types.Field
if t != nil { if t != nil {
expandmeth(t) expandmeth(t)
tms = t.AllMethods().Slice()
} }
i := 0
for _, im := range iface.Fields().Slice() { for _, im := range iface.Fields().Slice() {
if im.Broke() { if im.Broke() {
continue continue
} }
tm, followptr := ifacelookdot(im.Sym, t, false) for i < len(tms) && tms[i].Sym != im.Sym {
if tm == nil || tm.Nointerface() || !eqtype(tm.Type, im.Type) { i++
if tm == nil {
tm, followptr = ifacelookdot(im.Sym, t, true)
} }
if i == len(tms) {
*m = im
*samename, _ = ifacelookdot(im.Sym, t, true)
*ptr = 0
return false
}
tm := tms[i]
if tm.Nointerface() || !eqtype(tm.Type, im.Type) {
*m = im *m = im
*samename = tm *samename = tm
*ptr = 0 *ptr = 0
return false return false
} }
followptr := tm.Embedded == 2
// if pointer receiver in method, // if pointer receiver in method,
// the method does not exist for value types. // the method does not exist for value types.
rcvr := tm.Type.Recv().Type rcvr := tm.Type.Recv().Type
if rcvr.IsPtr() && !t0.IsPtr() && !followptr && !isifacemethod(tm.Type) { if rcvr.IsPtr() && !t0.IsPtr() && !followptr && !isifacemethod(tm.Type) {
if false && Debug['r'] != 0 { if false && Debug['r'] != 0 {
yyerror("interface pointer mismatch") yyerror("interface pointer mismatch")