mirror of
https://github.com/golang/go
synced 2024-11-26 04:58:00 -07:00
[dev.typeparams] reflect: support big endian architectures in callMethod
Currently, callMethod has some ABI translation code that is not agnostic of endianness. This change rectifies that by adding a method to internal/abi.RegArgs for safely returning an offset into a register slot that's endianness-dependent. No tests for this because it's just best-effort. There's no actual way to test this because we don't support a register ABI on any big endian architectures yet. Change-Id: Ic68d9ee1bfdea0fc2992d467d749e2b083e92de3 Reviewed-on: https://go-review.googlesource.com/c/go/+/328348 Trust: Michael Knyszek <mknyszek@google.com> Run-TryBot: Michael Knyszek <mknyszek@google.com> TryBot-Result: Go Bot <gobot@golang.org> Reviewed-by: Cherry Mui <cherryyz@google.com>
This commit is contained in:
parent
9f50d9a0b4
commit
fb84d213a8
@ -77,8 +77,8 @@ var depsRules = `
|
||||
unicode/utf8, unicode/utf16, unicode,
|
||||
unsafe;
|
||||
|
||||
# These packages depend only on unsafe.
|
||||
unsafe
|
||||
# These packages depend only on internal/goarch and unsafe.
|
||||
internal/goarch, unsafe
|
||||
< internal/abi;
|
||||
|
||||
# RUNTIME is the core runtime group of packages, all of them very light-weight.
|
||||
|
@ -4,7 +4,10 @@
|
||||
|
||||
package abi
|
||||
|
||||
import "unsafe"
|
||||
import (
|
||||
"internal/goarch"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
// RegArgs is a struct that has space for each argument
|
||||
// and return value register on the current architecture.
|
||||
@ -33,6 +36,46 @@ type RegArgs struct {
|
||||
ReturnIsPtr IntArgRegBitmap
|
||||
}
|
||||
|
||||
// IntRegArgAddr returns a pointer inside of r.Ints[reg] that is appropriately
|
||||
// offset for an argument of size argSize.
|
||||
//
|
||||
// argSize must be non-zero, fit in a register, and a power-of-two.
|
||||
//
|
||||
// This method is a helper for dealing with the endianness of different CPU
|
||||
// architectures, since sub-word-sized arguments in big endian architectures
|
||||
// need to be "aligned" to the upper edge of the register to be interpreted
|
||||
// by the CPU correctly.
|
||||
func (r *RegArgs) IntRegArgAddr(reg int, argSize uintptr) unsafe.Pointer {
|
||||
if argSize > goarch.PtrSize || argSize == 0 || argSize&(argSize-1) != 0 {
|
||||
panic("invalid argSize")
|
||||
}
|
||||
offset := uintptr(0)
|
||||
if goarch.BigEndian {
|
||||
offset = goarch.PtrSize - argSize
|
||||
}
|
||||
return unsafe.Pointer(uintptr(unsafe.Pointer(&r.Ints[reg])) + offset)
|
||||
}
|
||||
|
||||
// FloatRegArgAddr returns a pointer inside of r.Floats[reg] that is appropriately
|
||||
// offset for an argument of size argSize.
|
||||
//
|
||||
// argSize must be non-zero, fit in a register, and a power-of-two.
|
||||
//
|
||||
// This method is a helper for dealing with the endianness of different CPU
|
||||
// architectures, since sub-word-sized arguments in big endian architectures
|
||||
// need to be "aligned" to the upper edge of the register to be interpreted
|
||||
// by the CPU correctly.
|
||||
func (r *RegArgs) FloatRegArgAddr(reg int, argSize uintptr) unsafe.Pointer {
|
||||
if argSize > EffectiveFloatRegSize || argSize == 0 || argSize&(argSize-1) != 0 {
|
||||
panic("invalid argSize")
|
||||
}
|
||||
offset := uintptr(0)
|
||||
if goarch.BigEndian {
|
||||
offset = EffectiveFloatRegSize - argSize
|
||||
}
|
||||
return unsafe.Pointer(uintptr(unsafe.Pointer(&r.Floats[reg])) + offset)
|
||||
}
|
||||
|
||||
// IntArgRegBitmap is a bitmap large enough to hold one bit per
|
||||
// integer argument/return register.
|
||||
type IntArgRegBitmap [(IntArgRegs + 7) / 8]uint8
|
||||
|
@ -957,9 +957,6 @@ func callMethod(ctxt *methodValue, frame unsafe.Pointer, retValid *bool, regs *a
|
||||
// 2. Stack -> registers translation.
|
||||
// 3. Registers -> stack translation.
|
||||
// 4. Registers -> registers translation.
|
||||
// TODO(mknyszek): Cases 2 and 3 below only work on little endian
|
||||
// architectures. This is OK for now, but this needs to be fixed
|
||||
// before supporting the register ABI on big endian architectures.
|
||||
|
||||
// If the value ABI passes the value on the stack,
|
||||
// then the method ABI does too, because it has strictly
|
||||
@ -985,9 +982,9 @@ func callMethod(ctxt *methodValue, frame unsafe.Pointer, retValid *bool, regs *a
|
||||
methodRegs.Ptrs[mStep.ireg] = *(*unsafe.Pointer)(from)
|
||||
fallthrough // We need to make sure this ends up in Ints, too.
|
||||
case abiStepIntReg:
|
||||
memmove(unsafe.Pointer(&methodRegs.Ints[mStep.ireg]), from, mStep.size)
|
||||
memmove(methodRegs.IntRegArgAddr(mStep.ireg, mStep.size), from, mStep.size)
|
||||
case abiStepFloatReg:
|
||||
memmove(unsafe.Pointer(&methodRegs.Floats[mStep.freg]), from, mStep.size)
|
||||
memmove(methodRegs.FloatRegArgAddr(mStep.freg, mStep.size), from, mStep.size)
|
||||
default:
|
||||
panic("unexpected method step")
|
||||
}
|
||||
@ -1003,9 +1000,9 @@ func callMethod(ctxt *methodValue, frame unsafe.Pointer, retValid *bool, regs *a
|
||||
// Do the pointer copy directly so we get a write barrier.
|
||||
*(*unsafe.Pointer)(to) = valueRegs.Ptrs[vStep.ireg]
|
||||
case abiStepIntReg:
|
||||
memmove(to, unsafe.Pointer(&valueRegs.Ints[vStep.ireg]), vStep.size)
|
||||
memmove(to, valueRegs.IntRegArgAddr(vStep.ireg, vStep.size), vStep.size)
|
||||
case abiStepFloatReg:
|
||||
memmove(to, unsafe.Pointer(&valueRegs.Floats[vStep.freg]), vStep.size)
|
||||
memmove(to, valueRegs.FloatRegArgAddr(vStep.freg, vStep.size), vStep.size)
|
||||
default:
|
||||
panic("unexpected value step")
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user