diff --git a/src/cmd/compile/internal/gc/align.go b/src/cmd/compile/internal/gc/align.go index 2dc3f41212..cabb0a9bae 100644 --- a/src/cmd/compile/internal/gc/align.go +++ b/src/cmd/compile/internal/gc/align.go @@ -223,7 +223,7 @@ func dowidth(t *Type) { w = int64(Widthptr) checkwidth(t.Type) - checkwidth(t.Down) + checkwidth(t.Key()) case TFORW: // should have been filled in if !t.Broke { diff --git a/src/cmd/compile/internal/gc/bexport.go b/src/cmd/compile/internal/gc/bexport.go index 6bb14dea2f..67b0f97c0f 100644 --- a/src/cmd/compile/internal/gc/bexport.go +++ b/src/cmd/compile/internal/gc/bexport.go @@ -534,8 +534,8 @@ func (p *exporter) typ(t *Type) { case TMAP: p.tag(mapTag) - p.typ(t.Down) // key - p.typ(t.Type) // val + p.typ(t.Key()) // key + p.typ(t.Type) // val case TCHAN: p.tag(chanTag) diff --git a/src/cmd/compile/internal/gc/dcl.go b/src/cmd/compile/internal/gc/dcl.go index 6f02914643..8c9906cc16 100644 --- a/src/cmd/compile/internal/gc/dcl.go +++ b/src/cmd/compile/internal/gc/dcl.go @@ -827,12 +827,11 @@ func tostruct0(t *Type, l []*Node) { Fatalf("struct expected") } - tp := &t.Type + var fields []*Type for _, n := range l { - f := structfield(n) - *tp = f - tp = &f.Down + fields = append(fields, structfield(n)) } + t.SetFields(fields) for f, it := IterFields(t); f != nil && !t.Broke; f = it.Next() { if f.Broke { @@ -849,14 +848,12 @@ func tostruct0(t *Type, l []*Node) { } func tofunargs(l []*Node) *Type { - var f *Type - t := typ(TSTRUCT) t.Funarg = true - tp := &t.Type + var fields []*Type for _, n := range l { - f = structfield(n) + f := structfield(n) f.Funarg = true // esc.go needs to find f given a PPARAM to add the tag. @@ -864,9 +861,9 @@ func tofunargs(l []*Node) *Type { n.Left.Name.Param.Field = f } - *tp = f - tp = &f.Down + fields = append(fields, f) } + t.SetFields(fields) for f, it := IterFields(t); f != nil && !t.Broke; f = it.Next() { if f.Broke { @@ -955,7 +952,7 @@ func tointerface0(t *Type, l []*Node) *Type { Fatalf("interface expected") } - tp := &t.Type + var fields []*Type for _, n := range l { f := interfacefield(n) @@ -969,14 +966,13 @@ func tointerface0(t *Type, l []*Node) *Type { if f.Sym != nil { f.Nname = newname(f.Sym) } - *tp = f - tp = &f.Down + fields = append(fields, f) } } else { - *tp = f - tp = &f.Down + fields = append(fields, f) } } + t.SetFields(fields) for f, it := IterFields(t); f != nil && !t.Broke; f = it.Next() { if f.Broke { diff --git a/src/cmd/compile/internal/gc/fmt.go b/src/cmd/compile/internal/gc/fmt.go index 6d7a50a98b..4597cebffd 100644 --- a/src/cmd/compile/internal/gc/fmt.go +++ b/src/cmd/compile/internal/gc/fmt.go @@ -580,7 +580,7 @@ func typefmt(t *Type, flag int) string { return fmt.Sprintf("chan %v", t.Type) case TMAP: - return fmt.Sprintf("map[%v]%v", t.Down, t.Type) + return fmt.Sprintf("map[%v]%v", t.Key(), t.Type) case TINTER: var buf bytes.Buffer @@ -645,15 +645,15 @@ func typefmt(t *Type, flag int) string { // Format the bucket struct for map[x]y as map.bucket[x]y. // This avoids a recursive print that generates very long names. if t.Map.Bucket == t { - return fmt.Sprintf("map.bucket[%v]%v", t.Map.Down, t.Map.Type) + return fmt.Sprintf("map.bucket[%v]%v", t.Map.Key(), t.Map.Type) } if t.Map.Hmap == t { - return fmt.Sprintf("map.hdr[%v]%v", t.Map.Down, t.Map.Type) + return fmt.Sprintf("map.hdr[%v]%v", t.Map.Key(), t.Map.Type) } if t.Map.Hiter == t { - return fmt.Sprintf("map.iter[%v]%v", t.Map.Down, t.Map.Type) + return fmt.Sprintf("map.iter[%v]%v", t.Map.Key(), t.Map.Type) } Yyerror("unknown internal map type") diff --git a/src/cmd/compile/internal/gc/range.go b/src/cmd/compile/internal/gc/range.go index d4df16b52b..1459b7a477 100644 --- a/src/cmd/compile/internal/gc/range.go +++ b/src/cmd/compile/internal/gc/range.go @@ -56,7 +56,7 @@ func typecheckrange(n *Node) { t2 = t.Type case TMAP: - t1 = t.Down + t1 = t.Key() t2 = t.Type case TCHAN: @@ -228,12 +228,12 @@ func walkrange(n *Node) { hit := prealloc[n] hit.Type = th n.Left = nil - keyname := newname(th.Type.Sym) // depends on layout of iterator struct. See reflect.go:hiter - valname := newname(th.Type.Down.Sym) // ditto + keyname := newname(th.Field(0).Sym) // depends on layout of iterator struct. See reflect.go:hiter + valname := newname(th.Field(1).Sym) // ditto fn := syslook("mapiterinit") - substArgTypes(&fn, t.Down, t.Type, th) + substArgTypes(&fn, t.Key(), t.Type, th) init = append(init, mkcall1(fn, nil, nil, typename(t), ha, Nod(OADDR, hit, nil))) n.Left = Nod(ONE, Nod(ODOT, hit, keyname), nodnil()) diff --git a/src/cmd/compile/internal/gc/reflect.go b/src/cmd/compile/internal/gc/reflect.go index 306f7c7d36..b9cc215c8e 100644 --- a/src/cmd/compile/internal/gc/reflect.go +++ b/src/cmd/compile/internal/gc/reflect.go @@ -75,7 +75,7 @@ func mapbucket(t *Type) *Type { } bucket := typ(TSTRUCT) - keytype := t.Down + keytype := t.Key() valtype := t.Type dowidth(keytype) dowidth(valtype) @@ -119,7 +119,7 @@ func mapbucket(t *Type) *Type { // so if the struct needs 64-bit padding (because a key or value does) // then it would end with an extra 32-bit padding field. // Preempt that by emitting the padding here. - if int(t.Type.Align) > Widthptr || int(t.Down.Align) > Widthptr { + if int(t.Type.Align) > Widthptr || int(t.Key().Align) > Widthptr { field = append(field, makefield("pad", Types[TUINTPTR])) } @@ -130,7 +130,7 @@ func mapbucket(t *Type) *Type { // the type of the overflow field to uintptr in this case. // See comment on hmap.overflow in ../../../../runtime/hashmap.go. otyp := Ptrto(bucket) - if !haspointers(t.Type) && !haspointers(t.Down) && t.Type.Width <= MAXKEYSIZE && t.Down.Width <= MAXVALSIZE { + if !haspointers(t.Type) && !haspointers(t.Key()) && t.Type.Width <= MAXVALSIZE && t.Key().Width <= MAXKEYSIZE { otyp = Types[TUINTPTR] } ovf := makefield("overflow", otyp) @@ -139,11 +139,7 @@ func mapbucket(t *Type) *Type { // link up fields bucket.Noalg = true bucket.Local = t.Local - bucket.Type = field[0] - for n := int32(0); n < int32(len(field)-1); n++ { - field[n].Down = field[n+1] - } - field[len(field)-1].Down = nil + bucket.SetFields(field[:]) dowidth(bucket) // Double-check that overflow field is final memory in struct, @@ -179,11 +175,7 @@ func hmap(t *Type) *Type { h := typ(TSTRUCT) h.Noalg = true h.Local = t.Local - h.Type = field[0] - for n := int32(0); n < int32(len(field)-1); n++ { - field[n].Down = field[n+1] - } - field[len(field)-1].Down = nil + h.SetFields(field[:]) dowidth(h) t.Hmap = h h.Map = t @@ -212,8 +204,7 @@ func hiter(t *Type) *Type { // } // must match ../../../../runtime/hashmap.go:hiter. var field [12]*Type - field[0] = makefield("key", Ptrto(t.Down)) - + field[0] = makefield("key", Ptrto(t.Key())) field[1] = makefield("val", Ptrto(t.Type)) field[2] = makefield("t", Ptrto(Types[TUINT8])) field[3] = makefield("h", Ptrto(hmap(t))) @@ -228,13 +219,8 @@ func hiter(t *Type) *Type { // build iterator struct holding the above fields i := typ(TSTRUCT) - i.Noalg = true - i.Type = field[0] - for n := int32(0); n < int32(len(field)-1); n++ { - field[n].Down = field[n+1] - } - field[len(field)-1].Down = nil + i.SetFields(field[:]) dowidth(i) if i.Width != int64(12*Widthptr) { Yyerror("hash_iter size not correct %d %d", i.Width, 12*Widthptr) @@ -1124,8 +1110,7 @@ ok: // ../../../../runtime/type.go:/mapType case TMAP: - s1 := dtypesym(t.Down) - + s1 := dtypesym(t.Key()) s2 := dtypesym(t.Type) s3 := dtypesym(mapbucket(t)) s4 := dtypesym(hmap(t)) @@ -1134,11 +1119,11 @@ ok: ot = dsymptr(s, ot, s2, 0) ot = dsymptr(s, ot, s3, 0) ot = dsymptr(s, ot, s4, 0) - if t.Down.Width > MAXKEYSIZE { + if t.Key().Width > MAXKEYSIZE { ot = duint8(s, ot, uint8(Widthptr)) ot = duint8(s, ot, 1) // indirect } else { - ot = duint8(s, ot, uint8(t.Down.Width)) + ot = duint8(s, ot, uint8(t.Key().Width)) ot = duint8(s, ot, 0) // not indirect } @@ -1151,8 +1136,8 @@ ok: } ot = duint16(s, ot, uint16(mapbucket(t).Width)) - ot = duint8(s, ot, uint8(obj.Bool2int(isreflexive(t.Down)))) - ot = duint8(s, ot, uint8(obj.Bool2int(needkeyupdate(t.Down)))) + ot = duint8(s, ot, uint8(obj.Bool2int(isreflexive(t.Key())))) + ot = duint8(s, ot, uint8(obj.Bool2int(needkeyupdate(t.Key())))) ot = dextratype(s, ot, t, 0) case TPTR32, TPTR64: diff --git a/src/cmd/compile/internal/gc/sinit.go b/src/cmd/compile/internal/gc/sinit.go index 6edfe53dae..3b0d269395 100644 --- a/src/cmd/compile/internal/gc/sinit.go +++ b/src/cmd/compile/internal/gc/sinit.go @@ -979,7 +979,7 @@ func maplit(ctxt int, n *Node, var_ *Node, init *Nodes) { // build list of var[c] = expr. // use temporary so that mapassign1 can have addressable key, val. if key == nil { - key = temp(var_.Type.Down) + key = temp(var_.Type.Key()) val = temp(var_.Type.Type) } diff --git a/src/cmd/compile/internal/gc/subr.go b/src/cmd/compile/internal/gc/subr.go index 6c6816570d..96fca9493c 100644 --- a/src/cmd/compile/internal/gc/subr.go +++ b/src/cmd/compile/internal/gc/subr.go @@ -417,23 +417,9 @@ func (x methcmp) Less(i, j int) bool { } func sortinter(t *Type) *Type { - if t.Type == nil || t.Type.Down == nil { - return t - } - - var a []*Type - for f, it := IterFields(t); f != nil; f = it.Next() { - a = append(a, f) - } - sort.Sort(methcmp(a)) - - n := len(a) // n > 0 due to initial conditions. - for i := 0; i < n-1; i++ { - a[i].Down = a[i+1] - } - a[n-1].Down = nil - - t.Type = a[0] + s := t.FieldSlice() + sort.Sort(methcmp(s)) + t.SetFields(s) return t } @@ -740,12 +726,9 @@ func eqtype1(t1, t2 *Type, assumedEqual map[typePair]struct{}) bool { switch t1.Etype { case TINTER, TSTRUCT: - t1 = t1.Type - t2 = t2.Type - for ; t1 != nil && t2 != nil; t1, t2 = t1.Down, t2.Down { - if t1.Etype != TFIELD || t2.Etype != TFIELD { - Fatalf("struct/interface missing field: %v %v", t1, t2) - } + t1, i1 := IterFields(t1) + t2, i2 := IterFields(t2) + for ; t1 != nil && t2 != nil; t1, t2 = i1.Next(), i2.Next() { if t1.Sym != t2.Sym || t1.Embedded != t2.Embedded || !eqtype1(t1.Type, t2.Type, assumedEqual) || !eqnote(t1.Note, t2.Note) { return false } @@ -782,9 +765,14 @@ func eqtype1(t1, t2 *Type, assumedEqual map[typePair]struct{}) bool { if t1.Chan != t2.Chan { return false } + + case TMAP: + if !eqtype1(t1.Key(), t2.Key(), assumedEqual) { + return false + } } - return eqtype1(t1.Down, t2.Down, assumedEqual) && eqtype1(t1.Type, t2.Type, assumedEqual) + return eqtype1(t1.Type, t2.Type, assumedEqual) } // Are t1 and t2 equal struct types when field names are ignored? @@ -795,8 +783,8 @@ func eqtypenoname(t1 *Type, t2 *Type) bool { return false } - t1 = t1.Type - t2 = t2.Type + t1, i1 := IterFields(t1) + t2, i2 := IterFields(t2) for { if !Eqtype(t1, t2) { return false @@ -804,8 +792,8 @@ func eqtypenoname(t1 *Type, t2 *Type) bool { if t1 == nil { return true } - t1 = t1.Down - t2 = t2.Down + t1 = i1.Next() + t2 = i2.Next() } } @@ -2635,13 +2623,13 @@ func isdirectiface(t *Type) bool { TUNSAFEPTR: return true - // Array of 1 direct iface type can be direct. case TARRAY: + // Array of 1 direct iface type can be direct. return t.Bound == 1 && isdirectiface(t.Type) - // Struct with 1 field of direct iface type can be direct. case TSTRUCT: - return t.Type != nil && t.Type.Down == nil && isdirectiface(t.Type.Type) + // Struct with 1 field of direct iface type can be direct. + return countfield(t) == 1 && isdirectiface(t.Field(0).Type) } return false diff --git a/src/cmd/compile/internal/gc/type.go b/src/cmd/compile/internal/gc/type.go index ec06407ecf..e5e12f0bb8 100644 --- a/src/cmd/compile/internal/gc/type.go +++ b/src/cmd/compile/internal/gc/type.go @@ -274,6 +274,12 @@ var recvsParamsResults = [3]func(*Type) *Type{ (*Type).Recvs, (*Type).Params, (*Type).Results, } +// Key returns the key type of map type t. +func (t *Type) Key() *Type { + t.wantEtype(TMAP) + return t.Down +} + // Field returns the i'th field/method of struct/interface type t. func (t *Type) Field(i int) *Type { // TODO: store fields in a slice so we can @@ -294,6 +300,29 @@ func (t *Type) Field(i int) *Type { panic("not enough fields") } +// FieldSlice returns a slice of containing all fields/methods of +// struct/interface type t. +func (t *Type) FieldSlice() []*Type { + var s []*Type + for f, it := IterFields(t); f != nil; f = it.Next() { + s = append(s, f) + } + return s +} + +// SetFields sets struct/interface type t's fields/methods to fields. +func (t *Type) SetFields(fields []*Type) { + if t.Etype != TSTRUCT && t.Etype != TINTER { + Fatalf("SetFields: type %v does not have fields", t) + } + var next *Type + for i := len(fields) - 1; i >= 0; i-- { + fields[i].Down = next + next = fields[i] + } + t.Type = next +} + func (t *Type) Size() int64 { dowidth(t) return t.Width diff --git a/src/cmd/compile/internal/gc/typecheck.go b/src/cmd/compile/internal/gc/typecheck.go index fe2560e9f8..7840878da1 100644 --- a/src/cmd/compile/internal/gc/typecheck.go +++ b/src/cmd/compile/internal/gc/typecheck.go @@ -1021,9 +1021,9 @@ OpSwitch: case TMAP: n.Etype = 0 - defaultlit(&n.Right, t.Down) + defaultlit(&n.Right, t.Key()) if n.Right.Type != nil { - n.Right = assignconv(n.Right, t.Down, "map index") + n.Right = assignconv(n.Right, t.Key(), "map index") } n.Type = t.Type n.Op = OINDEXMAP @@ -1460,9 +1460,9 @@ OpSwitch: return } - t = n.List.First().Type.Type - l = t.Nname - r = t.Down.Nname + t = n.List.First().Type + l = t.Field(0).Nname + r = t.Field(1).Nname } else { if !twoarg(n) { n.Type = nil @@ -1575,7 +1575,7 @@ OpSwitch: return } - args.SetIndex(1, assignconv(r, l.Type.Down, "delete")) + args.SetIndex(1, assignconv(r, l.Type.Key(), "delete")) break OpSwitch case OAPPEND: @@ -3028,10 +3028,10 @@ func typecheckcomplit(np **Node) { } r = l.Left - pushtype(r, t.Down) + pushtype(r, t.Key()) typecheck(&r, Erv) - defaultlit(&r, t.Down) - l.Left = assignconv(r, t.Down, "map key") + defaultlit(&r, t.Key()) + l.Left = assignconv(r, t.Key(), "map key") if l.Left.Op != OCONV { keydup(l.Left, hash) } diff --git a/src/cmd/compile/internal/gc/unsafe.go b/src/cmd/compile/internal/gc/unsafe.go index 99e0ac82d7..7cac8516c3 100644 --- a/src/cmd/compile/internal/gc/unsafe.go +++ b/src/cmd/compile/internal/gc/unsafe.go @@ -104,19 +104,21 @@ func unsafenmagic(nn *Node) *Node { goto bad } + var f [2]*Type + f[0] = typ(TFIELD) + f[0].Type = Types[TUINT8] + f[1] = typ(TFIELD) + f[1].Type = tr + // make struct { byte; T; } t := typ(TSTRUCT) - - t.Type = typ(TFIELD) - t.Type.Type = Types[TUINT8] - t.Type.Down = typ(TFIELD) - t.Type.Down.Type = tr + t.SetFields(f[:]) // compute struct widths dowidth(t) // the offset of T is its required alignment - v = t.Type.Down.Width + v = t.Field(1).Width goto yes } diff --git a/src/cmd/compile/internal/gc/walk.go b/src/cmd/compile/internal/gc/walk.go index 3c397dfc1b..be0d5ff258 100644 --- a/src/cmd/compile/internal/gc/walk.go +++ b/src/cmd/compile/internal/gc/walk.go @@ -840,7 +840,7 @@ opswitch: t := r.Left.Type p := "" if t.Type.Width <= 128 { // Check ../../runtime/hashmap.go:maxValueSize before changing. - switch algtype(t.Down) { + switch algtype(t.Key()) { case AMEM32: p = "mapaccess2_fast32" case AMEM64: @@ -876,7 +876,7 @@ opswitch: // the boolean result of i.(T) is now untyped so we make it the // same type as the variable on the lhs. if !isblank(n.List.Second()) { - r.Type.Type.Down.Type = n.List.Second().Type + r.Type.Field(1).Type = n.List.Second().Type } n.Rlist.Set1(r) n.Op = OAS2FUNC @@ -1247,7 +1247,7 @@ opswitch: t := n.Left.Type p := "" if t.Type.Width <= 128 { // Check ../../runtime/hashmap.go:maxValueSize before changing. - switch algtype(t.Down) { + switch algtype(t.Key()) { case AMEM32: p = "mapaccess1_fast32" case AMEM64: @@ -1439,7 +1439,7 @@ opswitch: } fn := syslook("makemap") - substArgTypes(&fn, hmap(t), mapbucket(t), t.Down, t.Type) + substArgTypes(&fn, hmap(t), mapbucket(t), t.Key(), t.Type) n = mkcall1(fn, n.Type, init, typename(n.Type), conv(n.Left, Types[TINT64]), a, r) case OMAKESLICE: @@ -2690,7 +2690,7 @@ func mapfn(name string, t *Type) *Node { Fatalf("mapfn %v", t) } fn := syslook(name) - substArgTypes(&fn, t.Down, t.Type, t.Down, t.Type) + substArgTypes(&fn, t.Key(), t.Type, t.Key(), t.Type) return fn } @@ -2699,7 +2699,7 @@ func mapfndel(name string, t *Type) *Node { Fatalf("mapfn %v", t) } fn := syslook(name) - substArgTypes(&fn, t.Down, t.Type, t.Down) + substArgTypes(&fn, t.Key(), t.Type, t.Key()) return fn }