]> Cypherpunks repositories - gostls13.git/commitdiff
cmd/compile: add and use new Fields type
authorMatthew Dempsky <mdempsky@google.com>
Thu, 17 Mar 2016 07:44:07 +0000 (00:44 -0700)
committerMatthew Dempsky <mdempsky@google.com>
Thu, 17 Mar 2016 19:37:14 +0000 (19:37 +0000)
Analogous to the Nodes type used as a more space efficient []*Node
representation.

Passes toolstash -cmp.

Change-Id: I8341e45304777d6e4200bd36dadc935b07ccf3ff
Reviewed-on: https://go-review.googlesource.com/20793
Reviewed-by: David Crawshaw <crawshaw@golang.org>
Reviewed-by: Brad Fitzpatrick <bradfitz@golang.org>
Run-TryBot: Matthew Dempsky <mdempsky@google.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>

src/cmd/compile/internal/gc/dcl.go
src/cmd/compile/internal/gc/fmt.go
src/cmd/compile/internal/gc/reflect.go
src/cmd/compile/internal/gc/subr.go
src/cmd/compile/internal/gc/type.go
src/cmd/compile/internal/gc/typecheck.go

index 973016f97c034f1b67ff278cace97fc245b2fb70..6b65dd0a521ead8fbbe16e88b13a68274e734171 100644 (file)
@@ -1269,9 +1269,7 @@ func addmethod(msym *Sym, t *Type, tpkg *Pkg, local, nointerface bool) {
        n := Nod(ODCLFIELD, newname(msym), nil)
        n.Type = t
 
-       var d *Field // last found
        for f, it := IterMethods(pa); f != nil; f = it.Next() {
-               d = f
                if msym.Name != f.Sym.Name {
                        continue
                }
@@ -1291,11 +1289,7 @@ func addmethod(msym *Sym, t *Type, tpkg *Pkg, local, nointerface bool) {
                Fatalf("imported method name %v in wrong package %s\n", Sconv(f.Sym, FmtSign), tpkg.Name)
        }
 
-       if d == nil {
-               pa.Method = f
-       } else {
-               d.Down = f
-       }
+       pa.Methods().Append(f)
 }
 
 func funccompile(n *Node) {
index 55625e40e60f0245a83e92f6af877864d03b684b..3af269d4ddfeadf01a42c4cd75df5bd2e3714213 100644 (file)
@@ -602,24 +602,24 @@ func typefmt(t *Type, flag FmtFlag) string {
        case TINTER:
                var buf bytes.Buffer
                buf.WriteString("interface {")
-               for t1, it := IterFields(t); t1 != nil; t1 = it.Next() {
+               for i, f := range t.Fields().Slice() {
+                       if i != 0 {
+                               buf.WriteString(";")
+                       }
                        buf.WriteString(" ")
                        switch {
-                       case t1.Sym == nil:
+                       case f.Sym == nil:
                                // Check first that a symbol is defined for this type.
                                // Wrong interface definitions may have types lacking a symbol.
                                break
-                       case exportname(t1.Sym.Name):
-                               buf.WriteString(Sconv(t1.Sym, FmtShort))
+                       case exportname(f.Sym.Name):
+                               buf.WriteString(Sconv(f.Sym, FmtShort))
                        default:
-                               buf.WriteString(Sconv(t1.Sym, FmtUnsigned))
-                       }
-                       buf.WriteString(Tconv(t1.Type, FmtShort))
-                       if t1.Down != nil {
-                               buf.WriteString(";")
+                               buf.WriteString(Sconv(f.Sym, FmtUnsigned))
                        }
+                       buf.WriteString(Tconv(f.Type, FmtShort))
                }
-               if t.Fields != nil {
+               if t.NumFields() != 0 {
                        buf.WriteString(" ")
                }
                buf.WriteString("}")
@@ -679,32 +679,27 @@ func typefmt(t *Type, flag FmtFlag) string {
                var buf bytes.Buffer
                if t.Funarg {
                        buf.WriteString("(")
+                       var flag1 FmtFlag
                        if fmtmode == FTypeId || fmtmode == FErr { // no argument names on function signature, and no "noescape"/"nosplit" tags
-                               for t1, it := IterFields(t); t1 != nil; t1 = it.Next() {
-                                       buf.WriteString(Fldconv(t1, FmtShort))
-                                       if t1.Down != nil {
-                                               buf.WriteString(", ")
-                                       }
-                               }
-                       } else {
-                               for t1, it := IterFields(t); t1 != nil; t1 = it.Next() {
-                                       buf.WriteString(Fldconv(t1, 0))
-                                       if t1.Down != nil {
-                                               buf.WriteString(", ")
-                                       }
+                               flag1 = FmtShort
+                       }
+                       for i, f := range t.Fields().Slice() {
+                               if i != 0 {
+                                       buf.WriteString(", ")
                                }
+                               buf.WriteString(Fldconv(f, flag1))
                        }
                        buf.WriteString(")")
                } else {
                        buf.WriteString("struct {")
-                       for t1, it := IterFields(t); t1 != nil; t1 = it.Next() {
-                               buf.WriteString(" ")
-                               buf.WriteString(Fldconv(t1, FmtLong))
-                               if t1.Down != nil {
+                       for i, f := range t.Fields().Slice() {
+                               if i != 0 {
                                        buf.WriteString(";")
                                }
+                               buf.WriteString(" ")
+                               buf.WriteString(Fldconv(f, FmtLong))
                        }
-                       if t.Fields != nil {
+                       if t.NumFields() != 0 {
                                buf.WriteString(" ")
                        }
                        buf.WriteString("}")
index a8d0c93cf56a520cde2bb8f5ffb952a61c4d0f31..874d9e0069a3c31c8c5643cc75941063c107e411 100644 (file)
@@ -285,7 +285,7 @@ func methods(t *Type) []*Sig {
        // make list of methods for t,
        // generating code if necessary.
        var ms []*Sig
-       for f, it2 := IterAllMethods(mt); f != nil; f = it2.Next() {
+       for _, f := range mt.AllMethods().Slice() {
                if f.Type.Etype != TFUNC || f.Type.Thistuple == 0 {
                        Fatalf("non-method on %v method %v %v\n", mt, f.Sym, f)
                }
index 31efa6269e6007f894992b28a87cda0a431c5b50..da4d036f7140ee40b01a97e7639fe6cb2a9da7f5 100644 (file)
@@ -1725,12 +1725,10 @@ func adddot(n *Node) *Node {
 // the actual methods.
 type Symlink struct {
        field     *Field
-       link      *Symlink
-       good      bool
        followptr bool
 }
 
-var slist *Symlink
+var slist []Symlink
 
 func expand0(t *Type, followptr bool) {
        u := t
@@ -1740,17 +1738,12 @@ func expand0(t *Type, followptr bool) {
        }
 
        if u.Etype == TINTER {
-               var sl *Symlink
                for f, it := IterFields(u); f != nil; f = it.Next() {
                        if f.Sym.Flags&SymUniq != 0 {
                                continue
                        }
                        f.Sym.Flags |= SymUniq
-                       sl = new(Symlink)
-                       sl.field = f
-                       sl.link = slist
-                       sl.followptr = followptr
-                       slist = sl
+                       slist = append(slist, Symlink{field: f, followptr: followptr})
                }
 
                return
@@ -1758,17 +1751,12 @@ func expand0(t *Type, followptr bool) {
 
        u = methtype(t, 0)
        if u != nil {
-               var sl *Symlink
                for f, it := IterMethods(u); f != nil; f = it.Next() {
                        if f.Sym.Flags&SymUniq != 0 {
                                continue
                        }
                        f.Sym.Flags |= SymUniq
-                       sl = new(Symlink)
-                       sl.field = f
-                       sl.link = slist
-                       sl.followptr = followptr
-                       slist = sl
+                       slist = append(slist, Symlink{field: f, followptr: followptr})
                }
        }
 }
@@ -1808,7 +1796,7 @@ out:
 }
 
 func expandmeth(t *Type) {
-       if t == nil || t.Xmethod != nil {
+       if t == nil || t.AllMethods().Len() != 0 {
                return
        }
 
@@ -1819,41 +1807,40 @@ func expandmeth(t *Type) {
        }
 
        // generate all reachable methods
-       slist = nil
-
+       slist = slist[:0]
        expand1(t, true, false)
 
        // check each method to be uniquely reachable
-       for sl := slist; sl != nil; sl = sl.link {
+       var ms []*Field
+       for i, sl := range slist {
+               slist[i].field = nil
                sl.field.Sym.Flags &^= SymUniq
+
                var f *Field
                if path, _ := dotpath(sl.field.Sym, t, &f, false); path == nil {
                        continue
                }
+
                // dotpath may have dug out arbitrary fields, we only want methods.
-               if f.Type.Etype == TFUNC && f.Type.Thistuple > 0 {
-                       sl.good = true
-                       sl.field = f
+               if f.Type.Etype != TFUNC || f.Type.Thistuple == 0 {
+                       continue
                }
+
+               // add it to the base type method list
+               f = f.Copy()
+               f.Embedded = 1 // needs a trampoline
+               if sl.followptr {
+                       f.Embedded = 2
+               }
+               ms = append(ms, f)
        }
 
        for f, it := IterMethods(t); f != nil; f = it.Next() {
                f.Sym.Flags &^= SymUniq
        }
 
-       t.Xmethod = t.Method
-       for sl := slist; sl != nil; sl = sl.link {
-               if sl.good {
-                       // add it to the base type method list
-                       f := sl.field.Copy()
-                       f.Embedded = 1 // needs a trampoline
-                       if sl.followptr {
-                               f.Embedded = 2
-                       }
-                       f.Down = t.Xmethod
-                       t.Xmethod = f
-               }
-       }
+       ms = append(ms, t.Methods().Slice()...)
+       t.AllMethods().Set(ms)
 }
 
 // Given funarg struct list, return list of ODCLFIELD Node fn args.
index 9d0207d476a1e6d95022e43142defd142da601b9..9e285c058db91d0a1be31cba4e9b4dc9a1cefa2e 100644 (file)
@@ -123,8 +123,8 @@ type Type struct {
        Intuple   int
        Outnamed  bool
 
-       Method  *Field
-       Xmethod *Field
+       methods    Fields
+       allMethods Fields
 
        Sym    *Sym
        Vargen int32 // unique name for OTYPE/ONAME
@@ -137,7 +137,7 @@ type Type struct {
        Width int64
 
        // TSTRUCT
-       Fields *Field // first struct field
+       fields Fields
 
        Down *Type // key type in TMAP; next struct in Funarg TSTRUCT
 
@@ -172,7 +172,48 @@ type Field struct {
        Type  *Type   // field type
        Width int64   // TODO(mdempsky): Rename to offset.
        Note  *string // literal string annotation
-       Down  *Field  // next struct field
+}
+
+// Fields is a pointer to a slice of *Field.
+// This saves space in Types that do not have fields or methods
+// compared to a simple slice of *Field.
+type Fields struct {
+       s *[]*Field
+}
+
+// Len returns the number of entries in f.
+func (f *Fields) Len() int {
+       if f.s == nil {
+               return 0
+       }
+       return len(*f.s)
+}
+
+// Slice returns the entries in f as a slice.
+// Changes to the slice entries will be reflected in f.
+func (f *Fields) Slice() []*Field {
+       if f.s == nil {
+               return nil
+       }
+       return *f.s
+}
+
+// Set sets f to a slice.
+// This takes ownership of the slice.
+func (f *Fields) Set(s []*Field) {
+       if len(s) != 0 {
+               f.s = &s
+       } else {
+               f.s = nil
+       }
+}
+
+// Append appends entries to f.
+func (f *Fields) Append(s ...*Field) {
+       if f.s == nil {
+               f.s = new([]*Field)
+       }
+       *f.s = append(*f.s, s...)
 }
 
 // typ returns a new Type of the specified kind.
@@ -213,49 +254,38 @@ func (f *Field) Copy() *Field {
 // Iter provides an abstraction for iterating across struct fields and
 // interface methods.
 type Iter struct {
-       *Field
+       s []*Field
 }
 
 // IterFields returns the first field or method in struct or interface type t
 // and an Iter value to continue iterating across the rest.
 func IterFields(t *Type) (*Field, Iter) {
-       if t.Etype != TSTRUCT && t.Etype != TINTER {
-               Fatalf("IterFields: type %v does not have fields", t)
-       }
-       return RawIter(t.Fields)
+       return t.Fields().Iter()
 }
 
 // IterMethods returns the first method in type t's method set
 // and an Iter value to continue iterating across the rest.
 // IterMethods does not include promoted methods.
 func IterMethods(t *Type) (*Field, Iter) {
-       // TODO(mdempsky): Validate t?
-       return RawIter(t.Method)
-}
-
-// IterAllMethods returns the first (possibly promoted) method in type t's
-// method set and an Iter value to continue iterating across the rest.
-func IterAllMethods(t *Type) (*Field, Iter) {
-       // TODO(mdempsky): Validate t?
-       return RawIter(t.Xmethod)
+       return t.Methods().Iter()
 }
 
-// RawIter returns field t and an Iter value to continue iterating across
-// its successor fields. Most code should instead use one of the IterXXX
-// functions above.
-func RawIter(t *Field) (*Field, Iter) {
-       i := Iter{x: t}
+// Iter returns the first field in fs and an Iter value to continue iterating
+// across its successor fields.
+// Deprecated: New code should use Slice instead.
+func (fs *Fields) Iter() (*Field, Iter) {
+       i := Iter{s: fs.Slice()}
        f := i.Next()
        return f, i
 }
 
 // Next returns the next field or method, if any.
 func (i *Iter) Next() *Field {
-       if i.x == nil {
+       if len(i.s) == 0 {
                return nil
        }
-       f := i.x
-       i.x = f.Down
+       f := i.s[0]
+       i.s = i.s[1:]
        return f
 }
 
@@ -311,40 +341,37 @@ func (t *Type) Key() *Type {
        return t.Down
 }
 
+func (t *Type) Methods() *Fields {
+       // TODO(mdempsky): Validate t?
+       return &t.methods
+}
+
+func (t *Type) AllMethods() *Fields {
+       // TODO(mdempsky): Validate t?
+       return &t.allMethods
+}
+
+func (t *Type) Fields() *Fields {
+       if t.Etype != TSTRUCT && t.Etype != TINTER {
+               Fatalf("Fields: type %v does not have fields", t)
+       }
+       return &t.fields
+}
+
 // Field returns the i'th field/method of struct/interface type t.
 func (t *Type) Field(i int) *Field {
-       // TODO: store fields in a slice so we can
-       // look them up by index in constant time.
-       for f, it := IterFields(t); f != nil; f = it.Next() {
-               if i == 0 {
-                       return f
-               }
-               i--
-       }
-       panic("not enough fields")
+       return t.Fields().Slice()[i]
 }
 
 // FieldSlice returns a slice of containing all fields/methods of
 // struct/interface type t.
 func (t *Type) FieldSlice() []*Field {
-       var s []*Field
-       for f, it := IterFields(t); f != nil; f = it.Next() {
-               s = append(s, f)
-       }
-       return s
+       return t.Fields().Slice()
 }
 
 // SetFields sets struct/interface type t's fields/methods to fields.
 func (t *Type) SetFields(fields []*Field) {
-       if t.Etype != TSTRUCT && t.Etype != TINTER {
-               Fatalf("SetFields: type %v does not have fields", t)
-       }
-       var next *Field
-       for i := len(fields) - 1; i >= 0; i-- {
-               fields[i].Down = next
-               next = fields[i]
-       }
-       t.Fields = next
+       t.Fields().Set(fields)
 }
 
 func (t *Type) Size() int64 {
@@ -649,11 +676,7 @@ func (t *Type) PtrTo() ssa.Type {
 }
 
 func (t *Type) NumFields() int {
-       n := 0
-       for f, it := IterFields(t); f != nil; f = it.Next() {
-               n++
-       }
-       return n
+       return t.Fields().Len()
 }
 func (t *Type) FieldType(i int) ssa.Type {
        return t.Field(i).Type
index da2f695d3ef9f52d96e5f664fa610e27647be132..9100672e10ff036496ba8eb3553372ecdb532d62 100644 (file)
@@ -2362,9 +2362,9 @@ func twoarg(n *Node) bool {
        return true
 }
 
-func lookdot1(errnode *Node, s *Sym, t *Type, f *Field, dostrcmp int) *Field {
+func lookdot1(errnode *Node, s *Sym, t *Type, fs *Fields, dostrcmp int) *Field {
        var r *Field
-       for f, it := RawIter(f); f != nil; f = it.Next() {
+       for _, f := range fs.Slice() {
                if dostrcmp != 0 && f.Sym.Name == s.Name {
                        return f
                }
@@ -2395,7 +2395,7 @@ func looktypedot(n *Node, t *Type, dostrcmp int) bool {
        s := n.Right.Sym
 
        if t.Etype == TINTER {
-               f1 := lookdot1(n, s, t, t.Fields, dostrcmp)
+               f1 := lookdot1(n, s, t, t.Fields(), dostrcmp)
                if f1 == nil {
                        return false
                }
@@ -2415,7 +2415,7 @@ func looktypedot(n *Node, t *Type, dostrcmp int) bool {
        }
 
        expandmeth(mt)
-       f2 := lookdot1(n, s, mt, mt.Xmethod, dostrcmp)
+       f2 := lookdot1(n, s, mt, mt.AllMethods(), dostrcmp)
        if f2 == nil {
                return false
        }
@@ -2455,7 +2455,7 @@ func lookdot(n *Node, t *Type, dostrcmp int) *Field {
        dowidth(t)
        var f1 *Field
        if t.Etype == TSTRUCT || t.Etype == TINTER {
-               f1 = lookdot1(n, s, t, t.Fields, dostrcmp)
+               f1 = lookdot1(n, s, t, t.Fields(), dostrcmp)
        }
 
        var f2 *Field
@@ -2464,7 +2464,7 @@ func lookdot(n *Node, t *Type, dostrcmp int) *Field {
                if mt != nil {
                        // Use f2->method, not f2->xmethod: adddot has
                        // already inserted all the necessary embedded dots.
-                       f2 = lookdot1(n, s, mt, mt.Method, dostrcmp)
+                       f2 = lookdot1(n, s, mt, mt.Methods(), dostrcmp)
                }
        }
 
@@ -3103,7 +3103,7 @@ func typecheckcomplit(np **Node) {
                                        }
                                }
 
-                               f := lookdot1(nil, s, t, t.Fields, 0)
+                               f := lookdot1(nil, s, t, t.Fields(), 0)
                                if f == nil {
                                        Yyerror("unknown %v field '%v' in struct literal", t, s)
                                        continue
@@ -3524,8 +3524,8 @@ func copytype(n *Node, t *Type) {
        if n.Name != nil {
                t.Vargen = n.Name.Vargen
        }
-       t.Method = nil
-       t.Xmethod = nil
+       t.methods = Fields{}
+       t.allMethods = Fields{}
        t.Nod = nil
        t.Printed = false
        t.Deferwidth = false