mirror of
https://github.com/golang/go
synced 2024-07-20 09:44:05 +00:00
cmd/compile: use types2.Sizes instead of compiler own implementation
With #61035 fixed, types2.Sizes matches the compiler behavior, so use its Sizes implementation instead of rolling our own copy. Updates #61035 Change-Id: I7b9efd27a01f729a04c79cd6b4ee5f417fe6e664 Reviewed-on: https://go-review.googlesource.com/c/go/+/506716 TryBot-Result: Gopher Robot <gobot@golang.org> Auto-Submit: Cuong Manh Le <cuong.manhle.vn@gmail.com> Run-TryBot: Cuong Manh Le <cuong.manhle.vn@gmail.com> Reviewed-by: Matthew Dempsky <mdempsky@google.com> Reviewed-by: Robert Griesemer <gri@google.com>
This commit is contained in:
parent
5fa4aac0ce
commit
14a3ffc3d2
|
@ -6,6 +6,7 @@ package noder
|
|||
|
||||
import (
|
||||
"fmt"
|
||||
"internal/buildcfg"
|
||||
"internal/types/errors"
|
||||
"regexp"
|
||||
"sort"
|
||||
|
@ -51,7 +52,7 @@ func checkFiles(m posMap, noders []*noder) (*types2.Package, *types2.Info) {
|
|||
base.ErrorfAt(m.makeXPos(terr.Pos), terr.Code, "%s", msg)
|
||||
},
|
||||
Importer: &importer,
|
||||
Sizes: &gcSizes{},
|
||||
Sizes: types2.SizesFor("gc", buildcfg.GOARCH),
|
||||
}
|
||||
if base.Flag.ErrorURL {
|
||||
conf.ErrorURL = " [go.dev/e/%s]"
|
||||
|
|
|
@ -1,185 +0,0 @@
|
|||
// 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:
|
||||
if t.NumFields() == 0 && types2.IsSyncAtomicAlign64(T) {
|
||||
// Special case: sync/atomic.align64 is an
|
||||
// empty struct we recognize as a signal that
|
||||
// the struct it contains must be
|
||||
// 64-bit-aligned.
|
||||
//
|
||||
// This logic is equivalent to the logic in
|
||||
// cmd/compile/internal/types/size.go:calcStructOffset
|
||||
return 8
|
||||
}
|
||||
|
||||
// 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 offs int64
|
||||
for i, f := range fields {
|
||||
if offs < 0 {
|
||||
// all remaining offsets are too large
|
||||
offsets[i] = -1
|
||||
continue
|
||||
}
|
||||
// offs >= 0
|
||||
typ := f.Type()
|
||||
a := s.Alignof(typ)
|
||||
offs = types.RoundUp(offs, a) // possibly < 0 if align overflows
|
||||
offsets[i] = offs
|
||||
if d := s.Sizeof(typ); d >= 0 && offs >= 0 {
|
||||
offs += d // ok to overflow to < 0
|
||||
} else {
|
||||
offs = -1
|
||||
}
|
||||
}
|
||||
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.
|
||||
esize := s.Sizeof(t.Elem())
|
||||
if esize < 0 {
|
||||
return -1 // array element too large
|
||||
}
|
||||
if esize == 0 {
|
||||
return 0 // 0-size element
|
||||
}
|
||||
// esize > 0
|
||||
// Final size is esize * n; and size must be <= maxInt64.
|
||||
const maxInt64 = 1<<63 - 1
|
||||
if esize > maxInt64/n {
|
||||
return -1 // esize * n overflows
|
||||
}
|
||||
return esize * 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 non-zero-sized struct is not allowed to
|
||||
// have size 0.
|
||||
last := s.Sizeof(fields[n-1].Type())
|
||||
if last == 0 && offsets[n-1] > 0 {
|
||||
last = 1
|
||||
}
|
||||
|
||||
// gc: Size includes alignment padding.
|
||||
return types.RoundUp(offsets[n-1]+last, s.Alignof(t)) // may overflow to < 0 which is ok
|
||||
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.Invalid: 1,
|
||||
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,
|
||||
}
|
Loading…
Reference in a new issue