diff options
| author | Michael Anthony Knyszek <mknyszek@google.com> | 2020-10-22 16:55:55 +0000 |
|---|---|---|
| committer | Michael Knyszek <mknyszek@google.com> | 2021-03-11 17:26:22 +0000 |
| commit | f009b5b2268a7fcdfe046057cbf2a75306dbfc5e (patch) | |
| tree | 0c5da8482cab010c564e36528dab31c7364e095a /src/runtime/mfinal.go | |
| parent | 415ca3f1f0fa05a98561752e0787f59b77f19645 (diff) | |
| download | go-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.go | 46 |
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(®s.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), ®s) fingRunning = false |
