diff --git a/src/cmd/compile/internal/compare/compare.go b/src/cmd/compile/internal/compare/compare.go index 638eb37a622109..8517c053a1dd04 100644 --- a/src/cmd/compile/internal/compare/compare.go +++ b/src/cmd/compile/internal/compare/compare.go @@ -13,7 +13,7 @@ import ( "cmd/compile/internal/types" "fmt" "math/bits" - "sort" + "slices" ) // IsRegularMemory reports whether t can be compared/hashed as regular memory. @@ -236,8 +236,14 @@ func EqStruct(t *types.Type, np, nq ir.Node) ([]ir.Node, bool) { isCall := func(n ir.Node) bool { return n.Op() == ir.OCALL || n.Op() == ir.OCALLFUNC } - sort.SliceStable(c, func(i, j int) bool { - return !isCall(c[i]) && isCall(c[j]) + slices.SortStableFunc(c, func(a, b ir.Node) int { + if isCall(a) && !isCall(b) { + return +1 + } + if !isCall(a) && isCall(b) { + return -1 + } + return 0 }) flatConds = append(flatConds, c...) } diff --git a/src/cmd/compile/internal/dwarfgen/scope_test.go b/src/cmd/compile/internal/dwarfgen/scope_test.go index ee4170ef44fe11..c231a08c069e34 100644 --- a/src/cmd/compile/internal/dwarfgen/scope_test.go +++ b/src/cmd/compile/internal/dwarfgen/scope_test.go @@ -12,7 +12,7 @@ import ( "os" "path/filepath" "runtime" - "sort" + "slices" "strconv" "strings" "testing" @@ -400,8 +400,8 @@ func readScope(ctxt *scopexplainContext, scope *lexblock, entry *dwarf.Entry) { } switch e.Tag { case 0: - sort.Slice(scope.vars, func(i, j int) bool { - return scope.vars[i].expr < scope.vars[j].expr + slices.SortFunc(scope.vars, func(a, b variable) int { + return strings.Compare(a.expr, b.expr) }) return case dwarf.TagFormalParameter: diff --git a/src/cmd/compile/internal/gc/compile.go b/src/cmd/compile/internal/gc/compile.go index 5ade700d46756d..433324a892778a 100644 --- a/src/cmd/compile/internal/gc/compile.go +++ b/src/cmd/compile/internal/gc/compile.go @@ -5,9 +5,10 @@ package gc import ( + "cmp" "internal/race" "math/rand" - "sort" + "slices" "sync" "cmd/compile/internal/base" @@ -131,8 +132,8 @@ func compileFunctions(profile *pgoir.Profile) { // Compile the longest functions first, // since they're most likely to be the slowest. // This helps avoid stragglers. - sort.Slice(compilequeue, func(i, j int) bool { - return len(compilequeue[i].Body) > len(compilequeue[j].Body) + slices.SortFunc(compilequeue, func(a, b *ir.Func) int { + return cmp.Compare(len(a.Body), len(b.Body)) }) } diff --git a/src/cmd/compile/internal/inline/inlheur/analyze.go b/src/cmd/compile/internal/inline/inlheur/analyze.go index 9ed7d73af98222..a53af69bc5a58a 100644 --- a/src/cmd/compile/internal/inline/inlheur/analyze.go +++ b/src/cmd/compile/internal/inline/inlheur/analyze.go @@ -8,13 +8,14 @@ import ( "cmd/compile/internal/base" "cmd/compile/internal/ir" "cmd/compile/internal/types" + "cmp" "encoding/json" "fmt" "internal/buildcfg" "io" "os" "path/filepath" - "sort" + "slices" "strings" ) @@ -349,11 +350,11 @@ func dumpFnPreamble(w io.Writer, funcInlHeur *fnInlHeur, ecst encodedCallSiteTab // sortFnInlHeurSlice sorts a slice of fnInlHeur based on // the starting line of the function definition, then by name. func sortFnInlHeurSlice(sl []fnInlHeur) []fnInlHeur { - sort.SliceStable(sl, func(i, j int) bool { - if sl[i].line != sl[j].line { - return sl[i].line < sl[j].line + slices.SortStableFunc(sl, func(i, j fnInlHeur) int { + if r := cmp.Compare(i.line, j.line); r != 0 { + return r } - return sl[i].fname < sl[j].fname + return strings.Compare(i.fname, j.fname) }) return sl } diff --git a/src/cmd/compile/internal/inline/inlheur/scoring.go b/src/cmd/compile/internal/inline/inlheur/scoring.go index c49c087a6298fd..8181dab22b4e1a 100644 --- a/src/cmd/compile/internal/inline/inlheur/scoring.go +++ b/src/cmd/compile/internal/inline/inlheur/scoring.go @@ -9,9 +9,10 @@ import ( "cmd/compile/internal/ir" "cmd/compile/internal/pgoir" "cmd/compile/internal/types" + "cmp" "fmt" "os" - "sort" + "slices" "strconv" "strings" ) @@ -504,8 +505,8 @@ func (csa *callSiteAnalyzer) scoreCallsRegion(fn *ir.Func, region ir.Nodes, csta csl = append(csl, cs) } scoreCallsCache.csl = csl[:0] - sort.Slice(csl, func(i, j int) bool { - return csl[i].ID < csl[j].ID + slices.SortFunc(csl, func(a, b *CallSite) int { + return cmp.Compare(a.ID, b.ID) }) // Score each call site. @@ -700,18 +701,18 @@ func DumpInlCallSiteScores(profile *pgoir.Profile, budgetCallback func(fn *ir.Fu for _, cs := range allCallSites { sl = append(sl, cs) } - sort.Slice(sl, func(i, j int) bool { - if sl[i].Score != sl[j].Score { - return sl[i].Score < sl[j].Score + slices.SortFunc(sl, func(a, b *CallSite) int { + if a.Score != b.Score { + return cmp.Compare(a.Score, b.Score) } - fni := ir.PkgFuncName(sl[i].Callee) - fnj := ir.PkgFuncName(sl[j].Callee) - if fni != fnj { - return fni < fnj + fni := ir.PkgFuncName(a.Callee) + fnj := ir.PkgFuncName(b.Callee) + if r := strings.Compare(fni, fnj); r != 0 { + return r } - ecsi := EncodeCallSiteKey(sl[i]) - ecsj := EncodeCallSiteKey(sl[j]) - return ecsi < ecsj + ecsi := EncodeCallSiteKey(a) + ecsj := EncodeCallSiteKey(b) + return strings.Compare(ecsi, ecsj) }) mkname := func(fn *ir.Func) string { diff --git a/src/cmd/compile/internal/ir/mknode.go b/src/cmd/compile/internal/ir/mknode.go index ee9746689aace8..e5df481a2d431e 100644 --- a/src/cmd/compile/internal/ir/mknode.go +++ b/src/cmd/compile/internal/ir/mknode.go @@ -19,7 +19,7 @@ import ( "io/fs" "log" "os" - "sort" + "slices" "strings" ) @@ -143,8 +143,8 @@ func main() { } } // Sort for deterministic output. - sort.Slice(concreteNodes, func(i, j int) bool { - return concreteNodes[i].Name.Name < concreteNodes[j].Name.Name + slices.SortFunc(concreteNodes, func(a, b *ast.TypeSpec) int { + return strings.Compare(a.Name.Name, b.Name.Name) }) // Generate code for each concrete type. for _, t := range concreteNodes { diff --git a/src/cmd/compile/internal/liveness/mergelocals.go b/src/cmd/compile/internal/liveness/mergelocals.go index d0675128b8f53e..81a0d1c11fc4da 100644 --- a/src/cmd/compile/internal/liveness/mergelocals.go +++ b/src/cmd/compile/internal/liveness/mergelocals.go @@ -10,10 +10,11 @@ import ( "cmd/compile/internal/ir" "cmd/compile/internal/ssa" "cmd/internal/src" + "cmp" "fmt" "os" "path/filepath" - "sort" + "slices" "strings" ) @@ -160,8 +161,8 @@ func (mls *MergeLocalsState) Followers(n *ir.Name, tmp []*ir.Name) []*ir.Name { for _, k := range sl[1:] { tmp = append(tmp, mls.vars[k]) } - sort.SliceStable(tmp, func(i, j int) bool { - return tmp[i].Sym().Name < tmp[j].Sym().Name + slices.SortStableFunc(tmp, func(a, b *ir.Name) int { + return strings.Compare(a.Sym().Name, b.Sym().Name) }) return tmp } @@ -268,8 +269,8 @@ func (mls *MergeLocalsState) String() string { leaders = append(leaders, n) } } - sort.Slice(leaders, func(i, j int) bool { - return leaders[i].Sym().Name < leaders[j].Sym().Name + slices.SortFunc(leaders, func(a, b *ir.Name) int { + return strings.Compare(a.Sym().Name, b.Sym().Name) }) var sb strings.Builder for _, n := range leaders { @@ -312,9 +313,7 @@ func (cs *cstate) collectMergeCandidates() { } // Sort by pointerness, size, and then name. - sort.SliceStable(cands, func(i, j int) bool { - return nameLess(cands[i], cands[j]) - }) + slices.SortStableFunc(cands, nameCmp) if cs.trace > 1 { fmt.Fprintf(os.Stderr, "=-= raw cand list for func %v:\n", cs.fn) @@ -580,7 +579,7 @@ func (cs *cstate) populateIndirectUseTable(cands []*ir.Name) ([]*ir.Name, []cand for k := range indirectUE { ids = append(ids, k) } - sort.Slice(ids, func(i, j int) bool { return ids[i] < ids[j] }) + slices.Sort(ids) for _, id := range ids { fmt.Fprintf(os.Stderr, " v%d:", id) for _, n := range indirectUE[id] { @@ -594,9 +593,7 @@ func (cs *cstate) populateIndirectUseTable(cands []*ir.Name) ([]*ir.Name, []cand for k := range rawcands { pruned = append(pruned, k) } - sort.Slice(pruned, func(i, j int) bool { - return nameLess(pruned[i], pruned[j]) - }) + slices.SortFunc(pruned, nameCmp) var regions []candRegion pruned, regions = cs.genRegions(pruned) if len(pruned) < 2 { @@ -610,13 +607,13 @@ type nameCount struct { count int32 } -// nameLess compares ci with cj to see if ci should be less than cj in -// a relative ordering of candidate variables. This is used to sort -// vars by pointerness (variables with pointers first), then in order +// nameCmp compares ci with cj in a relative ordering +// of candidate variables. This is used to sort vars +// by pointerness (variables with pointers first), then in order // of decreasing alignment, then by decreasing size. We are assuming a // merging algorithm that merges later entries in the list into // earlier entries. An example ordered candidate list produced by -// nameLess: +// nameCmp: // // idx name type align size // 0: abc [10]*int 8 80 @@ -625,20 +622,24 @@ type nameCount struct { // 3: tuv [9]int 8 72 // 4: wxy [9]int32 4 36 // 5: jkl [8]int32 4 32 -func nameLess(ci, cj *ir.Name) bool { +func nameCmp(ci, cj *ir.Name) int { if ci.Type().HasPointers() != cj.Type().HasPointers() { - return ci.Type().HasPointers() + if ci.Type().HasPointers() { + return -1 + } + return +1 } - if ci.Type().Alignment() != cj.Type().Alignment() { - return cj.Type().Alignment() < ci.Type().Alignment() + if r := cmp.Compare(cj.Type().Alignment(), ci.Type().Alignment()); r != 0 { + return r } - if ci.Type().Size() != cj.Type().Size() { - return cj.Type().Size() < ci.Type().Size() + if r := cmp.Compare(cj.Type().Size(), ci.Type().Size()); r != 0 { + return r } - if ci.Sym().Name != cj.Sym().Name { - return ci.Sym().Name < cj.Sym().Name + if r := strings.Compare(ci.Sym().Name, cj.Sym().Name); r != 0 { + return r } - return fmt.Sprintf("%v", ci.Pos()) < fmt.Sprintf("%v", cj.Pos()) + + return ci.Pos().Compare(cj.Pos()) } // nextRegion starts at location idx and walks forward in the cands diff --git a/src/cmd/compile/internal/liveness/plive.go b/src/cmd/compile/internal/liveness/plive.go index 2ee007f4a656ea..fd7e34f1ef3af4 100644 --- a/src/cmd/compile/internal/liveness/plive.go +++ b/src/cmd/compile/internal/liveness/plive.go @@ -15,8 +15,10 @@ package liveness import ( + "cmp" "fmt" "os" + "slices" "sort" "strings" @@ -1445,7 +1447,9 @@ func (lv *liveness) emitStackObjects() *obj.LSym { } // Sort variables from lowest to highest address. - sort.Slice(vars, func(i, j int) bool { return vars[i].FrameOffset() < vars[j].FrameOffset() }) + slices.SortFunc(vars, func(a, b *ir.Name) int { + return cmp.Compare(a.FrameOffset(), b.FrameOffset()) + }) // Populate the stack object data. // Format must match runtime/stack.go:stackObjectRecord. diff --git a/src/cmd/compile/internal/noder/irgen.go b/src/cmd/compile/internal/noder/irgen.go index 05f0affe8a8a43..bd5e7e657e745a 100644 --- a/src/cmd/compile/internal/noder/irgen.go +++ b/src/cmd/compile/internal/noder/irgen.go @@ -9,7 +9,7 @@ import ( "internal/buildcfg" "internal/types/errors" "regexp" - "sort" + "slices" "cmd/compile/internal/base" "cmd/compile/internal/rangefunc" @@ -134,9 +134,8 @@ func checkFiles(m posMap, noders []*noder) (*types2.Package, *types2.Info, map[* } } } - sort.Slice(nihTargs, func(i, j int) bool { - ti, tj := nihTargs[i], nihTargs[j] - return ti.pos.Before(tj.pos) + slices.SortFunc(nihTargs, func(a, b nihTarg) int { + return a.pos.Compare(b.pos) }) for _, targ := range nihTargs { base.ErrorfAt(targ.pos, 0, "cannot use incomplete (or unallocatable) type as a type argument: %v", targ.typ) diff --git a/src/cmd/compile/internal/noder/unified.go b/src/cmd/compile/internal/noder/unified.go index c8dbc43e67ab29..b30f493a1c7168 100644 --- a/src/cmd/compile/internal/noder/unified.go +++ b/src/cmd/compile/internal/noder/unified.go @@ -5,13 +5,14 @@ package noder import ( + "cmp" "fmt" "internal/buildcfg" "internal/pkgbits" "internal/types/errors" "io" "runtime" - "sort" + "slices" "strings" "cmd/compile/internal/base" @@ -519,7 +520,7 @@ func writeUnifiedExport(out io.Writer) { for _, idx := range l.decls { idxs = append(idxs, idx) } - sort.Slice(idxs, func(i, j int) bool { return idxs[i] < idxs[j] }) + slices.Sort(idxs) w := publicRootWriter @@ -553,7 +554,9 @@ func writeUnifiedExport(out io.Writer) { for sym, idx := range l.bodies { bodies = append(bodies, symIdx{sym, idx}) } - sort.Slice(bodies, func(i, j int) bool { return bodies[i].idx < bodies[j].idx }) + slices.SortFunc(bodies, func(a, b symIdx) int { + return cmp.Compare(a.idx, b.idx) + }) w := privateRootWriter diff --git a/src/cmd/compile/internal/ssa/debug_lines_test.go b/src/cmd/compile/internal/ssa/debug_lines_test.go index a4c25d6d063881..99cc0bfee04d90 100644 --- a/src/cmd/compile/internal/ssa/debug_lines_test.go +++ b/src/cmd/compile/internal/ssa/debug_lines_test.go @@ -15,7 +15,7 @@ import ( "reflect" "regexp" "runtime" - "sort" + "slices" "strconv" "strings" "testing" @@ -167,16 +167,16 @@ func compileAndDump(t *testing.T, file, function, moreGCFlags string) []byte { } func sortInlineStacks(x [][]int) { - sort.Slice(x, func(i, j int) bool { - if len(x[i]) != len(x[j]) { - return len(x[i]) < len(x[j]) + slices.SortFunc(x, func(a, b []int) int { + if len(a) != len(b) { + return len(a) - len(b) } - for k := range x[i] { - if x[i][k] != x[j][k] { - return x[i][k] < x[j][k] + for i := range a { + if a[i] != b[i] { + return a[i] - b[i] } } - return false + return 0 }) } diff --git a/src/cmd/compile/internal/ssa/decompose.go b/src/cmd/compile/internal/ssa/decompose.go index 2293fc01ce6c61..8921f02b372644 100644 --- a/src/cmd/compile/internal/ssa/decompose.go +++ b/src/cmd/compile/internal/ssa/decompose.go @@ -6,7 +6,7 @@ package ssa import ( "cmd/compile/internal/types" - "sort" + "slices" ) // decompose converts phi ops on compound builtin types into phi @@ -433,12 +433,11 @@ type namedVal struct { // removes all values with OpInvalid, and re-sorts the list of Names. func deleteNamedVals(f *Func, toDelete []namedVal) { // Arrange to delete from larger indices to smaller, to ensure swap-with-end deletion does not invalidate pending indices. - sort.Slice(toDelete, func(i, j int) bool { - if toDelete[i].locIndex != toDelete[j].locIndex { - return toDelete[i].locIndex > toDelete[j].locIndex + slices.SortFunc(toDelete, func(a, b namedVal) int { + if a.locIndex != b.locIndex { + return a.locIndex - b.locIndex } - return toDelete[i].valIndex > toDelete[j].valIndex - + return a.valIndex - b.valIndex }) // Get rid of obsolete names diff --git a/src/cmd/compile/internal/ssa/memcombine.go b/src/cmd/compile/internal/ssa/memcombine.go index a7e8ede5bca82b..280d99224dcd25 100644 --- a/src/cmd/compile/internal/ssa/memcombine.go +++ b/src/cmd/compile/internal/ssa/memcombine.go @@ -8,7 +8,8 @@ import ( "cmd/compile/internal/base" "cmd/compile/internal/types" "cmd/internal/src" - "sort" + "cmp" + "slices" ) // memcombine combines smaller loads and stores into larger ones. @@ -232,8 +233,8 @@ func combineLoads(root *Value, n int64) bool { } // Sort in memory address order. - sort.Slice(r, func(i, j int) bool { - return r[i].offset < r[j].offset + slices.SortFunc(r, func(a, b LoadRecord) int { + return cmp.Compare(a.offset, b.offset) }) // Check that we have contiguous offsets. @@ -516,8 +517,8 @@ func combineStores(root *Value, n int64) bool { pos := a[n-1].store.Pos // Sort stores in increasing address order. - sort.Slice(a, func(i, j int) bool { - return a[i].offset < a[j].offset + slices.SortFunc(a, func(a, b StoreRecord) int { + return cmp.Compare(a.offset, b.offset) }) // Check that everything is written to sequential locations. diff --git a/src/cmd/compile/internal/ssa/schedule.go b/src/cmd/compile/internal/ssa/schedule.go index b42727674f4cd2..610cd171390a9e 100644 --- a/src/cmd/compile/internal/ssa/schedule.go +++ b/src/cmd/compile/internal/ssa/schedule.go @@ -261,8 +261,8 @@ func schedule(f *Func) { } // Sort all the edges by source Value ID. - sort.Slice(edges, func(i, j int) bool { - return edges[i].x.ID < edges[j].x.ID + slices.SortFunc(edges, func(i, j edge) int { + return int(i.x.ID - j.x.ID) }) // Compute inEdges for values in this block. for _, e := range edges { diff --git a/src/cmd/compile/internal/ssa/stmtlines_test.go b/src/cmd/compile/internal/ssa/stmtlines_test.go index 79bcab08a1e698..fab863d8911f86 100644 --- a/src/cmd/compile/internal/ssa/stmtlines_test.go +++ b/src/cmd/compile/internal/ssa/stmtlines_test.go @@ -18,7 +18,8 @@ import ( "io" "os" "runtime" - "sort" + "slices" + "strings" "testing" ) @@ -144,11 +145,11 @@ func TestStmtLines(t *testing.T) { } t.Logf("Saw %d out of %d lines without statement marks", len(nonStmtLines), len(lines)) if testing.Verbose() { - sort.Slice(nonStmtLines, func(i, j int) bool { - if nonStmtLines[i].File != nonStmtLines[j].File { - return nonStmtLines[i].File < nonStmtLines[j].File + slices.SortFunc(nonStmtLines, func(a, b Line) int { + if r := strings.Compare(a.File, b.File); r != 0 { + return r } - return nonStmtLines[i].Line < nonStmtLines[j].Line + return a.Line - b.Line }) for _, l := range nonStmtLines { t.Logf("%s:%d has no DWARF is_stmt mark\n", l.File, l.Line) diff --git a/src/cmd/compile/internal/ssagen/pgen.go b/src/cmd/compile/internal/ssagen/pgen.go index e666c22a7d3d59..8ddc4786f532ef 100644 --- a/src/cmd/compile/internal/ssagen/pgen.go +++ b/src/cmd/compile/internal/ssagen/pgen.go @@ -8,7 +8,8 @@ import ( "fmt" "internal/buildcfg" "os" - "sort" + "slices" + "strings" "sync" "cmd/compile/internal/base" @@ -24,17 +25,20 @@ import ( "cmd/internal/src" ) -// cmpstackvarlt reports whether the stack variable a sorts before b. -func cmpstackvarlt(a, b *ir.Name, mls *liveness.MergeLocalsState) bool { +// cmpstackvar compare the stack variable a and b. +func cmpstackvar(a, b *ir.Name, mls *liveness.MergeLocalsState) int { // Sort non-autos before autos. if needAlloc(a) != needAlloc(b) { - return needAlloc(b) + if needAlloc(b) { + return -1 + } + return +1 } // If both are non-auto (e.g., parameters, results), then sort by // frame offset (defined by ABI). if !needAlloc(a) { - return a.FrameOffset() < b.FrameOffset() + return int(a.FrameOffset() - b.FrameOffset()) } // From here on, a and b are both autos (i.e., local variables). @@ -44,14 +48,20 @@ func cmpstackvarlt(a, b *ir.Name, mls *liveness.MergeLocalsState) bool { aFollow := mls.Subsumed(a) bFollow := mls.Subsumed(b) if aFollow != bFollow { - return bFollow + if bFollow { + return -1 + } + return +1 } } // Sort used before unused (so AllocFrame can truncate unused // variables). if a.Used() != b.Used() { - return a.Used() + if a.Used() { + return -1 + } + return +1 } // Sort pointer-typed before non-pointer types. @@ -59,7 +69,10 @@ func cmpstackvarlt(a, b *ir.Name, mls *liveness.MergeLocalsState) bool { ap := a.Type().HasPointers() bp := b.Type().HasPointers() if ap != bp { - return ap + if ap { + return -1 + } + return +1 } // Group variables that need zeroing, so we can efficiently zero @@ -67,20 +80,29 @@ func cmpstackvarlt(a, b *ir.Name, mls *liveness.MergeLocalsState) bool { ap = a.Needzero() bp = b.Needzero() if ap != bp { - return ap + if ap { + return -1 + } + return +1 } // Sort variables in descending alignment order, so we can optimally // pack variables into the frame. if a.Type().Alignment() != b.Type().Alignment() { - return a.Type().Alignment() > b.Type().Alignment() + if a.Type().Alignment() > b.Type().Alignment() { + return -1 + } + return +1 } // Sort normal variables before open-coded-defer slots, so that the // latter are grouped together and near the top of the frame (to // minimize varint encoding of their varp offset). if a.OpenDeferSlot() != b.OpenDeferSlot() { - return a.OpenDeferSlot() + if a.OpenDeferSlot() { + return -1 + } + return +1 } // If a and b are both open-coded defer slots, then order them by @@ -89,11 +111,11 @@ func cmpstackvarlt(a, b *ir.Name, mls *liveness.MergeLocalsState) bool { // // Their index was saved in FrameOffset in state.openDeferSave. if a.OpenDeferSlot() { - return a.FrameOffset() > b.FrameOffset() + return int(b.FrameOffset() - a.FrameOffset()) } // Tie breaker for stable results. - return a.Sym().Name < b.Sym().Name + return strings.Compare(a.Sym().Name, b.Sym().Name) } // needAlloc reports whether n is within the current frame, for which we need to @@ -178,11 +200,11 @@ func (s *ssafn) AllocFrame(f *ssa.Func) { leaders = make(map[*ir.Name]int64) } - // Use sort.SliceStable instead of sort.Slice so stack layout (and thus + // Use SortStable instead of Sort so stack layout (and thus // compiler output) is less sensitive to frontend changes that // introduce or remove unused variables. - sort.SliceStable(fn.Dcl, func(i, j int) bool { - return cmpstackvarlt(fn.Dcl[i], fn.Dcl[j], mls) + slices.SortStableFunc(fn.Dcl, func(a, b *ir.Name) int { + return cmpstackvar(a, b, mls) }) if mls != nil { @@ -414,7 +436,9 @@ func fieldtrack(fnsym *obj.LSym, tracked map[*obj.LSym]struct{}) { for sym := range tracked { trackSyms = append(trackSyms, sym) } - sort.Slice(trackSyms, func(i, j int) bool { return trackSyms[i].Name < trackSyms[j].Name }) + slices.SortFunc(trackSyms, func(a, b *obj.LSym) int { + return strings.Compare(a.Name, b.Name) + }) for _, sym := range trackSyms { r := obj.Addrel(fnsym) r.Sym = sym @@ -437,8 +461,8 @@ var ( func CheckLargeStacks() { // Check whether any of the functions we have compiled have gigantic stack frames. - sort.Slice(largeStackFrames, func(i, j int) bool { - return largeStackFrames[i].pos.Before(largeStackFrames[j].pos) + slices.SortFunc(largeStackFrames, func(a, b largeStack) int { + return a.pos.Compare(b.pos) }) for _, large := range largeStackFrames { if large.callee != 0 { diff --git a/src/cmd/compile/internal/ssagen/ssa.go b/src/cmd/compile/internal/ssagen/ssa.go index 9a566732d27042..2d77bc5c4912b2 100644 --- a/src/cmd/compile/internal/ssagen/ssa.go +++ b/src/cmd/compile/internal/ssagen/ssa.go @@ -279,7 +279,7 @@ func abiForFunc(fn *ir.Func, abi0, abi1 *abi.ABIConfig) *abi.ABIConfig { func (s *state) emitOpenDeferInfo() { firstOffset := s.openDefers[0].closureNode.FrameOffset() - // Verify that cmpstackvarlt laid out the slots in order. + // Verify that cmpstackvar laid out the slots in order. for i, r := range s.openDefers { have := r.closureNode.FrameOffset() want := firstOffset + int64(i)*int64(types.PtrSize) @@ -4277,7 +4277,7 @@ func (s *state) openDeferSave(t *types.Type, val *ssa.Value) *ssa.Value { pos := val.Pos temp := typecheck.TempAt(pos.WithNotStmt(), s.curfn, t) temp.SetOpenDeferSlot(true) - temp.SetFrameOffset(int64(len(s.openDefers))) // so cmpstackvarlt can order them + temp.SetFrameOffset(int64(len(s.openDefers))) // so cmpstackvar can order them var addrTemp *ssa.Value // Use OpVarLive to make sure stack slot for the closure is not removed by // dead-store elimination diff --git a/src/cmd/compile/internal/staticdata/data.go b/src/cmd/compile/internal/staticdata/data.go index b6ca615c6efa09..acafe9d3393e85 100644 --- a/src/cmd/compile/internal/staticdata/data.go +++ b/src/cmd/compile/internal/staticdata/data.go @@ -10,8 +10,9 @@ import ( "go/constant" "io" "os" - "sort" + "slices" "strconv" + "strings" "sync" "cmd/compile/internal/base" @@ -264,8 +265,8 @@ func GlobalLinksym(n *ir.Name) *obj.LSym { } func WriteFuncSyms() { - sort.Slice(funcsyms, func(i, j int) bool { - return funcsyms[i].Linksym().Name < funcsyms[j].Linksym().Name + slices.SortFunc(funcsyms, func(a, b *ir.Name) int { + return strings.Compare(a.Linksym().Name, b.Linksym().Name) }) for _, nam := range funcsyms { s := nam.Sym() diff --git a/src/cmd/compile/internal/staticdata/embed.go b/src/cmd/compile/internal/staticdata/embed.go index be939db877fd34..8837188e4766bd 100644 --- a/src/cmd/compile/internal/staticdata/embed.go +++ b/src/cmd/compile/internal/staticdata/embed.go @@ -6,7 +6,7 @@ package staticdata import ( "path" - "sort" + "slices" "strings" "cmd/compile/internal/base" @@ -51,9 +51,7 @@ func embedFileList(v *ir.Name, kind int) []string { } } } - sort.Slice(list, func(i, j int) bool { - return embedFileLess(list[i], list[j]) - }) + slices.SortFunc(list, embedFileCmp) if kind == embedString || kind == embedBytes { if len(list) > 1 { @@ -88,12 +86,15 @@ func embedFileNameSplit(name string) (dir, elem string, isDir bool) { return name[:i], name[i+1:], isDir } -// embedFileLess implements the sort order for a list of embedded files. +// embedFileCmp implements the sort order for a list of embedded files. // See the comment inside ../../../../embed/embed.go's Files struct for rationale. -func embedFileLess(x, y string) bool { +func embedFileCmp(x, y string) int { xdir, xelem, _ := embedFileNameSplit(x) ydir, yelem, _ := embedFileNameSplit(y) - return xdir < ydir || xdir == ydir && xelem < yelem + if r := strings.Compare(xdir, ydir); r != 0 { + return r + } + return strings.Compare(xelem, yelem) } // WriteEmbed emits the init data for a //go:embed variable, diff --git a/src/cmd/compile/internal/syntax/error_test.go b/src/cmd/compile/internal/syntax/error_test.go index 55ea6345b90fdf..8714da88250f5d 100644 --- a/src/cmd/compile/internal/syntax/error_test.go +++ b/src/cmd/compile/internal/syntax/error_test.go @@ -29,13 +29,14 @@ package syntax import ( + "cmp" "flag" "fmt" "internal/testenv" "os" "path/filepath" "regexp" - "sort" + "slices" "strings" "testing" ) @@ -60,9 +61,11 @@ func sortedPositions(m map[position]string) []position { list[i] = pos i++ } - sort.Slice(list, func(i, j int) bool { - a, b := list[i], list[j] - return a.line < b.line || a.line == b.line && a.col < b.col + slices.SortFunc(list, func(a, b position) int { + if r := cmp.Compare(a.line, b.line); r != 0 { + return r + } + return cmp.Compare(a.col, b.col) }) return list } diff --git a/src/cmd/compile/internal/types/size.go b/src/cmd/compile/internal/types/size.go index 308245d9b7299b..4e8b04b69e6797 100644 --- a/src/cmd/compile/internal/types/size.go +++ b/src/cmd/compile/internal/types/size.go @@ -7,7 +7,6 @@ package types import ( "math" "slices" - "sort" "cmd/compile/internal/base" "cmd/internal/src" @@ -94,21 +93,25 @@ func expandiface(t *Type) { { methods := t.Methods() - sort.SliceStable(methods, func(i, j int) bool { - mi, mj := methods[i], methods[j] - + slices.SortStableFunc(methods, func(a, b *Field) int { // Sort embedded types by type name (if any). - if mi.Sym == nil && mj.Sym == nil { - return mi.Type.Sym().Less(mj.Type.Sym()) + if a.Sym == nil && b.Sym == nil { + return a.Type.Sym().Compare(b.Type.Sym()) } // Sort methods before embedded types. - if mi.Sym == nil || mj.Sym == nil { - return mi.Sym != nil + if a.Sym == nil || b.Sym == nil { + //return a.Sym != nil + if a.Sym != nil { + return +1 + } + if b.Sym != nil { + return -1 + } } // Sort methods by symbol name. - return mi.Sym.Less(mj.Sym) + return a.Sym.Compare(b.Sym) }) } diff --git a/src/cmd/compile/internal/types/sym.go b/src/cmd/compile/internal/types/sym.go index 67fa6bb1d0c1cc..4606a6dc728fe6 100644 --- a/src/cmd/compile/internal/types/sym.go +++ b/src/cmd/compile/internal/types/sym.go @@ -7,6 +7,7 @@ package types import ( "cmd/compile/internal/base" "cmd/internal/obj" + "strings" "unicode" "unicode/utf8" ) @@ -127,6 +128,45 @@ func (a *Sym) Less(b *Sym) bool { return false } +// Compare compares symbols a and b and returns -1, 0, or 1 if a is less than, +// equal to, or greater than b, respectively. +// +// Symbols are ordered exported before non-exported, then by name, and +// finally (for non-exported symbols) by package path. +func (a *Sym) Compare(b *Sym) int { + if a == b { + return 0 + } + + // Nil before non-nil. + if a == nil { + return -1 + } + if b == nil { + return 1 + } + + // Exported symbols before non-exported. + ea := IsExported(a.Name) + eb := IsExported(b.Name) + if ea != eb { + if ea { + return -1 + } + return +1 + } + + // Order by name and then (for non-exported names) by package + // height and path. + if r := strings.Compare(a.Name, b.Name); r != 0 { + return r + } + if !ea { + return strings.Compare(a.Pkg.Path, b.Pkg.Path) + } + return 0 +} + // IsExported reports whether name is an exported Go symbol (that is, // whether it begins with an upper-case letter). func IsExported(name string) bool { diff --git a/src/cmd/compile/internal/types/sym_test.go b/src/cmd/compile/internal/types/sym_test.go index 94efd42aa4ad44..2219b223cda022 100644 --- a/src/cmd/compile/internal/types/sym_test.go +++ b/src/cmd/compile/internal/types/sym_test.go @@ -7,11 +7,12 @@ package types_test import ( "cmd/compile/internal/types" "reflect" + "slices" "sort" "testing" ) -func TestSymLess(t *testing.T) { +func TestSymLessAndCmp(t *testing.T) { var ( local = types.NewPkg("", "") abc = types.NewPkg("abc", "") @@ -32,6 +33,7 @@ func TestSymLess(t *testing.T) { abc.Lookup("a"), local.Lookup("B"), } + data2 := slices.Clone(data) want := []*types.Sym{ local.Lookup("B"), local.Lookup("B"), @@ -56,4 +58,12 @@ func TestSymLess(t *testing.T) { t.Logf("data: %#v", data) t.Errorf("sorting failed") } + slices.SortFunc(data2, func(a, b *types.Sym) int { + return a.Compare(b) + }) + if !reflect.DeepEqual(data2, want) { + t.Logf("want: %#v", want) + t.Logf("data2: %#v", data2) + t.Errorf("sorting failed") + } } diff --git a/src/cmd/compile/internal/types2/initorder.go b/src/cmd/compile/internal/types2/initorder.go index 86cb9036c4cd93..e18427086849cd 100644 --- a/src/cmd/compile/internal/types2/initorder.go +++ b/src/cmd/compile/internal/types2/initorder.go @@ -8,7 +8,7 @@ import ( "container/heap" "fmt" . "internal/types/errors" - "sort" + "slices" ) // initOrder computes the Info.InitOrder for package variables. @@ -257,8 +257,8 @@ func dependencyGraph(objMap map[Object]*declInfo) []*graphNode { // throughout the function graph, the cost of removing a function at // position X is proportional to cost * (len(funcG)-X). Therefore, we should // remove high-cost functions last. - sort.Slice(funcG, func(i, j int) bool { - return funcG[i].cost() < funcG[j].cost() + slices.SortFunc(funcG, func(a, b *graphNode) int { + return a.cost() - b.cost() }) for _, n := range funcG { // connect each predecessor p of n with each successor s diff --git a/src/cmd/compile/internal/types2/stmt.go b/src/cmd/compile/internal/types2/stmt.go index c381187fd3a448..ac22f89ab8eb18 100644 --- a/src/cmd/compile/internal/types2/stmt.go +++ b/src/cmd/compile/internal/types2/stmt.go @@ -11,7 +11,7 @@ import ( "go/constant" "internal/buildcfg" . "internal/types/errors" - "sort" + "slices" ) func (check *Checker) funcBody(decl *declInfo, name string, sig *Signature, body *syntax.BlockStmt, iota constant.Value) { @@ -60,8 +60,8 @@ func (check *Checker) usage(scope *Scope) { unused = append(unused, v) } } - sort.Slice(unused, func(i, j int) bool { - return cmpPos(unused[i].pos, unused[j].pos) < 0 + slices.SortFunc(unused, func(a, b *Var) int { + return cmpPos(a.pos, b.pos) }) for _, v := range unused { check.softErrorf(v.pos, UnusedVar, "declared and not used: %s", v.name) diff --git a/src/cmd/compile/internal/walk/switch.go b/src/cmd/compile/internal/walk/switch.go index 119647912b8b87..5f0e9df95f3171 100644 --- a/src/cmd/compile/internal/walk/switch.go +++ b/src/cmd/compile/internal/walk/switch.go @@ -5,11 +5,13 @@ package walk import ( + "cmp" "fmt" "go/constant" "go/token" "math/bits" - "sort" + "slices" + "strings" "cmd/compile/internal/base" "cmd/compile/internal/ir" @@ -168,17 +170,11 @@ func (s *exprSwitch) flush() { // when there's only a single slice element). if s.exprname.Type().IsString() && len(cc) >= 2 { - // Sort strings by length and then by value. It is - // much cheaper to compare lengths than values, and - // all we need here is consistency. We respect this - // sorting below. - sort.Slice(cc, func(i, j int) bool { - si := ir.StringVal(cc[i].lo) - sj := ir.StringVal(cc[j].lo) - if len(si) != len(sj) { - return len(si) < len(sj) - } - return si < sj + // Sort strings + slices.SortFunc(cc, func(a, b exprClause) int { + si := ir.StringVal(a.lo) + sj := ir.StringVal(b.lo) + return strings.Compare(si, sj) }) // runLen returns the string length associated with a @@ -248,8 +244,16 @@ func (s *exprSwitch) flush() { return } - sort.Slice(cc, func(i, j int) bool { - return constant.Compare(cc[i].lo.Val(), token.LSS, cc[j].lo.Val()) + slices.SortFunc(cc, func(a, b exprClause) int { + aVal := a.lo.Val() + bVal := b.lo.Val() + if constant.Compare(aVal, token.LSS, bVal) { + return -1 + } + if constant.Compare(aVal, token.GTR, bVal) { + return +1 + } + return 0 }) // Merge consecutive integer cases. @@ -728,7 +732,9 @@ func (s *typeSwitch) flush(cc []typeClause, compiled *ir.Nodes) { return } - sort.Slice(cc, func(i, j int) bool { return cc[i].hash < cc[j].hash }) + slices.SortFunc(cc, func(a, b typeClause) int { + return cmp.Compare(a.hash, b.hash) + }) // Combine adjacent cases with the same hash. merged := cc[:1] @@ -783,9 +789,7 @@ func (s *typeSwitch) tryJumpTable(cc []typeClause, out *ir.Nodes) bool { hashes = append(hashes, h) } // Order by increasing hash. - sort.Slice(hashes, func(j, k int) bool { - return hashes[j] < hashes[k] - }) + slices.Sort(hashes) for j := 1; j < len(hashes); j++ { if hashes[j] == hashes[j-1] { // There is a duplicate hash; try a different b/i pair. diff --git a/src/cmd/distpack/archive.go b/src/cmd/distpack/archive.go index e52dae13a7e45d..1b2f813b6167df 100644 --- a/src/cmd/distpack/archive.go +++ b/src/cmd/distpack/archive.go @@ -10,7 +10,7 @@ import ( "os" "path" "path/filepath" - "sort" + "slices" "strings" "time" ) @@ -112,8 +112,14 @@ func nameLess(x, y string) bool { // NewArchive returns a sorted archive, and the other methods // preserve the sorting of the archive. func (a *Archive) Sort() { - sort.Slice(a.Files, func(i, j int) bool { - return nameLess(a.Files[i].Name, a.Files[j].Name) + slices.SortFunc(a.Files, func(a, b File) int { + if nameLess(a.Name, b.Name) { + return -1 + } else if nameLess(b.Name, a.Name) { + return +1 + } else { + return 0 + } }) } diff --git a/src/cmd/go/internal/envcmd/env.go b/src/cmd/go/internal/envcmd/env.go index a99b2ed140f457..a7b1571fcf3d41 100644 --- a/src/cmd/go/internal/envcmd/env.go +++ b/src/cmd/go/internal/envcmd/env.go @@ -16,7 +16,7 @@ import ( "os" "path/filepath" "runtime" - "sort" + "slices" "strings" "unicode" "unicode/utf8" @@ -744,7 +744,7 @@ func lineToKey(line string) string { // sortKeyValues sorts a sequence of lines by key. // It differs from sort.Strings in that GO386= sorts after GO=. func sortKeyValues(lines []string) { - sort.Slice(lines, func(i, j int) bool { - return lineToKey(lines[i]) < lineToKey(lines[j]) + slices.SortFunc(lines, func(a, b string) int { + return strings.Compare(lineToKey(a), lineToKey(b)) }) } diff --git a/src/cmd/go/internal/fsys/fsys.go b/src/cmd/go/internal/fsys/fsys.go index c5889a273954c6..1dc148e16ea51a 100644 --- a/src/cmd/go/internal/fsys/fsys.go +++ b/src/cmd/go/internal/fsys/fsys.go @@ -19,6 +19,7 @@ import ( "path/filepath" "runtime" "runtime/debug" + "slices" "sort" "strings" "sync" @@ -380,7 +381,9 @@ func ReadDir(dir string) ([]fs.FileInfo, error) { for _, f := range files { sortedFiles = append(sortedFiles, f) } - sort.Slice(sortedFiles, func(i, j int) bool { return sortedFiles[i].Name() < sortedFiles[j].Name() }) + slices.SortFunc(sortedFiles, func(i, j fs.FileInfo) int { + return strings.Compare(i.Name(), j.Name()) + }) return sortedFiles, nil } diff --git a/src/cmd/go/internal/gover/mod.go b/src/cmd/go/internal/gover/mod.go index d3cc17068def6d..03ead56c01f86c 100644 --- a/src/cmd/go/internal/gover/mod.go +++ b/src/cmd/go/internal/gover/mod.go @@ -5,11 +5,11 @@ package gover import ( - "sort" - "strings" - "golang.org/x/mod/module" "golang.org/x/mod/semver" + + "slices" + "strings" ) // IsToolchain reports whether the module path corresponds to the @@ -44,17 +44,15 @@ func ModCompare(path string, x, y string) int { // ModSort is like module.Sort but understands the "go" and "toolchain" // modules and their version ordering. func ModSort(list []module.Version) { - sort.Slice(list, func(i, j int) bool { - mi := list[i] - mj := list[j] - if mi.Path != mj.Path { - return mi.Path < mj.Path + slices.SortFunc(list, func(a, b module.Version) int { + if r := strings.Compare(a.Path, b.Path); r != 0 { + return r } // To help go.sum formatting, allow version/file. // Compare semver prefix by semver rules, // file by string order. - vi := mi.Version - vj := mj.Version + vi := a.Version + vj := b.Version var fi, fj string if k := strings.Index(vi, "/"); k >= 0 { vi, fi = vi[:k], vi[k:] @@ -62,10 +60,10 @@ func ModSort(list []module.Version) { if k := strings.Index(vj, "/"); k >= 0 { vj, fj = vj[:k], vj[k:] } - if vi != vj { - return ModCompare(mi.Path, vi, vj) < 0 + if r := strings.Compare(vi, vj); r != 0 { + return ModCompare(a.Path, vi, vj) } - return fi < fj + return strings.Compare(fi, fj) }) } diff --git a/src/cmd/go/internal/list/list.go b/src/cmd/go/internal/list/list.go index df3639cba75357..68bde7fbf96760 100644 --- a/src/cmd/go/internal/list/list.go +++ b/src/cmd/go/internal/list/list.go @@ -16,6 +16,7 @@ import ( "os" "reflect" "runtime" + "slices" "sort" "strconv" "strings" @@ -952,22 +953,22 @@ func collectDepsErrors(p *load.Package) { // Sort packages by the package on the top of the stack, which should be // the package the error was produced for. Each package can have at most // one error set on it. - sort.Slice(p.DepsErrors, func(i, j int) bool { - stki, stkj := p.DepsErrors[i].ImportStack, p.DepsErrors[j].ImportStack + slices.SortFunc(p.DepsErrors, func(a, b *load.PackageError) int { + stka, stkb := a.ImportStack, b.ImportStack // Some packages are missing import stacks. To ensure deterministic // sort order compare two errors that are missing import stacks by // their errors' error texts. - if len(stki) == 0 { - if len(stkj) != 0 { - return true + if len(stka) == 0 { + if len(stkb) != 0 { + return -1 } - return p.DepsErrors[i].Err.Error() < p.DepsErrors[j].Err.Error() - } else if len(stkj) == 0 { - return false + return strings.Compare(a.Err.Error(), b.Err.Error()) + } else if len(stkb) == 0 { + return +1 } - pathi, pathj := stki[len(stki)-1], stkj[len(stkj)-1] - return pathi < pathj + patha, pathb := stka[len(stka)-1], stkb[len(stkb)-1] + return strings.Compare(patha, pathb) }) } diff --git a/src/cmd/go/internal/load/test.go b/src/cmd/go/internal/load/test.go index 4e85c17053f88a..9340e71eb679f6 100644 --- a/src/cmd/go/internal/load/test.go +++ b/src/cmd/go/internal/load/test.go @@ -783,7 +783,9 @@ func (t *testFuncs) load(filename, pkg string, doImport, seen *bool) error { } } ex := doc.Examples(f) - sort.Slice(ex, func(i, j int) bool { return ex[i].Order < ex[j].Order }) + slices.SortFunc(ex, func(a, b *doc.Example) int { + return a.Order - b.Order + }) for _, e := range ex { *doImport = true // import test file whether executed or not if e.Output == "" && !e.EmptyOutput { diff --git a/src/cmd/go/internal/modfetch/codehost/git.go b/src/cmd/go/internal/modfetch/codehost/git.go index 474100bd59747e..79739a06fc08bd 100644 --- a/src/cmd/go/internal/modfetch/codehost/git.go +++ b/src/cmd/go/internal/modfetch/codehost/git.go @@ -294,8 +294,8 @@ func (r *gitRepo) Tags(ctx context.Context, prefix string) (*Tags, error) { } tags.List = append(tags.List, Tag{tag, hash}) } - sort.Slice(tags.List, func(i, j int) bool { - return tags.List[i].Name < tags.List[j].Name + slices.SortFunc(tags.List, func(a, b Tag) int { + return strings.Compare(a.Name, b.Name) }) dir := prefix[:strings.LastIndex(prefix, "/")+1] diff --git a/src/cmd/go/internal/modfetch/codehost/vcs.go b/src/cmd/go/internal/modfetch/codehost/vcs.go index 75fde763ae925d..4cb9f9f052d7cd 100644 --- a/src/cmd/go/internal/modfetch/codehost/vcs.go +++ b/src/cmd/go/internal/modfetch/codehost/vcs.go @@ -13,6 +13,7 @@ import ( "io/fs" "os" "path/filepath" + "slices" "sort" "strconv" "strings" @@ -324,8 +325,8 @@ func (r *vcsRepo) Tags(ctx context.Context, prefix string) (*Tags, error) { tags.List = append(tags.List, Tag{tag, ""}) } } - sort.Slice(tags.List, func(i, j int) bool { - return tags.List[i].Name < tags.List[j].Name + slices.SortFunc(tags.List, func(a, b Tag) int { + return strings.Compare(a.Name, b.Name) }) return tags, nil } diff --git a/src/cmd/go/internal/modfetch/toolchain.go b/src/cmd/go/internal/modfetch/toolchain.go index 0d7cfcfe7d1073..c5f887a6c714ab 100644 --- a/src/cmd/go/internal/modfetch/toolchain.go +++ b/src/cmd/go/internal/modfetch/toolchain.go @@ -8,7 +8,7 @@ import ( "context" "fmt" "io" - "sort" + "slices" "strings" "cmd/go/internal/gover" @@ -70,12 +70,12 @@ func (r *toolchainRepo) Versions(ctx context.Context, prefix string) (*Versions, } if r.path == "go" { - sort.Slice(list, func(i, j int) bool { - return gover.Compare(list[i], list[j]) < 0 + slices.SortFunc(list, func(a, b string) int { + return gover.Compare(a, b) }) } else { - sort.Slice(list, func(i, j int) bool { - return gover.Compare(gover.FromToolchain(list[i]), gover.FromToolchain(list[j])) < 0 + slices.SortFunc(list, func(a, b string) int { + return gover.Compare(gover.FromToolchain(a), gover.FromToolchain(b)) }) } versions.List = list diff --git a/src/cmd/go/internal/modget/get.go b/src/cmd/go/internal/modget/get.go index 96b72adba5fd24..29b888b6071b3e 100644 --- a/src/cmd/go/internal/modget/get.go +++ b/src/cmd/go/internal/modget/get.go @@ -31,7 +31,7 @@ import ( "os" "path/filepath" "runtime" - "sort" + "slices" "strconv" "strings" "sync" @@ -1055,8 +1055,8 @@ func (r *resolver) performPatternAllQueries(ctx context.Context) { // including in which errors it chooses to report, so sort the candidates // into a deterministic-but-arbitrary order. for _, q := range r.patternAllQueries { - sort.Slice(q.candidates, func(i, j int) bool { - return q.candidates[i].path < q.candidates[j].path + slices.SortFunc(q.candidates, func(a, b pathSet) int { + return strings.Compare(a.path, b.path) }) } } @@ -1146,8 +1146,8 @@ func (r *resolver) findAndUpgradeImports(ctx context.Context, queries []*query) // nondeterministic order. We want 'go get' to be fully deterministic, // including in which errors it chooses to report, so sort the candidates // into a deterministic-but-arbitrary order. - sort.Slice(upgrades, func(i, j int) bool { - return upgrades[i].path < upgrades[j].path + slices.SortFunc(upgrades, func(a, b pathSet) int { + return strings.Compare(a.path, b.path) }) return upgrades } @@ -1598,7 +1598,7 @@ func (r *resolver) checkPackageProblems(ctx context.Context, pkgPatterns []strin retractions = append(retractions, modMessage{m: m}) } } - sort.Slice(retractions, func(i, j int) bool { return retractions[i].m.Path < retractions[j].m.Path }) + slices.SortFunc(retractions, func(i, j modMessage) int { return strings.Compare(i.m.Path, j.m.Path) }) for i := range retractions { i := i r.work.Add(func() { @@ -1619,7 +1619,7 @@ func (r *resolver) checkPackageProblems(ctx context.Context, pkgPatterns []strin deprecations = append(deprecations, modMessage{m: m}) } } - sort.Slice(deprecations, func(i, j int) bool { return deprecations[i].m.Path < deprecations[j].m.Path }) + slices.SortFunc(deprecations, func(i, j modMessage) int { return strings.Compare(i.m.Path, j.m.Path) }) for i := range deprecations { i := i r.work.Add(func() { @@ -1777,24 +1777,24 @@ func (r *resolver) reportChanges(oldReqs, newReqs []module.Version) { for _, c := range changes { sortedChanges = append(sortedChanges, c) } - sort.Slice(sortedChanges, func(i, j int) bool { - pi := sortedChanges[i].path - pj := sortedChanges[j].path - if pi == pj { - return false - } - // go first; toolchain second - switch { - case pi == "go": - return true - case pj == "go": - return false - case pi == "toolchain": - return true - case pj == "toolchain": - return false + slices.SortFunc(sortedChanges, func(i, j change) int { + pi := i.path + pj := j.path + if ret := strings.Compare(pi, pj); ret != 0 { + // go first; toolchain second + switch { + case pi == "go": + return -1 + case pj == "go": + return 1 + case pi == "toolchain": + return -1 + case pj == "toolchain": + return 1 + } + return ret } - return pi < pj + return 0 }) for _, c := range sortedChanges { diff --git a/src/cmd/go/internal/modindex/write.go b/src/cmd/go/internal/modindex/write.go index cd18ad96dd19c3..a27ef144e76458 100644 --- a/src/cmd/go/internal/modindex/write.go +++ b/src/cmd/go/internal/modindex/write.go @@ -6,9 +6,10 @@ package modindex import ( "cmd/go/internal/base" + "cmp" "encoding/binary" "go/token" - "sort" + "slices" ) const indexVersion = "go index v2" // 11 bytes (plus \n), to align uint32s in index @@ -20,8 +21,8 @@ func encodeModuleBytes(packages []*rawPackage) []byte { e.Bytes([]byte(indexVersion + "\n")) stringTableOffsetPos := e.Pos() // fill this at the end e.Uint32(0) // string table offset - sort.Slice(packages, func(i, j int) bool { - return packages[i].dir < packages[j].dir + slices.SortFunc(packages, func(i, j *rawPackage) int { + return cmp.Compare(i.dir, j.dir) }) e.Int(len(packages)) packagesPos := e.Pos() diff --git a/src/cmd/go/internal/modload/import.go b/src/cmd/go/internal/modload/import.go index 97c88f193d205a..54199f2b74c699 100644 --- a/src/cmd/go/internal/modload/import.go +++ b/src/cmd/go/internal/modload/import.go @@ -13,7 +13,7 @@ import ( "os" pathpkg "path" "path/filepath" - "sort" + "slices" "strings" "cmd/go/internal/cfg" @@ -543,8 +543,8 @@ func queryImport(ctx context.Context, path string, rs *Requirements) (module.Ver // Every module path in mods is a prefix of the import path. // As in QueryPattern, prefer the longest prefix that satisfies the import. - sort.Slice(mods, func(i, j int) bool { - return len(mods[i].Path) > len(mods[j].Path) + slices.SortFunc(mods, func(i, j module.Version) int { + return len(j.Path) - len(i.Path) }) for _, m := range mods { root, isLocal, err := fetch(ctx, m) diff --git a/src/cmd/go/internal/modload/query.go b/src/cmd/go/internal/modload/query.go index c4cf55442ba69b..0fa9a3d01f468e 100644 --- a/src/cmd/go/internal/modload/query.go +++ b/src/cmd/go/internal/modload/query.go @@ -13,7 +13,6 @@ import ( "os" pathpkg "path" "slices" - "sort" "strings" "sync" "time" @@ -1202,8 +1201,8 @@ func (rr *replacementRepo) Versions(ctx context.Context, prefix string) (*modfet } path := rr.ModulePath() - sort.Slice(versions, func(i, j int) bool { - return gover.ModCompare(path, versions[i], versions[j]) < 0 + slices.SortFunc(versions, func(i, j string) int { + return gover.ModCompare(path, i, j) }) str.Uniq(&versions) return &modfetch.Versions{List: versions}, nil diff --git a/src/cmd/go/internal/mvs/mvs.go b/src/cmd/go/internal/mvs/mvs.go index b46c016c7809e9..2ff2f528d2c83d 100644 --- a/src/cmd/go/internal/mvs/mvs.go +++ b/src/cmd/go/internal/mvs/mvs.go @@ -9,7 +9,7 @@ package mvs import ( "fmt" "slices" - "sort" + "strings" "sync" "cmd/internal/par" @@ -265,8 +265,8 @@ func Req(mainModule module.Version, base []string, reqs Reqs) ([]module.Version, walk(m) } } - sort.Slice(min, func(i, j int) bool { - return min[i].Path < min[j].Path + slices.SortFunc(min, func(a, b module.Version) int { + return strings.Compare(a.Path, b.Path) }) return min, nil } diff --git a/src/cmd/go/internal/toolchain/switch.go b/src/cmd/go/internal/toolchain/switch.go index 37c1bcdcbec656..92bcb96ab57111 100644 --- a/src/cmd/go/internal/toolchain/switch.go +++ b/src/cmd/go/internal/toolchain/switch.go @@ -9,7 +9,7 @@ import ( "fmt" "os" "path/filepath" - "sort" + "slices" "strings" "cmd/go/internal/base" @@ -180,8 +180,8 @@ func pathToolchains(ctx context.Context) ([]string, error) { list = append(list, v) } } - sort.Slice(list, func(i, j int) bool { - return gover.Compare(list[i], list[j]) < 0 + slices.SortFunc(list, func(i, j string) int { + return gover.Compare(i, j) }) return list, nil } diff --git a/src/cmd/internal/moddeps/moddeps_test.go b/src/cmd/internal/moddeps/moddeps_test.go index 2def029325be55..f2b0247d9d976c 100644 --- a/src/cmd/internal/moddeps/moddeps_test.go +++ b/src/cmd/internal/moddeps/moddeps_test.go @@ -14,7 +14,6 @@ import ( "os" "path/filepath" "slices" - "sort" "strings" "sync" "testing" @@ -521,8 +520,8 @@ func findGorootModules(t *testing.T) []gorootModule { break } } - sort.Slice(goroot.modules, func(i, j int) bool { - return goroot.modules[i].Dir < goroot.modules[j].Dir + slices.SortFunc(goroot.modules, func(i, j gorootModule) int { + return strings.Compare(i.Dir, j.Dir) }) }) if goroot.err != nil { diff --git a/src/cmd/internal/obj/objfile.go b/src/cmd/internal/obj/objfile.go index 5ac15b82285052..363927eb44fc44 100644 --- a/src/cmd/internal/obj/objfile.go +++ b/src/cmd/internal/obj/objfile.go @@ -22,7 +22,6 @@ import ( "os" "path/filepath" "slices" - "sort" "strings" ) @@ -780,7 +779,7 @@ func genFuncInfoSyms(ctxt *Link) { o.File[i] = f i++ } - sort.Slice(o.File, func(i, j int) bool { return o.File[i] < o.File[j] }) + slices.Sort(o.File) o.InlTree = make([]goobj.InlTreeNode, len(pc.InlTree.nodes)) for i, inl := range pc.InlTree.nodes { f, l := ctxt.getFileIndexAndLine(inl.Pos) diff --git a/src/cmd/internal/obj/ppc64/asm9.go b/src/cmd/internal/obj/ppc64/asm9.go index 74f1772e3df72f..bcf3800aa568fb 100644 --- a/src/cmd/internal/obj/ppc64/asm9.go +++ b/src/cmd/internal/obj/ppc64/asm9.go @@ -38,7 +38,7 @@ import ( "log" "math" "math/bits" - "sort" + "slices" ) // ctxt9 holds state while assembling a single function. @@ -1188,47 +1188,45 @@ func cmp(a int, b int) bool { // Used when sorting the optab. Sorting is // done in a way so that the best choice of // opcode/operand combination is considered first. -func optabLess(i, j int) bool { - p1 := &optab[i] - p2 := &optab[j] +func optabCmp(p1, p2 Optab) int { n := int(p1.as) - int(p2.as) // same opcode if n != 0 { - return n < 0 + return n } // Consider those that generate fewer // instructions first. n = int(p1.size) - int(p2.size) if n != 0 { - return n < 0 + return n } // operand order should match // better choices first n = int(p1.a1) - int(p2.a1) if n != 0 { - return n < 0 + return n } n = int(p1.a2) - int(p2.a2) if n != 0 { - return n < 0 + return n } n = int(p1.a3) - int(p2.a3) if n != 0 { - return n < 0 + return n } n = int(p1.a4) - int(p2.a4) if n != 0 { - return n < 0 + return n } n = int(p1.a5) - int(p2.a5) if n != 0 { - return n < 0 + return n } n = int(p1.a6) - int(p2.a6) if n != 0 { - return n < 0 + return n } - return false + return 0 } // Add an entry to the opcode table for @@ -1283,7 +1281,7 @@ func buildop(ctxt *obj.Link) { optab = append(optab, optabBase...) optab = append(optab, optabGen...) optab = append(optab, prefixOptab...) - sort.Slice(optab, optabLess) + slices.SortFunc(optab, optabCmp) for i := range optab { // Use the legacy assembler function if none provided. diff --git a/src/cmd/internal/obj/sym.go b/src/cmd/internal/obj/sym.go index ac43a812b91c73..b7573f68b20405 100644 --- a/src/cmd/internal/obj/sym.go +++ b/src/cmd/internal/obj/sym.go @@ -41,7 +41,8 @@ import ( "internal/buildcfg" "log" "math" - "sort" + "slices" + "strings" ) func Linknew(arch *LinkArch) *Link { @@ -215,7 +216,7 @@ func (ctxt *Link) GCLocalsSym(data []byte) *LSym { }) } -// Assign index to symbols. +// NumberSyms Assign index to symbols. // asm is set to true if this is called by the assembler (i.e. not the compiler), // in which case all the symbols are non-package (for now). func (ctxt *Link) NumberSyms() { @@ -223,6 +224,10 @@ func (ctxt *Link) NumberSyms() { panic("NumberSyms called without package path") } + lsymCmp := func(a, b *LSym) int { + return strings.Compare(a.Name, b.Name) + } + if ctxt.Headtype == objabi.Haix { // Data must be in a reliable order for reproducible builds. // The original entries are in a reliable order, but the TOC symbols @@ -232,23 +237,17 @@ func (ctxt *Link) NumberSyms() { // any original entries with the same name (all DWARFVAR symbols // have empty names but different relocation sets) are not shuffled. // TODO: Find a better place and optimize to only sort TOC symbols. - sort.SliceStable(ctxt.Data, func(i, j int) bool { - return ctxt.Data[i].Name < ctxt.Data[j].Name - }) + slices.SortStableFunc(ctxt.Data, lsymCmp) } // Constant symbols are created late in the concurrent phase. Sort them // to ensure a deterministic order. - sort.Slice(ctxt.constSyms, func(i, j int) bool { - return ctxt.constSyms[i].Name < ctxt.constSyms[j].Name - }) + slices.SortFunc(ctxt.constSyms, lsymCmp) ctxt.Data = append(ctxt.Data, ctxt.constSyms...) ctxt.constSyms = nil // So are SEH symbols. - sort.Slice(ctxt.SEHSyms, func(i, j int) bool { - return ctxt.SEHSyms[i].Name < ctxt.SEHSyms[j].Name - }) + slices.SortFunc(ctxt.SEHSyms, lsymCmp) ctxt.Data = append(ctxt.Data, ctxt.SEHSyms...) ctxt.SEHSyms = nil @@ -446,7 +445,7 @@ func (ctxt *Link) traverseFuncAux(flag traverseFlag, fsym *LSym, fn func(parent for f := range pc.UsedFiles { usedFiles = append(usedFiles, f) } - sort.Slice(usedFiles, func(i, j int) bool { return usedFiles[i] < usedFiles[j] }) + slices.Sort(usedFiles) for _, f := range usedFiles { if filesym := ctxt.Lookup(files[f]); filesym != nil { fn(fsym, filesym) diff --git a/src/cmd/internal/pgo/pprof.go b/src/cmd/internal/pgo/pprof.go index 5e61a11141c048..947cbf1d37e20b 100644 --- a/src/cmd/internal/pgo/pprof.go +++ b/src/cmd/internal/pgo/pprof.go @@ -12,7 +12,8 @@ import ( "fmt" "internal/profile" "io" - "sort" + "slices" + "strings" ) // FromPProf parses Profile from a pprof profile. @@ -103,19 +104,17 @@ func createNamedEdgeMap(g *profile.Graph) (edgeMap NamedEdgeMap, totalWeight int } func sortByWeight(edges []NamedCallEdge, weight map[NamedCallEdge]int64) { - sort.Slice(edges, func(i, j int) bool { - ei, ej := edges[i], edges[j] - if wi, wj := weight[ei], weight[ej]; wi != wj { - return wi > wj // want larger weight first + slices.SortFunc(edges, func(i, j NamedCallEdge) int { + if wi, wj := weight[i], weight[j]; wi != wj { + return int(wj - wi) // want larger weight first } - // same weight, order by name/line number - if ei.CallerName != ej.CallerName { - return ei.CallerName < ej.CallerName + if r := strings.Compare(i.CallerName, j.CallerName); r != 0 { + return r } - if ei.CalleeName != ej.CalleeName { - return ei.CalleeName < ej.CalleeName + if r := strings.Compare(i.CalleeName, j.CalleeName); r != 0 { + return r } - return ei.CallSiteOffset < ej.CallSiteOffset + return i.CallSiteOffset - j.CallSiteOffset }) } diff --git a/src/cmd/internal/src/xpos.go b/src/cmd/internal/src/xpos.go index a74505997d2cfd..0049e1811d562a 100644 --- a/src/cmd/internal/src/xpos.go +++ b/src/cmd/internal/src/xpos.go @@ -47,6 +47,18 @@ func (p XPos) After(q XPos) bool { return n > m || n == m && p.lico > q.lico } +// Compare returns an integer comparing the two positions. +func (p XPos) Compare(q XPos) int { + //if r := cmp.Compare(p.index, q.index); r != 0 { + // return r + //} + //return cmp.Compare(p.lico, q.lico) + if p.index != q.index { + return int(p.index - q.index) + } + return int(p.lico) - int(q.lico) +} + // WithNotStmt returns the same location to be marked with DWARF is_stmt=0 func (p XPos) WithNotStmt() XPos { p.lico = p.lico.withNotStmt() diff --git a/src/cmd/internal/testdir/testdir_test.go b/src/cmd/internal/testdir/testdir_test.go index 86ebf7ded61955..55f38123e06542 100644 --- a/src/cmd/internal/testdir/testdir_test.go +++ b/src/cmd/internal/testdir/testdir_test.go @@ -1546,8 +1546,8 @@ func (a asmChecks) Envs() []buildEnv { for e := range a { envs = append(envs, e) } - sort.Slice(envs, func(i, j int) bool { - return string(envs[i]) < string(envs[j]) + slices.SortFunc(envs, func(i, j buildEnv) int { + return strings.Compare(string(i), string(j)) }) return envs } @@ -1720,7 +1720,7 @@ func (t test) asmCheck(outStr string, fn string, env buildEnv, fullops map[strin lastFunction := -1 var errbuf bytes.Buffer fmt.Fprintln(&errbuf) - sort.Slice(failed, func(i, j int) bool { return failed[i].line < failed[j].line }) + slices.SortFunc(failed, func(i, j wantedAsmOpcode) int { return i.line - j.line }) for _, o := range failed { // Dump the function in which this opcode check was supposed to // pass but failed. diff --git a/src/cmd/link/internal/ld/data.go b/src/cmd/link/internal/ld/data.go index cf4b88f895fa66..f5a36f14b0aebe 100644 --- a/src/cmd/link/internal/ld/data.go +++ b/src/cmd/link/internal/ld/data.go @@ -39,6 +39,7 @@ import ( "cmd/link/internal/loader" "cmd/link/internal/loadpe" "cmd/link/internal/sym" + "cmp" "compress/zlib" "debug/elf" "encoding/binary" @@ -47,7 +48,7 @@ import ( "log" "math/rand" "os" - "sort" + "slices" "strconv" "strings" "sync" @@ -2278,33 +2279,41 @@ func (state *dodataState) dodataSect(ctxt *Link, symn sym.SymKind, syms []loader // Perform the sort. if symn != sym.SPCLNTAB { - sort.Slice(sl, func(i, j int) bool { - si, sj := sl[i].sym, sl[j].sym - isz, jsz := sl[i].sz, sl[j].sz + slices.SortFunc(sl, func(i, j symNameSize) int { + si, sj := i.sym, j.sym + isz, jsz := i.sz, j.sz switch { case si == head, sj == tail: - return true + return -1 case sj == head, si == tail: - return false + return 1 + // put zerobase right after all the zero-sized symbols, // so zero-sized symbols have the same address as zerobase. case si == zerobase: - return jsz != 0 // zerobase < nonzero-sized + if jsz != 0 { + return -1 + } + return +1 case sj == zerobase: - return isz == 0 // 0-sized < zerobase + if isz == 0 { + return -1 + } + return +1 } if checkSize { if isz != jsz { - return isz < jsz + if isz < jsz { + return -1 + } + return +1 } } else { - iname := sl[i].name - jname := sl[j].name - if iname != jname { - return iname < jname + if r := strings.Compare(i.name, j.name); r != 0 { + return r } } - return si < sj + return cmp.Compare(si, sj) }) } else { // PCLNTAB was built internally, and already has the proper order. diff --git a/src/cmd/link/internal/ld/inittask.go b/src/cmd/link/internal/ld/inittask.go index ccf90b8b8c505f..3c2724c3f7299f 100644 --- a/src/cmd/link/internal/ld/inittask.go +++ b/src/cmd/link/internal/ld/inittask.go @@ -8,7 +8,9 @@ import ( "cmd/internal/objabi" "cmd/link/internal/loader" "cmd/link/internal/sym" + "cmp" "fmt" + "slices" "sort" ) @@ -146,8 +148,8 @@ func (ctxt *Link) inittaskSym(rootNames []string, symName string) loader.Sym { } // Sort edges so we can look them up by edge destination. - sort.Slice(edges, func(i, j int) bool { - return edges[i].to < edges[j].to + slices.SortFunc(edges, func(i, j edge) int { + return cmp.Compare(i.to, j.to) }) // Figure out the schedule. diff --git a/src/cmd/link/internal/ld/macho.go b/src/cmd/link/internal/ld/macho.go index 34624c25a9f333..60daa640608ba4 100644 --- a/src/cmd/link/internal/ld/macho.go +++ b/src/cmd/link/internal/ld/macho.go @@ -17,7 +17,7 @@ import ( "internal/buildcfg" "io" "os" - "sort" + "slices" "strings" "unsafe" ) @@ -1006,15 +1006,14 @@ func machosymorder(ctxt *Link) { } } collectmachosyms(ctxt) - sort.Slice(sortsym[:nsortsym], func(i, j int) bool { - s1 := sortsym[i] - s2 := sortsym[j] - k1 := symkind(ldr, s1) - k2 := symkind(ldr, s2) + slices.SortFunc(sortsym[:nsortsym], func(a, b loader.Sym) int { + k1 := symkind(ldr, a) + k2 := symkind(ldr, b) if k1 != k2 { - return k1 < k2 + return k1 - k2 } - return ldr.SymExtname(s1) < ldr.SymExtname(s2) // Note: unnamed symbols are not added in collectmachosyms + // Note: unnamed symbols are not added in collectmachosyms + return strings.Compare(ldr.SymExtname(a), ldr.SymExtname(b)) }) for i, s := range sortsym { ldr.SetSymDynid(s, int32(i)) diff --git a/src/cmd/link/internal/ld/pe.go b/src/cmd/link/internal/ld/pe.go index cd553e909ad2fe..2c9c53bf9cf125 100644 --- a/src/cmd/link/internal/ld/pe.go +++ b/src/cmd/link/internal/ld/pe.go @@ -18,7 +18,6 @@ import ( "internal/buildcfg" "math" "slices" - "sort" "strconv" "strings" ) @@ -1400,7 +1399,9 @@ func initdynexport(ctxt *Link) { dexport = append(dexport, s) } - sort.Slice(dexport, func(i, j int) bool { return ldr.SymExtname(dexport[i]) < ldr.SymExtname(dexport[j]) }) + slices.SortFunc(dexport, func(a, b loader.Sym) int { + return strings.Compare(ldr.SymExtname(a), ldr.SymExtname(b)) + }) } func addexports(ctxt *Link) { diff --git a/src/cmd/link/internal/ld/stackcheck.go b/src/cmd/link/internal/ld/stackcheck.go index 98e7edaeb1477b..52e887dbdc89c2 100644 --- a/src/cmd/link/internal/ld/stackcheck.go +++ b/src/cmd/link/internal/ld/stackcheck.go @@ -8,9 +8,10 @@ import ( "cmd/internal/obj" "cmd/internal/objabi" "cmd/link/internal/loader" + "cmp" "fmt" "internal/buildcfg" - "sort" + "slices" "strings" ) @@ -344,13 +345,13 @@ func (sc *stackCheck) findRoots() []loader.Sym { for k := range nodes { roots = append(roots, k) } - sort.Slice(roots, func(i, j int) bool { - h1, h2 := sc.height[roots[i]], sc.height[roots[j]] + slices.SortFunc(roots, func(i, j loader.Sym) int { + h1, h2 := sc.height[i], sc.height[j] if h1 != h2 { - return h1 > h2 + return int(h2 - h1) } // Secondary sort by Sym. - return roots[i] < roots[j] + return cmp.Compare(i, j) }) return roots } diff --git a/src/cmd/link/internal/ld/xcoff.go b/src/cmd/link/internal/ld/xcoff.go index d915ab393b541b..4880b9a11f84e4 100644 --- a/src/cmd/link/internal/ld/xcoff.go +++ b/src/cmd/link/internal/ld/xcoff.go @@ -6,12 +6,13 @@ package ld import ( "bytes" + "cmp" "encoding/binary" "fmt" "math/bits" "os" "path/filepath" - "sort" + "slices" "strings" "sync" @@ -1405,18 +1406,17 @@ func (f *xcoffFile) writeLdrScn(ctxt *Link, globalOff uint64) { /* Reloc */ // Ensure deterministic order - sort.Slice(f.loaderReloc, func(i, j int) bool { - r1, r2 := f.loaderReloc[i], f.loaderReloc[j] - if r1.sym != r2.sym { - return r1.sym < r2.sym + slices.SortFunc(f.loaderReloc, func(a, b *xcoffLoaderReloc) int { + if a.sym != b.sym { + return cmp.Compare(a.sym, b.sym) } - if r1.roff != r2.roff { - return r1.roff < r2.roff + if a.roff != b.roff { + return int(a.roff - b.roff) } - if r1.rtype != r2.rtype { - return r1.rtype < r2.rtype + if a.rtype != b.rtype { + return cmp.Compare(a.rtype, b.rtype) } - return r1.symndx < r2.symndx + return int(a.symndx - b.symndx) }) ep := ldr.Lookup(*flagEntrySymbol, 0) @@ -1704,8 +1704,10 @@ func (f *xcoffFile) emitRelocations(ctxt *Link, fileoff int64) { for i := 0; i < relocs.Count(); i++ { sorted[i] = i } - sort.Slice(sorted, func(i, j int) bool { - return relocs.At(sorted[i]).Off() < relocs.At(sorted[j]).Off() + slices.SortFunc(sorted, func(a, b int) int { + at := relocs.At(a) + bt := relocs.At(b) + return int(at.Off() - bt.Off()) }) for _, ri := range sorted { diff --git a/src/cmd/link/internal/loader/loader.go b/src/cmd/link/internal/loader/loader.go index a391c8ced93bba..5f6be52b99e691 100644 --- a/src/cmd/link/internal/loader/loader.go +++ b/src/cmd/link/internal/loader/loader.go @@ -19,6 +19,7 @@ import ( "log" "math/bits" "os" + "slices" "sort" "strings" ) @@ -1515,7 +1516,7 @@ func (l *Loader) DynidSyms() []Sym { for s := range l.dynid { sl = append(sl, s) } - sort.Slice(sl, func(i, j int) bool { return sl[i] < sl[j] }) + slices.Sort(sl) return sl } @@ -1838,10 +1839,12 @@ func (l *Loader) SortSub(s Sym) Sym { // SortSyms sorts a list of symbols by their value. func (l *Loader) SortSyms(ss []Sym) { - sort.SliceStable(ss, func(i, j int) bool { return l.SymValue(ss[i]) < l.SymValue(ss[j]) }) + slices.SortStableFunc(ss, func(a, b Sym) int { + return int(l.SymValue(a) - l.SymValue(b)) + }) } -// Insure that reachable bitmap and its siblings have enough size. +// Ensure that reachable bitmap and its siblings have enough size. func (l *Loader) growAttrBitmaps(reqLen int) { if reqLen > l.attrReachable.Len() { // These are indexed by global symbol diff --git a/src/cmd/nm/nm.go b/src/cmd/nm/nm.go index 752870654d5ccd..fa417f3215a68d 100644 --- a/src/cmd/nm/nm.go +++ b/src/cmd/nm/nm.go @@ -6,11 +6,13 @@ package main import ( "bufio" + "cmp" "flag" "fmt" "log" "os" - "sort" + "slices" + "strings" "cmd/internal/objfile" "cmd/internal/telemetry/counter" @@ -127,14 +129,22 @@ func nm(file string) { found = true + var sorter func(i, j objfile.Sym) int switch *sortOrder { case "address": - sort.Slice(syms, func(i, j int) bool { return syms[i].Addr < syms[j].Addr }) + sorter = func(i, j objfile.Sym) int { + return cmp.Compare(i.Addr, j.Addr) + } case "name": - sort.Slice(syms, func(i, j int) bool { return syms[i].Name < syms[j].Name }) + sorter = func(i, j objfile.Sym) int { + return strings.Compare(i.Name, j.Name) + } case "size": - sort.Slice(syms, func(i, j int) bool { return syms[i].Size > syms[j].Size }) + sorter = func(i, j objfile.Sym) int { + return cmp.Compare(j.Size, i.Size) + } } + slices.SortFunc(syms, sorter) for _, sym := range syms { if len(entries) > 1 { diff --git a/src/go/types/initorder.go b/src/go/types/initorder.go index e539219773bb32..e358894a4ef05d 100644 --- a/src/go/types/initorder.go +++ b/src/go/types/initorder.go @@ -11,7 +11,7 @@ import ( "container/heap" "fmt" . "internal/types/errors" - "sort" + "slices" ) // initOrder computes the Info.InitOrder for package variables. @@ -260,8 +260,8 @@ func dependencyGraph(objMap map[Object]*declInfo) []*graphNode { // throughout the function graph, the cost of removing a function at // position X is proportional to cost * (len(funcG)-X). Therefore, we should // remove high-cost functions last. - sort.Slice(funcG, func(i, j int) bool { - return funcG[i].cost() < funcG[j].cost() + slices.SortFunc(funcG, func(a, b *graphNode) int { + return a.cost() - b.cost() }) for _, n := range funcG { // connect each predecessor p of n with each successor s diff --git a/src/go/types/methodset.go b/src/go/types/methodset.go index ac8f0bdd288e27..87d2ca0aa7c1ec 100644 --- a/src/go/types/methodset.go +++ b/src/go/types/methodset.go @@ -8,6 +8,7 @@ package types import ( "fmt" + "slices" "sort" "strings" ) @@ -201,8 +202,8 @@ func NewMethodSet(T Type) *MethodSet { } } // sort by unique name - sort.Slice(list, func(i, j int) bool { - return list[i].obj.Id() < list[j].obj.Id() + slices.SortFunc(list, func(a, b *Selection) int { + return strings.Compare(a.obj.Id(), b.obj.Id()) }) return &MethodSet{list} } diff --git a/src/go/types/stmt.go b/src/go/types/stmt.go index f8514fdbb79ee4..88c505712526fc 100644 --- a/src/go/types/stmt.go +++ b/src/go/types/stmt.go @@ -12,7 +12,7 @@ import ( "go/token" "internal/buildcfg" . "internal/types/errors" - "sort" + "slices" ) func (check *Checker) funcBody(decl *declInfo, name string, sig *Signature, body *ast.BlockStmt, iota constant.Value) { @@ -61,8 +61,8 @@ func (check *Checker) usage(scope *Scope) { unused = append(unused, v) } } - sort.Slice(unused, func(i, j int) bool { - return cmpPos(unused[i].pos, unused[j].pos) < 0 + slices.SortFunc(unused, func(i, j *Var) int { + return cmpPos(i.pos, j.pos) }) for _, v := range unused { check.softErrorf(v, UnusedVar, "declared and not used: %s", v.name) diff --git a/src/net/http/pprof/pprof.go b/src/net/http/pprof/pprof.go index cf4b8415ca3aaf..a1f1285cb6178d 100644 --- a/src/net/http/pprof/pprof.go +++ b/src/net/http/pprof/pprof.go @@ -86,7 +86,7 @@ import ( "runtime" "runtime/pprof" "runtime/trace" - "sort" + "slices" "strconv" "strings" "time" @@ -412,8 +412,8 @@ func Index(w http.ResponseWriter, r *http.Request) { }) } - sort.Slice(profiles, func(i, j int) bool { - return profiles[i].Name < profiles[j].Name + slices.SortFunc(profiles, func(i, j profileEntry) int { + return strings.Compare(i.Name, j.Name) }) if err := indexTmplExecute(w, profiles); err != nil {