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 case *types.Signature:
49 // Even though functions in moxie are 2 pointers, they are not 2 pointer aligned
50 return s.PtrSize
51 }
52 53 a := s.Sizeof(T) // may be 0
54 // spec: "For a variable x of any type: unsafe.Alignof(x) is at least 1."
55 if a < 1 {
56 return 1
57 }
58 // complex{64,128} are aligned like [2]float{32,64}.
59 if t, ok := T.Underlying().(*types.Basic); ok && t.Info()&types.IsComplex != 0 {
60 a /= 2
61 }
62 if a > s.MaxAlign {
63 return s.MaxAlign
64 }
65 return a
66 }
67 68 func (s *stdSizes) Offsetsof(fields []*types.Var) []int64 {
69 offsets := make([]int64, len(fields))
70 var o int64
71 for i, f := range fields {
72 a := s.Alignof(f.Type())
73 o = align(o, a)
74 offsets[i] = o
75 o += s.Sizeof(f.Type())
76 }
77 return offsets
78 }
79 80 var basicSizes = [...]byte{
81 types.Bool: 1,
82 types.Int8: 1,
83 types.Int16: 2,
84 types.Int32: 4,
85 types.Int64: 8,
86 types.Uint8: 1,
87 types.Uint16: 2,
88 types.Uint32: 4,
89 types.Uint64: 8,
90 types.Float32: 4,
91 types.Float64: 8,
92 types.Complex64: 8,
93 types.Complex128: 16,
94 }
95 96 func (s *stdSizes) Sizeof(T types.Type) int64 {
97 switch t := T.Underlying().(type) {
98 case *types.Basic:
99 k := t.Kind()
100 if int(k) < len(basicSizes) {
101 if s := basicSizes[k]; s > 0 {
102 return int64(s)
103 }
104 }
105 if k == types.String {
106 return s.PtrSize * 3 // Moxie: string is {ptr, len, cap} like []byte
107 }
108 if k == types.Int || k == types.Uint {
109 return s.IntSize
110 }
111 if k == types.Uintptr {
112 return s.PtrSize
113 }
114 if k == types.UnsafePointer {
115 return s.PtrSize
116 }
117 if k == types.Invalid {
118 return 0 // only relevant when there is a type error somewhere
119 }
120 panic("unknown basic type: " + t.String())
121 case *types.Array:
122 n := t.Len()
123 if n <= 0 {
124 return 0
125 }
126 // n > 0
127 a := s.Alignof(t.Elem())
128 z := s.Sizeof(t.Elem())
129 return align(z, a)*(n-1) + z
130 case *types.Slice:
131 return s.PtrSize * 3
132 case *types.Struct:
133 n := t.NumFields()
134 if n == 0 {
135 return 0
136 }
137 fields := make([]*types.Var, t.NumFields())
138 maxAlign := int64(1)
139 for i := range fields {
140 field := t.Field(i)
141 fields[i] = field
142 al := s.Alignof(field.Type())
143 if al > maxAlign {
144 maxAlign = al
145 }
146 }
147 // Pick the size that fits this struct and add some alignment. Some
148 // structs have some extra padding at the end which should also be taken
149 // care of:
150 // struct { int32 n; byte b }
151 offsets := s.Offsetsof(fields)
152 return align(offsets[n-1]+s.Sizeof(fields[n-1].Type()), maxAlign)
153 case *types.Interface:
154 return s.PtrSize * 2
155 case *types.Pointer, *types.Chan, *types.Map:
156 return s.PtrSize
157 case *types.Signature:
158 // Func values in Moxie are two words in size.
159 return s.PtrSize * 2
160 default:
161 panic("unknown type: " + t.String())
162 }
163 }
164 165 // align returns the smallest y >= x such that y % a == 0.
166 func align(x, a int64) int64 {
167 y := x + a - 1
168 return y - y%a
169 }
170