From ea7d801130636601bf0fb0d9c15e1f19dff8805d Mon Sep 17 00:00:00 2001 From: =?utf8?q?R=C3=A9my=20Oudompheng?= Date: Thu, 20 Mar 2014 22:22:07 +0100 Subject: [PATCH] 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 --- src/pkg/reflect/type.go | 33 ++++++++++++++++++++++++--------- src/pkg/reflect/value.go | 24 ++++++++++++++++++------ 2 files changed, 42 insertions(+), 15 deletions(-) diff --git a/src/pkg/reflect/type.go b/src/pkg/reflect/type.go index 3b4fe2190e..47bd103fb0 100644 --- a/src/pkg/reflect/type.go +++ b/src/pkg/reflect/type.go @@ -1814,9 +1814,15 @@ type layoutKey struct { 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 { sync.RWMutex - m map[layoutKey]*rtype + m map[layoutKey]layoutType } // funcLayout computes a struct type representing the layout of the @@ -1825,21 +1831,21 @@ var layoutCache struct { // 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 // 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 { panic("reflect: funcSignature of non-func type") } k := layoutKey{t, rcvr} layoutCache.RLock() - if x := layoutCache.m[k]; x != nil { + if x := layoutCache.m[k]; x.t != nil { layoutCache.RUnlock() - return x + return x.t, x.argSize, x.retOffset } layoutCache.RUnlock() layoutCache.Lock() - if x := layoutCache.m[k]; x != nil { + if x := layoutCache.m[k]; x.t != nil { layoutCache.Unlock() - return x + return x.t, x.argSize, x.retOffset } tt := (*funcType)(unsafe.Pointer(t)) @@ -1868,7 +1874,12 @@ func funcLayout(t *rtype, rcvr *rtype) *rtype { } offset += arg.size } + argSize = offset + if runtime.GOARCH == "amd64p32" { + offset = align(offset, 8) + } offset = align(offset, ptrSize) + retOffset = offset for _, res := range tt.out { offset = align(offset, uintptr(res.align)) if res.pointers() { @@ -1893,9 +1904,13 @@ func funcLayout(t *rtype, rcvr *rtype) *rtype { // cache result for future callers 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() - return x + return x, argSize, retOffset } diff --git a/src/pkg/reflect/value.go b/src/pkg/reflect/value.go index fba0e1ef68..8b3f55e03c 100644 --- a/src/pkg/reflect/value.go +++ b/src/pkg/reflect/value.go @@ -532,7 +532,7 @@ func (v Value) call(op string, in []Value) []Value { } // Compute frame type, allocate a chunk of memory for frame - frametype := funcLayout(t, rcvrtype) + frametype, _, retOffset := funcLayout(t, rcvrtype) args := unsafe_New(frametype) off := uintptr(0) @@ -558,13 +558,13 @@ func (v Value) call(op string, in []Value) []Value { } off += n } - off = (off + ptrSize - 1) &^ (ptrSize - 1) // Call. call(fn, args, uint32(frametype.size)) // Copy return values out of args. ret := make([]Value, nout) + off = retOffset for i := 0; i < nout; i++ { tv := t.Out(i) a := uintptr(tv.Align()) @@ -628,6 +628,9 @@ func callReflect(ctxt *makeFuncImpl, frame unsafe.Pointer) { // Copy results back into argument frame. if len(ftyp.out) > 0 { off += -off & (ptrSize - 1) + if runtime.GOARCH == "amd64p32" { + off = align(off, 8) + } for i, arg := range ftyp.out { typ := arg v := out[i] @@ -738,20 +741,29 @@ func callMethod(ctxt *methodValue, frame unsafe.Pointer) { rcvr := ctxt.rcvr rcvrtype := rcvr.typ 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. args := unsafe_New(frametype) // Copy in receiver and rest of 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(fn, args, uint32(frametype.size)) - // Copy return values. - memmove(frame, unsafe.Pointer(uintptr(args)+ptrSize), frametype.size-ptrSize) + // Copy return values. On amd64p32, the beginning of return values + // 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. -- 2.50.0