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  }