1 // Copyright 2013 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.
5 // This file implements Sizes.
9 // Sizes defines the sizing functions for package unsafe.
10 type Sizes interface {
11 // Alignof returns the alignment of a variable of type T.
12 // Alignof must implement the alignment guarantees required by the spec.
15 // Offsetsof returns the offsets of the given struct fields, in bytes.
16 // Offsetsof must implement the offset guarantees required by the spec.
17 Offsetsof(fields []*Var) []int64
19 // Sizeof returns the size of a variable of type T.
20 // Sizeof must implement the size guarantees required by the spec.
24 // StdSizes is a convenience type for creating commonly used Sizes.
25 // It makes the following simplifying assumptions:
27 // - The size of explicitly sized basic types (int16, etc.) is the
29 // - The size of strings and interfaces is 2*WordSize.
30 // - The size of slices is 3*WordSize.
31 // - The size of an array of n elements corresponds to the size of
32 // a struct of n consecutive fields of the array's element type.
33 // - The size of a struct is the offset of the last field plus that
34 // field's size. As with all element types, if the struct is used
35 // in an array its size must first be aligned to a multiple of the
36 // struct's alignment.
37 // - All other types have size WordSize.
38 // - Arrays and structs are aligned per spec definition; all other
39 // types are naturally aligned with a maximum alignment MaxAlign.
41 // *StdSizes implements Sizes.
43 type StdSizes struct {
44 WordSize int64 // word size in bytes - must be >= 4 (32bits)
45 MaxAlign int64 // maximum alignment in bytes - must be >= 1
48 func (s *StdSizes) Alignof(T Type) int64 {
49 // For arrays and structs, alignment is defined in terms
50 // of alignment of the elements and fields, respectively.
51 switch t := T.Underlying().(type) {
53 // spec: "For a variable x of array type: unsafe.Alignof(x)
54 // is the same as unsafe.Alignof(x[0]), but at least 1."
55 return s.Alignof(t.elem)
57 // spec: "For a variable x of struct type: unsafe.Alignof(x)
58 // is the largest of the values unsafe.Alignof(x.f) for each
59 // field f of x, but at least 1."
61 for _, f := range t.fields {
62 if a := s.Alignof(f.typ); a > max {
67 case *Slice, *Interface:
68 // Multiword data structures are effectively structs
69 // in which each element has size WordSize.
72 // Strings are like slices and interfaces.
73 if t.Info()&IsString != 0 {
77 a := s.Sizeof(T) // may be 0
78 // spec: "For a variable x of any type: unsafe.Alignof(x) is at least 1."
82 // complex{64,128} are aligned like [2]float{32,64}.
92 func (s *StdSizes) Offsetsof(fields []*Var) []int64 {
93 offsets := make([]int64, len(fields))
95 for i, f := range fields {
104 var basicSizes = [...]byte{
120 func (s *StdSizes) Sizeof(T Type) int64 {
121 switch t := T.Underlying().(type) {
125 if int(k) < len(basicSizes) {
126 if s := basicSizes[k]; s > 0 {
131 return s.WordSize * 2
138 a := s.Alignof(t.elem)
139 z := s.Sizeof(t.elem)
140 return align(z, a)*(n-1) + z
142 return s.WordSize * 3
148 offsets := s.Offsetsof(t.fields)
149 return offsets[n-1] + s.Sizeof(t.fields[n-1].typ)
151 return s.WordSize * 2
153 return s.WordSize // catch-all
156 // common architecture word sizes and alignments
157 var gcArchSizes = map[string]*StdSizes{
170 // When adding more architectures here,
171 // update the doc string of SizesFor below.
174 // SizesFor returns the Sizes used by a compiler for an architecture.
175 // The result is nil if a compiler/architecture pair is not known.
177 // Supported architectures for compiler "gc":
178 // "386", "arm", "arm64", "amd64", "amd64p32", "mips", "mipsle",
179 // "mips64", "mips64le", "ppc64", "ppc64le", "s390x".
180 func SizesFor(compiler, arch string) Sizes {
181 var m map[string]*StdSizes
197 // stdSizes is used if Config.Sizes == nil.
198 var stdSizes = SizesFor("gc", "amd64")
200 func (conf *Config) alignof(T Type) int64 {
201 if s := conf.Sizes; s != nil {
202 if a := s.Alignof(T); a >= 1 {
205 panic("Config.Sizes.Alignof returned an alignment < 1")
207 return stdSizes.Alignof(T)
210 func (conf *Config) offsetsof(T *Struct) []int64 {
212 if T.NumFields() > 0 {
213 // compute offsets on demand
214 if s := conf.Sizes; s != nil {
215 offsets = s.Offsetsof(T.fields)
217 if len(offsets) != T.NumFields() {
218 panic("Config.Sizes.Offsetsof returned the wrong number of offsets")
220 for _, o := range offsets {
222 panic("Config.Sizes.Offsetsof returned an offset < 0")
226 offsets = stdSizes.Offsetsof(T.fields)
232 // offsetof returns the offset of the field specified via
233 // the index sequence relative to typ. All embedded fields
234 // must be structs (rather than pointer to structs).
235 func (conf *Config) offsetof(typ Type, index []int) int64 {
237 for _, i := range index {
238 s := typ.Underlying().(*Struct)
239 o += conf.offsetsof(s)[i]
240 typ = s.fields[i].typ
245 func (conf *Config) sizeof(T Type) int64 {
246 if s := conf.Sizes; s != nil {
247 if z := s.Sizeof(T); z >= 0 {
250 panic("Config.Sizes.Sizeof returned a size < 0")
252 return stdSizes.Sizeof(T)
255 // align returns the smallest y >= x such that y % a == 0.
256 func align(x, a int64) int64 {