Commit f38f43d0 authored by Josh Bleecher Snyder's avatar Josh Bleecher Snyder

cmd/compile: shrink gc.Type in half

Many of Type's fields are etype-specific.
This CL organizes them into their own auxiliary types,
duplicating a few fields as necessary,
and adds an Extra field to hold them.
It also sorts the remaining fields for better struct packing.
It also improves documentation for most fields.

This reduces the size of Type at the cost of some extra allocations.
There's no CPU impact; memory impact below.
It also makes the natural structure of Type clearer.

Passes toolstash -cmp on all architectures.

Ideas for future work in this vein:

(1) Width and Align probably only need to be
stored for Struct and Array types.
The refactoring to accomplish this would hopefully
also eliminate TFUNCARGS and TCHANARGS entirely.

(2) Maplineno is sparsely used and could probably better be
stored in a separate map[*Type]int32, with mapqueue updated
to store both a Node and a line number.

(3) The Printed field may be removable once the old (non-binary)
importer/exported has been removed.

(4) StructType's fields field could be changed from *[]*Field to []*Field,
which would remove a common allocation.

(5) I believe that Type.Nod can be moved to ForwardType. Separate CL.

name       old alloc/op     new alloc/op     delta
Template       57.9MB ± 0%      55.9MB ± 0%  -3.43%        (p=0.000 n=50+50)
Unicode        38.3MB ± 0%      37.8MB ± 0%  -1.39%        (p=0.000 n=50+50)
GoTypes         185MB ± 0%       180MB ± 0%  -2.56%        (p=0.000 n=50+50)
Compiler        824MB ± 0%       806MB ± 0%  -2.19%        (p=0.000 n=50+50)

name       old allocs/op    new allocs/op    delta
Template         486k ± 0%        497k ± 0%  +2.25%        (p=0.000 n=50+50)
Unicode          377k ± 0%        379k ± 0%  +0.55%        (p=0.000 n=50+50)
GoTypes         1.39M ± 0%       1.42M ± 0%  +1.63%        (p=0.000 n=50+50)
Compiler        5.52M ± 0%       5.57M ± 0%  +0.84%        (p=0.000 n=47+50)

