]> Cypherpunks repositories - gostls13.git/commitdiff
cmd/compile/internal/types: simpler signature type representation
authorMatthew Dempsky <mdempsky@google.com>
Sun, 20 Aug 2023 21:33:32 +0000 (14:33 -0700)
committerGopher Robot <gobot@golang.org>
Tue, 22 Aug 2023 20:56:59 +0000 (20:56 +0000)
Now that all of the uses of signature types have been cleaned up, we
can simplify the internal representation significantly.

In particular, instead of 3 separate struct objects each with 3
separate slices of fields, we can store all of the parameters in a
single slice and track the boundaries between them.

We still need a results tuple struct for representing the type of
multi-value call expressions, but just a single one and it can safely
reuse the results subsection of the full parameters slice.

Note: while Sizeof(Func) has increased (e.g., 32->56 on amd64), we're
saving on the allocation of 2 Types, 2 Structs, and 2 []*Field (288
bytes total on amd64), not counting any extra GC size class padding
from using a single shared []*Field instead of 3 separate ones.

Change-Id: I119b5e960e715b3bc4f1f726e58b910a098659da
Reviewed-on: https://go-review.googlesource.com/c/go/+/521335
Run-TryBot: Matthew Dempsky <mdempsky@google.com>
Reviewed-by: Than McIntosh <thanm@google.com>
Auto-Submit: Matthew Dempsky <mdempsky@google.com>
TryBot-Bypass: Matthew Dempsky <mdempsky@google.com>
Reviewed-by: Cuong Manh Le <cuong.manhle.vn@gmail.com>
src/cmd/compile/internal/types/sizeof_test.go
src/cmd/compile/internal/types/type.go

