]> Cypherpunks.ru repositories - gostls13.git/commitdiff
[dev.typeparams] runtime,cmd/compile,cmd/link: replace jmpdefer with a loop
authorAustin Clements <austin@google.com>
Mon, 26 Jul 2021 19:44:22 +0000 (15:44 -0400)
committerAustin Clements <austin@google.com>
Fri, 30 Jul 2021 18:49:44 +0000 (18:49 +0000)
Currently, deferreturn runs deferred functions by backing up its
return PC to the deferreturn call, and then effectively tail-calling
the deferred function (via jmpdefer). The effect of this is that the
deferred function appears to be called directly from the deferee, and
when it returns, the deferee calls deferreturn again so it can run the
next deferred function if necessary.

This unusual flow control leads to a large number of special cases and
complications all over the tool chain.

This used to be necessary because deferreturn copied the deferred
function's argument frame directly into its caller's frame and then
had to invoke that call as if it had been called from its caller's
frame so it could access it arguments. But now that we've simplified
defer processing so the runtime only deals with argument-less
closures, this approach is no longer necessary.

This CL simplifies all of this by making deferreturn simply call
deferred functions in a loop.

This eliminates the need for jmpdefer, so we can delete a bunch of
per-architecture assembly code.

This eliminates several special cases on Wasm, since it couldn't
support these calling shenanigans directly and thus had to simulate
the loop a different way. Now Wasm can largely work the way the other
platforms do.

This eliminates the per-architecture Ginsnopdefer operation. On PPC64,
this was necessary to reload the TOC pointer after the tail call
(since TOC pointers in general make tail calls impossible). The tail
call is gone, and in the case where we do force a jump to the
deferreturn call when recovering from an open-coded defer, we go
through gogo (via runtime.recovery), which handles the TOC. On other
platforms, we needed a NOP so traceback didn't get confused by seeing
the return to the CALL instruction, rather than the usual return to
the instruction following the CALL instruction. Now we don't inject a
return to the CALL instruction at all, so this NOP is also
unnecessary.

The one potential effect of this is that deferreturn could now appear
in stack traces from deferred functions. However, this could already
happen from open-coded defers, so we've long since marked deferreturn
as a "wrapper" so it gets elided not only from printed stack traces,
but from runtime.Callers*.

Change-Id: Ie9f700cd3fb774f498c9edce363772a868407bf7
Reviewed-on: https://go-review.googlesource.com/c/go/+/337652
Trust: Austin Clements <austin@google.com>
Run-TryBot: Austin Clements <austin@google.com>
TryBot-Result: Go Bot <gobot@golang.org>
Reviewed-by: Cherry Mui <cherryyz@google.com>
31 files changed:
src/cmd/compile/internal/amd64/galign.go
src/cmd/compile/internal/arm/galign.go
src/cmd/compile/internal/arm64/galign.go
src/cmd/compile/internal/mips/galign.go
src/cmd/compile/internal/mips64/galign.go
src/cmd/compile/internal/ppc64/galign.go
src/cmd/compile/internal/ppc64/ggen.go
src/cmd/compile/internal/riscv64/galign.go
src/cmd/compile/internal/s390x/galign.go
src/cmd/compile/internal/ssagen/arch.go
src/cmd/compile/internal/ssagen/ssa.go
src/cmd/compile/internal/wasm/ssa.go
src/cmd/compile/internal/x86/galign.go
src/cmd/internal/obj/arm/asm5.go
src/cmd/internal/obj/wasm/wasmobj.go
src/cmd/internal/obj/x86/asm6.go
src/cmd/internal/objabi/funcid.go
src/cmd/link/internal/ld/pcln.go
src/runtime/asm_386.s
src/runtime/asm_amd64.s
src/runtime/asm_arm.s
src/runtime/asm_arm64.s
src/runtime/asm_mips64x.s
src/runtime/asm_mipsx.s
src/runtime/asm_ppc64x.s
src/runtime/asm_riscv64.s
src/runtime/asm_s390x.s
src/runtime/asm_wasm.s
src/runtime/panic.go
src/runtime/stubs.go
src/runtime/symtab.go

