Skip to content

Commit bca70a6

Browse files
osocuriosodavecheney
authored andcommitted
cmd/compile/internal/gc: use sort.Interface for reflect methods
Generate slices of method *Sig(nature)s instead of linked lists. Remove custom lsort function in favor of sort.Interface. Eliminates another use of stringsCompare. Passes go build -a -toolexec 'toolstash -cmp' std cmd. Change-Id: I9ed1664b7f55be9e967dd7196e396a76f6ea3422 Reviewed-on: https://go-review.googlesource.com/14559 Reviewed-by: Dave Cheney <[email protected]>
1 parent ebd9693 commit bca70a6

File tree

3 files changed

+116
-148
lines changed

3 files changed

+116
-148
lines changed

src/cmd/compile/internal/gc/go.go

-1
Original file line numberDiff line numberDiff line change
@@ -376,7 +376,6 @@ type Sig struct {
376376
type_ *Type
377377
mtype *Type
378378
offset int32
379-
link *Sig
380379
}
381380

382381
type Io struct {

src/cmd/compile/internal/gc/reflect.go

+69-147
Original file line numberDiff line numberDiff line change
@@ -9,100 +9,38 @@ import (
99
"cmd/internal/obj"
1010
"fmt"
1111
"os"
12+
"sort"
1213
)
1314

1415
/*
1516
* runtime interface and reflection data structures
1617
*/
1718
var signatlist *NodeList
1819

19-
func sigcmp(a *Sig, b *Sig) int {
20-
i := stringsCompare(a.name, b.name)
21-
if i != 0 {
22-
return i
20+
// byMethodNameAndPackagePath sorts method signatures by name, then package path.
21+
type byMethodNameAndPackagePath []*Sig
22+
23+
func (x byMethodNameAndPackagePath) Len() int { return len(x) }
24+
func (x byMethodNameAndPackagePath) Swap(i, j int) { x[i], x[j] = x[j], x[i] }
25+
func (x byMethodNameAndPackagePath) Less(i, j int) bool {
26+
return siglt(x[i], x[j])
27+
}
28+
29+
// siglt reports whether a < b
30+
func siglt(a, b *Sig) bool {
31+
if a.name != b.name {
32+
return a.name < b.name
2333
}
2434
if a.pkg == b.pkg {
25-
return 0
35+
return false
2636
}
2737
if a.pkg == nil {
28-
return -1
38+
return true
2939
}
3040
if b.pkg == nil {
31-
return +1
32-
}
33-
return stringsCompare(a.pkg.Path, b.pkg.Path)
34-
}
35-
36-
func lsort(l *Sig, f func(*Sig, *Sig) int) *Sig {
37-
if l == nil || l.link == nil {
38-
return l
39-
}
40-
41-
l1 := l
42-
l2 := l
43-
for {
44-
l2 = l2.link
45-
if l2 == nil {
46-
break
47-
}
48-
l2 = l2.link
49-
if l2 == nil {
50-
break
51-
}
52-
l1 = l1.link
53-
}
54-
55-
l2 = l1.link
56-
l1.link = nil
57-
l1 = lsort(l, f)
58-
l2 = lsort(l2, f)
59-
60-
/* set up lead element */
61-
if f(l1, l2) < 0 {
62-
l = l1
63-
l1 = l1.link
64-
} else {
65-
l = l2
66-
l2 = l2.link
67-
}
68-
69-
le := l
70-
71-
for {
72-
if l1 == nil {
73-
for l2 != nil {
74-
le.link = l2
75-
le = l2
76-
l2 = l2.link
77-
}
78-
79-
le.link = nil
80-
break
81-
}
82-
83-
if l2 == nil {
84-
for l1 != nil {
85-
le.link = l1
86-
le = l1
87-
l1 = l1.link
88-
}
89-
90-
break
91-
}
92-
93-
if f(l1, l2) < 0 {
94-
le.link = l1
95-
le = l1
96-
l1 = l1.link
97-
} else {
98-
le.link = l2
99-
le = l2
100-
l2 = l2.link
101-
}
41+
return false
10242
}
103-
104-
le.link = nil
105-
return l
43+
return a.pkg.Path < b.pkg.Path
10644
}
10745

10846
// Builds a type representing a Bucket structure for
@@ -335,11 +273,9 @@ func methodfunc(f *Type, receiver *Type) *Type {
335273
return t
336274
}
337275

338-
/*
339-
* return methods of non-interface type t, sorted by name.
340-
* generates stub functions as needed.
341-
*/
342-
func methods(t *Type) *Sig {
276+
// methods returns the methods of the non-interface type t, sorted by name.
277+
// Generates stub functions as needed.
278+
func methods(t *Type) []*Sig {
343279
// method type
344280
mt := methtype(t, 0)
345281

@@ -357,11 +293,7 @@ func methods(t *Type) *Sig {
357293

358294
// make list of methods for t,
359295
// generating code if necessary.
360-
var a *Sig
361-
362-
var this *Type
363-
var b *Sig
364-
var method *Sym
296+
var ms []*Sig
365297
for f := mt.Xmethod; f != nil; f = f.Down {
366298
if f.Etype != TFIELD {
367299
Fatalf("methods: not field %v", f)
@@ -376,7 +308,7 @@ func methods(t *Type) *Sig {
376308
continue
377309
}
378310

379-
method = f.Sym
311+
method := f.Sym
380312
if method == nil {
381313
continue
382314
}
@@ -385,7 +317,7 @@ func methods(t *Type) *Sig {
385317
// if pointer receiver but non-pointer t and
386318
// this is not an embedded pointer inside a struct,
387319
// method does not apply.
388-
this = getthisx(f.Type).Type.Type
320+
this := getthisx(f.Type).Type.Type
389321

390322
if Isptr[this.Etype] && this.Type == t {
391323
continue
@@ -394,85 +326,77 @@ func methods(t *Type) *Sig {
394326
continue
395327
}
396328

397-
b = new(Sig)
398-
b.link = a
399-
a = b
329+
var sig Sig
330+
ms = append(ms, &sig)
400331

401-
a.name = method.Name
332+
sig.name = method.Name
402333
if !exportname(method.Name) {
403334
if method.Pkg == nil {
404335
Fatalf("methods: missing package")
405336
}
406-
a.pkg = method.Pkg
337+
sig.pkg = method.Pkg
407338
}
408339

409-
a.isym = methodsym(method, it, 1)
410-
a.tsym = methodsym(method, t, 0)
411-
a.type_ = methodfunc(f.Type, t)
412-
a.mtype = methodfunc(f.Type, nil)
340+
sig.isym = methodsym(method, it, 1)
341+
sig.tsym = methodsym(method, t, 0)
342+
sig.type_ = methodfunc(f.Type, t)
343+
sig.mtype = methodfunc(f.Type, nil)
413344

414-
if a.isym.Flags&SymSiggen == 0 {
415-
a.isym.Flags |= SymSiggen
345+
if sig.isym.Flags&SymSiggen == 0 {
346+
sig.isym.Flags |= SymSiggen
416347
if !Eqtype(this, it) || this.Width < Types[Tptr].Width {
417348
compiling_wrappers = 1
418-
genwrapper(it, f, a.isym, 1)
349+
genwrapper(it, f, sig.isym, 1)
419350
compiling_wrappers = 0
420351
}
421352
}
422353

423-
if a.tsym.Flags&SymSiggen == 0 {
424-
a.tsym.Flags |= SymSiggen
354+
if sig.tsym.Flags&SymSiggen == 0 {
355+
sig.tsym.Flags |= SymSiggen
425356
if !Eqtype(this, t) {
426357
compiling_wrappers = 1
427-
genwrapper(t, f, a.tsym, 0)
358+
genwrapper(t, f, sig.tsym, 0)
428359
compiling_wrappers = 0
429360
}
430361
}
431362
}
432363

433-
return lsort(a, sigcmp)
364+
sort.Sort(byMethodNameAndPackagePath(ms))
365+
return ms
434366
}
435367

436-
/*
437-
* return methods of interface type t, sorted by name.
438-
*/
439-
func imethods(t *Type) *Sig {
440-
var a *Sig
441-
var method *Sym
442-
var isym *Sym
443-
444-
var all *Sig
445-
var last *Sig
368+
// imethods returns the methods of the interface type t, sorted by name.
369+
func imethods(t *Type) []*Sig {
370+
var methods []*Sig
446371
for f := t.Type; f != nil; f = f.Down {
447372
if f.Etype != TFIELD {
448373
Fatalf("imethods: not field")
449374
}
450375
if f.Type.Etype != TFUNC || f.Sym == nil {
451376
continue
452377
}
453-
method = f.Sym
454-
a = new(Sig)
455-
a.name = method.Name
378+
method := f.Sym
379+
var sig = Sig{
380+
name: method.Name,
381+
}
456382
if !exportname(method.Name) {
457383
if method.Pkg == nil {
458384
Fatalf("imethods: missing package")
459385
}
460-
a.pkg = method.Pkg
386+
sig.pkg = method.Pkg
461387
}
462388

463-
a.mtype = f.Type
464-
a.offset = 0
465-
a.type_ = methodfunc(f.Type, nil)
389+
sig.mtype = f.Type
390+
sig.offset = 0
391+
sig.type_ = methodfunc(f.Type, nil)
466392

467-
if last != nil && sigcmp(last, a) >= 0 {
468-
Fatalf("sigcmp vs sortinter %s %s", last.name, a.name)
469-
}
470-
if last == nil {
471-
all = a
472-
} else {
473-
last.link = a
393+
if n := len(methods); n > 0 {
394+
last := methods[n-1]
395+
if !(siglt(last, &sig)) {
396+
Fatalf("sigcmp vs sortinter %s %s", last.name, sig.name)
397+
}
474398
}
475-
last = a
399+
methods = append(methods, &sig)
476400

477401
// Compiler can only refer to wrappers for non-blank methods.
478402
if isblanksym(method) {
@@ -483,15 +407,15 @@ func imethods(t *Type) *Sig {
483407
// IfaceType.Method is not in the reflect data.
484408
// Generate the method body, so that compiled
485409
// code can refer to it.
486-
isym = methodsym(method, t, 0)
410+
isym := methodsym(method, t, 0)
487411

488412
if isym.Flags&SymSiggen == 0 {
489413
isym.Flags |= SymSiggen
490414
genwrapper(t, f, isym, 0)
491415
}
492416
}
493417

494-
return all
418+
return methods
495419
}
496420

497421
var dimportpath_gopkg *Pkg
@@ -559,7 +483,7 @@ func dgopkgpath(s *Sym, ot int, pkg *Pkg) int {
559483
*/
560484
func dextratype(sym *Sym, off int, t *Type, ptroff int) int {
561485
m := methods(t)
562-
if t.Sym == nil && m == nil {
486+
if t.Sym == nil && len(m) == 0 {
563487
return off
564488
}
565489

@@ -568,10 +492,8 @@ func dextratype(sym *Sym, off int, t *Type, ptroff int) int {
568492

569493
dsymptr(sym, ptroff, sym, off)
570494

571-
n := 0
572-
for a := m; a != nil; a = a.link {
495+
for _, a := range m {
573496
dtypesym(a.type_)
574-
n++
575497
}
576498

577499
ot := off
@@ -591,11 +513,12 @@ func dextratype(sym *Sym, off int, t *Type, ptroff int) int {
591513
// slice header
592514
ot = dsymptr(s, ot, s, ot+Widthptr+2*Widthint)
593515

516+
n := len(m)
594517
ot = duintxx(s, ot, uint64(n), Widthint)
595518
ot = duintxx(s, ot, uint64(n), Widthint)
596519

597520
// methods
598-
for a := m; a != nil; a = a.link {
521+
for _, a := range m {
599522
// method
600523
// ../../runtime/type.go:/method
601524
ot = dgostringptr(s, ot, a.name)
@@ -1171,28 +1094,27 @@ ok:
11711094

11721095
case TINTER:
11731096
m := imethods(t)
1174-
n := 0
1175-
for a := m; a != nil; a = a.link {
1097+
n := len(m)
1098+
for _, a := range m {
11761099
dtypesym(a.type_)
1177-
n++
11781100
}
11791101

1180-
// ../../runtime/type.go:/InterfaceType
1102+
// ../../../runtime/type.go:/InterfaceType
11811103
ot = dcommontype(s, ot, t)
11821104

11831105
xt = ot - 2*Widthptr
11841106
ot = dsymptr(s, ot, s, ot+Widthptr+2*Widthint)
11851107
ot = duintxx(s, ot, uint64(n), Widthint)
11861108
ot = duintxx(s, ot, uint64(n), Widthint)
1187-
for a := m; a != nil; a = a.link {
1188-
// ../../runtime/type.go:/imethod
1109+
for _, a := range m {
1110+
// ../../../runtime/type.go:/imethod
11891111
ot = dgostringptr(s, ot, a.name)
11901112

11911113
ot = dgopkgpath(s, ot, a.pkg)
11921114
ot = dsymptr(s, ot, dtypesym(a.type_), 0)
11931115
}
11941116

1195-
// ../../runtime/type.go:/MapType
1117+
// ../../../runtime/type.go:/MapType
11961118
case TMAP:
11971119
s1 := dtypesym(t.Down)
11981120

0 commit comments

Comments
 (0)