diff --git a/src/runtime/syscall_windows.go b/src/runtime/syscall_windows.go index 6b9195bcd5..4763a440e7 100644 --- a/src/runtime/syscall_windows.go +++ b/src/runtime/syscall_windows.go @@ -64,6 +64,7 @@ type abiDesc struct { srcStackSize uintptr // stdcall/fastcall stack space tracking dstStackSize uintptr // Go stack space used + dstSpill uintptr // Extra stack space for argument spill slots dstRegisters int // Go ABI int argument registers used // retOffset is the offset of the uintptr-sized result in the Go @@ -110,7 +111,14 @@ func (p *abiDesc) assignArg(t *_type) { // arguments. The same is true on arm. oldParts := p.parts - if !p.tryRegAssignArg(t, 0) { + if p.tryRegAssignArg(t, 0) { + // Account for spill space. + // + // TODO(mknyszek): Remove this when we no longer have + // caller reserved spill space. + p.dstSpill = alignUp(p.dstSpill, uintptr(t.align)) + p.dstSpill += t.size + } else { // Register assignment failed. // Undo the work and stack assign. p.parts = oldParts @@ -277,7 +285,11 @@ func compileCallback(fn eface, cdecl bool) (code uintptr) { abiMap.dstStackSize += sys.PtrSize } - if abiMap.dstStackSize > callbackMaxFrame { + // TODO(mknyszek): Remove dstSpill from this calculation when we no longer have + // caller reserved spill space. + frameSize := alignUp(abiMap.dstStackSize, sys.PtrSize) + frameSize += abiMap.dstSpill + if frameSize > callbackMaxFrame { panic("compileCallback: function argument frame too large") } @@ -356,9 +368,14 @@ func callbackWrap(a *callbackArgs) { } } + // TODO(mknyszek): Remove this when we no longer have + // caller reserved spill space. + frameSize := alignUp(c.abiMap.dstStackSize, sys.PtrSize) + frameSize += c.abiMap.dstSpill + // Even though this is copying back results, we can pass a nil // type because those results must not require write barriers. - reflectcall(nil, unsafe.Pointer(c.fn), noescape(goArgs), uint32(c.abiMap.dstStackSize), uint32(c.abiMap.retOffset), uint32(c.abiMap.dstStackSize), ®s) + reflectcall(nil, unsafe.Pointer(c.fn), noescape(goArgs), uint32(c.abiMap.dstStackSize), uint32(c.abiMap.retOffset), uint32(frameSize), ®s) // Extract the result. // diff --git a/src/runtime/syscall_windows_test.go b/src/runtime/syscall_windows_test.go index 5e9694d444..e3f772ac4b 100644 --- a/src/runtime/syscall_windows_test.go +++ b/src/runtime/syscall_windows_test.go @@ -389,6 +389,10 @@ var cbFuncs = []cbFunc{ {func(i1, i2, i3, i4, i5 uint8Pair) uintptr { return uintptr(i1.x + i1.y + i2.x + i2.y + i3.x + i3.y + i4.x + i4.y + i5.x + i5.y) }}, + {func(i1, i2, i3, i4, i5, i6, i7, i8, i9 uint32) uintptr { + runtime.GC() + return uintptr(i1 + i2 + i3 + i4 + i5 + i6 + i7 + i8 + i9) + }}, } //go:registerparams @@ -461,6 +465,16 @@ func sum5andPair(i1, i2, i3, i4, i5 uint8Pair) uintptr { return uintptr(i1.x + i1.y + i2.x + i2.y + i3.x + i3.y + i4.x + i4.y + i5.x + i5.y) } +// This test forces a GC. The idea is to have enough arguments +// that insufficient spill slots allocated (according to the ABI) +// may cause compiler-generated spills to clobber the return PC. +// Then, the GC stack scanning will catch that. +//go:registerparams +func sum9andGC(i1, i2, i3, i4, i5, i6, i7, i8, i9 uint32) uintptr { + runtime.GC() + return uintptr(i1 + i2 + i3 + i4 + i5 + i6 + i7 + i8 + i9) +} + // TODO(register args): Remove this once we switch to using the register // calling convention by default, since this is redundant with the existing // tests. @@ -479,6 +493,7 @@ var cbFuncsRegABI = []cbFunc{ {sum9int8}, {sum5mix}, {sum5andPair}, + {sum9andGC}, } func getCallbackTestFuncs() []cbFunc {