index 3b13e123a74feade86830808e11460a1bcc91425..ca44263afc476c4eef177df64562920b13e7afdc 100644 (file)
@@ -18,7 +18,6 @@ func Init(arch *ssagen.ArchInfo) {
 
        arch.ZeroRange = zerorange
        arch.Ginsnop = ginsnop
-       arch.Ginsnopdefer = ginsnop
 
        arch.SSAMarkMoves = ssaMarkMoves
        arch.SSAGenValue = ssaGenValue
index d68500280d00b79376d976a39fab34286faa65a8..23e52bacbf2a3d077d7fc267859c0167283707a2 100644 (file)
@@ -18,7 +18,6 @@ func Init(arch *ssagen.ArchInfo) {
        arch.SoftFloat = buildcfg.GOARM == 5
        arch.ZeroRange = zerorange
        arch.Ginsnop = ginsnop
-       arch.Ginsnopdefer = ginsnop
 
        arch.SSAMarkMoves = func(s *ssagen.State, b *ssa.Block) {}
        arch.SSAGenValue = ssaGenValue
index 2a61b9dd9973b5bda2ade4c9354f1920f2205884..3ebd860de8f887c4c0b4dbc3934b7ed297995398 100644 (file)
@@ -18,7 +18,6 @@ func Init(arch *ssagen.ArchInfo) {
        arch.PadFrame = padframe
        arch.ZeroRange = zerorange
        arch.Ginsnop = ginsnop
-       arch.Ginsnopdefer = ginsnop
 
        arch.SSAMarkMoves = func(s *ssagen.State, b *ssa.Block) {}
        arch.SSAGenValue = ssaGenValue
index f892923ba038f32a370873af79a9671e55e65a1b..4e6897042ec04ce2e81fa58960a26541fa5aaeb0 100644 (file)
@@ -21,7 +21,6 @@ func Init(arch *ssagen.ArchInfo) {
        arch.SoftFloat = (buildcfg.GOMIPS == "softfloat")
        arch.ZeroRange = zerorange
        arch.Ginsnop = ginsnop
-       arch.Ginsnopdefer = ginsnop
        arch.SSAMarkMoves = func(s *ssagen.State, b *ssa.Block) {}
        arch.SSAGenValue = ssaGenValue
        arch.SSAGenBlock = ssaGenBlock
index af81366e51bdf51c4cd88b55da03440da29773c6..412bc71aab270d97befa5dd3296ad381db180dcc 100644 (file)
@@ -21,7 +21,6 @@ func Init(arch *ssagen.ArchInfo) {
        arch.SoftFloat = buildcfg.GOMIPS64 == "softfloat"
        arch.ZeroRange = zerorange
        arch.Ginsnop = ginsnop
-       arch.Ginsnopdefer = ginsnop
 
        arch.SSAMarkMoves = func(s *ssagen.State, b *ssa.Block) {}
        arch.SSAGenValue = ssaGenValue
index 590290fa371008db507ade8df55c54b4bc160f69..bff3e38f42dfef97e9b7013ffa1f93cbbfb568f6 100644 (file)
@@ -20,7 +20,6 @@ func Init(arch *ssagen.ArchInfo) {
 
        arch.ZeroRange = zerorange
        arch.Ginsnop = ginsnop
-       arch.Ginsnopdefer = ginsnopdefer
 
        arch.SSAMarkMoves = ssaMarkMoves
        arch.SSAGenValue = ssaGenValue
index c76962cfb811334d577ffc49b427533f0a8517b8..3ae6422bf9e26b0a1fb08e1f94f3a17a8965d3f1 100644 (file)
@@ -53,30 +53,3 @@ func ginsnop(pp *objw.Progs) *obj.Prog {
        p.To.Reg = ppc64.REG_R0
        return p
 }
-
-func ginsnopdefer(pp *objw.Progs) *obj.Prog {
-       // On PPC64 two nops are required in the defer case.
-       //
-       // (see gc/cgen.go, gc/plive.go -- copy of comment below)
-       //
-       // On ppc64, when compiling Go into position
-       // independent code on ppc64le we insert an
-       // instruction to reload the TOC pointer from the
-       // stack as well. See the long comment near
-       // jmpdefer in runtime/asm_ppc64.s for why.
-       // If the MOVD is not needed, insert a hardware NOP
-       // so that the same number of instructions are used
-       // on ppc64 in both shared and non-shared modes.
-
-       ginsnop(pp)
-       if base.Ctxt.Flag_shared {
-               p := pp.Prog(ppc64.AMOVD)
-               p.From.Type = obj.TYPE_MEM
-               p.From.Offset = 24
-               p.From.Reg = ppc64.REGSP
-               p.To.Type = obj.TYPE_REG
-               p.To.Reg = ppc64.REG_R2
-               return p
-       }
-       return ginsnop(pp)
-}
index 338248a7cf27ab13b71ec4ed25f90a015fdc6511..846ed8fb3802e43d603abe6bb0de2617a177dca8 100644 (file)
@@ -16,7 +16,6 @@ func Init(arch *ssagen.ArchInfo) {
        arch.MAXWIDTH = 1 << 50
 
        arch.Ginsnop = ginsnop
-       arch.Ginsnopdefer = ginsnop
        arch.ZeroRange = zeroRange
 
        arch.SSAMarkMoves = ssaMarkMoves
index b004a2db0a39b3f61c9b8e1d93d648d3d44bcd0a..d880834c220d91c763667614a46b241fb23484bb 100644 (file)
@@ -16,7 +16,6 @@ func Init(arch *ssagen.ArchInfo) {
 
        arch.ZeroRange = zerorange
        arch.Ginsnop = ginsnop
-       arch.Ginsnopdefer = ginsnop
 
        arch.SSAMarkMoves = ssaMarkMoves
        arch.SSAGenValue = ssaGenValue
index 957fb3e84a92dc7a6f52852bd3624fcefd3df145..483e45cad43c7445c46032111434fffe16cd62a7 100644 (file)
@@ -29,8 +29,7 @@ type ArchInfo struct {
        // at function entry, and it is ok to clobber registers.
        ZeroRange func(*objw.Progs, *obj.Prog, int64, int64, *uint32) *obj.Prog
 
-       Ginsnop      func(*objw.Progs) *obj.Prog
-       Ginsnopdefer func(*objw.Progs) *obj.Prog // special ginsnop for deferreturn
+       Ginsnop func(*objw.Progs) *obj.Prog
 
        // SSAMarkMoves marks any MOVXconst ops that need to avoid clobbering flags.
        SSAMarkMoves func(*State, *ssa.Block)
index 7e2f6a7471c06fc2a6a8a12564ce662115a15778..161469ea67c7e6026a3ff99be0b5d8d248f8948f 100644 (file)
@@ -7335,18 +7335,6 @@ func (s *State) PrepareCall(v *ssa.Value) {
 
        call, ok := v.Aux.(*ssa.AuxCall)
 
-       if ok && call.Fn == ir.Syms.Deferreturn {
-               // Deferred calls will appear to be returning to
-               // the CALL deferreturn(SB) that we are about to emit.
-               // However, the stack trace code will show the line
-               // of the instruction byte before the return PC.
-               // To avoid that being an unrelated instruction,
-               // insert an actual hardware NOP that will have the right line number.
-               // This is different from obj.ANOP, which is a virtual no-op
-               // that doesn't make it into the instruction stream.
-               Arch.Ginsnopdefer(s.pp)
-       }
-
        if ok {
                // Record call graph information for nowritebarrierrec
                // analysis.
index 31b09016eb98296a3838bc39125dbb3f4f73a101..0b2ca3fdbb83af3573a2af995d795ffd7bd80718 100644 (file)
@@ -24,7 +24,6 @@ func Init(arch *ssagen.ArchInfo) {
 
        arch.ZeroRange = zeroRange
        arch.Ginsnop = ginsnop
-       arch.Ginsnopdefer = ginsnop
 
        arch.SSAMarkMoves = ssaMarkMoves
        arch.SSAGenValue = ssaGenValue
@@ -126,7 +125,11 @@ func ssaGenValue(s *ssagen.State, v *ssa.Value) {
        case ssa.OpWasmLoweredStaticCall, ssa.OpWasmLoweredClosureCall, ssa.OpWasmLoweredInterCall:
                s.PrepareCall(v)
                if call, ok := v.Aux.(*ssa.AuxCall); ok && call.Fn == ir.Syms.Deferreturn {
-                       // add a resume point before call to deferreturn so it can be called again via jmpdefer
+                       // The runtime needs to inject jumps to
+                       // deferreturn calls using the address in
+                       // _func.deferreturn. Hence, the call to
+                       // deferreturn must itself be a resumption
+                       // point so it gets a target PC.
                        s.Prog(wasm.ARESUMEPOINT)
                }
                if v.Op == ssa.OpWasmLoweredClosureCall {
index 00a20e429f1d6112cbf985e0b3c8706b187b0356..5565bd32c765b36debf7cde83eab4f3d2d8a71dd 100644 (file)
@@ -34,7 +34,6 @@ func Init(arch *ssagen.ArchInfo) {
 
        arch.ZeroRange = zerorange
        arch.Ginsnop = ginsnop
-       arch.Ginsnopdefer = ginsnop
 
        arch.SSAMarkMoves = ssaMarkMoves
 }
index ccf5f9e7f8d959da412e76835290e8f694b85599..7b1682776e5316ad657f49a361329300eab6098c 100644 (file)
@@ -355,11 +355,10 @@ var oprange [ALAST & obj.AMask][]Optab
 var xcmp [C_GOK + 1][C_GOK + 1]bool
 
 var (
-       deferreturn *obj.LSym
-       symdiv      *obj.LSym
-       symdivu     *obj.LSym
-       symmod      *obj.LSym
-       symmodu     *obj.LSym
+       symdiv  *obj.LSym
+       symdivu *obj.LSym
+       symmod  *obj.LSym
+       symmodu *obj.LSym
 )
 
 // Note about encoding: Prog.scond holds the condition encoding,
@@ -1219,8 +1218,6 @@ func buildop(ctxt *obj.Link) {
                return
        }
 
-       deferreturn = ctxt.LookupABI("runtime.deferreturn", obj.ABIInternal)
-
        symdiv = ctxt.Lookup("runtime._div")
        symdivu = ctxt.Lookup("runtime._divu")
        symmod = ctxt.Lookup("runtime._mod")
index ceeae7a257cdcc33313b85c31715fe53ead79a74..4d276db678041b0d4c9b80d75475c1e565a80d87 100644 (file)
@@ -129,8 +129,6 @@ var (
        morestackNoCtxt *obj.LSym
        gcWriteBarrier  *obj.LSym
        sigpanic        *obj.LSym
-       deferreturn     *obj.LSym
-       jmpdefer        *obj.LSym
 )
 
 const (
@@ -143,10 +141,6 @@ func instinit(ctxt *obj.Link) {
        morestackNoCtxt = ctxt.Lookup("runtime.morestack_noctxt")
        gcWriteBarrier = ctxt.LookupABI("runtime.gcWriteBarrier", obj.ABIInternal)
        sigpanic = ctxt.LookupABI("runtime.sigpanic", obj.ABIInternal)
-       deferreturn = ctxt.LookupABI("runtime.deferreturn", obj.ABIInternal)
-       // jmpdefer is defined in assembly as ABI0. The compiler will
-       // generate a direct ABI0 call from Go, so look for that.
-       jmpdefer = ctxt.LookupABI(`"".jmpdefer`, obj.ABI0)
 }
 
 func preprocess(ctxt *obj.Link, s *obj.LSym, newprog obj.ProgAlloc) {
@@ -423,12 +417,6 @@ func preprocess(ctxt *obj.Link, s *obj.LSym, newprog obj.ProgAlloc) {
                                pcAfterCall-- // sigpanic expects to be called without advancing the pc
                        }
 
-                       // jmpdefer manipulates the return address on the stack so deferreturn gets called repeatedly.
-                       // Model this in WebAssembly with a loop.
-                       if call.To.Sym == deferreturn {
-                               p = appendp(p, ALoop)
-                       }
-
                        // SP -= 8
                        p = appendp(p, AGet, regAddr(REG_SP))
                        p = appendp(p, AI32Const, constAddr(8))
@@ -479,15 +467,6 @@ func preprocess(ctxt *obj.Link, s *obj.LSym, newprog obj.ProgAlloc) {
                                break
                        }
 
-                       // jmpdefer removes the frame of deferreturn from the Go stack.
-                       // However, its WebAssembly function still returns normally,
-                       // so we need to return from deferreturn without removing its
-                       // stack frame (no RET), because the frame is already gone.
-                       if call.To.Sym == jmpdefer {
-                               p = appendp(p, AReturn)
-                               break
-                       }
-
                        // return value of call is on the top of the stack, indicating whether to unwind the WebAssembly stack
                        if call.As == ACALLNORESUME && call.To.Sym != sigpanic { // sigpanic unwinds the stack, but it never resumes
                                // trying to unwind WebAssembly stack but call has no resume point, terminate with error
@@ -500,21 +479,6 @@ func preprocess(ctxt *obj.Link, s *obj.LSym, newprog obj.ProgAlloc) {
                                unwindExitBranches = append(unwindExitBranches, p)
                        }
 
-                       // jump to before the call if jmpdefer has reset the return address to the call's PC
-                       if call.To.Sym == deferreturn {
-                               // get PC_B from -8(SP)
-                               p = appendp(p, AGet, regAddr(REG_SP))
-                               p = appendp(p, AI32Const, constAddr(8))
-                               p = appendp(p, AI32Sub)
-                               p = appendp(p, AI32Load16U, constAddr(0))
-                               p = appendp(p, ATee, regAddr(REG_PC_B))
-
-                               p = appendp(p, AI32Const, constAddr(call.Pc))
-                               p = appendp(p, AI32Eq)
-                               p = appendp(p, ABrIf, constAddr(0))
-                               p = appendp(p, AEnd) // end of Loop
-                       }
-
                case obj.ARET, ARETUNWIND:
                        ret := *p
                        p.As = obj.ANOP
index 17fa76727e6212061f46548664530c88570ff734..331a98dfef9a00df9399016f1c9daa2f07505aed 100644 (file)
@@ -43,7 +43,6 @@ import (
 
 var (
        plan9privates *obj.LSym
-       deferreturn   *obj.LSym
 )
 
 // Instruction layout.
index d881cdd0618a71621d1a58d363146c939f4947b4..68f6a26a76ca4c8deb8d5d4f61e671480c111c8d 100644 (file)
@@ -34,7 +34,6 @@ const (
        FuncID_gogo
        FuncID_gopanic
        FuncID_handleAsyncEvent
-       FuncID_jmpdefer
        FuncID_mcall
        FuncID_morestack
        FuncID_mstart
@@ -60,7 +59,6 @@ var funcIDs = map[string]FuncID{
        "gogo":             FuncID_gogo,
        "gopanic":          FuncID_gopanic,
        "handleAsyncEvent": FuncID_handleAsyncEvent,
-       "jmpdefer":         FuncID_jmpdefer,
        "main":             FuncID_runtime_main,
        "mcall":            FuncID_mcall,
        "morestack":        FuncID_morestack,
index 05fd30236949671419e6fd0e7efa13b7763b575c..70e3e1284b9a1ac621741d2c6f843511257fc126 100644 (file)
@@ -129,11 +129,10 @@ func computeDeferReturn(ctxt *Link, deferReturnSym, s loader.Sym) uint32 {
        for ri := 0; ri < relocs.Count(); ri++ {
                r := relocs.At(ri)
                if target.IsWasm() && r.Type() == objabi.R_ADDR {
-                       // Wasm does not have a live variable set at the deferreturn
-                       // call itself. Instead it has one identified by the
-                       // resumption point immediately preceding the deferreturn.
-                       // The wasm code has a R_ADDR relocation which is used to
-                       // set the resumption point to PC_B.
+                       // wasm/ssa.go generates an ARESUMEPOINT just
+                       // before the deferreturn call. The "PC" of
+                       // the deferreturn call is stored in the
+                       // R_ADDR relocation on the ARESUMEPOINT.
                        lastWasmAddr = uint32(r.Add())
                }
                if r.Type().IsDirectCall() && (r.Sym() == deferReturnSym || ldr.IsDeferReturnTramp(r.Sym())) {
index dd2ea458cc59ac18069512cb7c3c7b6af6c403dd..11c60309f4e07e55895bff83d97737fa8a1ba288 100644 (file)
@@ -582,26 +582,6 @@ TEXT ·publicationBarrier(SB),NOSPLIT,$0-0
        // compile barrier.
        RET
 
-// void jmpdefer(fn, sp);
-// called from deferreturn.
-// 1. pop the caller
-// 2. sub 5 bytes (the length of CALL & a 32 bit displacement) from the callers
-//    return (when building for shared libraries, subtract 16 bytes -- 5 bytes
-//    for CALL & displacement to call __x86.get_pc_thunk.cx, 6 bytes for the
-//    LEAL to load the offset into BX, and finally 5 for the call & displacement)
-// 3. jmp to the argument
-TEXT runtime·jmpdefer(SB), NOSPLIT, $0-8
-       MOVL    fv+0(FP), DX    // fn
-       MOVL    argp+4(FP), BX  // caller sp
-       LEAL    -4(BX), SP      // caller sp after CALL
-#ifdef GOBUILDMODE_shared
-       SUBL    $16, (SP)       // return to CALL again
-#else
-       SUBL    $5, (SP)        // return to CALL again
-#endif
-       MOVL    0(DX), BX
-       JMP     BX      // but first run the deferred function
-
 // Save state of caller into g->sched,
 // but using fake PC from systemstack_switch.
 // Must only be called from functions with no locals ($0)
index 0f719b2664aeebfa4e687df65157894ecae3ce61..2d8f4c241203c6acf6cf448e47a1f1044aedc508 100644 (file)
@@ -662,21 +662,6 @@ TEXT ·publicationBarrier(SB),NOSPLIT,$0-0
        // compile barrier.
        RET
 
-// func jmpdefer(fv func(), argp uintptr)
-// argp is a caller SP.
-// called from deferreturn.
-// 1. pop the caller
-// 2. sub 5 bytes from the callers return
-// 3. jmp to the argument
-TEXT runtime·jmpdefer(SB), NOSPLIT, $0-16
-       MOVQ    fv+0(FP), DX    // fn
-       MOVQ    argp+8(FP), BX  // caller sp
-       LEAQ    -8(BX), SP      // caller sp after CALL
-       MOVQ    -8(SP), BP      // restore BP as if deferreturn returned (harmless if framepointers not in use)
-       SUBQ    $5, (SP)        // return to CALL again
-       MOVQ    0(DX), BX
-       JMP     BX      // but first run the deferred function
-
 // Save state of caller into g->sched,
 // but using fake PC from systemstack_switch.
 // Must only be called from functions with no locals ($0)
index 5c2bc00fe811eb9105a1f5e91937e61c013a3550..a1164781d2eff652e8eafd1d523c44d329dd192e 100644 (file)
@@ -506,20 +506,6 @@ CALLFN(·call268435456, 268435456)
 CALLFN(·call536870912, 536870912)
 CALLFN(·call1073741824, 1073741824)
 
-// void jmpdefer(fn, sp);
-// called from deferreturn.
-// 1. grab stored LR for caller
-// 2. sub 4 bytes to get back to BL deferreturn
-// 3. B to fn
-TEXT runtime·jmpdefer(SB),NOSPLIT,$0-8
-       MOVW    0(R13), LR
-       MOVW    $-4(LR), LR     // BL deferreturn
-       MOVW    fv+0(FP), R7
-       MOVW    argp+4(FP), R13
-       MOVW    $-4(R13), R13   // SP is 4 below argp, due to saved LR
-       MOVW    0(R7), R1
-       B       (R1)
-
 // Save state of caller into g->sched,
 // but using fake PC from systemstack_switch.
 // Must only be called from functions with no locals ($0)
index e7c5fa32252b9e42bb06bff94b3a769cc43203c4..e51ce2f8316b4010b952f7b4e5f99eb7b1a2b31d 100644 (file)
@@ -982,23 +982,6 @@ again:
        CBNZ    R0, again
        RET
 
-// void jmpdefer(fv, sp);
-// called from deferreturn.
-// 1. grab stored LR for caller
-// 2. sub 4 bytes to get back to BL deferreturn
-// 3. BR to fn
-TEXT runtime·jmpdefer(SB), NOSPLIT|NOFRAME, $0-16
-       MOVD    0(RSP), R0
-       SUB     $4, R0
-       MOVD    R0, LR
-
-       MOVD    fv+0(FP), R26
-       MOVD    argp+8(FP), R0
-       MOVD    R0, RSP
-       SUB     $8, RSP
-       MOVD    0(R26), R3
-       B       (R3)
-
 // Save state of caller into g->sched,
 // but using fake PC from systemstack_switch.
 // Must only be called from functions with no locals ($0)
index f3ac453d998bbe3139f33ef313948304b45541ed..b2e2384c3681f28bbc37e51bc46ed79066ebe280 100644 (file)
@@ -384,22 +384,6 @@ CALLFN(·call1073741824, 1073741824)
 TEXT runtime·procyield(SB),NOSPLIT,$0-0
        RET
 
-// void jmpdefer(fv, sp);
-// called from deferreturn.
-// 1. grab stored LR for caller
-// 2. sub 8 bytes to get back to JAL deferreturn
-// 3. JMP to fn
-TEXT runtime·jmpdefer(SB), NOSPLIT|NOFRAME, $0-16
-       MOVV    0(R29), R31
-       ADDV    $-8, R31
-
-       MOVV    fv+0(FP), REGCTXT
-       MOVV    argp+8(FP), R29
-       ADDV    $-8, R29
-       NOR     R0, R0  // prevent scheduling
-       MOVV    0(REGCTXT), R4
-       JMP     (R4)
-
 // Save state of caller into g->sched,
 // but using fake PC from systemstack_switch.
 // Must only be called from functions with no locals ($0)
index 4dc165849e280ffe8c314cd843b52d3cb4482fc0..87a1344e8f6de574193f56089fe0dc0ffe4d97c9 100644 (file)
@@ -382,22 +382,6 @@ CALLFN(·call1073741824, 1073741824)
 TEXT runtime·procyield(SB),NOSPLIT,$0-4
        RET
 
-// void jmpdefer(fv, sp);
-// called from deferreturn.
-// 1. grab stored LR for caller
-// 2. sub 8 bytes to get back to JAL deferreturn
-// 3. JMP to fn
-TEXT runtime·jmpdefer(SB),NOSPLIT,$0-8
-       MOVW    0(R29), R31
-       ADDU    $-8, R31
-
-       MOVW    fv+0(FP), REGCTXT
-       MOVW    argp+4(FP), R29
-       ADDU    $-4, R29
-       NOR     R0, R0  // prevent scheduling
-       MOVW    0(REGCTXT), R4
-       JMP     (R4)
-
 // Save state of caller into g->sched,
 // but using fake PC from systemstack_switch.
 // Must only be called from functions with no locals ($0)
index a789d041e43eaa43b51a7f05bc4367dd9800c167..5dc96c594732ffc86899fb964914cc98e2a2cda5 100644 (file)
@@ -503,34 +503,6 @@ again:
        OR      R6, R6, R6      // Set PPR priority back to medium-low
        RET
 
-// void jmpdefer(fv, sp);
-// called from deferreturn.
-// 1. grab stored LR for caller
-// 2. sub 8 bytes to get back to either nop or toc reload before deferreturn
-// 3. BR to fn
-// When dynamically linking Go, it is not sufficient to rewind to the BL
-// deferreturn -- we might be jumping between modules and so we need to reset
-// the TOC pointer in r2. To do this, codegen inserts MOVD 24(R1), R2 *before*
-// the BL deferreturn and jmpdefer rewinds to that.
-TEXT runtime·jmpdefer(SB), NOSPLIT|NOFRAME, $0-16
-       MOVD    0(R1), R31
-       SUB     $8, R31
-       MOVD    R31, LR
-
-       MOVD    fv+0(FP), R11
-       MOVD    argp+8(FP), R1
-       SUB     $FIXED_FRAME, R1
-#ifdef GOOS_aix
-       // AIX won't trigger a SIGSEGV if R11 = nil
-       // So it manually triggers it
-       CMP     R0, R11
-       BNE     2(PC)
-       MOVD    R0, 0(R0)
-#endif
-       MOVD    0(R11), R12
-       MOVD    R12, CTR
-       BR      (CTR)
-
 // Save state of caller into g->sched,
 // but using fake PC from systemstack_switch.
 // Must only be called from functions with no locals ($0)
index 9957ae201bc32b5653343294e0db09aa7686c64f..9927a817f7274a86761b711bce09b7b8b5282c6c 100644 (file)
@@ -248,21 +248,6 @@ TEXT gogo<>(SB), NOSPLIT|NOFRAME, $0
        MOV     gobuf_pc(T0), T0
        JALR    ZERO, T0
 
-// func jmpdefer(fv func(), argp uintptr)
-// called from deferreturn
-// 1. grab stored return address from the caller's frame
-// 2. sub 8 bytes to get back to JAL deferreturn
-// 3. JMP to fn
-TEXT runtime·jmpdefer(SB), NOSPLIT|NOFRAME, $0-16
-       MOV     0(X2), RA
-       ADD     $-8, RA
-
-       MOV     fv+0(FP), CTXT
-       MOV     argp+8(FP), X2
-       ADD     $-8, X2
-       MOV     0(CTXT), T0
-       JALR    ZERO, T0
-
 // func procyield(cycles uint32)
 TEXT runtime·procyield(SB),NOSPLIT,$0-0
        RET
index 534cb6112c61ec2cc57cb9f20917c8e9c076f1c8..d4110d563f444efc1142eaba94b0f0c76b2dfab0 100644 (file)
@@ -480,21 +480,6 @@ TEXT callfnMVC<>(SB),NOSPLIT|NOFRAME,$0-0
 TEXT runtime·procyield(SB),NOSPLIT,$0-0
        RET
 
-// void jmpdefer(fv, sp);
-// called from deferreturn.
-// 1. grab stored LR for caller
-// 2. sub 6 bytes to get back to BL deferreturn (size of BRASL instruction)
-// 3. BR to fn
-TEXT runtime·jmpdefer(SB),NOSPLIT|NOFRAME,$0-16
-       MOVD    0(R15), R1
-       SUB     $6, R1, LR
-
-       MOVD    fv+0(FP), R12
-       MOVD    argp+8(FP), R15
-       SUB     $8, R15
-       MOVD    0(R12), R3
-       BR      (R3)
-
 // Save state of caller into g->sched,
 // but using fake PC from systemstack_switch.
 // Must only be called from functions with no locals ($0)
index 53c271aa708993b70b1b76510411f1080b735835..d885da6e70f4398d36e04b7a4ac25613d749048d 100644 (file)
@@ -193,35 +193,6 @@ TEXT runtime·return0(SB), NOSPLIT, $0-0
        MOVD $0, RET0
        RET
 
-TEXT runtime·jmpdefer(SB), NOSPLIT, $0-16
-       MOVD fv+0(FP), CTXT
-
-       Get CTXT
-       I64Eqz
-       If
-               CALLNORESUME runtime·sigpanic<ABIInternal>(SB)
-       End
-
-       // caller sp after CALL
-       I64Load argp+8(FP)
-       I64Const $8
-       I64Sub
-       I32WrapI64
-       Set SP
-
-       // decrease PC_B by 1 to CALL again
-       Get SP
-       I32Load16U (SP)
-       I32Const $1
-       I32Sub
-       I32Store16 $0
-
-       // but first run the deferred function
-       Get CTXT
-       I32WrapI64
-       I64Load $0
-       JMP
-
 TEXT runtime·asminit(SB), NOSPLIT, $0-0
        // No per-thread init.
        RET
index e66fe27be0bfb1d62e1d378cd98221c847007f3f..4b8bca6c5667ff9af3f379b1c720780318391d44 100644 (file)
@@ -396,47 +396,39 @@ func freedeferfn() {
        throw("freedefer with d.fn != nil")
 }
 
-// Run a deferred function if there is one.
+// deferreturn runs deferred functions for the caller's frame.
 // The compiler inserts a call to this at the end of any
 // function which calls defer.
-// If there is a deferred function, this will call runtime·jmpdefer,
-// which will jump to the deferred function such that it appears
-// to have been called by the caller of deferreturn at the point
-// just before deferreturn was called. The effect is that deferreturn
-// is called again and again until there are no more deferred functions.
 func deferreturn() {
        gp := getg()
-       d := gp._defer
-       if d == nil {
-               return
-       }
-       sp := getcallersp()
-       if d.sp != sp {
-               return
-       }
-       if d.openDefer {
-               done := runOpenDeferFrame(gp, d)
-               if !done {
-                       throw("unfinished open-coded defers in deferreturn")
+       for {
+               d := gp._defer
+               if d == nil {
+                       return
                }
+               sp := getcallersp()
+               if d.sp != sp {
+                       return
+               }
+               if d.openDefer {
+                       done := runOpenDeferFrame(gp, d)
+                       if !done {
+                               throw("unfinished open-coded defers in deferreturn")
+                       }
+                       gp._defer = d.link
+                       freedefer(d)
+                       // If this frame uses open defers, then this
+                       // must be the only defer record for the
+                       // frame, so we can just return.
+                       return
+               }
+
+               fn := d.fn
+               d.fn = nil
                gp._defer = d.link
                freedefer(d)
-               return
+               fn()
        }
-
-       fn := d.fn
-       d.fn = nil
-       gp._defer = d.link
-       freedefer(d)
-       // If the defer function pointer is nil, force the seg fault to happen
-       // here rather than in jmpdefer. gentraceback() throws an error if it is
-       // called with a callback on an LR architecture and jmpdefer is on the
-       // stack, because jmpdefer manipulates SP (see issue #8153).
-       _ = **(**funcval)(unsafe.Pointer(&fn))
-       // We must not split the stack between computing argp and
-       // calling jmpdefer because argp is a uintptr stack pointer.
-       argp := getcallersp() + sys.MinFrameSize
-       jmpdefer(fn, argp)
 }
 
 // Goexit terminates the goroutine that calls it. No other goroutine is affected.
index b94acdea1f65f2a58588d86011174c45387663d4..fc29a1bac3192377156b817438505ac2c61b47c3 100644 (file)
@@ -176,8 +176,6 @@ func cgocallback(fn, frame, ctxt uintptr)
 
 func gogo(buf *gobuf)
 
-//go:noescape
-func jmpdefer(fv func(), argp uintptr)
 func asminit()
 func setg(gg *g)
 func breakpoint()
index 44ea0710c651812d99161de5a2c252123e8dd702..d08aa0b320470506aa2ef42ba2f3ceecd58783d4 100644 (file)
@@ -331,7 +331,6 @@ const (
        funcID_gogo
        funcID_gopanic
        funcID_handleAsyncEvent
-       funcID_jmpdefer
        funcID_mcall
        funcID_morestack
        funcID_mstart