]> Cypherpunks repositories - gostls13.git/commitdiff
[dev.typeparams] cmd/compile: add types2.Sizes implementation
authorMatthew Dempsky <mdempsky@google.com>
Sat, 9 Jan 2021 03:27:51 +0000 (19:27 -0800)
committerMatthew Dempsky <mdempsky@google.com>
Mon, 11 Jan 2021 19:59:28 +0000 (19:59 +0000)
This CL adds an implementation of types2.Sizes that calculates sizes
using the same sizing algorithm as cmd/compile. In particular, it
matches how cmd/compile pads structures and includes padding in size
calculations.

Change-Id: I4dd8e51f95c90f9d7bd1e7463e40edcd3955a219
Reviewed-on: https://go-review.googlesource.com/c/go/+/282915
Trust: Matthew Dempsky <mdempsky@google.com>
Trust: Robert Griesemer <gri@golang.org>
Run-TryBot: Matthew Dempsky <mdempsky@google.com>
TryBot-Result: Go Bot <gobot@golang.org>
Reviewed-by: Robert Griesemer <gri@golang.org>
src/cmd/compile/internal/noder/noder.go
src/cmd/compile/internal/noder/sizes.go [new file with mode: 0644]

index 938ffe05ce1a57c3a0e4832c0d29c411164dc5e4..099e3a6956322d73f1bb10c393d87298dd2c5c13 100644 (file)
@@ -133,6 +133,7 @@ func ParseFiles(filenames []string) (lines uint) {
                                        return os.Open(file)
                                },
                        },
+                       Sizes: &gcSizes{},
                }
                info := types2.Info{
                        Types:      make(map[syntax.Expr]types2.TypeAndValue),
diff --git a/src/cmd/compile/internal/noder/sizes.go b/src/cmd/compile/internal/noder/sizes.go
new file mode 100644 (file)
index 0000000..7cda6da
--- /dev/null
@@ -0,0 +1,150 @@
+// Copyright 2021 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package noder
+
+import (
+       "fmt"
+
+       "cmd/compile/internal/types"
+       "cmd/compile/internal/types2"
+)
+
+// Code below based on go/types.StdSizes.
+// Intentional differences are marked with "gc:".
+
+type gcSizes struct{}
+
+func (s *gcSizes) Alignof(T types2.Type) int64 {
+       // For arrays and structs, alignment is defined in terms
+       // of alignment of the elements and fields, respectively.
+       switch t := T.Underlying().(type) {
+       case *types2.Array:
+               // spec: "For a variable x of array type: unsafe.Alignof(x)
+               // is the same as unsafe.Alignof(x[0]), but at least 1."
+               return s.Alignof(t.Elem())
+       case *types2.Struct:
+               // spec: "For a variable x of struct type: unsafe.Alignof(x)
+               // is the largest of the values unsafe.Alignof(x.f) for each
+               // field f of x, but at least 1."
+               max := int64(1)
+               for i, nf := 0, t.NumFields(); i < nf; i++ {
+                       if a := s.Alignof(t.Field(i).Type()); a > max {
+                               max = a
+                       }
+               }
+               return max
+       case *types2.Slice, *types2.Interface:
+               // Multiword data structures are effectively structs
+               // in which each element has size PtrSize.
+               return int64(types.PtrSize)
+       case *types2.Basic:
+               // Strings are like slices and interfaces.
+               if t.Info()&types2.IsString != 0 {
+                       return int64(types.PtrSize)
+               }
+       }
+       a := s.Sizeof(T) // may be 0
+       // spec: "For a variable x of any type: unsafe.Alignof(x) is at least 1."
+       if a < 1 {
+               return 1
+       }
+       // complex{64,128} are aligned like [2]float{32,64}.
+       if isComplex(T) {
+               a /= 2
+       }
+       if a > int64(types.RegSize) {
+               return int64(types.RegSize)
+       }
+       return a
+}
+
+func isComplex(T types2.Type) bool {
+       basic, ok := T.Underlying().(*types2.Basic)
+       return ok && basic.Info()&types2.IsComplex != 0
+}
+
+func (s *gcSizes) Offsetsof(fields []*types2.Var) []int64 {
+       offsets := make([]int64, len(fields))
+       var o int64
+       for i, f := range fields {
+               typ := f.Type()
+               a := s.Alignof(typ)
+               o = types.Rnd(o, a)
+               offsets[i] = o
+               o += s.Sizeof(typ)
+       }
+       return offsets
+}
+
+func (s *gcSizes) Sizeof(T types2.Type) int64 {
+       switch t := T.Underlying().(type) {
+       case *types2.Basic:
+               k := t.Kind()
+               if int(k) < len(basicSizes) {
+                       if s := basicSizes[k]; s > 0 {
+                               return int64(s)
+                       }
+               }
+               switch k {
+               case types2.String:
+                       return int64(types.PtrSize) * 2
+               case types2.Int, types2.Uint, types2.Uintptr, types2.UnsafePointer:
+                       return int64(types.PtrSize)
+               }
+               panic(fmt.Sprintf("unimplemented basic: %v (kind %v)", T, k))
+       case *types2.Array:
+               n := t.Len()
+               if n <= 0 {
+                       return 0
+               }
+               // n > 0
+               // gc: Size includes alignment padding.
+               return s.Sizeof(t.Elem()) * n
+       case *types2.Slice:
+               return int64(types.PtrSize) * 3
+       case *types2.Struct:
+               n := t.NumFields()
+               if n == 0 {
+                       return 0
+               }
+               fields := make([]*types2.Var, n)
+               for i := range fields {
+                       fields[i] = t.Field(i)
+               }
+               offsets := s.Offsetsof(fields)
+
+               // gc: The last field of a struct is not allowed to
+               // have size 0.
+               last := s.Sizeof(fields[n-1].Type())
+               if last == 0 {
+                       last = 1
+               }
+
+               // gc: Size includes alignment padding.
+               return types.Rnd(offsets[n-1]+last, s.Alignof(t))
+       case *types2.Interface:
+               return int64(types.PtrSize) * 2
+       case *types2.Chan, *types2.Map, *types2.Pointer, *types2.Signature:
+               return int64(types.PtrSize)
+       default:
+               panic(fmt.Sprintf("unimplemented type: %T", t))
+       }
+}
+
+var basicSizes = [...]byte{
+       types2.Bool:       1,
+       types2.Int8:       1,
+       types2.Int16:      2,
+       types2.Int32:      4,
+       types2.Int64:      8,
+       types2.Uint8:      1,
+       types2.Uint16:     2,
+       types2.Uint32:     4,
+       types2.Uint64:     8,
+       types2.Float32:    4,
+       types2.Float64:    8,
+       types2.Complex64:  8,
+       types2.Complex128: 16,
+}