]> Cypherpunks repositories - gostls13.git/commitdiff
cmd/compile/internal/gc: use sort.Interface for reflect methods
authorHÃ¥vard Haugen <havard.haugen@gmail.com>
Mon, 14 Sep 2015 22:16:35 +0000 (00:16 +0200)
committerDave Cheney <dave@cheney.net>
Mon, 21 Sep 2015 22:27:53 +0000 (22:27 +0000)
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>
src/cmd/compile/internal/gc/go.go
src/cmd/compile/internal/gc/reflect.go
src/cmd/compile/internal/gc/reflect_test.go [new file with mode: 0644]

index 5d7c3d63f194daab148bd01a4c1086914b2bcb1c..777c560bc1fa0815fd50ea2b0ed360224ff61974 100644 (file)
@@ -376,7 +376,6 @@ type Sig struct {
        type_  *Type
        mtype  *Type
        offset int32
-       link   *Sig
 }
 
 type Io struct {
index baac7f71cb182e8b86183c58794737f441d13d4f..e7138d9c58858c7cac7e22ec65b34880bdddf02d 100644 (file)
@@ -9,6 +9,7 @@ import (
        "cmd/internal/obj"
        "fmt"
        "os"
+       "sort"
 )
 
 /*
@@ -16,93 +17,30 @@ import (
  */
 var signatlist *NodeList
 
-func sigcmp(a *Sig, b *Sig) int {
-       i := stringsCompare(a.name, b.name)
-       if i != 0 {
-               return i
+// byMethodNameAndPackagePath sorts method signatures by name, then package path.
+type byMethodNameAndPackagePath []*Sig
+
+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 {
-               return 0
+               return false
        }
        if a.pkg == nil {
-               return -1
+               return true
        }
        if b.pkg == nil {
-               return +1
-       }
-       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 false
        }
-
-       le.link = nil
-       return l
+       return a.pkg.Path < b.pkg.Path
 }
 
 // Builds a type representing a Bucket structure for
@@ -335,11 +273,9 @@ func methodfunc(f *Type, receiver *Type) *Type {
        return t
 }
 
-/*
- * return methods of non-interface type t, sorted by name.
- * generates stub functions as needed.
- */
-func methods(t *Type) *Sig {
+// methods returns the methods of the non-interface type t, sorted by name.
+// Generates stub functions as needed.
+func methods(t *Type) []*Sig {
        // method type
        mt := methtype(t, 0)
 
@@ -357,11 +293,7 @@ func methods(t *Type) *Sig {
 
        // make list of methods for t,
        // generating code if necessary.
-       var a *Sig
-
-       var this *Type
-       var b *Sig
-       var method *Sym
+       var ms []*Sig
        for f := mt.Xmethod; f != nil; f = f.Down {
                if f.Etype != TFIELD {
                        Fatalf("methods: not field %v", f)
@@ -376,7 +308,7 @@ func methods(t *Type) *Sig {
                        continue
                }
 
-               method = f.Sym
+               method := f.Sym
                if method == nil {
                        continue
                }
@@ -385,7 +317,7 @@ func methods(t *Type) *Sig {
                // if pointer receiver but non-pointer t and
                // this is not an embedded pointer inside a struct,
                // method does not apply.
-               this = getthisx(f.Type).Type.Type
+               this := getthisx(f.Type).Type.Type
 
                if Isptr[this.Etype] && this.Type == t {
                        continue
@@ -394,55 +326,48 @@ func methods(t *Type) *Sig {
                        continue
                }
 
-               b = new(Sig)
-               b.link = a
-               a = b
+               var sig Sig
+               ms = append(ms, &sig)
 
-               a.name = method.Name
+               sig.name = method.Name
                if !exportname(method.Name) {
                        if method.Pkg == nil {
                                Fatalf("methods: missing package")
                        }
-                       a.pkg = method.Pkg
+                       sig.pkg = method.Pkg
                }
 
-               a.isym = methodsym(method, it, 1)
-               a.tsym = methodsym(method, t, 0)
-               a.type_ = methodfunc(f.Type, t)
-               a.mtype = methodfunc(f.Type, nil)
+               sig.isym = methodsym(method, it, 1)
+               sig.tsym = methodsym(method, t, 0)
+               sig.type_ = methodfunc(f.Type, t)
+               sig.mtype = methodfunc(f.Type, nil)
 
-               if a.isym.Flags&SymSiggen == 0 {
-                       a.isym.Flags |= SymSiggen
+               if sig.isym.Flags&SymSiggen == 0 {
+                       sig.isym.Flags |= SymSiggen
                        if !Eqtype(this, it) || this.Width < Types[Tptr].Width {
                                compiling_wrappers = 1
-                               genwrapper(it, f, a.isym, 1)
+                               genwrapper(it, f, sig.isym, 1)
                                compiling_wrappers = 0
                        }
                }
 
-               if a.tsym.Flags&SymSiggen == 0 {
-                       a.tsym.Flags |= SymSiggen
+               if sig.tsym.Flags&SymSiggen == 0 {
+                       sig.tsym.Flags |= SymSiggen
                        if !Eqtype(this, t) {
                                compiling_wrappers = 1
-                               genwrapper(t, f, a.tsym, 0)
+                               genwrapper(t, f, sig.tsym, 0)
                                compiling_wrappers = 0
                        }
                }
        }
 
-       return lsort(a, sigcmp)
+       sort.Sort(byMethodNameAndPackagePath(ms))
+       return ms
 }
 
-/*
- * return methods of interface type t, sorted by name.
- */
-func imethods(t *Type) *Sig {
-       var a *Sig
-       var method *Sym
-       var isym *Sym
-
-       var all *Sig
-       var last *Sig
+// imethods returns the methods of the interface type t, sorted by name.
+func imethods(t *Type) []*Sig {
+       var methods []*Sig
        for f := t.Type; f != nil; f = f.Down {
                if f.Etype != TFIELD {
                        Fatalf("imethods: not field")
@@ -450,29 +375,28 @@ func imethods(t *Type) *Sig {
                if f.Type.Etype != TFUNC || f.Sym == nil {
                        continue
                }
-               method = f.Sym
-               a = new(Sig)
-               a.name = method.Name
+               method := f.Sym
+               var sig = Sig{
+                       name: method.Name,
+               }
                if !exportname(method.Name) {
                        if method.Pkg == nil {
                                Fatalf("imethods: missing package")
                        }
-                       a.pkg = method.Pkg
+                       sig.pkg = method.Pkg
                }
 
-               a.mtype = f.Type
-               a.offset = 0
-               a.type_ = methodfunc(f.Type, nil)
+               sig.mtype = f.Type
+               sig.offset = 0
+               sig.type_ = methodfunc(f.Type, nil)
 
-               if last != nil && sigcmp(last, a) >= 0 {
-                       Fatalf("sigcmp vs sortinter %s %s", last.name, a.name)
-               }
-               if last == nil {
-                       all = a
-               } else {
-                       last.link = a
+               if n := len(methods); n > 0 {
+                       last := methods[n-1]
+                       if !(siglt(last, &sig)) {
+                               Fatalf("sigcmp vs sortinter %s %s", last.name, sig.name)
+                       }
                }
-               last = a
+               methods = append(methods, &sig)
 
                // Compiler can only refer to wrappers for non-blank methods.
                if isblanksym(method) {
@@ -483,7 +407,7 @@ func imethods(t *Type) *Sig {
                // IfaceType.Method is not in the reflect data.
                // Generate the method body, so that compiled
                // code can refer to it.
-               isym = methodsym(method, t, 0)
+               isym := methodsym(method, t, 0)
 
                if isym.Flags&SymSiggen == 0 {
                        isym.Flags |= SymSiggen
@@ -491,7 +415,7 @@ func imethods(t *Type) *Sig {
                }
        }
 
-       return all
+       return methods
 }
 
 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 {
        m := methods(t)
-       if t.Sym == nil && m == nil {
+       if t.Sym == nil && len(m) == 0 {
                return off
        }
 
@@ -568,10 +492,8 @@ func dextratype(sym *Sym, off int, t *Type, ptroff int) int {
 
        dsymptr(sym, ptroff, sym, off)
 
-       n := 0
-       for a := m; a != nil; a = a.link {
+       for _, a := range m {
                dtypesym(a.type_)
-               n++
        }
 
        ot := off
@@ -591,11 +513,12 @@ func dextratype(sym *Sym, off int, t *Type, ptroff int) int {
        // slice header
        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)
 
        // methods
-       for a := m; a != nil; a = a.link {
+       for _, a := range m {
                // method
                // ../../runtime/type.go:/method
                ot = dgostringptr(s, ot, a.name)
@@ -1171,28 +1094,27 @@ ok:
 
        case TINTER:
                m := imethods(t)
-               n := 0
-               for a := m; a != nil; a = a.link {
+               n := len(m)
+               for _, a := range m {
                        dtypesym(a.type_)
-                       n++
                }
 
-               // ../../runtime/type.go:/InterfaceType
+               // ../../../runtime/type.go:/InterfaceType
                ot = dcommontype(s, ot, t)
 
                xt = ot - 2*Widthptr
                ot = dsymptr(s, ot, s, ot+Widthptr+2*Widthint)
                ot = duintxx(s, ot, uint64(n), Widthint)
                ot = duintxx(s, ot, uint64(n), Widthint)
-               for a := m; a != nil; a = a.link {
-                       // ../../runtime/type.go:/imethod
+               for _, a := range m {
+                       // ../../../runtime/type.go:/imethod
                        ot = dgostringptr(s, ot, a.name)
 
                        ot = dgopkgpath(s, ot, a.pkg)
                        ot = dsymptr(s, ot, dtypesym(a.type_), 0)
                }
 
-               // ../../runtime/type.go:/MapType
+               // ../../../runtime/type.go:/MapType
        case TMAP:
                s1 := dtypesym(t.Down)
 
diff --git a/src/cmd/compile/internal/gc/reflect_test.go b/src/cmd/compile/internal/gc/reflect_test.go
new file mode 100644 (file)
index 0000000..9e39933
--- /dev/null
@@ -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")
+       }
+
+}