mirror of
https://github.com/golang/go
synced 2024-09-15 22:20:06 +00:00
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
This commit is contained in:
parent
ceb346685d
commit
ea7d801130
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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.
|
||||
|
|
Loading…
Reference in a new issue