sizes.go raw

   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