Commit ea7d8011 authored by Rémy Oudompheng's avatar Rémy Oudompheng

reflect: correct alignment of call arguments on amd64p32.

Changes adapted from original CL 15680044.

LGTM=iant
R=rsc, iant, dave
CC=golang-codereviews
https://golang.org/cl/76150044
parent ceb34668
...@@ -1814,9 +1814,15 @@ type layoutKey struct { ...@@ -1814,9 +1814,15 @@ type layoutKey struct {
rcvr *rtype // receiver type, or nil if none rcvr *rtype // receiver type, or nil if none
} }
type layoutType struct {
t *rtype
argSize uintptr // size of arguments
retOffset uintptr // offset of return values.
}
var layoutCache struct { var layoutCache struct {
sync.RWMutex sync.RWMutex
m map[layoutKey]*rtype m map[layoutKey]layoutType
} }
// funcLayout computes a struct type representing the layout of the // funcLayout computes a struct type representing the layout of the
...@@ -1825,21 +1831,21 @@ var layoutCache struct { ...@@ -1825,21 +1831,21 @@ var layoutCache struct {
// The returned type exists only for GC, so we only fill out GC relevant info. // The returned type exists only for GC, so we only fill out GC relevant info.
// Currently, that's just size and the GC program. We also fill in // Currently, that's just size and the GC program. We also fill in
// the name for possible debugging use. // the name for possible debugging use.
func funcLayout(t *rtype, rcvr *rtype) *rtype { func funcLayout(t *rtype, rcvr *rtype) (frametype *rtype, argSize, retOffset uintptr) {
if t.Kind() != Func { if t.Kind() != Func {
panic("reflect: funcSignature of non-func type") panic("reflect: funcSignature of non-func type")
} }
k := layoutKey{t, rcvr} k := layoutKey{t, rcvr}
layoutCache.RLock() layoutCache.RLock()
if x := layoutCache.m[k]; x != nil { if x := layoutCache.m[k]; x.t != nil {
layoutCache.RUnlock() layoutCache.RUnlock()
return x return x.t, x.argSize, x.retOffset
} }
layoutCache.RUnlock() layoutCache.RUnlock()
layoutCache.Lock() layoutCache.Lock()
if x := layoutCache.m[k]; x != nil { if x := layoutCache.m[k]; x.t != nil {
layoutCache.Unlock() layoutCache.Unlock()
return x return x.t, x.argSize, x.retOffset
} }
tt := (*funcType)(unsafe.Pointer(t)) tt := (*funcType)(unsafe.Pointer(t))
...@@ -1868,7 +1874,12 @@ func funcLayout(t *rtype, rcvr *rtype) *rtype { ...@@ -1868,7 +1874,12 @@ func funcLayout(t *rtype, rcvr *rtype) *rtype {
} }
offset += arg.size offset += arg.size
} }
argSize = offset
if runtime.GOARCH == "amd64p32" {
offset = align(offset, 8)
}
offset = align(offset, ptrSize) offset = align(offset, ptrSize)
retOffset = offset
for _, res := range tt.out { for _, res := range tt.out {
offset = align(offset, uintptr(res.align)) offset = align(offset, uintptr(res.align))
if res.pointers() { if res.pointers() {
...@@ -1893,9 +1904,13 @@ func funcLayout(t *rtype, rcvr *rtype) *rtype { ...@@ -1893,9 +1904,13 @@ func funcLayout(t *rtype, rcvr *rtype) *rtype {
// cache result for future callers // cache result for future callers
if layoutCache.m == nil { if layoutCache.m == nil {
layoutCache.m = make(map[layoutKey]*rtype) layoutCache.m = make(map[layoutKey]layoutType)
}
layoutCache.m[k] = layoutType{
t: x,
argSize: argSize,
retOffset: retOffset,
} }
layoutCache.m[k] = x
layoutCache.Unlock() layoutCache.Unlock()
return x return x, argSize, retOffset
} }
...@@ -532,7 +532,7 @@ func (v Value) call(op string, in []Value) []Value { ...@@ -532,7 +532,7 @@ func (v Value) call(op string, in []Value) []Value {
} }
// Compute frame type, allocate a chunk of memory for frame // Compute frame type, allocate a chunk of memory for frame
frametype := funcLayout(t, rcvrtype) frametype, _, retOffset := funcLayout(t, rcvrtype)
args := unsafe_New(frametype) args := unsafe_New(frametype)
off := uintptr(0) off := uintptr(0)
...@@ -558,13 +558,13 @@ func (v Value) call(op string, in []Value) []Value { ...@@ -558,13 +558,13 @@ func (v Value) call(op string, in []Value) []Value {
} }
off += n off += n
} }
off = (off + ptrSize - 1) &^ (ptrSize - 1)
// Call. // Call.
call(fn, args, uint32(frametype.size)) call(fn, args, uint32(frametype.size))
// Copy return values out of args. // Copy return values out of args.
ret := make([]Value, nout) ret := make([]Value, nout)
off = retOffset
for i := 0; i < nout; i++ { for i := 0; i < nout; i++ {
tv := t.Out(i) tv := t.Out(i)
a := uintptr(tv.Align()) a := uintptr(tv.Align())
...@@ -628,6 +628,9 @@ func callReflect(ctxt *makeFuncImpl, frame unsafe.Pointer) { ...@@ -628,6 +628,9 @@ func callReflect(ctxt *makeFuncImpl, frame unsafe.Pointer) {
// Copy results back into argument frame. // Copy results back into argument frame.
if len(ftyp.out) > 0 { if len(ftyp.out) > 0 {
off += -off & (ptrSize - 1) off += -off & (ptrSize - 1)
if runtime.GOARCH == "amd64p32" {
off = align(off, 8)
}
for i, arg := range ftyp.out { for i, arg := range ftyp.out {
typ := arg typ := arg
v := out[i] v := out[i]
...@@ -738,20 +741,29 @@ func callMethod(ctxt *methodValue, frame unsafe.Pointer) { ...@@ -738,20 +741,29 @@ func callMethod(ctxt *methodValue, frame unsafe.Pointer) {
rcvr := ctxt.rcvr rcvr := ctxt.rcvr
rcvrtype := rcvr.typ rcvrtype := rcvr.typ
t, fn := methodReceiver("call", rcvr, ctxt.method) t, fn := methodReceiver("call", rcvr, ctxt.method)
frametype := funcLayout(t, rcvrtype) frametype, argSize, retOffset := funcLayout(t, rcvrtype)
// Make a new frame that is one word bigger so we can store the receiver. // Make a new frame that is one word bigger so we can store the receiver.
args := unsafe_New(frametype) args := unsafe_New(frametype)
// Copy in receiver and rest of args. // Copy in receiver and rest of args.
storeRcvr(rcvr, args) storeRcvr(rcvr, args)
memmove(unsafe.Pointer(uintptr(args)+ptrSize), frame, frametype.size-ptrSize) memmove(unsafe.Pointer(uintptr(args)+ptrSize), frame, argSize-ptrSize)
// Call. // Call.
call(fn, args, uint32(frametype.size)) call(fn, args, uint32(frametype.size))
// Copy return values. // Copy return values. On amd64p32, the beginning of return values
memmove(frame, unsafe.Pointer(uintptr(args)+ptrSize), frametype.size-ptrSize) // is 64-bit aligned, so the caller's frame layout (which doesn't have
// a receiver) is different from the layout of the fn call, which has
// a receiver.
// Ignore any changes to args and just copy return values.
callerRetOffset := retOffset - ptrSize
if runtime.GOARCH == "amd64p32" {
callerRetOffset = align(argSize-ptrSize, 8)
}
memmove(unsafe.Pointer(uintptr(frame)+callerRetOffset),
unsafe.Pointer(uintptr(args)+retOffset), frametype.size-retOffset)
} }
// funcName returns the name of f, for use in error messages. // funcName returns the name of f, for use in error messages.
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment