github.com/amarpal/go-tools@v0.0.0-20240422043104-40142f59f616/go/gcsizes/sizes.go (about) 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. 4 5 // Package gcsizes provides a types.Sizes implementation that adheres 6 // to the rules used by the gc compiler. 7 package gcsizes 8 9 import ( 10 "go/build" 11 "go/types" 12 ) 13 14 type Sizes struct { 15 WordSize int64 16 MaxAlign int64 17 } 18 19 // ForArch returns a correct Sizes for the given architecture. 20 func ForArch(arch string) *Sizes { 21 wordSize := int64(8) 22 maxAlign := int64(8) 23 switch build.Default.GOARCH { 24 case "386", "arm": 25 wordSize, maxAlign = 4, 4 26 case "amd64p32": 27 wordSize = 4 28 } 29 return &Sizes{WordSize: wordSize, MaxAlign: maxAlign} 30 } 31 32 func (s *Sizes) Alignof(T types.Type) int64 { 33 switch t := T.Underlying().(type) { 34 case *types.Array: 35 return s.Alignof(t.Elem()) 36 case *types.Struct: 37 max := int64(1) 38 n := t.NumFields() 39 var fields []*types.Var 40 for i := 0; i < n; i++ { 41 fields = append(fields, t.Field(i)) 42 } 43 for _, f := range fields { 44 if a := s.Alignof(f.Type()); a > max { 45 max = a 46 } 47 } 48 return max 49 } 50 a := s.Sizeof(T) // may be 0 51 if a < 1 { 52 return 1 53 } 54 if a > s.MaxAlign { 55 return s.MaxAlign 56 } 57 return a 58 } 59 60 func (s *Sizes) Offsetsof(fields []*types.Var) []int64 { 61 offsets := make([]int64, len(fields)) 62 var o int64 63 for i, f := range fields { 64 a := s.Alignof(f.Type()) 65 o = align(o, a) 66 offsets[i] = o 67 o += s.Sizeof(f.Type()) 68 } 69 return offsets 70 } 71 72 var basicSizes = [...]byte{ 73 types.Bool: 1, 74 types.Int8: 1, 75 types.Int16: 2, 76 types.Int32: 4, 77 types.Int64: 8, 78 types.Uint8: 1, 79 types.Uint16: 2, 80 types.Uint32: 4, 81 types.Uint64: 8, 82 types.Float32: 4, 83 types.Float64: 8, 84 types.Complex64: 8, 85 types.Complex128: 16, 86 } 87 88 func (s *Sizes) Sizeof(T types.Type) int64 { 89 switch t := T.Underlying().(type) { 90 case *types.Basic: 91 k := t.Kind() 92 if int(k) < len(basicSizes) { 93 if s := basicSizes[k]; s > 0 { 94 return int64(s) 95 } 96 } 97 if k == types.String { 98 return s.WordSize * 2 99 } 100 case *types.Array: 101 n := t.Len() 102 if n == 0 { 103 return 0 104 } 105 a := s.Alignof(t.Elem()) 106 z := s.Sizeof(t.Elem()) 107 return align(z, a)*(n-1) + z 108 case *types.Slice: 109 return s.WordSize * 3 110 case *types.Struct: 111 n := t.NumFields() 112 if n == 0 { 113 return 0 114 } 115 116 var fields []*types.Var 117 for i := 0; i < n; i++ { 118 fields = append(fields, t.Field(i)) 119 } 120 offsets := s.Offsetsof(fields) 121 a := s.Alignof(T) 122 lsz := s.Sizeof(fields[n-1].Type()) 123 if lsz == 0 { 124 lsz = 1 125 } 126 z := offsets[n-1] + lsz 127 return align(z, a) 128 case *types.Interface: 129 return s.WordSize * 2 130 } 131 return s.WordSize // catch-all 132 } 133 134 // align returns the smallest y >= x such that y % a == 0. 135 func align(x, a int64) int64 { 136 y := x + a - 1 137 return y - y%a 138 }