diff --git a/src/cmd/compile/internal/gc/reflect.go b/src/cmd/compile/internal/gc/reflect.go index b11ca7082a8..815086777a2 100644 --- a/src/cmd/compile/internal/gc/reflect.go +++ b/src/cmd/compile/internal/gc/reflect.go @@ -34,7 +34,7 @@ type ptabEntry struct { } // runtime interface and reflection data structures -var signatlist []*Type +var signatlist = make(map[*Type]bool) var itabs []itabEntry var ptabs []ptabEntry @@ -933,24 +933,22 @@ func typesymprefix(prefix string, t *Type) *Sym { func typenamesym(t *Type) *Sym { if t == nil || (t.IsPtr() && t.Elem() == nil) || t.IsUntyped() { - Fatalf("typename %v", t) + Fatalf("typenamesym %v", t) } s := typesym(t) + addsignat(t) + return s +} + +func typename(t *Type) *Node { + s := typenamesym(t) if s.Def == nil { n := newnamel(src.NoXPos, s) n.Type = Types[TUINT8] n.Class = PEXTERN n.Typecheck = 1 s.Def = n - - signatlist = append(signatlist, t) } - - return s.Def.Sym -} - -func typename(t *Type) *Node { - s := typenamesym(t) n := nod(OADDR, s.Def, nil) n.Type = typPtr(s.Def.Type) n.SetAddable(true) @@ -1417,21 +1415,35 @@ func itabsym(it *obj.LSym, offset int64) *obj.LSym { return syms[methodnum] } +func addsignat(t *Type) { + signatlist[t] = true +} + func dumptypestructs() { // copy types from externdcl list to signatlist for _, n := range externdcl { if n.Op == OTYPE { - signatlist = append(signatlist, n.Type) + addsignat(n.Type) } } - // Process signatlist. This can't use range, as entries are - // added to the list while it is being processed. - for i := 0; i < len(signatlist); i++ { - t := signatlist[i] - dtypesym(t) - if t.Sym != nil { - dtypesym(typPtr(t)) + // Process signatlist. Use a loop, as dtypesym adds + // entries to signatlist while it is being processed. + signats := make([]typeAndStr, len(signatlist)) + for len(signatlist) > 0 { + signats = signats[:0] + // Transfer entries to a slice and sort, for reproducible builds. + for t := range signatlist { + signats = append(signats, typeAndStr{t: t, s: t.LongString()}) + delete(signatlist, t) + } + sort.Sort(typesByLongString(signats)) + for _, ts := range signats { + t := ts.t + dtypesym(t) + if t.Sym != nil { + dtypesym(typPtr(t)) + } } } @@ -1532,6 +1544,18 @@ func dumptypestructs() { } } +type typeAndStr struct { + t *Type + s string +} + +// TODO(josharian): simplify this to just use Type.cmp once issue 19869 has been fixed. +type typesByLongString []typeAndStr + +func (a typesByLongString) Len() int { return len(a) } +func (a typesByLongString) Less(i, j int) bool { return a[i].s < a[j].s } +func (a typesByLongString) Swap(i, j int) { a[i], a[j] = a[j], a[i] } + type pkgByPath []*Pkg func (a pkgByPath) Len() int { return len(a) } diff --git a/src/cmd/compile/internal/gc/type.go b/src/cmd/compile/internal/gc/type.go index b7411127112..61220648cdc 100644 --- a/src/cmd/compile/internal/gc/type.go +++ b/src/cmd/compile/internal/gc/type.go @@ -976,6 +976,8 @@ func (r *Sym) cmpsym(s *Sym) ssa.Cmp { // cmp compares two *Types t and x, returning ssa.CMPlt, // ssa.CMPeq, ssa.CMPgt as tx, for an arbitrary // and optimizer-centric notion of comparison. +// TODO(josharian): make this safe for recursive interface types +// and use in signatlist sorting. See issue 19869. func (t *Type) cmp(x *Type) ssa.Cmp { // This follows the structure of eqtype in subr.go // with two exceptions.