]> Cypherpunks repositories - gostls13.git/commitdiff
[dev.typeparams] reflect: support big endian architectures in callMethod
authorMichael Anthony Knyszek <mknyszek@google.com>
Wed, 16 Jun 2021 19:08:52 +0000 (19:08 +0000)
committerMichael Knyszek <mknyszek@google.com>
Thu, 17 Jun 2021 21:30:24 +0000 (21:30 +0000)
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>
src/go/build/deps_test.go
src/internal/abi/abi.go
src/reflect/value.go

index b440f7d235180696ff20358fd60605bf1ece6fe2..80f8e1a00d70b66a1033bb242f230e8ce0b47d2f 100644 (file)
@@ -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.
index aaff9cece35720aef56455742b2f4556ba1f98d8..eadff248d99ff3a81f95b6b1643bcd8123625474 100644 (file)
@@ -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
index d8a0b5245edcc9b013ea9c5917250da4a8e2751e..4341fd3f90127a7f0ff8ce314c501a4182c5f4bc 100644 (file)
@@ -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")
                                }