diff options
Diffstat (limited to 'src/cmd/internal/obj')
| -rw-r--r-- | src/cmd/internal/obj/arm/asm5.go | 11 | ||||
| -rw-r--r-- | src/cmd/internal/obj/wasm/wasmobj.go | 36 | ||||
| -rw-r--r-- | src/cmd/internal/obj/x86/asm6.go | 1 |
3 files changed, 44 insertions, 4 deletions
diff --git a/src/cmd/internal/obj/arm/asm5.go b/src/cmd/internal/obj/arm/asm5.go index 7b1682776e..ccf5f9e7f8 100644 --- a/src/cmd/internal/obj/arm/asm5.go +++ b/src/cmd/internal/obj/arm/asm5.go @@ -355,10 +355,11 @@ var oprange [ALAST & obj.AMask][]Optab var xcmp [C_GOK + 1][C_GOK + 1]bool var ( - symdiv *obj.LSym - symdivu *obj.LSym - symmod *obj.LSym - symmodu *obj.LSym + deferreturn *obj.LSym + symdiv *obj.LSym + symdivu *obj.LSym + symmod *obj.LSym + symmodu *obj.LSym ) // Note about encoding: Prog.scond holds the condition encoding, @@ -1218,6 +1219,8 @@ 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") diff --git a/src/cmd/internal/obj/wasm/wasmobj.go b/src/cmd/internal/obj/wasm/wasmobj.go index 4d276db678..ceeae7a257 100644 --- a/src/cmd/internal/obj/wasm/wasmobj.go +++ b/src/cmd/internal/obj/wasm/wasmobj.go @@ -129,6 +129,8 @@ var ( morestackNoCtxt *obj.LSym gcWriteBarrier *obj.LSym sigpanic *obj.LSym + deferreturn *obj.LSym + jmpdefer *obj.LSym ) const ( @@ -141,6 +143,10 @@ 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) { @@ -417,6 +423,12 @@ 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)) @@ -467,6 +479,15 @@ 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 @@ -479,6 +500,21 @@ 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 diff --git a/src/cmd/internal/obj/x86/asm6.go b/src/cmd/internal/obj/x86/asm6.go index 331a98dfef..17fa76727e 100644 --- a/src/cmd/internal/obj/x86/asm6.go +++ b/src/cmd/internal/obj/x86/asm6.go @@ -43,6 +43,7 @@ import ( var ( plan9privates *obj.LSym + deferreturn *obj.LSym ) // Instruction layout. |
