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
5package abi
6
7import (
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.
21type 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
47func (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.
74func (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.
87type IntArgRegBitmap [(IntArgRegs + 7) / 8]uint8
88
89// Set sets the i'th bit of the bitmap to 1.
90func (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
100func (b *IntArgRegBitmap) Get(i int) bool {
101	return b[i/8]&(uint8(1)<<(i%8)) != 0
102}
103