Change-Id: I828488eeb74902b013d5ae4cf844de0b6c0dfc87
Reviewed-on: https://go-review.googlesource.com/21611Reviewed-by: default avatarMatthew Dempsky <mdempsky@google.com>
Reviewed-by: default avatarBrad Fitzpatrick <bradfitz@golang.org>
parent a25e368f
...@@ -198,11 +198,11 @@ func dowidth(t *Type) { ...@@ -198,11 +198,11 @@ func dowidth(t *Type) {
// make fake type to check later to // make fake type to check later to
// trigger channel argument check. // trigger channel argument check.
t1 := typWrapper(TCHANARGS, t) t1 := typChanArgs(t)
checkwidth(t1) checkwidth(t1)
case TCHANARGS: case TCHANARGS:
t1 := t.Wrapped() t1 := t.ChanArgs()
dowidth(t1) // just in case dowidth(t1) // just in case
if t1.Elem().Width >= 1<<16 { if t1.Elem().Width >= 1<<16 {
Yyerror("channel element type too large (>64kB)") Yyerror("channel element type too large (>64kB)")
...@@ -271,18 +271,18 @@ func dowidth(t *Type) { ...@@ -271,18 +271,18 @@ func dowidth(t *Type) {
// make fake type to check later to // make fake type to check later to
// trigger function argument computation. // trigger function argument computation.
case TFUNC: case TFUNC:
t1 := typWrapper(TFUNCARGS, t) t1 := typFuncArgs(t)
checkwidth(t1) checkwidth(t1)
w = int64(Widthptr) // width of func type is pointer w = int64(Widthptr) // width of func type is pointer
// function is 3 cated structures; // function is 3 cated structures;
// compute their widths as side-effect. // compute their widths as side-effect.
case TFUNCARGS: case TFUNCARGS:
t1 := t.Wrapped() t1 := t.FuncArgs()
w = widstruct(t1, t1.Recvs(), 0, 0) w = widstruct(t1, t1.Recvs(), 0, 0)
w = widstruct(t1, t1.Params(), w, Widthreg) w = widstruct(t1, t1.Params(), w, Widthreg)
w = widstruct(t1, t1.Results(), w, Widthreg) w = widstruct(t1, t1.Results(), w, Widthreg)
t1.Argwid = w t1.Extra.(*FuncType).Argwid = w
if w%int64(Widthreg) != 0 { if w%int64(Widthreg) != 0 {
Warn("bad type %v %d\n", t1, w) Warn("bad type %v %d\n", t1, w)
} }
...@@ -386,7 +386,7 @@ func Argsize(t *Type) int { ...@@ -386,7 +386,7 @@ func Argsize(t *Type) int {
} }
} }
w = (w + int64(Widthptr) - 1) &^ (int64(Widthptr) - 1) w = Rnd(w, int64(Widthptr))
if int64(int(w)) != w { if int64(int(w)) != w {
Fatalf("argsize too big") Fatalf("argsize too big")
} }
......
...@@ -602,7 +602,7 @@ func (p *exporter) typ(t *Type) { ...@@ -602,7 +602,7 @@ func (p *exporter) typ(t *Type) {
case TDDDFIELD: case TDDDFIELD:
// see p.param use of TDDDFIELD // see p.param use of TDDDFIELD
p.tag(dddTag) p.tag(dddTag)
p.typ(t.Wrapped()) p.typ(t.DDDField())
case TSTRUCT: case TSTRUCT:
p.tag(structTag) p.tag(structTag)
...@@ -768,7 +768,7 @@ func (p *exporter) param(q *Field, n int, numbered bool) { ...@@ -768,7 +768,7 @@ func (p *exporter) param(q *Field, n int, numbered bool) {
t := q.Type t := q.Type
if q.Isddd { if q.Isddd {
// create a fake type to encode ... just for the p.typ call // create a fake type to encode ... just for the p.typ call
t = typWrapper(TDDDFIELD, t.Elem()) t = typDDDField(t.Elem())
} }
p.typ(t) p.typ(t)
if n > 0 { if n > 0 {
......
...@@ -359,16 +359,20 @@ func (p *importer) typ() *Type { ...@@ -359,16 +359,20 @@ func (p *importer) typ() *Type {
case arrayTag, sliceTag: case arrayTag, sliceTag:
t = p.newtyp(TARRAY) t = p.newtyp(TARRAY)
var bound int64
if i == arrayTag { if i == arrayTag {
t.SetNumElem(p.int64()) bound = p.int64()
}
elem := p.typ()
if i == arrayTag {
t.Extra = &ArrayType{Elem: elem, Bound: bound}
} else { } else {
t.SetNumElem(sliceBound) t.Extra = SliceType{Elem: elem}
} }
t.Type = p.typ()
case dddTag: case dddTag:
t = p.newtyp(TDDDFIELD) t = p.newtyp(TDDDFIELD)
t.Type = p.typ() t.Extra = DDDFieldType{T: p.typ()}
case structTag: case structTag:
t = p.newtyp(TSTRUCT) t = p.newtyp(TSTRUCT)
...@@ -376,7 +380,7 @@ func (p *importer) typ() *Type { ...@@ -376,7 +380,7 @@ func (p *importer) typ() *Type {
case pointerTag: case pointerTag:
t = p.newtyp(Tptr) t = p.newtyp(Tptr)
t.Type = p.typ() t.Extra = PtrType{Elem: p.typ()}
case signatureTag: case signatureTag:
t = p.newtyp(TFUNC) t = p.newtyp(TFUNC)
...@@ -393,13 +397,15 @@ func (p *importer) typ() *Type { ...@@ -393,13 +397,15 @@ func (p *importer) typ() *Type {
case mapTag: case mapTag:
t = p.newtyp(TMAP) t = p.newtyp(TMAP)
t.Down = p.typ() // key mt := t.MapType()
t.Type = p.typ() // val mt.Key = p.typ()
mt.Val = p.typ()
case chanTag: case chanTag:
t = p.newtyp(TCHAN) t = p.newtyp(TCHAN)
t.Chan = ChanDir(p.int()) ct := t.ChanType()
t.Type = p.typ() ct.Dir = ChanDir(p.int())
ct.Elem = p.typ()
default: default:
Fatalf("importer: unexpected type (tag = %d)", i) Fatalf("importer: unexpected type (tag = %d)", i)
...@@ -444,7 +450,7 @@ func (p *importer) field() *Node { ...@@ -444,7 +450,7 @@ func (p *importer) field() *Node {
// anonymous field - typ must be T or *T and T must be a type name // anonymous field - typ must be T or *T and T must be a type name
s := typ.Sym s := typ.Sym
if s == nil && typ.IsPtr() { if s == nil && typ.IsPtr() {
s = typ.Type.Sym // deref s = typ.Elem().Sym // deref
} }
pkg := importpkg pkg := importpkg
if sym != nil { if sym != nil {
...@@ -531,7 +537,7 @@ func (p *importer) param(named bool) *Node { ...@@ -531,7 +537,7 @@ func (p *importer) param(named bool) *Node {
isddd := false isddd := false
if typ.Etype == TDDDFIELD { if typ.Etype == TDDDFIELD {
// TDDDFIELD indicates wrapped ... slice type // TDDDFIELD indicates wrapped ... slice type
typ = typSlice(typ.Wrapped()) typ = typSlice(typ.DDDField())
isddd = true isddd = true
} }
......
...@@ -743,8 +743,8 @@ func checkembeddedtype(t *Type) { ...@@ -743,8 +743,8 @@ func checkembeddedtype(t *Type) {
if t.IsPtr() { if t.IsPtr() {
Yyerror("embedded type cannot be a pointer") Yyerror("embedded type cannot be a pointer")
} else if t.Etype == TFORW && t.Embedlineno == 0 { } else if t.Etype == TFORW && t.ForwardType().Embedlineno == 0 {
t.Embedlineno = lineno t.ForwardType().Embedlineno = lineno
} }
} }
...@@ -855,7 +855,7 @@ func tostruct0(t *Type, l []*Node) { ...@@ -855,7 +855,7 @@ func tostruct0(t *Type, l []*Node) {
func tofunargs(l []*Node) *Type { func tofunargs(l []*Node) *Type {
t := typ(TSTRUCT) t := typ(TSTRUCT)
t.Funarg = true t.StructType().Funarg = true
fields := make([]*Field, len(l)) fields := make([]*Field, len(l))
for i, n := range l { for i, n := range l {
...@@ -1061,11 +1061,11 @@ func functype0(t *Type, this *Node, in, out []*Node) { ...@@ -1061,11 +1061,11 @@ func functype0(t *Type, this *Node, in, out []*Node) {
t.Broke = true t.Broke = true
} }
t.Outnamed = false t.FuncType().Outnamed = false
if len(out) > 0 && out[0].Left != nil && out[0].Left.Orig != nil { if len(out) > 0 && out[0].Left != nil && out[0].Left.Orig != nil {
s := out[0].Left.Orig.Sym s := out[0].Left.Orig.Sym
if s != nil && (s.Name[0] != '~' || s.Name[1] != 'r') { // ~r%d is the name invented for an unnamed result if s != nil && (s.Name[0] != '~' || s.Name[1] != 'r') { // ~r%d is the name invented for an unnamed result
t.Outnamed = true t.FuncType().Outnamed = true
} }
} }
} }
......
...@@ -592,7 +592,7 @@ func dumpasmhdr() { ...@@ -592,7 +592,7 @@ func dumpasmhdr() {
case OTYPE: case OTYPE:
t := n.Type t := n.Type
if !t.IsStruct() || t.Map != nil || t.IsFuncArgStruct() { if !t.IsStruct() || t.StructType().Map != nil || t.IsFuncArgStruct() {
break break
} }
fmt.Fprintf(b, "#define %s__size %d\n", t.Sym.Name, int(t.Width)) fmt.Fprintf(b, "#define %s__size %d\n", t.Sym.Name, int(t.Width))
......
...@@ -671,19 +671,20 @@ func typefmt(t *Type, flag FmtFlag) string { ...@@ -671,19 +671,20 @@ func typefmt(t *Type, flag FmtFlag) string {
return buf.String() return buf.String()
case TSTRUCT: case TSTRUCT:
if t.Map != nil { if m := t.StructType().Map; m != nil {
mt := m.MapType()
// Format the bucket struct for map[x]y as map.bucket[x]y. // Format the bucket struct for map[x]y as map.bucket[x]y.
// This avoids a recursive print that generates very long names. // This avoids a recursive print that generates very long names.
if t.Map.Bucket == t { if mt.Bucket == t {
return "map.bucket[" + t.Map.Key().String() + "]" + t.Map.Val().String() return "map.bucket[" + m.Key().String() + "]" + m.Val().String()
} }
if t.Map.Hmap == t { if mt.Hmap == t {
return "map.hdr[" + t.Map.Key().String() + "]" + t.Map.Val().String() return "map.hdr[" + m.Key().String() + "]" + m.Val().String()
} }
if t.Map.Hiter == t { if mt.Hiter == t {
return "map.iter[" + t.Map.Key().String() + "]" + t.Map.Val().String() return "map.iter[" + m.Key().String() + "]" + m.Val().String()
} }
Yyerror("unknown internal map type") Yyerror("unknown internal map type")
...@@ -735,7 +736,7 @@ func typefmt(t *Type, flag FmtFlag) string { ...@@ -735,7 +736,7 @@ func typefmt(t *Type, flag FmtFlag) string {
if fmtmode == FExp { if fmtmode == FExp {
Fatalf("cannot use TDDDFIELD with old exporter") Fatalf("cannot use TDDDFIELD with old exporter")
} }
return fmt.Sprintf("%v <%v> %v", Econv(t.Etype), t.Sym, t.Wrapped()) return fmt.Sprintf("%v <%v> %v", Econv(t.Etype), t.Sym, t.DDDField())
} }
if fmtmode == FExp { if fmtmode == FExp {
......
...@@ -375,7 +375,7 @@ func compile(fn *Node) { ...@@ -375,7 +375,7 @@ func compile(fn *Node) {
// set up domain for labels // set up domain for labels
clearlabels() clearlabels()
if Curfn.Type.Outnamed { if Curfn.Type.FuncType().Outnamed {
// add clearing of the output parameters // add clearing of the output parameters
for _, t := range Curfn.Type.Results().Fields().Slice() { for _, t := range Curfn.Type.Results().Fields().Slice() {
if t.Nname != nil { if t.Nname != nil {
......
...@@ -10,6 +10,14 @@ import ( ...@@ -10,6 +10,14 @@ import (
"testing" "testing"
) )
func typeWithoutPointers() *Type {
return &Type{Etype: TSTRUCT, Extra: &StructType{Haspointers: 1}} // haspointers -> false
}
func typeWithPointers() *Type {
return &Type{Etype: TSTRUCT, Extra: &StructType{Haspointers: 2}} // haspointers -> true
}
// Test all code paths for cmpstackvarlt. // Test all code paths for cmpstackvarlt.
func TestCmpstackvar(t *testing.T) { func TestCmpstackvar(t *testing.T) {
testdata := []struct { testdata := []struct {
...@@ -62,13 +70,13 @@ func TestCmpstackvar(t *testing.T) { ...@@ -62,13 +70,13 @@ func TestCmpstackvar(t *testing.T) {
false, false,
}, },
{ {
Node{Class: PAUTO, Type: &Type{Haspointers: 1}}, // haspointers -> false Node{Class: PAUTO, Type: typeWithoutPointers()},
Node{Class: PAUTO, Type: &Type{Haspointers: 2}}, // haspointers -> true Node{Class: PAUTO, Type: typeWithPointers()},
false, false,
}, },
{ {
Node{Class: PAUTO, Type: &Type{Haspointers: 2}}, // haspointers -> true Node{Class: PAUTO, Type: typeWithPointers()},
Node{Class: PAUTO, Type: &Type{Haspointers: 1}}, // haspointers -> false Node{Class: PAUTO, Type: typeWithoutPointers()},
true, true,
}, },
{ {
...@@ -127,7 +135,7 @@ func TestStackvarSort(t *testing.T) { ...@@ -127,7 +135,7 @@ func TestStackvarSort(t *testing.T) {
{Class: PFUNC, Xoffset: 10, Type: &Type{}, Name: &Name{}, Sym: &Sym{}}, {Class: PFUNC, Xoffset: 10, Type: &Type{}, Name: &Name{}, Sym: &Sym{}},
{Class: PFUNC, Xoffset: 20, Type: &Type{}, Name: &Name{}, Sym: &Sym{}}, {Class: PFUNC, Xoffset: 20, Type: &Type{}, Name: &Name{}, Sym: &Sym{}},
{Class: PAUTO, Used: true, Type: &Type{}, Name: &Name{}, Sym: &Sym{}}, {Class: PAUTO, Used: true, Type: &Type{}, Name: &Name{}, Sym: &Sym{}},
{Class: PAUTO, Type: &Type{Haspointers: 1}, Name: &Name{}, Sym: &Sym{}}, // haspointers -> false {Class: PAUTO, Type: typeWithoutPointers(), Name: &Name{}, Sym: &Sym{}},
{Class: PAUTO, Type: &Type{}, Name: &Name{}, Sym: &Sym{}}, {Class: PAUTO, Type: &Type{}, Name: &Name{}, Sym: &Sym{}},
{Class: PAUTO, Type: &Type{}, Name: &Name{Needzero: true}, Sym: &Sym{}}, {Class: PAUTO, Type: &Type{}, Name: &Name{Needzero: true}, Sym: &Sym{}},
{Class: PAUTO, Type: &Type{Width: 1}, Name: &Name{}, Sym: &Sym{}}, {Class: PAUTO, Type: &Type{Width: 1}, Name: &Name{}, Sym: &Sym{}},
...@@ -148,7 +156,7 @@ func TestStackvarSort(t *testing.T) { ...@@ -148,7 +156,7 @@ func TestStackvarSort(t *testing.T) {
{Class: PAUTO, Type: &Type{}, Name: &Name{}, Sym: &Sym{}}, {Class: PAUTO, Type: &Type{}, Name: &Name{}, Sym: &Sym{}},
{Class: PAUTO, Type: &Type{}, Name: &Name{}, Sym: &Sym{Name: "abc"}}, {Class: PAUTO, Type: &Type{}, Name: &Name{}, Sym: &Sym{Name: "abc"}},
{Class: PAUTO, Type: &Type{}, Name: &Name{}, Sym: &Sym{Name: "xyz"}}, {Class: PAUTO, Type: &Type{}, Name: &Name{}, Sym: &Sym{Name: "xyz"}},
{Class: PAUTO, Type: &Type{Haspointers: 1}, Name: &Name{}, Sym: &Sym{}}, // haspointers -> false {Class: PAUTO, Type: typeWithoutPointers(), Name: &Name{}, Sym: &Sym{}},
} }
// haspointers updates Type.Haspointers as a side effect, so // haspointers updates Type.Haspointers as a side effect, so
// exercise this function on all inputs so that reflect.DeepEqual // exercise this function on all inputs so that reflect.DeepEqual
......
...@@ -86,8 +86,8 @@ func makefield(name string, t *Type) *Field { ...@@ -86,8 +86,8 @@ func makefield(name string, t *Type) *Field {
} }
func mapbucket(t *Type) *Type { func mapbucket(t *Type) *Type {
if t.Bucket != nil { if t.MapType().Bucket != nil {
return t.Bucket return t.MapType().Bucket
} }
bucket := typ(TSTRUCT) bucket := typ(TSTRUCT)
...@@ -157,17 +157,17 @@ func mapbucket(t *Type) *Type { ...@@ -157,17 +157,17 @@ func mapbucket(t *Type) *Type {
Yyerror("bad math in mapbucket for %v", t) Yyerror("bad math in mapbucket for %v", t)
} }
t.Bucket = bucket t.MapType().Bucket = bucket
bucket.Map = t bucket.StructType().Map = t
return bucket return bucket
} }
// Builds a type representing a Hmap structure for the given map type. // Builds a type representing a Hmap structure for the given map type.
// Make sure this stays in sync with ../../../../runtime/hashmap.go! // Make sure this stays in sync with ../../../../runtime/hashmap.go!
func hmap(t *Type) *Type { func hmap(t *Type) *Type {
if t.Hmap != nil { if t.MapType().Hmap != nil {
return t.Hmap return t.MapType().Hmap
} }
bucket := mapbucket(t) bucket := mapbucket(t)
...@@ -186,14 +186,14 @@ func hmap(t *Type) *Type { ...@@ -186,14 +186,14 @@ func hmap(t *Type) *Type {
h.Local = t.Local h.Local = t.Local
h.SetFields(field[:]) h.SetFields(field[:])
dowidth(h) dowidth(h)
t.Hmap = h t.MapType().Hmap = h
h.Map = t h.StructType().Map = t
return h return h
} }
func hiter(t *Type) *Type { func hiter(t *Type) *Type {
if t.Hiter != nil { if t.MapType().Hiter != nil {
return t.Hiter return t.MapType().Hiter
} }
// build a struct: // build a struct:
...@@ -234,8 +234,8 @@ func hiter(t *Type) *Type { ...@@ -234,8 +234,8 @@ func hiter(t *Type) *Type {
if i.Width != int64(12*Widthptr) { if i.Width != int64(12*Widthptr) {
Yyerror("hash_iter size not correct %d %d", i.Width, 12*Widthptr) Yyerror("hash_iter size not correct %d %d", i.Width, 12*Widthptr)
} }
t.Hiter = i t.MapType().Hiter = i
i.Map = t i.StructType().Map = t
return i return i
} }
...@@ -664,67 +664,47 @@ var kinds = []int{ ...@@ -664,67 +664,47 @@ var kinds = []int{
} }
func haspointers(t *Type) bool { func haspointers(t *Type) bool {
if t.Haspointers != 0 {
return t.Haspointers-1 != 0
}
var ret bool
switch t.Etype { switch t.Etype {
case TINT, case TINT, TUINT, TINT8, TUINT8, TINT16, TUINT16, TINT32, TUINT32, TINT64,
TUINT, TUINT64, TUINTPTR, TFLOAT32, TFLOAT64, TCOMPLEX64, TCOMPLEX128, TBOOL:
TINT8, return false
TUINT8,
TINT16,
TUINT16,
TINT32,
TUINT32,
TINT64,
TUINT64,
TUINTPTR,
TFLOAT32,
TFLOAT64,
TCOMPLEX64,
TCOMPLEX128,
TBOOL:
ret = false
case TARRAY: case TARRAY:
if t.IsSlice() { if t.IsSlice() {
ret = true return true
break
} }
if t.NumElem() == 0 { // empty array at := t.Extra.(*ArrayType)
ret = false if at.Haspointers != 0 {
break return at.Haspointers-1 != 0
} }
ret = haspointers(t.Elem()) ret := false
if t.NumElem() != 0 { // non-empty array
ret = haspointers(t.Elem())
}
at.Haspointers = 1 + uint8(obj.Bool2int(ret))
return ret
case TSTRUCT: case TSTRUCT:
ret = false st := t.StructType()
if st.Haspointers != 0 {
return st.Haspointers-1 != 0
}
ret := false
for _, t1 := range t.Fields().Slice() { for _, t1 := range t.Fields().Slice() {
if haspointers(t1.Type) { if haspointers(t1.Type) {
ret = true ret = true
break break
} }
} }
st.Haspointers = 1 + uint8(obj.Bool2int(ret))
case TSTRING, return ret
TPTR32,
TPTR64,
TUNSAFEPTR,
TINTER,
TCHAN,
TMAP,
TFUNC:
fallthrough
default:
ret = true
} }
t.Haspointers = 1 + uint8(obj.Bool2int(ret)) return true
return ret
} }
// typeptrdata returns the length in bytes of the prefix of t // typeptrdata returns the length in bytes of the prefix of t
......
...@@ -27,7 +27,21 @@ func TestSizeof(t *testing.T) { ...@@ -27,7 +27,21 @@ func TestSizeof(t *testing.T) {
{Name{}, 52, 80}, {Name{}, 52, 80},
{Node{}, 92, 144}, {Node{}, 92, 144},
{Sym{}, 60, 112}, {Sym{}, 60, 112},
{Type{}, 116, 184}, {Type{}, 56, 88},
{MapType{}, 20, 40},
{ForwardType{}, 16, 32},
{FuncType{}, 28, 48},
{StructType{}, 12, 24},
{InterType{}, 4, 8},
{ChanType{}, 8, 16},
{ArrayType{}, 16, 24},
{InterMethType{}, 4, 8},
{DDDFieldType{}, 4, 8},
{FuncArgsType{}, 4, 8},
{ChanArgsType{}, 4, 8},
{PtrType{}, 4, 8},
{SliceType{}, 4, 8},
{DDDArrayType{}, 4, 8},
} }
for _, tt := range tests { for _, tt := range tests {
......
...@@ -4218,7 +4218,7 @@ func (e *ssaExport) SplitInterface(name ssa.LocalSlot) (ssa.LocalSlot, ssa.Local ...@@ -4218,7 +4218,7 @@ func (e *ssaExport) SplitInterface(name ssa.LocalSlot) (ssa.LocalSlot, ssa.Local
func (e *ssaExport) SplitSlice(name ssa.LocalSlot) (ssa.LocalSlot, ssa.LocalSlot, ssa.LocalSlot) { func (e *ssaExport) SplitSlice(name ssa.LocalSlot) (ssa.LocalSlot, ssa.LocalSlot, ssa.LocalSlot) {
n := name.N.(*Node) n := name.N.(*Node)
ptrType := Ptrto(n.Type.Type) ptrType := Ptrto(n.Type.Elem())
lenType := Types[TINT] lenType := Types[TINT]
if n.Class == PAUTO && !n.Addrtaken { if n.Class == PAUTO && !n.Addrtaken {
// Split this slice up into three separate variables. // Split this slice up into three separate variables.
......
This diff is collapsed.
...@@ -2103,7 +2103,7 @@ OpSwitch: ...@@ -2103,7 +2103,7 @@ OpSwitch:
return n return n
} }
if Curfn.Type.Outnamed && n.List.Len() == 0 { if Curfn.Type.FuncType().Outnamed && n.List.Len() == 0 {
break OpSwitch break OpSwitch
} }
typecheckaste(ORETURN, nil, false, Curfn.Type.Results(), n.List, func() string { return "return argument" }) typecheckaste(ORETURN, nil, false, Curfn.Type.Results(), n.List, func() string { return "return argument" })
...@@ -2161,12 +2161,8 @@ OpSwitch: ...@@ -2161,12 +2161,8 @@ OpSwitch:
t := n.Type t := n.Type
if t != nil && !t.IsFuncArgStruct() && n.Op != OTYPE { if t != nil && !t.IsFuncArgStruct() && n.Op != OTYPE {
switch t.Etype { switch t.Etype {
case TFUNC, // might have TANY; wait until its called case TFUNC, // might have TANY; wait until it's called
TANY, TANY, TFORW, TIDEAL, TNIL, TBLANK:
TFORW,
TIDEAL,
TNIL,
TBLANK:
break break
default: default:
...@@ -3522,13 +3518,13 @@ var mapqueue []*Node ...@@ -3522,13 +3518,13 @@ var mapqueue []*Node
func copytype(n *Node, t *Type) { func copytype(n *Node, t *Type) {
if t.Etype == TFORW { if t.Etype == TFORW {
// This type isn't computed yet; when it is, update n. // This type isn't computed yet; when it is, update n.
t.Copyto = append(t.Copyto, n) t.ForwardType().Copyto = append(t.ForwardType().Copyto, n)
return return
} }
maplineno := n.Type.Maplineno maplineno := n.Type.Maplineno
embedlineno := n.Type.Embedlineno embedlineno := n.Type.ForwardType().Embedlineno
l := n.Type.Copyto l := n.Type.ForwardType().Copyto
// TODO(mdempsky): Fix Type rekinding. // TODO(mdempsky): Fix Type rekinding.
*n.Type = *t *n.Type = *t
...@@ -3544,7 +3540,6 @@ func copytype(n *Node, t *Type) { ...@@ -3544,7 +3540,6 @@ func copytype(n *Node, t *Type) {
t.Nod = nil t.Nod = nil
t.Printed = false t.Printed = false
t.Deferwidth = false t.Deferwidth = false
t.Copyto = nil
// Update nodes waiting on this type. // Update nodes waiting on this type.
for _, n := range l { for _, n := range l {
......
...@@ -359,16 +359,16 @@ func lexinit1() { ...@@ -359,16 +359,16 @@ func lexinit1() {
// t = interface { Error() string } // t = interface { Error() string }
rcvr := typ(TSTRUCT) rcvr := typ(TSTRUCT)
rcvr.Funarg = true rcvr.StructType().Funarg = true
field := newField() field := newField()
field.Type = Ptrto(typ(TSTRUCT)) field.Type = Ptrto(typ(TSTRUCT))
rcvr.SetFields([]*Field{field}) rcvr.SetFields([]*Field{field})
in := typ(TSTRUCT) in := typ(TSTRUCT)
in.Funarg = true in.StructType().Funarg = true
out := typ(TSTRUCT) out := typ(TSTRUCT)
out.Funarg = true out.StructType().Funarg = true
field = newField() field = newField()
field.Type = Types[TSTRING] field.Type = Types[TSTRING]
out.SetFields([]*Field{field}) out.SetFields([]*Field{field})
......
...@@ -287,7 +287,7 @@ func walkstmt(n *Node) *Node { ...@@ -287,7 +287,7 @@ func walkstmt(n *Node) *Node {
if n.List.Len() == 0 { if n.List.Len() == 0 {
break break
} }
if (Curfn.Type.Outnamed && n.List.Len() > 1) || paramoutheap(Curfn) { if (Curfn.Type.FuncType().Outnamed && n.List.Len() > 1) || paramoutheap(Curfn) {
// assign to the function out parameters, // assign to the function out parameters,
// so that reorder3 can fix up conflicts // so that reorder3 can fix up conflicts
var rl []*Node var rl []*Node
......
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