Commit bca70a66 authored by Håvard Haugen's avatar Håvard Haugen Committed by Dave Cheney

cmd/compile/internal/gc: use sort.Interface for reflect methods

Generate slices of method *Sig(nature)s instead of linked lists.
Remove custom lsort function in favor of sort.Interface.

Eliminates another use of stringsCompare.

Passes go build -a -toolexec 'toolstash -cmp' std cmd.

Change-Id: I9ed1664b7f55be9e967dd7196e396a76f6ea3422
Reviewed-on: https://go-review.googlesource.com/14559Reviewed-by: default avatarDave Cheney <dave@cheney.net>
parent ebd96933
...@@ -376,7 +376,6 @@ type Sig struct { ...@@ -376,7 +376,6 @@ type Sig struct {
type_ *Type type_ *Type
mtype *Type mtype *Type
offset int32 offset int32
link *Sig
} }
type Io struct { type Io struct {
......
...@@ -9,6 +9,7 @@ import ( ...@@ -9,6 +9,7 @@ import (
"cmd/internal/obj" "cmd/internal/obj"
"fmt" "fmt"
"os" "os"
"sort"
) )
/* /*
...@@ -16,93 +17,30 @@ import ( ...@@ -16,93 +17,30 @@ import (
*/ */
var signatlist *NodeList var signatlist *NodeList
func sigcmp(a *Sig, b *Sig) int { // byMethodNameAndPackagePath sorts method signatures by name, then package path.
i := stringsCompare(a.name, b.name) type byMethodNameAndPackagePath []*Sig
if i != 0 {
return i func (x byMethodNameAndPackagePath) Len() int { return len(x) }
func (x byMethodNameAndPackagePath) Swap(i, j int) { x[i], x[j] = x[j], x[i] }
func (x byMethodNameAndPackagePath) Less(i, j int) bool {
return siglt(x[i], x[j])
}
// siglt reports whether a < b
func siglt(a, b *Sig) bool {
if a.name != b.name {
return a.name < b.name
} }
if a.pkg == b.pkg { if a.pkg == b.pkg {
return 0 return false
} }
if a.pkg == nil { if a.pkg == nil {
return -1 return true
} }
if b.pkg == nil { if b.pkg == nil {
return +1 return false
}
return stringsCompare(a.pkg.Path, b.pkg.Path)
}
func lsort(l *Sig, f func(*Sig, *Sig) int) *Sig {
if l == nil || l.link == nil {
return l
}
l1 := l
l2 := l
for {
l2 = l2.link
if l2 == nil {
break
}
l2 = l2.link
if l2 == nil {
break
}
l1 = l1.link
}
l2 = l1.link
l1.link = nil
l1 = lsort(l, f)
l2 = lsort(l2, f)
/* set up lead element */
if f(l1, l2) < 0 {
l = l1
l1 = l1.link
} else {
l = l2
l2 = l2.link
}
le := l
for {
if l1 == nil {
for l2 != nil {
le.link = l2
le = l2
l2 = l2.link
}
le.link = nil
break
}
if l2 == nil {
for l1 != nil {
le.link = l1
le = l1
l1 = l1.link
}
break
}
if f(l1, l2) < 0 {
le.link = l1
le = l1
l1 = l1.link
} else {
le.link = l2
le = l2
l2 = l2.link
}
} }
return a.pkg.Path < b.pkg.Path
le.link = nil
return l
} }
// Builds a type representing a Bucket structure for // Builds a type representing a Bucket structure for
...@@ -335,11 +273,9 @@ func methodfunc(f *Type, receiver *Type) *Type { ...@@ -335,11 +273,9 @@ func methodfunc(f *Type, receiver *Type) *Type {
return t return t
} }
/* // methods returns the methods of the non-interface type t, sorted by name.
* return methods of non-interface type t, sorted by name. // Generates stub functions as needed.
* generates stub functions as needed. func methods(t *Type) []*Sig {
*/
func methods(t *Type) *Sig {
// method type // method type
mt := methtype(t, 0) mt := methtype(t, 0)
...@@ -357,11 +293,7 @@ func methods(t *Type) *Sig { ...@@ -357,11 +293,7 @@ func methods(t *Type) *Sig {
// make list of methods for t, // make list of methods for t,
// generating code if necessary. // generating code if necessary.
var a *Sig var ms []*Sig
var this *Type
var b *Sig
var method *Sym
for f := mt.Xmethod; f != nil; f = f.Down { for f := mt.Xmethod; f != nil; f = f.Down {
if f.Etype != TFIELD { if f.Etype != TFIELD {
Fatalf("methods: not field %v", f) Fatalf("methods: not field %v", f)
...@@ -376,7 +308,7 @@ func methods(t *Type) *Sig { ...@@ -376,7 +308,7 @@ func methods(t *Type) *Sig {
continue continue
} }
method = f.Sym method := f.Sym
if method == nil { if method == nil {
continue continue
} }
...@@ -385,7 +317,7 @@ func methods(t *Type) *Sig { ...@@ -385,7 +317,7 @@ func methods(t *Type) *Sig {
// if pointer receiver but non-pointer t and // if pointer receiver but non-pointer t and
// this is not an embedded pointer inside a struct, // this is not an embedded pointer inside a struct,
// method does not apply. // method does not apply.
this = getthisx(f.Type).Type.Type this := getthisx(f.Type).Type.Type
if Isptr[this.Etype] && this.Type == t { if Isptr[this.Etype] && this.Type == t {
continue continue
...@@ -394,55 +326,48 @@ func methods(t *Type) *Sig { ...@@ -394,55 +326,48 @@ func methods(t *Type) *Sig {
continue continue
} }
b = new(Sig) var sig Sig
b.link = a ms = append(ms, &sig)
a = b
a.name = method.Name sig.name = method.Name
if !exportname(method.Name) { if !exportname(method.Name) {
if method.Pkg == nil { if method.Pkg == nil {
Fatalf("methods: missing package") Fatalf("methods: missing package")
} }
a.pkg = method.Pkg sig.pkg = method.Pkg
} }
a.isym = methodsym(method, it, 1) sig.isym = methodsym(method, it, 1)
a.tsym = methodsym(method, t, 0) sig.tsym = methodsym(method, t, 0)
a.type_ = methodfunc(f.Type, t) sig.type_ = methodfunc(f.Type, t)
a.mtype = methodfunc(f.Type, nil) sig.mtype = methodfunc(f.Type, nil)
if a.isym.Flags&SymSiggen == 0 { if sig.isym.Flags&SymSiggen == 0 {
a.isym.Flags |= SymSiggen sig.isym.Flags |= SymSiggen
if !Eqtype(this, it) || this.Width < Types[Tptr].Width { if !Eqtype(this, it) || this.Width < Types[Tptr].Width {
compiling_wrappers = 1 compiling_wrappers = 1
genwrapper(it, f, a.isym, 1) genwrapper(it, f, sig.isym, 1)
compiling_wrappers = 0 compiling_wrappers = 0
} }
} }
if a.tsym.Flags&SymSiggen == 0 { if sig.tsym.Flags&SymSiggen == 0 {
a.tsym.Flags |= SymSiggen sig.tsym.Flags |= SymSiggen
if !Eqtype(this, t) { if !Eqtype(this, t) {
compiling_wrappers = 1 compiling_wrappers = 1
genwrapper(t, f, a.tsym, 0) genwrapper(t, f, sig.tsym, 0)
compiling_wrappers = 0 compiling_wrappers = 0
} }
} }
} }
return lsort(a, sigcmp) sort.Sort(byMethodNameAndPackagePath(ms))
return ms
} }
/* // imethods returns the methods of the interface type t, sorted by name.
* return methods of interface type t, sorted by name. func imethods(t *Type) []*Sig {
*/ var methods []*Sig
func imethods(t *Type) *Sig {
var a *Sig
var method *Sym
var isym *Sym
var all *Sig
var last *Sig
for f := t.Type; f != nil; f = f.Down { for f := t.Type; f != nil; f = f.Down {
if f.Etype != TFIELD { if f.Etype != TFIELD {
Fatalf("imethods: not field") Fatalf("imethods: not field")
...@@ -450,29 +375,28 @@ func imethods(t *Type) *Sig { ...@@ -450,29 +375,28 @@ func imethods(t *Type) *Sig {
if f.Type.Etype != TFUNC || f.Sym == nil { if f.Type.Etype != TFUNC || f.Sym == nil {
continue continue
} }
method = f.Sym method := f.Sym
a = new(Sig) var sig = Sig{
a.name = method.Name name: method.Name,
}
if !exportname(method.Name) { if !exportname(method.Name) {
if method.Pkg == nil { if method.Pkg == nil {
Fatalf("imethods: missing package") Fatalf("imethods: missing package")
} }
a.pkg = method.Pkg sig.pkg = method.Pkg
} }
a.mtype = f.Type sig.mtype = f.Type
a.offset = 0 sig.offset = 0
a.type_ = methodfunc(f.Type, nil) sig.type_ = methodfunc(f.Type, nil)
if last != nil && sigcmp(last, a) >= 0 { if n := len(methods); n > 0 {
Fatalf("sigcmp vs sortinter %s %s", last.name, a.name) last := methods[n-1]
} if !(siglt(last, &sig)) {
if last == nil { Fatalf("sigcmp vs sortinter %s %s", last.name, sig.name)
all = a }
} else {
last.link = a
} }
last = a methods = append(methods, &sig)
// Compiler can only refer to wrappers for non-blank methods. // Compiler can only refer to wrappers for non-blank methods.
if isblanksym(method) { if isblanksym(method) {
...@@ -483,7 +407,7 @@ func imethods(t *Type) *Sig { ...@@ -483,7 +407,7 @@ func imethods(t *Type) *Sig {
// IfaceType.Method is not in the reflect data. // IfaceType.Method is not in the reflect data.
// Generate the method body, so that compiled // Generate the method body, so that compiled
// code can refer to it. // code can refer to it.
isym = methodsym(method, t, 0) isym := methodsym(method, t, 0)
if isym.Flags&SymSiggen == 0 { if isym.Flags&SymSiggen == 0 {
isym.Flags |= SymSiggen isym.Flags |= SymSiggen
...@@ -491,7 +415,7 @@ func imethods(t *Type) *Sig { ...@@ -491,7 +415,7 @@ func imethods(t *Type) *Sig {
} }
} }
return all return methods
} }
var dimportpath_gopkg *Pkg var dimportpath_gopkg *Pkg
...@@ -559,7 +483,7 @@ func dgopkgpath(s *Sym, ot int, pkg *Pkg) int { ...@@ -559,7 +483,7 @@ func dgopkgpath(s *Sym, ot int, pkg *Pkg) int {
*/ */
func dextratype(sym *Sym, off int, t *Type, ptroff int) int { func dextratype(sym *Sym, off int, t *Type, ptroff int) int {
m := methods(t) m := methods(t)
if t.Sym == nil && m == nil { if t.Sym == nil && len(m) == 0 {
return off return off
} }
...@@ -568,10 +492,8 @@ func dextratype(sym *Sym, off int, t *Type, ptroff int) int { ...@@ -568,10 +492,8 @@ func dextratype(sym *Sym, off int, t *Type, ptroff int) int {
dsymptr(sym, ptroff, sym, off) dsymptr(sym, ptroff, sym, off)
n := 0 for _, a := range m {
for a := m; a != nil; a = a.link {
dtypesym(a.type_) dtypesym(a.type_)
n++
} }
ot := off ot := off
...@@ -591,11 +513,12 @@ func dextratype(sym *Sym, off int, t *Type, ptroff int) int { ...@@ -591,11 +513,12 @@ func dextratype(sym *Sym, off int, t *Type, ptroff int) int {
// slice header // slice header
ot = dsymptr(s, ot, s, ot+Widthptr+2*Widthint) ot = dsymptr(s, ot, s, ot+Widthptr+2*Widthint)
n := len(m)
ot = duintxx(s, ot, uint64(n), Widthint) ot = duintxx(s, ot, uint64(n), Widthint)
ot = duintxx(s, ot, uint64(n), Widthint) ot = duintxx(s, ot, uint64(n), Widthint)
// methods // methods
for a := m; a != nil; a = a.link { for _, a := range m {
// method // method
// ../../runtime/type.go:/method // ../../runtime/type.go:/method
ot = dgostringptr(s, ot, a.name) ot = dgostringptr(s, ot, a.name)
...@@ -1171,28 +1094,27 @@ ok: ...@@ -1171,28 +1094,27 @@ ok:
case TINTER: case TINTER:
m := imethods(t) m := imethods(t)
n := 0 n := len(m)
for a := m; a != nil; a = a.link { for _, a := range m {
dtypesym(a.type_) dtypesym(a.type_)
n++
} }
// ../../runtime/type.go:/InterfaceType // ../../../runtime/type.go:/InterfaceType
ot = dcommontype(s, ot, t) ot = dcommontype(s, ot, t)
xt = ot - 2*Widthptr xt = ot - 2*Widthptr
ot = dsymptr(s, ot, s, ot+Widthptr+2*Widthint) ot = dsymptr(s, ot, s, ot+Widthptr+2*Widthint)
ot = duintxx(s, ot, uint64(n), Widthint) ot = duintxx(s, ot, uint64(n), Widthint)
ot = duintxx(s, ot, uint64(n), Widthint) ot = duintxx(s, ot, uint64(n), Widthint)
for a := m; a != nil; a = a.link { for _, a := range m {
// ../../runtime/type.go:/imethod // ../../../runtime/type.go:/imethod
ot = dgostringptr(s, ot, a.name) ot = dgostringptr(s, ot, a.name)
ot = dgopkgpath(s, ot, a.pkg) ot = dgopkgpath(s, ot, a.pkg)
ot = dsymptr(s, ot, dtypesym(a.type_), 0) ot = dsymptr(s, ot, dtypesym(a.type_), 0)
} }
// ../../runtime/type.go:/MapType // ../../../runtime/type.go:/MapType
case TMAP: case TMAP:
s1 := dtypesym(t.Down) s1 := dtypesym(t.Down)
......
// Copyright 2015 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 gc
import (
"reflect"
"sort"
"testing"
)
func TestSortingByMethodNameAndPackagePath(t *testing.T) {
data := []*Sig{
&Sig{name: "b", pkg: &Pkg{Path: "abc"}},
&Sig{name: "b", pkg: nil},
&Sig{name: "c", pkg: nil},
&Sig{name: "c", pkg: &Pkg{Path: "uvw"}},
&Sig{name: "c", pkg: nil},
&Sig{name: "b", pkg: &Pkg{Path: "xyz"}},
&Sig{name: "a", pkg: &Pkg{Path: "abc"}},
&Sig{name: "b", pkg: nil},
}
want := []*Sig{
&Sig{name: "a", pkg: &Pkg{Path: "abc"}},
&Sig{name: "b", pkg: nil},
&Sig{name: "b", pkg: nil},
&Sig{name: "b", pkg: &Pkg{Path: "abc"}},
&Sig{name: "b", pkg: &Pkg{Path: "xyz"}},
&Sig{name: "c", pkg: nil},
&Sig{name: "c", pkg: nil},
&Sig{name: "c", pkg: &Pkg{Path: "uvw"}},
}
if len(data) != len(want) {
t.Fatal("want and data must match")
}
if reflect.DeepEqual(data, want) {
t.Fatal("data must be shuffled")
}
sort.Sort(byMethodNameAndPackagePath(data))
if !reflect.DeepEqual(data, want) {
t.Logf("want: %#v", want)
t.Logf("data: %#v", data)
t.Errorf("sorting failed")
}
}
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment