| // 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) |
| } |