Commit 517b6131 authored by Matthew Dempsky's avatar Matthew Dempsky

cmd/compile: add and use new Fields type

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/20793Reviewed-by: 's avatarDavid Crawshaw <crawshaw@golang.org>
Reviewed-by: 's avatarBrad Fitzpatrick <bradfitz@golang.org>
Run-TryBot: Matthew Dempsky <mdempsky@google.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
parent 857d0b48
......@@ -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) {
......
......@@ -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("}")
......
......@@ -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)
}
......
......@@ -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.
......
......@@ -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 {
x *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
......
......@@ -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
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment