mirror of
https://github.com/golang/go
synced 2024-11-12 08:20:22 -07:00
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/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>
This commit is contained in:
parent
857d0b48db
commit
517b6131b2
@ -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)
|
||||
return t.Methods().Iter()
|
||||
}
|
||||
|
||||
// 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)
|
||||
}
|
||||
|
||||
// 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
|
||||
|
Loading…
Reference in New Issue
Block a user