Skip to content

Commit

Permalink
[dev.typeparams] cmd/compile: add types2.Sizes implementation
Browse files Browse the repository at this point in the history
This CL adds an implementation of types2.Sizes that calculates sizes
using the same sizing algorithm as cmd/compile. In particular, it
matches how cmd/compile pads structures and includes padding in size
calculations.

Change-Id: I4dd8e51f95c90f9d7bd1e7463e40edcd3955a219
Reviewed-on: https://go-review.googlesource.com/c/go/+/282915
Trust: Matthew Dempsky <mdempsky@google.com>
Trust: Robert Griesemer <gri@golang.org>
Run-TryBot: Matthew Dempsky <mdempsky@google.com>
TryBot-Result: Go Bot <gobot@golang.org>
Reviewed-by: Robert Griesemer <gri@golang.org>
  • Loading branch information
mdempsky committed Jan 11, 2021
1 parent 44d1a85 commit 2e8f29b
Show file tree
Hide file tree
Showing 2 changed files with 151 additions and 0 deletions.
1 change: 1 addition & 0 deletions src/cmd/compile/internal/noder/noder.go
Expand Up @@ -133,6 +133,7 @@ func ParseFiles(filenames []string) (lines uint) {
return os.Open(file)
},
},
Sizes: &gcSizes{},
}
info := types2.Info{
Types: make(map[syntax.Expr]types2.TypeAndValue),
Expand Down
150 changes: 150 additions & 0 deletions src/cmd/compile/internal/noder/sizes.go
@@ -0,0 +1,150 @@
// Copyright 2021 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 noder

import (
"fmt"

"cmd/compile/internal/types"
"cmd/compile/internal/types2"
)

// Code below based on go/types.StdSizes.
// Intentional differences are marked with "gc:".

type gcSizes struct{}

func (s *gcSizes) Alignof(T types2.Type) int64 {
// For arrays and structs, alignment is defined in terms
// of alignment of the elements and fields, respectively.
switch t := T.Underlying().(type) {
case *types2.Array:
// spec: "For a variable x of array type: unsafe.Alignof(x)
// is the same as unsafe.Alignof(x[0]), but at least 1."
return s.Alignof(t.Elem())
case *types2.Struct:
// spec: "For a variable x of struct type: unsafe.Alignof(x)
// is the largest of the values unsafe.Alignof(x.f) for each
// field f of x, but at least 1."
max := int64(1)
for i, nf := 0, t.NumFields(); i < nf; i++ {
if a := s.Alignof(t.Field(i).Type()); a > max {
max = a
}
}
return max
case *types2.Slice, *types2.Interface:
// Multiword data structures are effectively structs
// in which each element has size PtrSize.
return int64(types.PtrSize)
case *types2.Basic:
// Strings are like slices and interfaces.
if t.Info()&types2.IsString != 0 {
return int64(types.PtrSize)
}
}
a := s.Sizeof(T) // may be 0
// spec: "For a variable x of any type: unsafe.Alignof(x) is at least 1."
if a < 1 {
return 1
}
// complex{64,128} are aligned like [2]float{32,64}.
if isComplex(T) {
a /= 2
}
if a > int64(types.RegSize) {
return int64(types.RegSize)
}
return a
}

func isComplex(T types2.Type) bool {
basic, ok := T.Underlying().(*types2.Basic)
return ok && basic.Info()&types2.IsComplex != 0
}

func (s *gcSizes) Offsetsof(fields []*types2.Var) []int64 {
offsets := make([]int64, len(fields))
var o int64
for i, f := range fields {
typ := f.Type()
a := s.Alignof(typ)
o = types.Rnd(o, a)
offsets[i] = o
o += s.Sizeof(typ)
}
return offsets
}

func (s *gcSizes) Sizeof(T types2.Type) int64 {
switch t := T.Underlying().(type) {
case *types2.Basic:
k := t.Kind()
if int(k) < len(basicSizes) {
if s := basicSizes[k]; s > 0 {
return int64(s)
}
}
switch k {
case types2.String:
return int64(types.PtrSize) * 2
case types2.Int, types2.Uint, types2.Uintptr, types2.UnsafePointer:
return int64(types.PtrSize)
}
panic(fmt.Sprintf("unimplemented basic: %v (kind %v)", T, k))
case *types2.Array:
n := t.Len()
if n <= 0 {
return 0
}
// n > 0
// gc: Size includes alignment padding.
return s.Sizeof(t.Elem()) * n
case *types2.Slice:
return int64(types.PtrSize) * 3
case *types2.Struct:
n := t.NumFields()
if n == 0 {
return 0
}
fields := make([]*types2.Var, n)
for i := range fields {
fields[i] = t.Field(i)
}
offsets := s.Offsetsof(fields)

// gc: The last field of a struct is not allowed to
// have size 0.
last := s.Sizeof(fields[n-1].Type())
if last == 0 {
last = 1
}

// gc: Size includes alignment padding.
return types.Rnd(offsets[n-1]+last, s.Alignof(t))
case *types2.Interface:
return int64(types.PtrSize) * 2
case *types2.Chan, *types2.Map, *types2.Pointer, *types2.Signature:
return int64(types.PtrSize)
default:
panic(fmt.Sprintf("unimplemented type: %T", t))
}
}

var basicSizes = [...]byte{
types2.Bool: 1,
types2.Int8: 1,
types2.Int16: 2,
types2.Int32: 4,
types2.Int64: 8,
types2.Uint8: 1,
types2.Uint16: 2,
types2.Uint32: 4,
types2.Uint64: 8,
types2.Float32: 4,
types2.Float64: 8,
types2.Complex64: 8,
types2.Complex128: 16,
}

0 comments on commit 2e8f29b

Please sign in to comment.