github.com/go-asm/go@v1.21.1-0.20240213172139-40c5ead50c48/abi/abi.go (about) 1 // Copyright 2020 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 import ( 8 "unsafe" 9 10 "github.com/go-asm/go/goarch" 11 ) 12 13 // RegArgs is a struct that has space for each argument 14 // and return value register on the current architecture. 15 // 16 // Assembly code knows the layout of the first two fields 17 // of RegArgs. 18 // 19 // RegArgs also contains additional space to hold pointers 20 // when it may not be safe to keep them only in the integer 21 // register space otherwise. 22 type RegArgs struct { 23 // Values in these slots should be precisely the bit-by-bit 24 // representation of how they would appear in a register. 25 // 26 // This means that on big endian arches, integer values should 27 // be in the top bits of the slot. Floats are usually just 28 // directly represented, but some architectures treat narrow 29 // width floating point values specially (e.g. they're promoted 30 // first, or they need to be NaN-boxed). 31 Ints [IntArgRegs]uintptr // untyped integer registers 32 Floats [FloatArgRegs]uint64 // untyped float registers 33 34 // Fields above this point are known to assembly. 35 36 // Ptrs is a space that duplicates Ints but with pointer type, 37 // used to make pointers passed or returned in registers 38 // visible to the GC by making the type unsafe.Pointer. 39 Ptrs [IntArgRegs]unsafe.Pointer 40 41 // ReturnIsPtr is a bitmap that indicates which registers 42 // contain or will contain pointers on the return path from 43 // a reflectcall. The i'th bit indicates whether the i'th 44 // register contains or will contain a valid Go pointer. 45 ReturnIsPtr IntArgRegBitmap 46 } 47 48 func (r *RegArgs) Dump() { 49 print("Ints:") 50 for _, x := range r.Ints { 51 print(" ", x) 52 } 53 println() 54 print("Floats:") 55 for _, x := range r.Floats { 56 print(" ", x) 57 } 58 println() 59 print("Ptrs:") 60 for _, x := range r.Ptrs { 61 print(" ", x) 62 } 63 println() 64 } 65 66 // IntRegArgAddr returns a pointer inside of r.Ints[reg] that is appropriately 67 // offset for an argument of size argSize. 68 // 69 // argSize must be non-zero, fit in a register, and a power-of-two. 70 // 71 // This method is a helper for dealing with the endianness of different CPU 72 // architectures, since sub-word-sized arguments in big endian architectures 73 // need to be "aligned" to the upper edge of the register to be interpreted 74 // by the CPU correctly. 75 func (r *RegArgs) IntRegArgAddr(reg int, argSize uintptr) unsafe.Pointer { 76 if argSize > goarch.PtrSize || argSize == 0 || argSize&(argSize-1) != 0 { 77 panic("invalid argSize") 78 } 79 offset := uintptr(0) 80 if goarch.BigEndian { 81 offset = goarch.PtrSize - argSize 82 } 83 return unsafe.Pointer(uintptr(unsafe.Pointer(&r.Ints[reg])) + offset) 84 } 85 86 // IntArgRegBitmap is a bitmap large enough to hold one bit per 87 // integer argument/return register. 88 type IntArgRegBitmap [(IntArgRegs + 7) / 8]uint8 89 90 // Set sets the i'th bit of the bitmap to 1. 91 func (b *IntArgRegBitmap) Set(i int) { 92 b[i/8] |= uint8(1) << (i % 8) 93 } 94 95 // Get returns whether the i'th bit of the bitmap is set. 96 // 97 // nosplit because it's called in extremely sensitive contexts, like 98 // on the reflectcall return path. 99 // 100 //go:nosplit 101 func (b *IntArgRegBitmap) Get(i int) bool { 102 return b[i/8]&(uint8(1)<<(i%8)) != 0 103 }