Commit 0a338f75 authored by Russ Cox's avatar Russ Cox Committed by Brad Fitzpatrick

sort: simplify bootstrap

We compile package sort as part of the compiler bootstrap,
to make sure the compiler uses a consistent sort algorithm
no matter what version of Go it is compiled against.
(This matters for elements that compare "equal" but are distinguishable.)

Package sort was compiled in such a way as to disallow
sort.Slice entirely during bootstrap (at least with some compilers),
while cmd/internal/obj was compiled in such a way as to
make obj.SortSlice available to all compilers, precisely because
sort.Slice was not. This is all highly confusing.
Simplify by making sort.Slice available all the time.

Followup to CL 169137 and #30440
(and also CL 40114 and CL 73951).

Change-Id: I127f4e02d6c71392805d256c3a90ef7c51f9ba0c
Reviewed-on: https://go-review.googlesource.com/c/go/+/174525
Run-TryBot: Russ Cox <rsc@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: default avatarBrad Fitzpatrick <bradfitz@golang.org>
parent d2765de8
...@@ -202,12 +202,12 @@ import ( ...@@ -202,12 +202,12 @@ import (
"bufio" "bufio"
"bytes" "bytes"
"cmd/compile/internal/types" "cmd/compile/internal/types"
"cmd/internal/obj"
"cmd/internal/src" "cmd/internal/src"
"encoding/binary" "encoding/binary"
"fmt" "fmt"
"io" "io"
"math/big" "math/big"
"sort"
"strings" "strings"
) )
...@@ -321,12 +321,12 @@ func (w *exportWriter) writeIndex(index map[*Node]uint64, mainIndex bool) { ...@@ -321,12 +321,12 @@ func (w *exportWriter) writeIndex(index map[*Node]uint64, mainIndex bool) {
for pkg, objs := range pkgObjs { for pkg, objs := range pkgObjs {
pkgs = append(pkgs, pkg) pkgs = append(pkgs, pkg)
obj.SortSlice(objs, func(i, j int) bool { sort.Slice(objs, func(i, j int) bool {
return objs[i].Sym.Name < objs[j].Sym.Name return objs[i].Sym.Name < objs[j].Sym.Name
}) })
} }
obj.SortSlice(pkgs, func(i, j int) bool { sort.Slice(pkgs, func(i, j int) bool {
return pkgs[i].Path < pkgs[j].Path return pkgs[i].Path < pkgs[j].Path
}) })
......
...@@ -27,6 +27,7 @@ import ( ...@@ -27,6 +27,7 @@ import (
"path" "path"
"regexp" "regexp"
"runtime" "runtime"
"sort"
"strconv" "strconv"
"strings" "strings"
) )
...@@ -723,7 +724,7 @@ func Main(archInit func(*Arch)) { ...@@ -723,7 +724,7 @@ func Main(archInit func(*Arch)) {
} }
// Check whether any of the functions we have compiled have gigantic stack frames. // Check whether any of the functions we have compiled have gigantic stack frames.
obj.SortSlice(largeStackFrames, func(i, j int) bool { sort.Slice(largeStackFrames, func(i, j int) bool {
return largeStackFrames[i].pos.Before(largeStackFrames[j].pos) return largeStackFrames[i].pos.Before(largeStackFrames[j].pos)
}) })
for _, large := range largeStackFrames { for _, large := range largeStackFrames {
...@@ -1313,7 +1314,7 @@ func clearImports() { ...@@ -1313,7 +1314,7 @@ func clearImports() {
} }
} }
obj.SortSlice(unused, func(i, j int) bool { return unused[i].pos.Before(unused[j].pos) }) sort.Slice(unused, func(i, j int) bool { return unused[i].pos.Before(unused[j].pos) })
for _, pkg := range unused { for _, pkg := range unused {
pkgnotused(pkg.pos, pkg.path, pkg.name) pkgnotused(pkg.pos, pkg.path, pkg.name)
} }
......
...@@ -14,6 +14,7 @@ import ( ...@@ -14,6 +14,7 @@ import (
"encoding/json" "encoding/json"
"fmt" "fmt"
"io" "io"
"sort"
"strconv" "strconv"
) )
...@@ -259,7 +260,7 @@ func dumpglobls() { ...@@ -259,7 +260,7 @@ func dumpglobls() {
} }
} }
obj.SortSlice(funcsyms, func(i, j int) bool { sort.Slice(funcsyms, func(i, j int) bool {
return funcsyms[i].LinksymName() < funcsyms[j].LinksymName() return funcsyms[i].LinksymName() < funcsyms[j].LinksymName()
}) })
for _, s := range funcsyms { for _, s := range funcsyms {
......
...@@ -348,7 +348,7 @@ func compileFunctions() { ...@@ -348,7 +348,7 @@ func compileFunctions() {
// Compile the longest functions first, // Compile the longest functions first,
// since they're most likely to be the slowest. // since they're most likely to be the slowest.
// This helps avoid stragglers. // This helps avoid stragglers.
obj.SortSlice(compilequeue, func(i, j int) bool { sort.Slice(compilequeue, func(i, j int) bool {
return compilequeue[i].Nbody.Len() > compilequeue[j].Nbody.Len() return compilequeue[i].Nbody.Len() > compilequeue[j].Nbody.Len()
}) })
} }
......
...@@ -6,8 +6,8 @@ package types_test ...@@ -6,8 +6,8 @@ package types_test
import ( import (
"cmd/compile/internal/types" "cmd/compile/internal/types"
"cmd/internal/obj"
"reflect" "reflect"
"sort"
"testing" "testing"
) )
...@@ -50,7 +50,7 @@ func TestSymLess(t *testing.T) { ...@@ -50,7 +50,7 @@ func TestSymLess(t *testing.T) {
if reflect.DeepEqual(data, want) { if reflect.DeepEqual(data, want) {
t.Fatal("data must be shuffled") t.Fatal("data must be shuffled")
} }
obj.SortSlice(data, func(i, j int) bool { return data[i].Less(data[j]) }) sort.Slice(data, func(i, j int) bool { return data[i].Less(data[j]) })
if !reflect.DeepEqual(data, want) { if !reflect.DeepEqual(data, want) {
t.Logf("want: %#v", want) t.Logf("want: %#v", want)
t.Logf("data: %#v", data) t.Logf("data: %#v", data)
......
// Copyright 2017 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.
// +build !go1.8
package obj
import (
"reflect"
"sort"
)
func SortSlice(slice interface{}, less func(i, j int) bool) {
val := reflect.ValueOf(slice)
tmp := reflect.New(val.Type().Elem()).Elem()
x := sliceByFn{val: val, tmp: tmp, less: less}
sort.Sort(x)
}
type sliceByFn struct {
val reflect.Value
tmp reflect.Value
less func(i, j int) bool
}
func (x sliceByFn) Len() int { return x.val.Len() }
func (x sliceByFn) Less(i, j int) bool { return x.less(i, j) }
func (x sliceByFn) Swap(i, j int) {
a, b := x.val.Index(i), x.val.Index(j)
x.tmp.Set(a)
a.Set(b)
b.Set(x.tmp)
}
...@@ -104,7 +104,7 @@ func WriteObjFile(ctxt *Link, b *bufio.Writer) { ...@@ -104,7 +104,7 @@ func WriteObjFile(ctxt *Link, b *bufio.Writer) {
// As they are created during Progedit, two symbols can be switched between // As they are created during Progedit, two symbols can be switched between
// two different compilations. Therefore, BuildID will be different. // two different compilations. Therefore, BuildID will be different.
// TODO: find a better place and optimize to only sort TOC symbols // TODO: find a better place and optimize to only sort TOC symbols
SortSlice(ctxt.Data, func(i, j int) bool { sort.Slice(ctxt.Data, func(i, j int) bool {
return ctxt.Data[i].Name < ctxt.Data[j].Name return ctxt.Data[i].Name < ctxt.Data[j].Name
}) })
} }
......
...@@ -586,9 +586,8 @@ func findImports(pkg string) ([]string, error) { ...@@ -586,9 +586,8 @@ func findImports(pkg string) ([]string, error) {
var haveImport = map[string]bool{} var haveImport = map[string]bool{}
for _, file := range files { for _, file := range files {
name := file.Name() name := file.Name()
if name == "slice_pre113.go" { if name == "slice_go14.go" || name == "slice_go18.go" {
// This file is ignored by build tags which aren't // These files are for compiler bootstrap with older versions of Go and not built in the standard build.
// handled by this findImports func.
continue continue
} }
if !strings.HasSuffix(name, ".go") || strings.HasSuffix(name, "_test.go") { if !strings.HasSuffix(name, ".go") || strings.HasSuffix(name, "_test.go") {
......
...@@ -2,14 +2,8 @@ ...@@ -2,14 +2,8 @@
// Use of this source code is governed by a BSD-style // Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
// +build !compiler_bootstrap go1.13
package sort package sort
import (
"internal/reflectlite"
)
// Slice sorts the provided slice given the provided less function. // Slice sorts the provided slice given the provided less function.
// //
// The sort is not guaranteed to be stable. For a stable sort, use // The sort is not guaranteed to be stable. For a stable sort, use
...@@ -17,8 +11,8 @@ import ( ...@@ -17,8 +11,8 @@ import (
// //
// The function panics if the provided interface is not a slice. // The function panics if the provided interface is not a slice.
func Slice(slice interface{}, less func(i, j int) bool) { func Slice(slice interface{}, less func(i, j int) bool) {
rv := reflectlite.ValueOf(slice) rv := reflectValueOf(slice)
swap := reflectlite.Swapper(slice) swap := reflectSwapper(slice)
length := rv.Len() length := rv.Len()
quickSort_func(lessSwap{less, swap}, 0, length, maxDepth(length)) quickSort_func(lessSwap{less, swap}, 0, length, maxDepth(length))
} }
...@@ -28,8 +22,8 @@ func Slice(slice interface{}, less func(i, j int) bool) { ...@@ -28,8 +22,8 @@ func Slice(slice interface{}, less func(i, j int) bool) {
// //
// The function panics if the provided interface is not a slice. // The function panics if the provided interface is not a slice.
func SliceStable(slice interface{}, less func(i, j int) bool) { func SliceStable(slice interface{}, less func(i, j int) bool) {
rv := reflectlite.ValueOf(slice) rv := reflectValueOf(slice)
swap := reflectlite.Swapper(slice) swap := reflectSwapper(slice)
stable_func(lessSwap{less, swap}, rv.Len()) stable_func(lessSwap{less, swap}, rv.Len())
} }
...@@ -37,7 +31,7 @@ func SliceStable(slice interface{}, less func(i, j int) bool) { ...@@ -37,7 +31,7 @@ func SliceStable(slice interface{}, less func(i, j int) bool) {
// //
// The function panics if the provided interface is not a slice. // The function panics if the provided interface is not a slice.
func SliceIsSorted(slice interface{}, less func(i, j int) bool) bool { func SliceIsSorted(slice interface{}, less func(i, j int) bool) bool {
rv := reflectlite.ValueOf(slice) rv := reflectValueOf(slice)
n := rv.Len() n := rv.Len()
for i := n - 1; i > 0; i-- { for i := n - 1; i > 0; i-- {
if less(i, i-1) { if less(i, i-1) {
......
// Copyright 2017 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.
// +build go1.13
package sort
import "internal/reflectlite"
var reflectValueOf = reflectlite.ValueOf
var reflectSwapper = reflectlite.Swapper
// Copyright 2017 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.
// +build !go1.8
package sort
import "reflect"
var reflectValueOf = reflect.ValueOf
func reflectSwapper(x interface{}) func(int, int) {
v := reflectValueOf(x)
tmp := reflect.New(v.Type().Elem()).Elem()
return func(i, j int) {
a, b := v.Index(i), v.Index(j)
tmp.Set(a)
a.Set(b)
b.Set(tmp)
}
}
...@@ -2,12 +2,11 @@ ...@@ -2,12 +2,11 @@
// Use of this source code is governed by a BSD-style // Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
// +build go1.8 // +build go1.8,!go1.13
package obj package sort
import "sort" import "reflect"
func SortSlice(slice interface{}, less func(i, j int) bool) { var reflectValueOf = reflect.ValueOf
sort.Slice(slice, less) var reflectSwapper = reflect.Swapper
}
// Copyright 2017 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.
// +build go1.8,!go1.13
package sort
import "reflect"
// Slice sorts the provided slice given the provided less function.
//
// The sort is not guaranteed to be stable. For a stable sort, use
// SliceStable.
//
// The function panics if the provided interface is not a slice.
func Slice(slice interface{}, less func(i, j int) bool) {
rv := reflect.ValueOf(slice)
swap := reflect.Swapper(slice)
length := rv.Len()
quickSort_func(lessSwap{less, swap}, 0, length, maxDepth(length))
}
// SliceStable sorts the provided slice given the provided less
// function while keeping the original order of equal elements.
//
// The function panics if the provided interface is not a slice.
func SliceStable(slice interface{}, less func(i, j int) bool) {
rv := reflect.ValueOf(slice)
swap := reflect.Swapper(slice)
stable_func(lessSwap{less, swap}, rv.Len())
}
// SliceIsSorted tests whether a slice is sorted.
//
// The function panics if the provided interface is not a slice.
func SliceIsSorted(slice interface{}, less func(i, j int) bool) bool {
rv := reflect.ValueOf(slice)
n := rv.Len()
for i := n - 1; i > 0; i-- {
if less(i, i-1) {
return false
}
}
return true
}
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