github.com/bir3/gocompiler@v0.3.205/src/cmd/compile/internal/noder/sizes.go (about) 1 // Copyright 2021 The Go Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 package noder 6 7 import ( 8 "fmt" 9 10 "github.com/bir3/gocompiler/src/cmd/compile/internal/types" 11 "github.com/bir3/gocompiler/src/cmd/compile/internal/types2" 12 ) 13 14 // Code below based on go/types.StdSizes. 15 // Intentional differences are marked with "gc:". 16 17 type gcSizes struct{} 18 19 func (s *gcSizes) Alignof(T types2.Type) int64 { 20 // For arrays and structs, alignment is defined in terms 21 // of alignment of the elements and fields, respectively. 22 switch t := T.Underlying().(type) { 23 case *types2.Array: 24 // spec: "For a variable x of array type: unsafe.Alignof(x) 25 // is the same as unsafe.Alignof(x[0]), but at least 1." 26 return s.Alignof(t.Elem()) 27 case *types2.Struct: 28 if t.NumFields() == 0 && types2.IsSyncAtomicAlign64(T) { 29 // Special case: sync/atomic.align64 is an 30 // empty struct we recognize as a signal that 31 // the struct it contains must be 32 // 64-bit-aligned. 33 // 34 // This logic is equivalent to the logic in 35 // cmd/compile/internal/types/size.go:calcStructOffset 36 return 8 37 } 38 39 // spec: "For a variable x of struct type: unsafe.Alignof(x) 40 // is the largest of the values unsafe.Alignof(x.f) for each 41 // field f of x, but at least 1." 42 max := int64(1) 43 for i, nf := 0, t.NumFields(); i < nf; i++ { 44 if a := s.Alignof(t.Field(i).Type()); a > max { 45 max = a 46 } 47 } 48 return max 49 case *types2.Slice, *types2.Interface: 50 // Multiword data structures are effectively structs 51 // in which each element has size PtrSize. 52 return int64(types.PtrSize) 53 case *types2.Basic: 54 // Strings are like slices and interfaces. 55 if t.Info()&types2.IsString != 0 { 56 return int64(types.PtrSize) 57 } 58 } 59 a := s.Sizeof(T) // may be 0 60 // spec: "For a variable x of any type: unsafe.Alignof(x) is at least 1." 61 if a < 1 { 62 return 1 63 } 64 // complex{64,128} are aligned like [2]float{32,64}. 65 if isComplex(T) { 66 a /= 2 67 } 68 if a > int64(types.RegSize) { 69 return int64(types.RegSize) 70 } 71 return a 72 } 73 74 func isComplex(T types2.Type) bool { 75 basic, ok := T.Underlying().(*types2.Basic) 76 return ok && basic.Info()&types2.IsComplex != 0 77 } 78 79 func (s *gcSizes) Offsetsof(fields []*types2.Var) []int64 { 80 offsets := make([]int64, len(fields)) 81 var o int64 82 for i, f := range fields { 83 typ := f.Type() 84 a := s.Alignof(typ) 85 o = types.RoundUp(o, a) 86 offsets[i] = o 87 o += s.Sizeof(typ) 88 } 89 return offsets 90 } 91 92 func (s *gcSizes) Sizeof(T types2.Type) int64 { 93 switch t := T.Underlying().(type) { 94 case *types2.Basic: 95 k := t.Kind() 96 if int(k) < len(basicSizes) { 97 if s := basicSizes[k]; s > 0 { 98 return int64(s) 99 } 100 } 101 switch k { 102 case types2.String: 103 return int64(types.PtrSize) * 2 104 case types2.Int, types2.Uint, types2.Uintptr, types2.UnsafePointer: 105 return int64(types.PtrSize) 106 } 107 panic(fmt.Sprintf("unimplemented basic: %v (kind %v)", T, k)) 108 case *types2.Array: 109 n := t.Len() 110 if n <= 0 { 111 return 0 112 } 113 // n > 0 114 // gc: Size includes alignment padding. 115 return s.Sizeof(t.Elem()) * n 116 case *types2.Slice: 117 return int64(types.PtrSize) * 3 118 case *types2.Struct: 119 n := t.NumFields() 120 if n == 0 { 121 return 0 122 } 123 fields := make([]*types2.Var, n) 124 for i := range fields { 125 fields[i] = t.Field(i) 126 } 127 offsets := s.Offsetsof(fields) 128 129 // gc: The last field of a non-zero-sized struct is not allowed to 130 // have size 0. 131 last := s.Sizeof(fields[n-1].Type()) 132 if last == 0 && offsets[n-1] > 0 { 133 last = 1 134 } 135 136 // gc: Size includes alignment padding. 137 return types.RoundUp(offsets[n-1]+last, s.Alignof(t)) 138 case *types2.Interface: 139 return int64(types.PtrSize) * 2 140 case *types2.Chan, *types2.Map, *types2.Pointer, *types2.Signature: 141 return int64(types.PtrSize) 142 default: 143 panic(fmt.Sprintf("unimplemented type: %T", t)) 144 } 145 } 146 147 var basicSizes = [...]byte{ 148 types2.Invalid: 1, 149 types2.Bool: 1, 150 types2.Int8: 1, 151 types2.Int16: 2, 152 types2.Int32: 4, 153 types2.Int64: 8, 154 types2.Uint8: 1, 155 types2.Uint16: 2, 156 types2.Uint32: 4, 157 types2.Uint64: 8, 158 types2.Float32: 4, 159 types2.Float64: 8, 160 types2.Complex64: 8, 161 types2.Complex128: 16, 162 }