github.com/aykevl/tinygo@v0.5.0/compiler/sizes.go (about) 1 package compiler 2 3 import ( 4 "go/types" 5 ) 6 7 // The code in this file has been copied from 8 // https://golang.org/src/go/types/sizes.go and modified to allow for int and 9 // pointer sizes to differ. 10 // The original license can be found here: 11 // https://golang.org/LICENSE 12 13 type StdSizes struct { 14 IntSize int64 15 PtrSize int64 16 MaxAlign int64 17 } 18 19 func (s *StdSizes) Alignof(T types.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 *types.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 *types.Struct: 28 // spec: "For a variable x of struct type: unsafe.Alignof(x) 29 // is the largest of the values unsafe.Alignof(x.f) for each 30 // field f of x, but at least 1." 31 max := int64(1) 32 for i := 0; i < t.NumFields(); i++ { 33 f := t.Field(i) 34 if a := s.Alignof(f.Type()); a > max { 35 max = a 36 } 37 } 38 return max 39 case *types.Slice, *types.Interface: 40 // Multiword data structures are effectively structs 41 // in which each element has size WordSize. 42 return s.PtrSize 43 case *types.Basic: 44 // Strings are like slices and interfaces. 45 if t.Info()&types.IsString != 0 { 46 return s.PtrSize 47 } 48 } 49 a := s.Sizeof(T) // may be 0 50 // spec: "For a variable x of any type: unsafe.Alignof(x) is at least 1." 51 if a < 1 { 52 return 1 53 } 54 // complex{64,128} are aligned like [2]float{32,64}. 55 if t, ok := T.Underlying().(*types.Basic); ok && t.Info()&types.IsComplex != 0 { 56 a /= 2 57 } 58 if a > s.MaxAlign { 59 return s.MaxAlign 60 } 61 return a 62 } 63 64 func (s *StdSizes) Offsetsof(fields []*types.Var) []int64 { 65 offsets := make([]int64, len(fields)) 66 if len(fields) > 1 && fields[0].Name() == "C union" { 67 // This struct contains the magic "C union" field which indicates that 68 // this is actually a union from CGo. 69 // All fields in the union start at 0 so return that. 70 return offsets // all fields are still set to 0 71 } 72 var o int64 73 for i, f := range fields { 74 a := s.Alignof(f.Type()) 75 o = align(o, a) 76 offsets[i] = o 77 o += s.Sizeof(f.Type()) 78 } 79 return offsets 80 } 81 82 var basicSizes = [...]byte{ 83 types.Bool: 1, 84 types.Int8: 1, 85 types.Int16: 2, 86 types.Int32: 4, 87 types.Int64: 8, 88 types.Uint8: 1, 89 types.Uint16: 2, 90 types.Uint32: 4, 91 types.Uint64: 8, 92 types.Float32: 4, 93 types.Float64: 8, 94 types.Complex64: 8, 95 types.Complex128: 16, 96 } 97 98 func (s *StdSizes) Sizeof(T types.Type) int64 { 99 switch t := T.Underlying().(type) { 100 case *types.Basic: 101 k := t.Kind() 102 if int(k) < len(basicSizes) { 103 if s := basicSizes[k]; s > 0 { 104 return int64(s) 105 } 106 } 107 if k == types.String { 108 return s.PtrSize * 2 109 } 110 if k == types.Int || k == types.Uint { 111 return s.IntSize 112 } 113 if k == types.Uintptr { 114 return s.PtrSize 115 } 116 panic("unknown basic type: " + t.String()) 117 case *types.Array: 118 n := t.Len() 119 if n <= 0 { 120 return 0 121 } 122 // n > 0 123 a := s.Alignof(t.Elem()) 124 z := s.Sizeof(t.Elem()) 125 return align(z, a)*(n-1) + z 126 case *types.Slice: 127 return s.PtrSize * 3 128 case *types.Struct: 129 n := t.NumFields() 130 if n == 0 { 131 return 0 132 } 133 fields := make([]*types.Var, t.NumFields()) 134 maxAlign := int64(1) 135 for i := range fields { 136 field := t.Field(i) 137 fields[i] = field 138 al := s.Alignof(field.Type()) 139 if al > maxAlign { 140 maxAlign = al 141 } 142 } 143 if fields[0].Name() == "C union" { 144 // Magic field that indicates this is a CGo union and not a struct. 145 // The size is the biggest element, aligned to the element with the 146 // biggest alignment. This is not necessarily the same, for example 147 // in the following union: 148 // union { int32_t l; int16_t s[3] } 149 maxSize := int64(0) 150 for _, field := range fields[1:] { 151 si := s.Sizeof(field.Type()) 152 if si > maxSize { 153 maxSize = si 154 } 155 } 156 return align(maxSize, maxAlign) 157 } else { 158 // This is a regular struct. 159 // Pick the size that fits this struct and add some alignment. Some 160 // structs have some extra padding at the end which should also be 161 // taken care of: 162 // struct { int32 n; byte b } 163 offsets := s.Offsetsof(fields) 164 return align(offsets[n-1]+s.Sizeof(fields[n-1].Type()), maxAlign) 165 } 166 case *types.Interface: 167 return s.PtrSize * 2 168 case *types.Pointer: 169 return s.PtrSize 170 default: 171 panic("unknown type: " + t.String()) 172 } 173 } 174 175 // align returns the smallest y >= x such that y % a == 0. 176 func align(x, a int64) int64 { 177 y := x + a - 1 178 return y - y%a 179 }