index cec12834358f6c364b713100216823997edcb897..8a6f24124a88960ec70f4cf9159df441d0601391 100644 (file)
@@ -24,7 +24,7 @@ func TestSizeof(t *testing.T) {
                {Type{}, 56, 96},
                {Map{}, 12, 24},
                {Forward{}, 20, 32},
-               {Func{}, 20, 32},
+               {Func{}, 32, 56},
                {Struct{}, 12, 24},
                {Interface{}, 0, 0},
                {Chan{}, 8, 16},
index f03aabe4305c82eb266f0f81fa82058a0693cb91..d80a03fa086ff5a753167a88a395fc4666921b5b 100644 (file)
@@ -299,9 +299,12 @@ func (t *Type) forwardType() *Forward {
 
 // Func contains Type fields specific to func types.
 type Func struct {
-       Receiver *Type // function receiver
-       Results  *Type // function results
-       Params   *Type // function params
+       allParams []*Field // slice of all parameters, in receiver/params/results order
+
+       startParams  int // index of the start of the (regular) parameters section
+       startResults int // index of the start of the results section
+
+       resultsTuple *Type // struct-like type representing multi-value results
 
        // Argwid is the total width of the function receiver, params, and results.
        // It gets calculated via a temporary TFUNCARGS type.
@@ -309,6 +312,10 @@ type Func struct {
        Argwid int64
 }
 
+func (ft *Func) recvs() []*Field   { return ft.allParams[:ft.startParams] }
+func (ft *Func) params() []*Field  { return ft.allParams[ft.startParams:ft.startResults] }
+func (ft *Func) results() []*Field { return ft.allParams[ft.startResults:] }
+
 // funcType returns t's extra func-specific fields.
 func (t *Type) funcType() *Func {
        t.wantEtype(TFUNC)
@@ -702,27 +709,23 @@ func SubstAny(t *Type, types *[]*Type) *Type {
                }
 
        case TFUNC:
-               recvs := SubstAny(t.recvsTuple(), types)
-               params := SubstAny(t.paramsTuple(), types)
-               results := SubstAny(t.ResultsTuple(), types)
-               if recvs != t.recvsTuple() || params != t.paramsTuple() || results != t.ResultsTuple() {
-                       t = t.copy()
-                       t.funcType().Receiver = recvs
-                       t.funcType().Results = results
-                       t.funcType().Params = params
-               }
+               ft := t.funcType()
+               allParams := substFields(ft.allParams, types)
+
+               t = t.copy()
+               ft = t.funcType()
+               ft.allParams = allParams
+
+               rt := ft.resultsTuple
+               rt = rt.copy()
+               ft.resultsTuple = rt
+               rt.setFields(t.Results())
 
        case TSTRUCT:
                // Make a copy of all fields, including ones whose type does not change.
                // This prevents aliasing across functions, which can lead to later
                // fields getting their Offset incorrectly overwritten.
-               fields := t.Fields()
-               nfs := make([]*Field, len(fields))
-               for i, f := range fields {
-                       nft := SubstAny(f.Type, types)
-                       nfs[i] = f.Copy()
-                       nfs[i].Type = nft
-               }
+               nfs := substFields(t.Fields(), types)
                t = t.copy()
                t.setFields(nfs)
        }
@@ -730,6 +733,16 @@ func SubstAny(t *Type, types *[]*Type) *Type {
        return t
 }
 
+func substFields(fields []*Field, types *[]*Type) []*Field {
+       nfs := make([]*Field, len(fields))
+       for i, f := range fields {
+               nft := SubstAny(f.Type, types)
+               nfs[i] = f.Copy()
+               nfs[i].Type = nft
+       }
+       return nfs
+}
+
 // copy returns a shallow copy of the Type.
 func (t *Type) copy() *Type {
        if t == nil {
@@ -780,26 +793,23 @@ func (t *Type) wantEtype(et Kind) {
        }
 }
 
-func (t *Type) recvsTuple() *Type  { return t.funcType().Receiver }
-func (t *Type) paramsTuple() *Type { return t.funcType().Params }
-
 // ResultTuple returns the result type of signature type t as a tuple.
 // This can be used as the type of multi-valued call expressions.
-func (t *Type) ResultsTuple() *Type { return t.funcType().Results }
+func (t *Type) ResultsTuple() *Type { return t.funcType().resultsTuple }
 
 // Recvs returns a slice of receiver parameters of signature type t.
 // The returned slice always has length 0 or 1.
-func (t *Type) Recvs() []*Field { return t.funcType().Receiver.Fields() }
+func (t *Type) Recvs() []*Field { return t.funcType().recvs() }
 
 // Params returns a slice of regular parameters of signature type t.
-func (t *Type) Params() []*Field { return t.funcType().Params.Fields() }
+func (t *Type) Params() []*Field { return t.funcType().params() }
 
 // Results returns a slice of result parameters of signature type t.
-func (t *Type) Results() []*Field { return t.funcType().Results.Fields() }
+func (t *Type) Results() []*Field { return t.funcType().results() }
 
-func (t *Type) NumRecvs() int   { return t.funcType().Receiver.NumFields() }
-func (t *Type) NumParams() int  { return t.funcType().Params.NumFields() }
-func (t *Type) NumResults() int { return t.funcType().Results.NumFields() }
+func (t *Type) NumRecvs() int   { return len(t.Recvs()) }
+func (t *Type) NumParams() int  { return len(t.Params()) }
+func (t *Type) NumResults() int { return len(t.Results()) }
 
 // IsVariadic reports whether function type t is variadic.
 func (t *Type) IsVariadic() bool {
@@ -809,11 +819,10 @@ func (t *Type) IsVariadic() bool {
 
 // Recv returns the receiver of function type t, if any.
 func (t *Type) Recv() *Field {
-       s := t.recvsTuple()
-       if s.NumFields() == 0 {
-               return nil
+       if s := t.Recvs(); len(s) == 1 {
+               return s[0]
        }
-       return s.Field(0)
+       return nil
 }
 
 // Param returns the i'th parameter of signature type t.
@@ -1688,10 +1697,18 @@ func NewInterface(methods []*Field) *Type {
 // NewSignature returns a new function type for the given receiver,
 // parameters, and results, any of which may be nil.
 func NewSignature(recv *Field, params, results []*Field) *Type {
-       var recvs []*Field
+       startParams := 0
        if recv != nil {
-               recvs = []*Field{recv}
+               startParams = 1
        }
+       startResults := startParams + len(params)
+
+       allParams := make([]*Field, startResults+len(results))
+       if recv != nil {
+               allParams[0] = recv
+       }
+       copy(allParams[startParams:], params)
+       copy(allParams[startResults:], results)
 
        t := newType(TFUNC)
        ft := t.funcType()
@@ -1702,10 +1719,13 @@ func NewSignature(recv *Field, params, results []*Field) *Type {
                return s
        }
 
-       ft.Receiver = funargs(recvs)
-       ft.Params = funargs(params)
-       ft.Results = funargs(results)
-       if fieldsHasShape(recvs) || fieldsHasShape(params) || fieldsHasShape(results) {
+       ft.allParams = allParams
+       ft.startParams = startParams
+       ft.startResults = startResults
+
+       ft.resultsTuple = funargs(allParams[startResults:])
+
+       if fieldsHasShape(allParams) {
                t.SetHasShape(true)
        }