github.com/golangci/go-tools@v0.0.0-20190318060251-af6baa5dc196/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 // import "github.com/golangci/go-tools/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  }