| // 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, | |
| } |