--- /dev/null
+// Copyright 2013 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package gcsizes provides a types.Sizes implementation that adheres
+// to the rules used by the gc compiler.
+package gcsizes // import "honnef.co/go/tools/gcsizes"
+
+import (
+ "go/build"
+ "go/types"
+)
+
+type Sizes struct {
+ WordSize int64
+ MaxAlign int64
+}
+
+// ForArch returns a correct Sizes for the given architecture.
+func ForArch(arch string) *Sizes {
+ wordSize := int64(8)
+ maxAlign := int64(8)
+ switch build.Default.GOARCH {
+ case "386", "arm":
+ wordSize, maxAlign = 4, 4
+ case "amd64p32":
+ wordSize = 4
+ }
+ return &Sizes{WordSize: wordSize, MaxAlign: maxAlign}
+}
+
+func (s *Sizes) Alignof(T types.Type) int64 {
+ switch t := T.Underlying().(type) {
+ case *types.Array:
+ return s.Alignof(t.Elem())
+ case *types.Struct:
+ max := int64(1)
+ n := t.NumFields()
+ var fields []*types.Var
+ for i := 0; i < n; i++ {
+ fields = append(fields, t.Field(i))
+ }
+ for _, f := range fields {
+ if a := s.Alignof(f.Type()); a > max {
+ max = a
+ }
+ }
+ return max
+ }
+ a := s.Sizeof(T) // may be 0
+ if a < 1 {
+ return 1
+ }
+ if a > s.MaxAlign {
+ return s.MaxAlign
+ }
+ return a
+}
+
+func (s *Sizes) Offsetsof(fields []*types.Var) []int64 {
+ offsets := make([]int64, len(fields))
+ var o int64
+ for i, f := range fields {
+ a := s.Alignof(f.Type())
+ o = align(o, a)
+ offsets[i] = o
+ o += s.Sizeof(f.Type())
+ }
+ return offsets
+}
+
+var basicSizes = [...]byte{
+ types.Bool: 1,
+ types.Int8: 1,
+ types.Int16: 2,
+ types.Int32: 4,
+ types.Int64: 8,
+ types.Uint8: 1,
+ types.Uint16: 2,
+ types.Uint32: 4,
+ types.Uint64: 8,
+ types.Float32: 4,
+ types.Float64: 8,
+ types.Complex64: 8,
+ types.Complex128: 16,
+}
+
+func (s *Sizes) Sizeof(T types.Type) int64 {
+ switch t := T.Underlying().(type) {
+ case *types.Basic:
+ k := t.Kind()
+ if int(k) < len(basicSizes) {
+ if s := basicSizes[k]; s > 0 {
+ return int64(s)
+ }
+ }
+ if k == types.String {
+ return s.WordSize * 2
+ }
+ case *types.Array:
+ n := t.Len()
+ if n == 0 {
+ return 0
+ }
+ a := s.Alignof(t.Elem())
+ z := s.Sizeof(t.Elem())
+ return align(z, a)*(n-1) + z
+ case *types.Slice:
+ return s.WordSize * 3
+ case *types.Struct:
+ n := t.NumFields()
+ if n == 0 {
+ return 0
+ }
+
+ var fields []*types.Var
+ for i := 0; i < n; i++ {
+ fields = append(fields, t.Field(i))
+ }
+ offsets := s.Offsetsof(fields)
+ a := s.Alignof(T)
+ lsz := s.Sizeof(fields[n-1].Type())
+ if lsz == 0 {
+ lsz = 1
+ }
+ z := offsets[n-1] + lsz
+ return align(z, a)
+ case *types.Interface:
+ return s.WordSize * 2
+ }
+ return s.WordSize // catch-all
+}
+
+// align returns the smallest y >= x such that y % a == 0.
+func align(x, a int64) int64 {
+ y := x + a - 1
+ return y - y%a
+}