Skip to content

Commit 91bbe53

Browse files
committed
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 <[email protected]> TryBot-Result: Gobot Gobot <[email protected]> Reviewed-by: Robert Griesemer <[email protected]>
1 parent dfaed7f commit 91bbe53

File tree

2 files changed

+33
-27
lines changed

2 files changed

+33
-27
lines changed

src/cmd/compile/internal/gc/reflect.go

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -454,7 +454,6 @@ func methods(t *types.Type) []*Sig {
454454
}
455455
}
456456

457-
obj.SortSlice(ms, func(i, j int) bool { return siglt(ms[i], ms[j]) })
458457
return ms
459458
}
460459

src/cmd/compile/internal/gc/subr.go

Lines changed: 33 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1628,6 +1628,7 @@ func expandmeth(t *types.Type) {
16281628
}
16291629

16301630
ms = append(ms, t.Methods().Slice()...)
1631+
sort.Sort(methcmp(ms))
16311632
t.AllMethods().Set(ms)
16321633
}
16331634

@@ -1847,57 +1848,63 @@ func implements(t, iface *types.Type, m, samename **types.Field, ptr *int) bool
18471848
return false
18481849
}
18491850

1850-
// if this is too slow,
1851-
// could sort these first
1852-
// and then do one loop.
1853-
18541851
if t.IsInterface() {
1855-
Outer:
1852+
i := 0
1853+
tms := t.Fields().Slice()
18561854
for _, im := range iface.Fields().Slice() {
1857-
for _, tm := range t.Fields().Slice() {
1858-
if tm.Sym == im.Sym {
1859-
if eqtype(tm.Type, im.Type) {
1860-
continue Outer
1861-
}
1862-
*m = im
1863-
*samename = tm
1864-
*ptr = 0
1865-
return false
1866-
}
1855+
for i < len(tms) && tms[i].Sym != im.Sym {
1856+
i++
1857+
}
1858+
if i == len(tms) {
1859+
*m = im
1860+
*samename = nil
1861+
*ptr = 0
1862+
return false
1863+
}
1864+
tm := tms[i]
1865+
if !eqtype(tm.Type, im.Type) {
1866+
*m = im
1867+
*samename = tm
1868+
*ptr = 0
1869+
return false
18671870
}
1868-
1869-
*m = im
1870-
*samename = nil
1871-
*ptr = 0
1872-
return false
18731871
}
18741872

18751873
return true
18761874
}
18771875

18781876
t = methtype(t)
1877+
var tms []*types.Field
18791878
if t != nil {
18801879
expandmeth(t)
1880+
tms = t.AllMethods().Slice()
18811881
}
1882+
i := 0
18821883
for _, im := range iface.Fields().Slice() {
18831884
if im.Broke() {
18841885
continue
18851886
}
1886-
tm, followptr := ifacelookdot(im.Sym, t, false)
1887-
if tm == nil || tm.Nointerface() || !eqtype(tm.Type, im.Type) {
1888-
if tm == nil {
1889-
tm, followptr = ifacelookdot(im.Sym, t, true)
1890-
}
1887+
for i < len(tms) && tms[i].Sym != im.Sym {
1888+
i++
1889+
}
1890+
if i == len(tms) {
1891+
*m = im
1892+
*samename, _ = ifacelookdot(im.Sym, t, true)
1893+
*ptr = 0
1894+
return false
1895+
}
1896+
tm := tms[i]
1897+
if tm.Nointerface() || !eqtype(tm.Type, im.Type) {
18911898
*m = im
18921899
*samename = tm
18931900
*ptr = 0
18941901
return false
18951902
}
1903+
followptr := tm.Embedded == 2
18961904

18971905
// if pointer receiver in method,
18981906
// the method does not exist for value types.
18991907
rcvr := tm.Type.Recv().Type
1900-
19011908
if rcvr.IsPtr() && !t0.IsPtr() && !followptr && !isifacemethod(tm.Type) {
19021909
if false && Debug['r'] != 0 {
19031910
yyerror("interface pointer mismatch")

0 commit comments

Comments
 (0)