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