| // 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: |
| if t.NumFields() == 0 && types2.IsSyncAtomicAlign64(T) { |
| // Special case: sync/atomic.align64 is an |
| // empty struct we recognize as a signal that |
| // the struct it contains must be |
| // 64-bit-aligned. |
| // |
| // This logic is equivalent to the logic in |
| // cmd/compile/internal/types/size.go:calcStructOffset |
| return 8 |
| } |
| |
| // 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 non-zero-sized struct is not allowed to |
| // have size 0. |
| last := s.Sizeof(fields[n-1].Type()) |
| if last == 0 && offsets[n-1] > 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.Invalid: 1, |
| 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, |
| } |