github.com/AndrienkoAleksandr/go@v0.0.19/src/intern/abi/compiletype.go (about) 1 // Copyright 2023 The Go Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 package abi 6 7 // These functions are the build-time version of the Go type data structures. 8 9 // Their contents must be kept in sync with their definitions. 10 // Because the host and target type sizes can differ, the compiler and 11 // linker cannot use the host information that they might get from 12 // either unsafe.Sizeof and Alignof, nor runtime, reflect, or reflectlite. 13 14 // CommonSize returns sizeof(Type) for a compilation target with a given ptrSize 15 func CommonSize(ptrSize int) int { return 4*ptrSize + 8 + 8 } 16 17 // StructFieldSize returns sizeof(StructField) for a compilation target with a given ptrSize 18 func StructFieldSize(ptrSize int) int { return 3 * ptrSize } 19 20 // UncommonSize returns sizeof(UncommonType). This currently does not depend on ptrSize. 21 // This exported function is in an internal package, so it may change to depend on ptrSize in the future. 22 func UncommonSize() uint64 { return 4 + 2 + 2 + 4 + 4 } 23 24 // IMethodSize returns sizeof(IMethod) for a compilation target with a given ptrSize 25 func IMethodSize(ptrSize int) int { return 4 + 4 } 26 27 // KindOff returns the offset of Type.Kind_ for a compilation target with a given ptrSize 28 func KindOff(ptrSize int) int { return 2*ptrSize + 7 } 29 30 // SizeOff returns the offset of Type.Size_ for a compilation target with a given ptrSize 31 func SizeOff(ptrSize int) int { return 0 } 32 33 // PtrBytes returns the offset of Type.PtrBytes for a compilation target with a given ptrSize 34 func PtrBytesOff(ptrSize int) int { return ptrSize } 35 36 // TFlagOff returns the offset of Type.TFlag for a compilation target with a given ptrSize 37 func TFlagOff(ptrSize int) int { return 2*ptrSize + 4 } 38 39 // Offset is for computing offsets of type data structures at compile/link time; 40 // the target platform may not be the host platform. Its state includes the 41 // current offset, necessary alignment for the sequence of types, and the size 42 // of pointers and alignment of slices, interfaces, and strings (this is for tearing- 43 // resistant access to these types, if/when that is supported). 44 type Offset struct { 45 off uint64 // the current offset 46 align uint8 // the required alignmentof the container 47 ptrSize uint8 // the size of a pointer in bytes 48 sliceAlign uint8 // the alignment of slices (and interfaces and strings) 49 } 50 51 // NewOffset returns a new Offset with offset 0 and alignment 1. 52 func NewOffset(ptrSize uint8, twoWordAlignSlices bool) Offset { 53 if twoWordAlignSlices { 54 return Offset{off: 0, align: 1, ptrSize: ptrSize, sliceAlign: 2 * ptrSize} 55 } 56 return Offset{off: 0, align: 1, ptrSize: ptrSize, sliceAlign: ptrSize} 57 } 58 59 func assertIsAPowerOfTwo(x uint8) { 60 if x == 0 { 61 panic("Zero is not a power of two") 62 } 63 if x&-x == x { 64 return 65 } 66 panic("Not a power of two") 67 } 68 69 // InitializedOffset returns a new Offset with specified offset, alignment, pointer size, and slice alignment. 70 func InitializedOffset(off int, align uint8, ptrSize uint8, twoWordAlignSlices bool) Offset { 71 assertIsAPowerOfTwo(align) 72 o0 := NewOffset(ptrSize, twoWordAlignSlices) 73 o0.off = uint64(off) 74 o0.align = align 75 return o0 76 } 77 78 func (o Offset) align_(a uint8) Offset { 79 o.off = (o.off + uint64(a) - 1) & ^(uint64(a) - 1) 80 if o.align < a { 81 o.align = a 82 } 83 return o 84 } 85 86 // Align returns the offset obtained by aligning offset to a multiple of a. 87 // a must be a power of two. 88 func (o Offset) Align(a uint8) Offset { 89 assertIsAPowerOfTwo(a) 90 return o.align_(a) 91 } 92 93 // plus returns the offset obtained by appending a power-of-2-sized-and-aligned object to o. 94 func (o Offset) plus(x uint64) Offset { 95 o = o.align_(uint8(x)) 96 o.off += x 97 return o 98 } 99 100 // D8 returns the offset obtained by appending an 8-bit field to o. 101 func (o Offset) D8() Offset { 102 return o.plus(1) 103 } 104 105 // D16 returns the offset obtained by appending a 16-bit field to o. 106 func (o Offset) D16() Offset { 107 return o.plus(2) 108 } 109 110 // D32 returns the offset obtained by appending a 32-bit field to o. 111 func (o Offset) D32() Offset { 112 return o.plus(4) 113 } 114 115 // D64 returns the offset obtained by appending a 64-bit field to o. 116 func (o Offset) D64() Offset { 117 return o.plus(8) 118 } 119 120 // D64 returns the offset obtained by appending a pointer field to o. 121 func (o Offset) P() Offset { 122 if o.ptrSize == 0 { 123 panic("This offset has no defined pointer size") 124 } 125 return o.plus(uint64(o.ptrSize)) 126 } 127 128 // Slice returns the offset obtained by appending a slice field to o. 129 func (o Offset) Slice() Offset { 130 o = o.align_(o.sliceAlign) 131 o.off += 3 * uint64(o.ptrSize) 132 // There's been discussion of whether slices should be 2-word aligned to allow 133 // use of aligned 2-word load/store to prevent tearing, this is future proofing. 134 // In general, for purposes of struct layout (and very likely default C layout 135 // compatibility) the "size" of a Go type is rounded up to its alignment. 136 return o.Align(o.sliceAlign) 137 } 138 139 // String returns the offset obtained by appending a string field to o. 140 func (o Offset) String() Offset { 141 o = o.align_(o.sliceAlign) 142 o.off += 2 * uint64(o.ptrSize) 143 return o // We "know" it needs no further alignment 144 } 145 146 // Interface returns the offset obtained by appending an interface field to o. 147 func (o Offset) Interface() Offset { 148 o = o.align_(o.sliceAlign) 149 o.off += 2 * uint64(o.ptrSize) 150 return o // We "know" it needs no further alignment 151 } 152 153 // Offset returns the struct-aligned offset (size) of o. 154 // This is at least as large as the current internal offset; it may be larger. 155 func (o Offset) Offset() uint64 { 156 return o.Align(o.align).off 157 } 158 159 func (o Offset) PlusUncommon() Offset { 160 o.off += UncommonSize() 161 return o 162 } 163 164 // CommonOffset returns the Offset to the data after the common portion of type data structures. 165 func CommonOffset(ptrSize int, twoWordAlignSlices bool) Offset { 166 return InitializedOffset(CommonSize(ptrSize), uint8(ptrSize), uint8(ptrSize), twoWordAlignSlices) 167 }