aboutsummaryrefslogtreecommitdiff
path: root/src/runtime/mfinal.go
diff options
context:
space:
mode:
authorMichael Anthony Knyszek <mknyszek@google.com>2020-10-22 16:55:55 +0000
committerMichael Knyszek <mknyszek@google.com>2021-03-11 17:26:22 +0000
commitf009b5b2268a7fcdfe046057cbf2a75306dbfc5e (patch)
tree0c5da8482cab010c564e36528dab31c7364e095a /src/runtime/mfinal.go
parent415ca3f1f0fa05a98561752e0787f59b77f19645 (diff)
downloadgo-f009b5b2268a7fcdfe046057cbf2a75306dbfc5e.tar.xz
runtime: support register ABI for finalizers
This change modifies runfinq to properly pass arguments to finalizers in registers via reflectcall. For #40724. Change-Id: I414c0eff466ef315a0eb10507994e598dd29ccb2 Reviewed-on: https://go-review.googlesource.com/c/go/+/300112 Trust: Michael Knyszek <mknyszek@google.com> Run-TryBot: Michael Knyszek <mknyszek@google.com> TryBot-Result: Go Bot <gobot@golang.org> Reviewed-by: Cherry Zhang <cherryyz@google.com>
Diffstat (limited to 'src/runtime/mfinal.go')
-rw-r--r--src/runtime/mfinal.go46
1 files changed, 32 insertions, 14 deletions
diff --git a/src/runtime/mfinal.go b/src/runtime/mfinal.go
index e92ec80e3c..fd318d49a8 100644
--- a/src/runtime/mfinal.go
+++ b/src/runtime/mfinal.go
@@ -163,6 +163,7 @@ func runfinq() {
var (
frame unsafe.Pointer
framecap uintptr
+ argRegs int
)
for {
@@ -176,6 +177,7 @@ func runfinq() {
goparkunlock(&finlock, waitReasonFinalizerWait, traceEvGoBlock, 1)
continue
}
+ argRegs = intArgRegs
unlock(&finlock)
if raceenabled {
racefingo()
@@ -184,7 +186,22 @@ func runfinq() {
for i := fb.cnt; i > 0; i-- {
f := &fb.fin[i-1]
- framesz := unsafe.Sizeof((interface{})(nil)) + f.nret
+ var regs abi.RegArgs
+ var framesz uintptr
+ if argRegs > 0 {
+ // The args can always be passed in registers if they're
+ // available, because platforms we support always have no
+ // argument registers available, or more than 2.
+ //
+ // But unfortunately because we can have an arbitrary
+ // amount of returns and it would be complex to try and
+ // figure out how many of those can get passed in registers,
+ // just conservatively assume none of them do.
+ framesz = f.nret
+ } else {
+ // Need to pass arguments on the stack too.
+ framesz = unsafe.Sizeof((interface{})(nil)) + f.nret
+ }
if framecap < framesz {
// The frame does not contain pointers interesting for GC,
// all not yet finalized objects are stored in finq.
@@ -197,33 +214,34 @@ func runfinq() {
if f.fint == nil {
throw("missing type in runfinq")
}
- // frame is effectively uninitialized
- // memory. That means we have to clear
- // it before writing to it to avoid
- // confusing the write barrier.
- *(*[2]uintptr)(frame) = [2]uintptr{}
+ r := frame
+ if argRegs > 0 {
+ r = unsafe.Pointer(&regs.Ints)
+ } else {
+ // frame is effectively uninitialized
+ // memory. That means we have to clear
+ // it before writing to it to avoid
+ // confusing the write barrier.
+ *(*[2]uintptr)(frame) = [2]uintptr{}
+ }
switch f.fint.kind & kindMask {
case kindPtr:
// direct use of pointer
- *(*unsafe.Pointer)(frame) = f.arg
+ *(*unsafe.Pointer)(r) = f.arg
case kindInterface:
ityp := (*interfacetype)(unsafe.Pointer(f.fint))
// set up with empty interface
- (*eface)(frame)._type = &f.ot.typ
- (*eface)(frame).data = f.arg
+ (*eface)(r)._type = &f.ot.typ
+ (*eface)(r).data = f.arg
if len(ityp.mhdr) != 0 {
// convert to interface with methods
// this conversion is guaranteed to succeed - we checked in SetFinalizer
- (*iface)(frame).tab = assertE2I(ityp, (*eface)(frame)._type)
+ (*iface)(r).tab = assertE2I(ityp, (*eface)(r)._type)
}
default:
throw("bad kind in runfinq")
}
fingRunning = true
- // Pass a dummy RegArgs for now.
- //
- // TODO(mknyszek): Pass arguments in registers.
- var regs abi.RegArgs
reflectcall(nil, unsafe.Pointer(f.fn), frame, uint32(framesz), uint32(framesz), uint32(framesz), &regs)
fingRunning = false