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
139 a
:= s
.Alignof(t
.elem
)
140 z
:= s
.Sizeof(t
.elem
)
141 return align(z
, a
)*(n
-1) + z
143 return s
.WordSize
* 3
149 offsets
:= s
.Offsetsof(t
.fields
)
150 return offsets
[n
-1] + s
.Sizeof(t
.fields
[n
-1].typ
)
152 return s
.WordSize
* 2
154 return s
.WordSize
// catch-all
157 // common architecture word sizes and alignments
158 var gcArchSizes
= map[string]*StdSizes
{
173 // When adding more architectures here,
174 // update the doc string of SizesFor below.
177 // SizesFor returns the Sizes used by a compiler for an architecture.
178 // The result is nil if a compiler/architecture pair is not known.
180 // Supported architectures for compiler "gc":
181 // "386", "arm", "arm64", "amd64", "amd64p32", "mips", "mipsle",
182 // "mips64", "mips64le", "ppc64", "ppc64le", "riscv64", "s390x", "wasm".
183 func SizesFor(compiler
, arch
string) Sizes
{
184 var m
map[string]*StdSizes
200 // stdSizes is used if Config.Sizes == nil.
201 var stdSizes
= SizesFor("gc", "amd64")
203 func (conf
*Config
) alignof(T Type
) int64 {
204 if s
:= conf
.Sizes
; s
!= nil {
205 if a
:= s
.Alignof(T
); a
>= 1 {
208 panic("Config.Sizes.Alignof returned an alignment < 1")
210 return stdSizes
.Alignof(T
)
213 func (conf
*Config
) offsetsof(T
*Struct
) []int64 {
215 if T
.NumFields() > 0 {
216 // compute offsets on demand
217 if s
:= conf
.Sizes
; s
!= nil {
218 offsets
= s
.Offsetsof(T
.fields
)
220 if len(offsets
) != T
.NumFields() {
221 panic("Config.Sizes.Offsetsof returned the wrong number of offsets")
223 for _
, o
:= range offsets
{
225 panic("Config.Sizes.Offsetsof returned an offset < 0")
229 offsets
= stdSizes
.Offsetsof(T
.fields
)
235 // offsetof returns the offset of the field specified via
236 // the index sequence relative to typ. All embedded fields
237 // must be structs (rather than pointer to structs).
238 func (conf
*Config
) offsetof(typ Type
, index
[]int) int64 {
240 for _
, i
:= range index
{
241 s
:= typ
.Underlying().(*Struct
)
242 o
+= conf
.offsetsof(s
)[i
]
243 typ
= s
.fields
[i
].typ
248 func (conf
*Config
) sizeof(T Type
) int64 {
249 if s
:= conf
.Sizes
; s
!= nil {
250 if z
:= s
.Sizeof(T
); z
>= 0 {
253 panic("Config.Sizes.Sizeof returned a size < 0")
255 return stdSizes
.Sizeof(T
)
258 // align returns the smallest y >= x such that y % a == 0.
259 func align(x
, a
int64) int64 {