mirror of
https://github.com/golang/go.git
synced 2025-12-08 06:10:04 +00:00
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/14559 Reviewed-by: Dave Cheney <dave@cheney.net>
This commit is contained in:
parent
ebd96933c1
commit
bca70a66a7
3 changed files with 117 additions and 149 deletions
|
|
@ -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 (
|
||||||
"cmd/internal/obj"
|
"cmd/internal/obj"
|
||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
|
"sort"
|
||||||
)
|
)
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
@ -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)
|
return 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
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
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 {
|
||||||
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 {
|
||||||
|
|
||||||
// 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 {
|
||||||
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 {
|
||||||
// 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 {
|
||||||
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 {
|
||||||
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)) {
|
||||||
|
Fatalf("sigcmp vs sortinter %s %s", last.name, sig.name)
|
||||||
}
|
}
|
||||||
if last == nil {
|
|
||||||
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 {
|
||||||
// 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 {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
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 {
|
||||||
*/
|
*/
|
||||||
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 {
|
||||||
|
|
||||||
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 {
|
||||||
// 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:
|
||||||
|
|
||||||
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)
|
||||||
|
|
||||||
|
|
|
||||||
47
src/cmd/compile/internal/gc/reflect_test.go
Normal file
47
src/cmd/compile/internal/gc/reflect_test.go
Normal file
|
|
@ -0,0 +1,47 @@
|
||||||
|
// 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")
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
Loading…
Add table
Add a link
Reference in a new issue