blob: d92addec25508b46a199453537abc1b7bc40e36b [file] [log] [blame]
// Copyright 2023 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 abi
// These functions are the build-time version of the Go type data structures.
// Their contents must be kept in sync with their definitions.
// Because the host and target type sizes can differ, the compiler and
// linker cannot use the host information that they might get from
// either unsafe.Sizeof and Alignof, nor runtime, reflect, or reflectlite.
// CommonSize returns sizeof(Type) for a compilation target with a given ptrSize
func CommonSize(ptrSize int) int { return 4*ptrSize + 8 + 8 }
// StructFieldSize returns sizeof(StructField) for a compilation target with a given ptrSize
func StructFieldSize(ptrSize int) int { return 3 * ptrSize }
// UncommonSize returns sizeof(UncommonType). This currently does not depend on ptrSize.
// This exported function is in an internal package, so it may change to depend on ptrSize in the future.
func UncommonSize() uint64 { return 4 + 2 + 2 + 4 + 4 }
// IMethodSize returns sizeof(IMethod) for a compilation target with a given ptrSize
func IMethodSize(ptrSize int) int { return 4 + 4 }
// KindOff returns the offset of Type.Kind_ for a compilation target with a given ptrSize
func KindOff(ptrSize int) int { return 2*ptrSize + 7 }
// SizeOff returns the offset of Type.Size_ for a compilation target with a given ptrSize
func SizeOff(ptrSize int) int { return 0 }
// PtrBytes returns the offset of Type.PtrBytes for a compilation target with a given ptrSize
func PtrBytesOff(ptrSize int) int { return ptrSize }
// TFlagOff returns the offset of Type.TFlag for a compilation target with a given ptrSize
func TFlagOff(ptrSize int) int { return 2*ptrSize + 4 }
// Offset is for computing offsets of type data structures at compile/link time;
// the target platform may not be the host platform. Its state includes the
// current offset, necessary alignment for the sequence of types, and the size
// of pointers and alignment of slices, interfaces, and strings (this is for tearing-
// resistant access to these types, if/when that is supported).
type Offset struct {
off uint64 // the current offset
align uint8 // the required alignmentof the container
ptrSize uint8 // the size of a pointer in bytes
sliceAlign uint8 // the alignment of slices (and interfaces and strings)
}
// NewOffset returns a new Offset with offset 0 and alignment 1.
func NewOffset(ptrSize uint8, twoWordAlignSlices bool) Offset {
if twoWordAlignSlices {
return Offset{off: 0, align: 1, ptrSize: ptrSize, sliceAlign: 2 * ptrSize}
}
return Offset{off: 0, align: 1, ptrSize: ptrSize, sliceAlign: ptrSize}
}
func assertIsAPowerOfTwo(x uint8) {
if x == 0 {
panic("Zero is not a power of two")
}
if x&-x == x {
return
}
panic("Not a power of two")
}
// InitializedOffset returns a new Offset with specified offset, alignment, pointer size, and slice alignment.
func InitializedOffset(off int, align uint8, ptrSize uint8, twoWordAlignSlices bool) Offset {
assertIsAPowerOfTwo(align)
o0 := NewOffset(ptrSize, twoWordAlignSlices)
o0.off = uint64(off)
o0.align = align
return o0
}
func (o Offset) align_(a uint8) Offset {
o.off = (o.off + uint64(a) - 1) & ^(uint64(a) - 1)
if o.align < a {
o.align = a
}
return o
}
// Align returns the offset obtained by aligning offset to a multiple of a.
// a must be a power of two.
func (o Offset) Align(a uint8) Offset {
assertIsAPowerOfTwo(a)
return o.align_(a)
}
// plus returns the offset obtained by appending a power-of-2-sized-and-aligned object to o.
func (o Offset) plus(x uint64) Offset {
o = o.align_(uint8(x))
o.off += x
return o
}
// D8 returns the offset obtained by appending an 8-bit field to o.
func (o Offset) D8() Offset {
return o.plus(1)
}
// D16 returns the offset obtained by appending a 16-bit field to o.
func (o Offset) D16() Offset {
return o.plus(2)
}
// D32 returns the offset obtained by appending a 32-bit field to o.
func (o Offset) D32() Offset {
return o.plus(4)
}
// D64 returns the offset obtained by appending a 64-bit field to o.
func (o Offset) D64() Offset {
return o.plus(8)
}
// D64 returns the offset obtained by appending a pointer field to o.
func (o Offset) P() Offset {
if o.ptrSize == 0 {
panic("This offset has no defined pointer size")
}
return o.plus(uint64(o.ptrSize))
}
// Slice returns the offset obtained by appending a slice field to o.
func (o Offset) Slice() Offset {
o = o.align_(o.sliceAlign)
o.off += 3 * uint64(o.ptrSize)
// There's been discussion of whether slices should be 2-word aligned to allow
// use of aligned 2-word load/store to prevent tearing, this is future proofing.
// In general, for purposes of struct layout (and very likely default C layout
// compatibility) the "size" of a Go type is rounded up to its alignment.
return o.Align(o.sliceAlign)
}
// String returns the offset obtained by appending a string field to o.
func (o Offset) String() Offset {
o = o.align_(o.sliceAlign)
o.off += 2 * uint64(o.ptrSize)
return o // We "know" it needs no further alignment
}
// Interface returns the offset obtained by appending an interface field to o.
func (o Offset) Interface() Offset {
o = o.align_(o.sliceAlign)
o.off += 2 * uint64(o.ptrSize)
return o // We "know" it needs no further alignment
}
// Offset returns the struct-aligned offset (size) of o.
// This is at least as large as the current internal offset; it may be larger.
func (o Offset) Offset() uint64 {
return o.Align(o.align).off
}
func (o Offset) PlusUncommon() Offset {
o.off += UncommonSize()
return o
}
// CommonOffset returns the Offset to the data after the common portion of type data structures.
func CommonOffset(ptrSize int, twoWordAlignSlices bool) Offset {
return InitializedOffset(CommonSize(ptrSize), uint8(ptrSize), uint8(ptrSize), twoWordAlignSlices)
}