diff options
-rw-r--r-- | src/cmd/compile/internal/noder/noder.go | 1 | ||||
-rw-r--r-- | src/cmd/compile/internal/noder/sizes.go | 150 |
2 files changed, 151 insertions, 0 deletions
diff --git a/src/cmd/compile/internal/noder/noder.go b/src/cmd/compile/internal/noder/noder.go index 938ffe05ce..099e3a6956 100644 --- a/src/cmd/compile/internal/noder/noder.go +++ b/src/cmd/compile/internal/noder/noder.go @@ -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 index 0000000000..7cda6da9a6 --- /dev/null +++ b/src/cmd/compile/internal/noder/sizes.go @@ -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, +} |