]> Cypherpunks repositories - gostls13.git/commitdiff
Revert "cmd/compile, cmd/link, runtime: make defers low-cost through inline code...
authorBryan C. Mills <bcmills@google.com>
Wed, 16 Oct 2019 20:41:53 +0000 (20:41 +0000)
committerBryan C. Mills <bcmills@google.com>
Wed, 16 Oct 2019 20:59:53 +0000 (20:59 +0000)
This reverts CL 190098.

Reason for revert: broke several builders.

Change-Id: I69161352f9ded02537d8815f259c4d391edd9220
Reviewed-on: https://go-review.googlesource.com/c/go/+/201519
Run-TryBot: Bryan C. Mills <bcmills@google.com>
Reviewed-by: Austin Clements <austin@google.com>
Reviewed-by: Dan Scales <danscales@google.com>
27 files changed:
src/cmd/compile/internal/gc/escape.go
src/cmd/compile/internal/gc/main.go
src/cmd/compile/internal/gc/obj.go
src/cmd/compile/internal/gc/reflect.go
src/cmd/compile/internal/gc/sizeof_test.go
src/cmd/compile/internal/gc/ssa.go
src/cmd/compile/internal/gc/syntax.go
src/cmd/compile/internal/gc/walk.go
src/cmd/compile/internal/ssa/deadstore.go
src/cmd/compile/internal/ssa/func.go
src/cmd/internal/obj/link.go
src/cmd/internal/objabi/funcdata.go
src/cmd/internal/objabi/funcid.go
src/cmd/internal/objabi/stack.go
src/cmd/link/internal/ld/pcln.go
src/cmd/link/internal/ld/symtab.go
src/runtime/callers_test.go
src/runtime/defer_test.go
src/runtime/funcdata.h
src/runtime/panic.go
src/runtime/runtime2.go
src/runtime/runtime_test.go
src/runtime/stack.go
src/runtime/symtab.go
test/defererrcheck.go [deleted file]
test/live.go
test/nosplit.go

index 3dc6b981235013a5429256e04508d4607b0ff77e..b855f4a1748e53e5dc3593b7bfc5ddde71fc4ed1 100644 (file)
@@ -371,7 +371,6 @@ func (e *Escape) stmt(n *Node) {
                e.stmts(n.Right.Ninit)
                e.call(e.addrs(n.List), n.Right, nil)
        case ORETURN:
-               e.curfn.Func.numReturns++
                results := e.curfn.Type.Results().FieldSlice()
                for i, v := range n.List.Slice() {
                        e.assign(asNode(results[i].Nname), v, "return", n)
@@ -379,16 +378,6 @@ func (e *Escape) stmt(n *Node) {
        case OCALLFUNC, OCALLMETH, OCALLINTER, OCLOSE, OCOPY, ODELETE, OPANIC, OPRINT, OPRINTN, ORECOVER:
                e.call(nil, n, nil)
        case OGO, ODEFER:
-               if n.Op == ODEFER {
-                       e.curfn.Func.SetHasDefer(true)
-                       e.curfn.Func.numDefers++
-                       if e.curfn.Func.numDefers > maxOpenDefers {
-                               // Don't allow open defers if there are more than
-                               // 8 defers in the function, since we use a single
-                               // byte to record active defers.
-                               e.curfn.Func.SetOpenCodedDeferDisallowed(true)
-                       }
-               }
                e.stmts(n.Left.Ninit)
                e.call(nil, n.Left, n)
 
@@ -883,13 +872,8 @@ func (e *Escape) augmentParamHole(k EscHole, where *Node) EscHole {
        // non-transient location to avoid arguments from being
        // transiently allocated.
        if where.Op == ODEFER && e.loopDepth == 1 {
-               // force stack allocation of defer record, unless open-coded
-               // defers are used (see ssa.go)
-               where.Esc = EscNever
+               where.Esc = EscNever // force stack allocation of defer record (see ssa.go)
                return e.later(k)
-       } else if where.Op == ODEFER {
-               // If any defer occurs in a loop, open-coded defers cannot be used
-               e.curfn.Func.SetOpenCodedDeferDisallowed(true)
        }
 
        return e.heapHole()
index 8806386707d76e72a1eace13da24fed864909e46..05aac9ecb2763fc9782e0e6b6ff9da78fabd4999 100644 (file)
@@ -52,7 +52,6 @@ var (
        Debug_typecheckinl int
        Debug_gendwarfinl  int
        Debug_softfloat    int
-       Debug_defer        int
 )
 
 // Debug arguments.
@@ -82,7 +81,6 @@ var debugtab = []struct {
        {"typecheckinl", "eager typechecking of inline function bodies", &Debug_typecheckinl},
        {"dwarfinl", "print information about DWARF inlined function creation", &Debug_gendwarfinl},
        {"softfloat", "force compiler to emit soft-float code", &Debug_softfloat},
-       {"defer", "print information about defer compilation", &Debug_defer},
 }
 
 const debugHelpHeader = `usage: -d arg[,arg]* and arg is <key>[=<value>]
index 83371fabf5aa4a6334b3d1c580dc137d911eead8..be13b278921c6b920ae0b03b183dfdf8d84986a5 100644 (file)
@@ -294,9 +294,6 @@ func addGCLocals() {
                        }
                        ggloblsym(x, int32(len(x.P)), attr)
                }
-               if x := s.Func.OpenCodedDeferInfo; x != nil {
-                       ggloblsym(x, int32(len(x.P)), obj.RODATA|obj.DUPOK)
-               }
        }
 }
 
index 00a24f2dff34b2de826465f45eba23d5d69ed20e..9e3dca25c81e4e36e00bb7c10f11cc8dc52a2760 100644 (file)
@@ -338,7 +338,6 @@ func deferstruct(stksize int64) *types.Type {
                makefield("siz", types.Types[TUINT32]),
                makefield("started", types.Types[TBOOL]),
                makefield("heap", types.Types[TBOOL]),
-               makefield("openDefer", types.Types[TBOOL]),
                makefield("sp", types.Types[TUINTPTR]),
                makefield("pc", types.Types[TUINTPTR]),
                // Note: the types here don't really matter. Defer structures
@@ -347,9 +346,6 @@ func deferstruct(stksize int64) *types.Type {
                makefield("fn", types.Types[TUINTPTR]),
                makefield("_panic", types.Types[TUINTPTR]),
                makefield("link", types.Types[TUINTPTR]),
-               makefield("framepc", types.Types[TUINTPTR]),
-               makefield("varp", types.Types[TUINTPTR]),
-               makefield("fd", types.Types[TUINTPTR]),
                makefield("args", argtype),
        }
 
index ce4a216c2e2daa1090910c62eb2dd7b4cda4e2d5..f4725c0eb2977a8092e1f48eadbe308561e68076 100644 (file)
@@ -20,7 +20,7 @@ func TestSizeof(t *testing.T) {
                _32bit uintptr     // size on 32bit platforms
                _64bit uintptr     // size on 64bit platforms
        }{
-               {Func{}, 124, 224},
+               {Func{}, 116, 208},
                {Name{}, 32, 56},
                {Param{}, 24, 48},
                {Node{}, 76, 128},
index 200cca1063c38e66df72c224ef6f1fc84b40c9e9..dd8dacd1497749174f619b6c1c9a60dcf240c598 100644 (file)
@@ -29,10 +29,6 @@ var ssaDumpStdout bool // whether to dump to stdout
 var ssaDumpCFG string  // generate CFGs for these phases
 const ssaDumpFile = "ssa.html"
 
-// The max number of defers in a function using open-coded defers. We enforce this
-// limit because the deferBits bitmask is currently a single byte (to minimize code size)
-const maxOpenDefers = 8
-
 // ssaDumpInlined holds all inlined functions when ssaDump contains a function name.
 var ssaDumpInlined []*Node
 
@@ -169,107 +165,6 @@ func initssaconfig() {
        SigPanic = sysfunc("sigpanic")
 }
 
-// getParam returns the Field of ith param of node n (which is a
-// function/method/interface call), where the receiver of a method call is
-// considered as the 0th parameter. This does not include the receiver of an
-// interface call.
-func getParam(n *Node, i int) *types.Field {
-       t := n.Left.Type
-       if n.Op == OCALLMETH {
-               if i == 0 {
-                       return t.Recv()
-               }
-               return t.Params().Field(i - 1)
-       }
-       return t.Params().Field(i)
-}
-
-// dvarint writes a varint v to the funcdata in symbol x and returns the new offset
-func dvarint(x *obj.LSym, off int, v int64) int {
-       if v < 0 || v > 1e9 {
-               panic(fmt.Sprintf("dvarint: bad offset for funcdata - %v", v))
-       }
-       if v < 1<<7 {
-               return duint8(x, off, uint8(v))
-       }
-       off = duint8(x, off, uint8((v&127)|128))
-       if v < 1<<14 {
-               return duint8(x, off, uint8(v>>7))
-       }
-       off = duint8(x, off, uint8(((v>>7)&127)|128))
-       if v < 1<<21 {
-               return duint8(x, off, uint8(v>>14))
-       }
-       off = duint8(x, off, uint8(((v>>14)&127)|128))
-       if v < 1<<28 {
-               return duint8(x, off, uint8(v>>21))
-       }
-       off = duint8(x, off, uint8(((v>>21)&127)|128))
-       return duint8(x, off, uint8(v>>28))
-}
-
-// emitOpenDeferInfo emits FUNCDATA information about the defers in a function
-// that is using open-coded defers.  This funcdata is used to determine the active
-// defers in a function and execute those defers during panic processing.
-//
-// The funcdata is all encoded in varints (since values will almost always be less
-// than 128, but stack offsets could potentially be up to 2Gbyte). All "locations"
-// for stack variables are specified as the number of bytes below varp for their
-// starting address. The format is:
-//
-//  - Max total argument size among all the defers
-//  - Location of the deferBits variable
-//  - Number of defers in the function
-//  - Information about each defer call, in reverse order of appearance in the function:
-//    - Total argument size of the call
-//    - Location of the closure value to call
-//    - 1 or 0 to indicate if there is a receiver for the call
-//      - If yes, then the location of the receiver value
-//    - Number of arguments
-//    - Information about each argument
-//      - Location of the stored defer argument in this function's frame
-//      - Size of the argument
-//      - Offset of where argument should be placed in the args frame when making call
-func emitOpenDeferInfo(s state) {
-       x := Ctxt.Lookup(s.curfn.Func.lsym.Name + ".opendefer")
-       s.curfn.Func.lsym.Func.OpenCodedDeferInfo = x
-       off := 0
-
-       // Compute maxargsize (max size of arguments for all defers)
-       // first, so we can output it first to the funcdata
-       var maxargsize int64
-       for i := len(s.opendefers) - 1; i >= 0; i-- {
-               r := s.opendefers[i]
-               argsize := r.n.Left.Type.ArgWidth()
-               if argsize > maxargsize {
-                       maxargsize = argsize
-               }
-       }
-       off = dvarint(x, off, maxargsize)
-       off = dvarint(x, off, -s.deferBitsTemp.Xoffset)
-       off = dvarint(x, off, int64(len(s.opendefers)))
-
-       // Write in reverse-order, for ease of running in that order at runtime
-       for i := len(s.opendefers) - 1; i >= 0; i-- {
-               r := s.opendefers[i]
-               off = dvarint(x, off, r.n.Left.Type.ArgWidth())
-               off = dvarint(x, off, -r.closureNode.Xoffset)
-               if r.rcvrNode != nil {
-                       off = dvarint(x, off, 1)
-                       off = dvarint(x, off, -r.rcvrNode.Xoffset)
-               } else {
-                       off = dvarint(x, off, 0)
-               }
-               off = dvarint(x, off, int64(len(r.argNodes)))
-               for j, arg := range r.argNodes {
-                       f := getParam(r.n, j)
-                       off = dvarint(x, off, -arg.Xoffset)
-                       off = dvarint(x, off, f.Type.Size())
-                       off = dvarint(x, off, f.Offset)
-               }
-       }
-}
-
 // buildssa builds an SSA function for fn.
 // worker indicates which of the backend workers is doing the processing.
 func buildssa(fn *Node, worker int) *ssa.Func {
@@ -332,48 +227,11 @@ func buildssa(fn *Node, worker int) *ssa.Func {
        s.labeledNodes = map[*Node]*ssaLabel{}
        s.fwdVars = map[*Node]*ssa.Value{}
        s.startmem = s.entryNewValue0(ssa.OpInitMem, types.TypeMem)
-
-       s.hasOpenDefers = Debug['N'] == 0 && s.hasdefer && !s.curfn.Func.OpenCodedDeferDisallowed()
-       if s.hasOpenDefers && s.curfn.Func.Exit.Len() > 0 {
-               // Skip doing open defers if there is any extra exit code (likely
-               // copying heap-allocated return values or race detection), since
-               // we will not generate that code in the case of the extra
-               // deferreturn/ret segment.
-               s.hasOpenDefers = false
-       }
-       if s.hasOpenDefers &&
-               s.curfn.Func.numReturns*s.curfn.Func.numDefers > 15 {
-               // Since we are generating defer calls at every exit for
-               // open-coded defers, skip doing open-coded defers if there are
-               // too many returns (especially if there are multiple defers).
-               // Open-coded defers are most important for improving performance
-               // for smaller functions (which don't have many returns).
-               s.hasOpenDefers = false
-       }
-
        s.sp = s.entryNewValue0(ssa.OpSP, types.Types[TUINTPTR]) // TODO: use generic pointer type (unsafe.Pointer?) instead
        s.sb = s.entryNewValue0(ssa.OpSB, types.Types[TUINTPTR])
 
        s.startBlock(s.f.Entry)
        s.vars[&memVar] = s.startmem
-       if s.hasOpenDefers {
-               // Create the deferBits variable and stack slot.  deferBits is a
-               // bitmask showing which of the open-coded defers in this function
-               // have been activated.
-               deferBitsTemp := tempAt(src.NoXPos, s.curfn, types.Types[TUINT8])
-               s.deferBitsTemp = deferBitsTemp
-               // For this value, AuxInt is initialized to zero by default
-               startDeferBits := s.entryNewValue0(ssa.OpConst8, types.Types[TUINT8])
-               s.vars[&deferBitsVar] = startDeferBits
-               s.deferBitsAddr = s.addr(deferBitsTemp, false)
-               s.store(types.Types[TUINT8], s.deferBitsAddr, startDeferBits)
-               // Make sure that the deferBits stack slot is kept alive (for use
-               // by panics) and stores to deferBits are not eliminated, even if
-               // all checking code on deferBits in the function exit can be
-               // eliminated, because the defer statements were all
-               // unconditional.
-               s.vars[&memVar] = s.newValue1Apos(ssa.OpVarLive, types.TypeMem, deferBitsTemp, s.mem(), false)
-       }
 
        // Generate addresses of local declarations
        s.decladdrs = map[*Node]*ssa.Value{}
@@ -429,11 +287,6 @@ func buildssa(fn *Node, worker int) *ssa.Func {
 
        // Main call to ssa package to compile function
        ssa.Compile(s.f)
-
-       if s.hasOpenDefers {
-               emitOpenDeferInfo(s)
-       }
-
        return s.f
 }
 
@@ -522,29 +375,6 @@ func (s *state) updateUnsetPredPos(b *ssa.Block) {
        }
 }
 
-// Information about each open-coded defer.
-type openDeferInfo struct {
-       // The ODEFER node representing the function call of the defer
-       n *Node
-       // If defer call is closure call, the address of the argtmp where the
-       // closure is stored.
-       closure *ssa.Value
-       // The node representing the argtmp where the closure is stored - used for
-       // function, method, or interface call, to store a closure that panic
-       // processing can use for this defer.
-       closureNode *Node
-       // If defer call is interface call, the address of the argtmp where the
-       // receiver is stored
-       rcvr *ssa.Value
-       // The node representing the argtmp where the receiver is stored
-       rcvrNode *Node
-       // The addresses of the argtmps where the evaluated arguments of the defer
-       // function call are stored.
-       argVals []*ssa.Value
-       // The nodes representing the argtmps where the args of the defer are stored
-       argNodes []*Node
-}
-
 type state struct {
        // configuration (arch) information
        config *ssa.Config
@@ -586,9 +416,6 @@ type state struct {
        startmem *ssa.Value
        sp       *ssa.Value
        sb       *ssa.Value
-       // value representing address of where deferBits autotmp is stored
-       deferBitsAddr *ssa.Value
-       deferBitsTemp *Node
 
        // line number stack. The current line number is top of stack
        line []src.XPos
@@ -605,19 +432,6 @@ type state struct {
        cgoUnsafeArgs bool
        hasdefer      bool // whether the function contains a defer statement
        softFloat     bool
-       hasOpenDefers bool // whether we are doing open-coded defers
-
-       // If doing open-coded defers, list of info about the defer calls in
-       // scanning order. Hence, at exit we should run these defers in reverse
-       // order of this list
-       opendefers []*openDeferInfo
-       // For open-coded defers, this is the beginning and end blocks of the last
-       // defer exit code that we have generated so far. We use these to share
-       // code between exits if the shareDeferExits option (disabled by default)
-       // is on.
-       lastDeferExit       *ssa.Block // Entry block of last defer exit code we generated
-       lastDeferFinalBlock *ssa.Block // Final block of last defer exit code we generated
-       lastDeferCount      int        // Number of defers encountered at that point
 }
 
 type funcLine struct {
@@ -655,13 +469,12 @@ var (
        memVar = Node{Op: ONAME, Sym: &types.Sym{Name: "mem"}}
 
        // dummy nodes for temporary variables
-       ptrVar       = Node{Op: ONAME, Sym: &types.Sym{Name: "ptr"}}
-       lenVar       = Node{Op: ONAME, Sym: &types.Sym{Name: "len"}}
-       newlenVar    = Node{Op: ONAME, Sym: &types.Sym{Name: "newlen"}}
-       capVar       = Node{Op: ONAME, Sym: &types.Sym{Name: "cap"}}
-       typVar       = Node{Op: ONAME, Sym: &types.Sym{Name: "typ"}}
-       okVar        = Node{Op: ONAME, Sym: &types.Sym{Name: "ok"}}
-       deferBitsVar = Node{Op: ONAME, Sym: &types.Sym{Name: "deferBits"}}
+       ptrVar    = Node{Op: ONAME, Sym: &types.Sym{Name: "ptr"}}
+       lenVar    = Node{Op: ONAME, Sym: &types.Sym{Name: "len"}}
+       newlenVar = Node{Op: ONAME, Sym: &types.Sym{Name: "newlen"}}
+       capVar    = Node{Op: ONAME, Sym: &types.Sym{Name: "cap"}}
+       typVar    = Node{Op: ONAME, Sym: &types.Sym{Name: "typ"}}
+       okVar     = Node{Op: ONAME, Sym: &types.Sym{Name: "ok"}}
 )
 
 // startBlock sets the current block we're generating code in to b.
@@ -1052,27 +865,11 @@ func (s *state) stmt(n *Node) {
                        }
                }
        case ODEFER:
-               if Debug_defer > 0 {
-                       var defertype string
-                       if s.hasOpenDefers {
-                               defertype = "open-coded"
-                       } else if n.Esc == EscNever {
-                               defertype = "stack-allocated"
-                       } else {
-                               defertype = "heap-allocated"
-                       }
-                       Warnl(n.Pos, "defer: %s defer in function %s",
-                               defertype, s.curfn.funcname())
-               }
-               if s.hasOpenDefers {
-                       s.openDeferRecord(n.Left)
-               } else {
-                       d := callDefer
-                       if n.Esc == EscNever {
-                               d = callDeferStack
-                       }
-                       s.call(n.Left, d)
+               d := callDefer
+               if n.Esc == EscNever {
+                       d = callDeferStack
                }
+               s.call(n.Left, d)
        case OGO:
                s.call(n.Left, callGo)
 
@@ -1489,28 +1286,12 @@ func (s *state) stmt(n *Node) {
        }
 }
 
-// If true, share as many open-coded defer exits as possible (with the downside of
-// worse line-number information)
-const shareDeferExits = false
-
 // exit processes any code that needs to be generated just before returning.
 // It returns a BlockRet block that ends the control flow. Its control value
 // will be set to the final memory state.
 func (s *state) exit() *ssa.Block {
        if s.hasdefer {
-               if s.hasOpenDefers {
-                       if shareDeferExits && s.lastDeferExit != nil && len(s.opendefers) == s.lastDeferCount {
-                               if s.curBlock.Kind != ssa.BlockPlain {
-                                       panic("Block for an exit should be BlockPlain")
-                               }
-                               s.curBlock.AddEdgeTo(s.lastDeferExit)
-                               s.endBlock()
-                               return s.lastDeferFinalBlock
-                       }
-                       s.openDeferExit()
-               } else {
-                       s.rtcall(Deferreturn, true, nil)
-               }
+               s.rtcall(Deferreturn, true, nil)
        }
 
        // Run exit code. Typically, this code copies heap-allocated PPARAMOUT
@@ -1533,9 +1314,6 @@ func (s *state) exit() *ssa.Block {
        b := s.endBlock()
        b.Kind = ssa.BlockRet
        b.SetControl(m)
-       if s.hasdefer && s.hasOpenDefers {
-               s.lastDeferFinalBlock = b
-       }
        return b
 }
 
@@ -3986,230 +3764,6 @@ func (s *state) intrinsicArgs(n *Node) []*ssa.Value {
        return args
 }
 
-// openDeferRecord adds code to evaluate and store the args for an open-code defer
-// call, and records info about the defer, so we can generate proper code on the
-// exit paths. n is the sub-node of the defer node that is the actual function
-// call. We will also record funcdata information on where the args are stored
-// (as well as the deferBits variable), and this will enable us to run the proper
-// defer calls during panics.
-func (s *state) openDeferRecord(n *Node) {
-       index := len(s.opendefers)
-
-       // Do any needed expression evaluation for the args (including the
-       // receiver, if any). This may be evaluating something like 'autotmp_3 =
-       // once.mutex'. Such a statement will create a mapping in s.vars[] from
-       // the autotmp name to the evaluated SSA arg value, but won't do any
-       // stores to the stack.
-       s.stmtList(n.List)
-
-       args := []*ssa.Value{}
-       argNodes := []*Node{}
-
-       opendefer := &openDeferInfo{
-               n: n,
-       }
-       fn := n.Left
-       if n.Op == OCALLFUNC {
-               // We must always store the function value in a stack slot for the
-               // runtime panic code to use. But in the defer exit code, we will
-               // call the function directly if it is a static function.
-               closureVal := s.expr(fn)
-               closure := s.openDeferSave(fn, fn.Type, closureVal)
-               opendefer.closureNode = closure.Aux.(*Node)
-               if !(fn.Op == ONAME && fn.Class() == PFUNC) {
-                       opendefer.closure = closure
-               }
-       } else if n.Op == OCALLMETH {
-               if fn.Op != ODOTMETH {
-                       Fatalf("OCALLMETH: n.Left not an ODOTMETH: %v", fn)
-               }
-               closureVal := s.getMethodClosure(fn)
-               // We must always store the function value in a stack slot for the
-               // runtime panic code to use. But in the defer exit code, we will
-               // call the method directly.
-               closure := s.openDeferSave(fn, fn.Type, closureVal)
-               opendefer.closureNode = closure.Aux.(*Node)
-       } else {
-               if fn.Op != ODOTINTER {
-                       Fatalf("OCALLINTER: n.Left not an ODOTINTER: %v", fn.Op)
-               }
-               closure, rcvr := s.getClosureAndRcvr(fn)
-               opendefer.closure = s.openDeferSave(fn, closure.Type, closure)
-               // Important to get the receiver type correct, so it is recognized
-               // as a pointer for GC purposes.
-               opendefer.rcvr = s.openDeferSave(nil, fn.Type.Recv().Type, rcvr)
-               opendefer.closureNode = opendefer.closure.Aux.(*Node)
-               opendefer.rcvrNode = opendefer.rcvr.Aux.(*Node)
-       }
-       for _, argn := range n.Rlist.Slice() {
-               v := s.openDeferSave(argn, argn.Type, s.expr(argn))
-               args = append(args, v)
-               argNodes = append(argNodes, v.Aux.(*Node))
-       }
-       opendefer.argVals = args
-       opendefer.argNodes = argNodes
-       s.opendefers = append(s.opendefers, opendefer)
-
-       // Update deferBits only after evaluation and storage to stack of
-       // args/receiver/interface is successful.
-       bitvalue := s.constInt8(types.Types[TUINT8], 1<<uint(index))
-       newDeferBits := s.newValue2(ssa.OpOr8, types.Types[TUINT8], s.variable(&deferBitsVar, types.Types[TUINT8]), bitvalue)
-       s.vars[&deferBitsVar] = newDeferBits
-       s.store(types.Types[TUINT8], s.deferBitsAddr, newDeferBits)
-}
-
-// openDeferSave generates SSA nodes to store a value val (with type t) for an
-// open-coded defer on the stack at an explicit autotmp location, so it can be
-// reloaded and used for the appropriate call on exit. n is the associated node,
-// which is only needed if the associated type is non-SSAable. It returns an SSA
-// value representing a pointer to the stack location.
-func (s *state) openDeferSave(n *Node, t *types.Type, val *ssa.Value) *ssa.Value {
-       argTemp := tempAt(val.Pos.WithNotStmt(), s.curfn, t)
-       var addrArgTemp *ssa.Value
-       // Use OpVarLive to make sure stack slots for the args, etc. are not
-       // removed by dead-store elimination
-       if s.curBlock.ID != s.f.Entry.ID {
-               // Force the argtmp storing this defer function/receiver/arg to be
-               // declared in the entry block, so that it will be live for the
-               // defer exit code (which will actually access it only if the
-               // associated defer call has been activated).
-               s.defvars[s.f.Entry.ID][&memVar] = s.entryNewValue1A(ssa.OpVarDef, types.TypeMem, argTemp, s.defvars[s.f.Entry.ID][&memVar])
-               s.defvars[s.f.Entry.ID][&memVar] = s.entryNewValue1A(ssa.OpVarLive, types.TypeMem, argTemp, s.defvars[s.f.Entry.ID][&memVar])
-               addrArgTemp = s.entryNewValue2A(ssa.OpLocalAddr, types.NewPtr(argTemp.Type), argTemp, s.sp, s.defvars[s.f.Entry.ID][&memVar])
-       } else {
-               // Special case if we're still in the entry block. We can't use
-               // the above code, since s.defvars[s.f.Entry.ID] isn't defined
-               // until we end the entry block with s.endBlock().
-               s.vars[&memVar] = s.newValue1Apos(ssa.OpVarDef, types.TypeMem, argTemp, s.mem(), false)
-               s.vars[&memVar] = s.newValue1Apos(ssa.OpVarLive, types.TypeMem, argTemp, s.mem(), false)
-               addrArgTemp = s.newValue2Apos(ssa.OpLocalAddr, types.NewPtr(argTemp.Type), argTemp, s.sp, s.mem(), false)
-       }
-       if types.Haspointers(t) {
-               // Since we may use this argTemp during exit depending on the
-               // deferBits, we must define it unconditionally on entry.
-               // Therefore, we must make sure it is zeroed out in the entry
-               // block if it contains pointers, else GC may wrongly follow an
-               // uninitialized pointer value.
-               argTemp.Name.SetNeedzero(true)
-       }
-       if !canSSAType(t) {
-               if n.Op != ONAME {
-                       panic(fmt.Sprintf("Non-SSAable value should be a named location: %v", n))
-               }
-               a := s.addr(n, false)
-               s.move(t, addrArgTemp, a)
-               return addrArgTemp
-       }
-       // We are storing to the stack, hence we can avoid the full checks in
-       // storeType() (no write barrier) and do a simple store().
-       s.store(t, addrArgTemp, val)
-       return addrArgTemp
-}
-
-// openDeferExit generates SSA for processing all the open coded defers at exit.
-// The code involves loading deferBits, and checking each of the bits to see if
-// the corresponding defer statement was executed. For each bit that is turned
-// on, the associated defer call is made.
-func (s *state) openDeferExit() {
-       deferExit := s.f.NewBlock(ssa.BlockPlain)
-       s.endBlock().AddEdgeTo(deferExit)
-       s.startBlock(deferExit)
-       s.lastDeferExit = deferExit
-       s.lastDeferCount = len(s.opendefers)
-       zeroval := s.constInt8(types.Types[TUINT8], 0)
-       // Test for and run defers in reverse order
-       for i := len(s.opendefers) - 1; i >= 0; i-- {
-               r := s.opendefers[i]
-               bCond := s.f.NewBlock(ssa.BlockPlain)
-               bEnd := s.f.NewBlock(ssa.BlockPlain)
-
-               deferBits := s.variable(&deferBitsVar, types.Types[TUINT8])
-               // Generate code to check if the bit associated with the current
-               // defer is set.
-               bitval := s.constInt8(types.Types[TUINT8], 1<<uint(i))
-               andval := s.newValue2(ssa.OpAnd8, types.Types[TUINT8], deferBits, bitval)
-               eqVal := s.newValue2(ssa.OpEq8, types.Types[TBOOL], andval, zeroval)
-               b := s.endBlock()
-               b.Kind = ssa.BlockIf
-               b.SetControl(eqVal)
-               b.AddEdgeTo(bEnd)
-               b.AddEdgeTo(bCond)
-               bCond.AddEdgeTo(bEnd)
-               s.startBlock(bCond)
-
-               // Clear this bit in deferBits and force store back to stack, so
-               // we will not try to re-run this defer call if this defer call panics.
-               nbitval := s.newValue1(ssa.OpCom8, types.Types[TUINT8], bitval)
-               maskedval := s.newValue2(ssa.OpAnd8, types.Types[TUINT8], deferBits, nbitval)
-               s.store(types.Types[TUINT8], s.deferBitsAddr, maskedval)
-               // Use this value for following tests, so we keep previous
-               // bits cleared.
-               s.vars[&deferBitsVar] = maskedval
-
-               // Generate code to call the function call of the defer, using the
-               // closure/receiver/args that were stored in argtmps at the point
-               // of the defer statement.
-               argStart := Ctxt.FixedFrameSize()
-               fn := r.n.Left
-               stksize := fn.Type.ArgWidth()
-               if r.rcvr != nil {
-                       // rcvr in case of OCALLINTER
-                       v := s.load(r.rcvr.Type.Elem(), r.rcvr)
-                       addr := s.constOffPtrSP(s.f.Config.Types.UintptrPtr, argStart)
-                       s.store(types.Types[TUINTPTR], addr, v)
-               }
-               for j, argAddrVal := range r.argVals {
-                       f := getParam(r.n, j)
-                       pt := types.NewPtr(f.Type)
-                       addr := s.constOffPtrSP(pt, argStart+f.Offset)
-                       if !canSSAType(f.Type) {
-                               s.move(f.Type, addr, argAddrVal)
-                       } else {
-                               argVal := s.load(f.Type, argAddrVal)
-                               s.storeType(f.Type, addr, argVal, 0, false)
-                       }
-               }
-               var call *ssa.Value
-               if r.closure != nil {
-                       v := s.load(r.closure.Type.Elem(), r.closure)
-                       s.maybeNilCheckClosure(v, callDefer)
-                       codeptr := s.rawLoad(types.Types[TUINTPTR], v)
-                       call = s.newValue3(ssa.OpClosureCall, types.TypeMem, codeptr, v, s.mem())
-               } else {
-                       // Do a static call if the original call was a static function or method
-                       call = s.newValue1A(ssa.OpStaticCall, types.TypeMem, fn.Sym.Linksym(), s.mem())
-               }
-               call.AuxInt = stksize
-               s.vars[&memVar] = call
-               // Make sure that the stack slots with pointers are kept live
-               // through the call (which is a pre-emption point). Also, we will
-               // use the first call of the last defer exit to compute liveness
-               // for the deferreturn, so we want all stack slots to be live.
-               if r.closureNode != nil {
-                       s.vars[&memVar] = s.newValue1Apos(ssa.OpVarLive, types.TypeMem, r.closureNode, s.mem(), false)
-               }
-               if r.rcvrNode != nil {
-                       if types.Haspointers(r.rcvrNode.Type) {
-                               s.vars[&memVar] = s.newValue1Apos(ssa.OpVarLive, types.TypeMem, r.rcvrNode, s.mem(), false)
-                       }
-               }
-               for _, argNode := range r.argNodes {
-                       if types.Haspointers(argNode.Type) {
-                               s.vars[&memVar] = s.newValue1Apos(ssa.OpVarLive, types.TypeMem, argNode, s.mem(), false)
-                       }
-               }
-
-               if i == len(s.opendefers)-1 {
-                       // Record the call of the first defer. This will be used
-                       // to set liveness info for the deferreturn (which is also
-                       // used for any location that causes a runtime panic)
-                       s.f.LastDeferExit = call
-               }
-               s.endBlock()
-               s.startBlock(bEnd)
-       }
-}
-
 // Calls the function n using the specified call type.
 // Returns the address of the return value (or nil if none).
 func (s *state) call(n *Node, k callKind) *ssa.Value {
@@ -4225,10 +3779,11 @@ func (s *state) call(n *Node, k callKind) *ssa.Value {
                        break
                }
                closure = s.expr(fn)
-               if k != callDefer && k != callDeferStack {
-                       // Deferred nil function needs to panic when the function is invoked,
-                       // not the point of defer statement.
-                       s.maybeNilCheckClosure(closure, k)
+               if k != callDefer && k != callDeferStack && (thearch.LinkArch.Family == sys.Wasm || objabi.GOOS == "aix" && k != callGo) {
+                       // Deferred nil function needs to panic when the function is invoked, not the point of defer statement.
+                       // On AIX, the closure needs to be verified as fn can be nil, except if it's a call go. This needs to be handled by the runtime to have the "go of nil func value" error.
+                       // TODO(neelance): On other architectures this should be eliminated by the optimization steps
+                       s.nilCheck(closure)
                }
        case OCALLMETH:
                if fn.Op != ODOTMETH {
@@ -4238,20 +3793,35 @@ func (s *state) call(n *Node, k callKind) *ssa.Value {
                        sym = fn.Sym
                        break
                }
-               closure = s.getMethodClosure(fn)
+               // Make a name n2 for the function.
+               // fn.Sym might be sync.(*Mutex).Unlock.
+               // Make a PFUNC node out of that, then evaluate it.
+               // We get back an SSA value representing &sync.(*Mutex).Unlock·f.
+               // We can then pass that to defer or go.
+               n2 := newnamel(fn.Pos, fn.Sym)
+               n2.Name.Curfn = s.curfn
+               n2.SetClass(PFUNC)
+               // n2.Sym already existed, so it's already marked as a function.
+               n2.Pos = fn.Pos
+               n2.Type = types.Types[TUINT8] // dummy type for a static closure. Could use runtime.funcval if we had it.
+               closure = s.expr(n2)
                // Note: receiver is already present in n.Rlist, so we don't
                // want to set it here.
        case OCALLINTER:
                if fn.Op != ODOTINTER {
                        s.Fatalf("OCALLINTER: n.Left not an ODOTINTER: %v", fn.Op)
                }
-               var iclosure *ssa.Value
-               iclosure, rcvr = s.getClosureAndRcvr(fn)
+               i := s.expr(fn.Left)
+               itab := s.newValue1(ssa.OpITab, types.Types[TUINTPTR], i)
+               s.nilCheck(itab)
+               itabidx := fn.Xoffset + 2*int64(Widthptr) + 8 // offset of fun field in runtime.itab
+               itab = s.newValue1I(ssa.OpOffPtr, s.f.Config.Types.UintptrPtr, itabidx, itab)
                if k == callNormal {
-                       codeptr = s.load(types.Types[TUINTPTR], iclosure)
+                       codeptr = s.load(types.Types[TUINTPTR], itab)
                } else {
-                       closure = iclosure
+                       closure = itab
                }
+               rcvr = s.newValue1(ssa.OpIData, types.Types[TUINTPTR], i)
        }
        dowidth(fn.Type)
        stksize := fn.Type.ArgWidth() // includes receiver, args, and results
@@ -4277,22 +3847,18 @@ func (s *state) call(n *Node, k callKind) *ssa.Value {
                        s.constInt32(types.Types[TUINT32], int32(stksize)))
                // 1: started, set in deferprocStack
                // 2: heap, set in deferprocStack
-               // 3: openDefer
-               // 4: sp, set in deferprocStack
-               // 5: pc, set in deferprocStack
-               // 6: fn
+               // 3: sp, set in deferprocStack
+               // 4: pc, set in deferprocStack
+               // 5: fn
                s.store(closure.Type,
-                       s.newValue1I(ssa.OpOffPtr, closure.Type.PtrTo(), t.FieldOff(6), addr),
+                       s.newValue1I(ssa.OpOffPtr, closure.Type.PtrTo(), t.FieldOff(5), addr),
                        closure)
-               // 7: panic, set in deferprocStack
-               // 8: link, set in deferprocStack
-               // 9: framepc
-               // 10: varp
-               // 11: fd
+               // 6: panic, set in deferprocStack
+               // 7: link, set in deferprocStack
 
                // Then, store all the arguments of the defer call.
                ft := fn.Type
-               off := t.FieldOff(12)
+               off := t.FieldOff(8)
                args := n.Rlist.Slice()
 
                // Set receiver (for interface calls). Always a pointer.
@@ -4407,44 +3973,6 @@ func (s *state) call(n *Node, k callKind) *ssa.Value {
        return s.constOffPtrSP(types.NewPtr(fp.Type), fp.Offset+Ctxt.FixedFrameSize())
 }
 
-// maybeNilCheckClosure checks if a nil check of a closure is needed in some
-// architecture-dependent situations and, if so, emits the nil check.
-func (s *state) maybeNilCheckClosure(closure *ssa.Value, k callKind) {
-       if thearch.LinkArch.Family == sys.Wasm || objabi.GOOS == "aix" && k != callGo {
-               // On AIX, the closure needs to be verified as fn can be nil, except if it's a call go. This needs to be handled by the runtime to have the "go of nil func value" error.
-               // TODO(neelance): On other architectures this should be eliminated by the optimization steps
-               s.nilCheck(closure)
-       }
-}
-
-// getMethodClosure returns a value representing the closure for a method call
-func (s *state) getMethodClosure(fn *Node) *ssa.Value {
-       // Make a name n2 for the function.
-       // fn.Sym might be sync.(*Mutex).Unlock.
-       // Make a PFUNC node out of that, then evaluate it.
-       // We get back an SSA value representing &sync.(*Mutex).Unlock·f.
-       // We can then pass that to defer or go.
-       n2 := newnamel(fn.Pos, fn.Sym)
-       n2.Name.Curfn = s.curfn
-       n2.SetClass(PFUNC)
-       // n2.Sym already existed, so it's already marked as a function.
-       n2.Pos = fn.Pos
-       n2.Type = types.Types[TUINT8] // dummy type for a static closure. Could use runtime.funcval if we had it.
-       return s.expr(n2)
-}
-
-// getClosureAndRcvr returns values for the appropriate closure and receiver of an
-// interface call
-func (s *state) getClosureAndRcvr(fn *Node) (*ssa.Value, *ssa.Value) {
-       i := s.expr(fn.Left)
-       itab := s.newValue1(ssa.OpITab, types.Types[TUINTPTR], i)
-       s.nilCheck(itab)
-       itabidx := fn.Xoffset + 2*int64(Widthptr) + 8 // offset of fun field in runtime.itab
-       closure := s.newValue1I(ssa.OpOffPtr, s.f.Config.Types.UintptrPtr, itabidx, itab)
-       rcvr := s.newValue1(ssa.OpIData, types.Types[TUINTPTR], i)
-       return closure, rcvr
-}
-
 // etypesign returns the signed-ness of e, for integer/pointer etypes.
 // -1 means signed, +1 means unsigned, 0 means non-integer/non-pointer.
 func etypesign(e types.EType) int8 {
@@ -5618,16 +5146,6 @@ func (s *state) addNamedValue(n *Node, v *ssa.Value) {
        s.f.NamedValues[loc] = append(values, v)
 }
 
-// Generate a disconnected call to a runtime routine and a return.
-func gencallret(pp *Progs, sym *obj.LSym) *obj.Prog {
-       p := pp.Prog(obj.ACALL)
-       p.To.Type = obj.TYPE_MEM
-       p.To.Name = obj.NAME_EXTERN
-       p.To.Sym = sym
-       p = pp.Prog(obj.ARET)
-       return p
-}
-
 // Branch is an unresolved branch.
 type Branch struct {
        P *obj.Prog  // branch instruction
@@ -5663,11 +5181,6 @@ type SSAGenState struct {
 
        // wasm: The number of values on the WebAssembly stack. This is only used as a safeguard.
        OnWasmStackSkipped int
-
-       // Liveness index for the first function call in the final defer exit code
-       // path that we generated. All defer functions and args should be live at
-       // this point. This will be used to set the liveness for the deferreturn.
-       lastDeferLiveness LivenessIndex
 }
 
 // Prog appends a new Prog.
@@ -5795,17 +5308,6 @@ func genssa(f *ssa.Func, pp *Progs) {
        s.livenessMap = liveness(e, f, pp)
        emitStackObjects(e, pp)
 
-       openDeferInfo := e.curfn.Func.lsym.Func.OpenCodedDeferInfo
-       if openDeferInfo != nil {
-               // This function uses open-coded defers -- write out the funcdata
-               // info that we computed at the end of genssa.
-               p := pp.Prog(obj.AFUNCDATA)
-               Addrconst(&p.From, objabi.FUNCDATA_OpenCodedDeferInfo)
-               p.To.Type = obj.TYPE_MEM
-               p.To.Name = obj.NAME_EXTERN
-               p.To.Sym = openDeferInfo
-       }
-
        // Remember where each block starts.
        s.bstart = make([]*obj.Prog, f.NumBlocks())
        s.pp = pp
@@ -5870,12 +5372,6 @@ func genssa(f *ssa.Func, pp *Progs) {
                        // Attach this safe point to the next
                        // instruction.
                        s.pp.nextLive = s.livenessMap.Get(v)
-
-                       // Remember the liveness index of the first defer call of
-                       // the last defer exit
-                       if v.Block.Func.LastDeferExit != nil && v == v.Block.Func.LastDeferExit {
-                               s.lastDeferLiveness = s.pp.nextLive
-                       }
                        switch v.Op {
                        case ssa.OpInitMem:
                                // memory arg needs no code
@@ -5959,13 +5455,6 @@ func genssa(f *ssa.Func, pp *Progs) {
                // nop (which will never execute) after the call.
                thearch.Ginsnop(pp)
        }
-       if openDeferInfo != nil {
-               // When doing open-coded defers, generate a disconnected call to
-               // deferreturn and a return. This will be used to during panic
-               // recovery to unwind the stack and return back to the runtime.
-               s.pp.nextLive = s.lastDeferLiveness
-               gencallret(pp, Deferreturn)
-       }
 
        if inlMarks != nil {
                // We have some inline marks. Try to find other instructions we're
index e0137acfb7d0b9081d2c1ce428148557fb3d28e5..98903100fc0ccbe72426ec13a573218588d85521 100644 (file)
@@ -491,9 +491,7 @@ type Func struct {
 
        Pragma syntax.Pragma // go:xxx function annotations
 
-       flags      bitset16
-       numDefers  int // number of defer calls in the function
-       numReturns int // number of explicit returns in the function
+       flags bitset16
 
        // nwbrCalls records the LSyms of functions called by this
        // function for go:nowritebarrierrec analysis. Only filled in
@@ -529,37 +527,34 @@ const (
        funcNeedctxt                  // function uses context register (has closure variables)
        funcReflectMethod             // function calls reflect.Type.Method or MethodByName
        funcIsHiddenClosure
-       funcHasDefer                 // contains a defer statement
-       funcNilCheckDisabled         // disable nil checks when compiling this function
-       funcInlinabilityChecked      // inliner has already determined whether the function is inlinable
-       funcExportInline             // include inline body in export data
-       funcInstrumentBody           // add race/msan instrumentation during SSA construction
-       funcOpenCodedDeferDisallowed // can't do open-coded defers
+       funcHasDefer            // contains a defer statement
+       funcNilCheckDisabled    // disable nil checks when compiling this function
+       funcInlinabilityChecked // inliner has already determined whether the function is inlinable
+       funcExportInline        // include inline body in export data
+       funcInstrumentBody      // add race/msan instrumentation during SSA construction
 )
 
-func (f *Func) Dupok() bool                    { return f.flags&funcDupok != 0 }
-func (f *Func) Wrapper() bool                  { return f.flags&funcWrapper != 0 }
-func (f *Func) Needctxt() bool                 { return f.flags&funcNeedctxt != 0 }
-func (f *Func) ReflectMethod() bool            { return f.flags&funcReflectMethod != 0 }
-func (f *Func) IsHiddenClosure() bool          { return f.flags&funcIsHiddenClosure != 0 }
-func (f *Func) HasDefer() bool                 { return f.flags&funcHasDefer != 0 }
-func (f *Func) NilCheckDisabled() bool         { return f.flags&funcNilCheckDisabled != 0 }
-func (f *Func) InlinabilityChecked() bool      { return f.flags&funcInlinabilityChecked != 0 }
-func (f *Func) ExportInline() bool             { return f.flags&funcExportInline != 0 }
-func (f *Func) InstrumentBody() bool           { return f.flags&funcInstrumentBody != 0 }
-func (f *Func) OpenCodedDeferDisallowed() bool { return f.flags&funcOpenCodedDeferDisallowed != 0 }
-
-func (f *Func) SetDupok(b bool)                    { f.flags.set(funcDupok, b) }
-func (f *Func) SetWrapper(b bool)                  { f.flags.set(funcWrapper, b) }
-func (f *Func) SetNeedctxt(b bool)                 { f.flags.set(funcNeedctxt, b) }
-func (f *Func) SetReflectMethod(b bool)            { f.flags.set(funcReflectMethod, b) }
-func (f *Func) SetIsHiddenClosure(b bool)          { f.flags.set(funcIsHiddenClosure, b) }
-func (f *Func) SetHasDefer(b bool)                 { f.flags.set(funcHasDefer, b) }
-func (f *Func) SetNilCheckDisabled(b bool)         { f.flags.set(funcNilCheckDisabled, b) }
-func (f *Func) SetInlinabilityChecked(b bool)      { f.flags.set(funcInlinabilityChecked, b) }
-func (f *Func) SetExportInline(b bool)             { f.flags.set(funcExportInline, b) }
-func (f *Func) SetInstrumentBody(b bool)           { f.flags.set(funcInstrumentBody, b) }
-func (f *Func) SetOpenCodedDeferDisallowed(b bool) { f.flags.set(funcOpenCodedDeferDisallowed, b) }
+func (f *Func) Dupok() bool               { return f.flags&funcDupok != 0 }
+func (f *Func) Wrapper() bool             { return f.flags&funcWrapper != 0 }
+func (f *Func) Needctxt() bool            { return f.flags&funcNeedctxt != 0 }
+func (f *Func) ReflectMethod() bool       { return f.flags&funcReflectMethod != 0 }
+func (f *Func) IsHiddenClosure() bool     { return f.flags&funcIsHiddenClosure != 0 }
+func (f *Func) HasDefer() bool            { return f.flags&funcHasDefer != 0 }
+func (f *Func) NilCheckDisabled() bool    { return f.flags&funcNilCheckDisabled != 0 }
+func (f *Func) InlinabilityChecked() bool { return f.flags&funcInlinabilityChecked != 0 }
+func (f *Func) ExportInline() bool        { return f.flags&funcExportInline != 0 }
+func (f *Func) InstrumentBody() bool      { return f.flags&funcInstrumentBody != 0 }
+
+func (f *Func) SetDupok(b bool)               { f.flags.set(funcDupok, b) }
+func (f *Func) SetWrapper(b bool)             { f.flags.set(funcWrapper, b) }
+func (f *Func) SetNeedctxt(b bool)            { f.flags.set(funcNeedctxt, b) }
+func (f *Func) SetReflectMethod(b bool)       { f.flags.set(funcReflectMethod, b) }
+func (f *Func) SetIsHiddenClosure(b bool)     { f.flags.set(funcIsHiddenClosure, b) }
+func (f *Func) SetHasDefer(b bool)            { f.flags.set(funcHasDefer, b) }
+func (f *Func) SetNilCheckDisabled(b bool)    { f.flags.set(funcNilCheckDisabled, b) }
+func (f *Func) SetInlinabilityChecked(b bool) { f.flags.set(funcInlinabilityChecked, b) }
+func (f *Func) SetExportInline(b bool)        { f.flags.set(funcExportInline, b) }
+func (f *Func) SetInstrumentBody(b bool)      { f.flags.set(funcInstrumentBody, b) }
 
 func (f *Func) setWBPos(pos src.XPos) {
        if Debug_wb != 0 {
index b064e7d71c92227c6a5386e1a1e6f484b04a4496..39d1ab689d276c89386c5e074cbaa98adf34f38d 100644 (file)
@@ -213,6 +213,7 @@ func walkstmt(n *Node) *Node {
                yyerror("case statement out of place")
 
        case ODEFER:
+               Curfn.Func.SetHasDefer(true)
                fallthrough
        case OGO:
                switch n.Left.Op {
index 88af7a6f4afe1aa624750e6c34a674984bcd4ad9..6b9bcedadbfc66b757aaf977a66f4740b2574e6a 100644 (file)
@@ -170,11 +170,6 @@ func elimDeadAutosGeneric(f *Func) {
                        return
                case OpVarLive:
                        // Don't delete the auto if it needs to be kept alive.
-
-                       // We depend on this check to keep the autotmp stack slots
-                       // for open-coded defers from being removed (since they
-                       // may not be used by the inline code, but will be used by
-                       // panic processing).
                        n, ok := v.Aux.(GCNode)
                        if !ok || n.StorageClass() != ClassAuto {
                                return
index 332e201899747c70bc55edbd0f816d730cb3fbd6..cdd5161913c5e19b3bc33e412420f64015a81075 100644 (file)
@@ -32,16 +32,8 @@ type Func struct {
        Type   *types.Type // type signature of the function.
        Blocks []*Block    // unordered set of all basic blocks (note: not indexable by ID)
        Entry  *Block      // the entry basic block
-
-       // If we are using open-coded defers, this is the first call to a deferred
-       // function in the final defer exit sequence that we generated. This call
-       // should be after all defer statements, and will have all args, etc. of
-       // all defer calls as live. The liveness info of this call will be used
-       // for the deferreturn/ret segment generated for functions with open-coded
-       // defers.
-       LastDeferExit *Value
-       bid           idAlloc // block ID allocator
-       vid           idAlloc // value ID allocator
+       bid    idAlloc     // block ID allocator
+       vid    idAlloc     // value ID allocator
 
        // Given an environment variable used for debug hash match,
        // what file (if any) receives the yes/no logging?
index 468e9402eeb1d23d4960ebc9597e3b4a64eaf2f2..1c101bfc27119cc819492884a382b8f1d1f880c8 100644 (file)
@@ -405,11 +405,10 @@ type FuncInfo struct {
        dwarfAbsFnSym      *LSym
        dwarfDebugLinesSym *LSym
 
-       GCArgs             *LSym
-       GCLocals           *LSym
-       GCRegs             *LSym
-       StackObjects       *LSym
-       OpenCodedDeferInfo *LSym
+       GCArgs       *LSym
+       GCLocals     *LSym
+       GCRegs       *LSym
+       StackObjects *LSym
 }
 
 type InlMark struct {
index 08b75eb9fed2df59a3677b97ad89fc1fe4d15a05..addbd2ac88b00b99fd863ce8c9c151e1c9673a93 100644 (file)
@@ -15,12 +15,11 @@ const (
        PCDATA_StackMapIndex = 1
        PCDATA_InlTreeIndex  = 2
 
-       FUNCDATA_ArgsPointerMaps    = 0
-       FUNCDATA_LocalsPointerMaps  = 1
-       FUNCDATA_RegPointerMaps     = 2
-       FUNCDATA_StackObjects       = 3
-       FUNCDATA_InlTree            = 4
-       FUNCDATA_OpenCodedDeferInfo = 5
+       FUNCDATA_ArgsPointerMaps   = 0
+       FUNCDATA_LocalsPointerMaps = 1
+       FUNCDATA_RegPointerMaps    = 2
+       FUNCDATA_StackObjects      = 3
+       FUNCDATA_InlTree           = 4
 
        // ArgsSizeUnknown is set in Func.argsize to mark all functions
        // whose argument size is unknown (C vararg functions, and
index 487f009830731ab8829eb5cf77663ce2992333a5..c13c3cb45894d5595fe5efce5c4f9592cf0bd8b7 100644 (file)
@@ -85,12 +85,6 @@ func GetFuncID(name, file string) FuncID {
                return FuncID_panicwrap
        case "runtime.handleAsyncEvent":
                return FuncID_handleAsyncEvent
-       case "runtime.deferreturn":
-               // Don't show in the call stack (used when invoking defer functions)
-               return FuncID_wrapper
-       case "runtime.runOpenDeferFrame":
-               // Don't show in the call stack (used when invoking defer functions)
-               return FuncID_wrapper
        }
        if file == "<autogenerated>" {
                return FuncID_wrapper
index 7320dbf365fc87a867e81d7d1c3411ba7b6823ff..62ab0398a6653407859428a2d750214dac6d127c 100644 (file)
@@ -18,7 +18,7 @@ const (
 )
 
 // Initialize StackGuard and StackLimit according to target system.
-var StackGuard = 896*stackGuardMultiplier() + StackSystem
+var StackGuard = 880*stackGuardMultiplier() + StackSystem
 var StackLimit = StackGuard - StackSystem - StackSmall
 
 // stackGuardMultiplier returns a multiplier to apply to the default
index 3d7b42b18712993d79551b10817c1a6c3edbb004..d9904f90931c6ef7be73056b89450c43641bd73c 100644 (file)
@@ -11,7 +11,6 @@ import (
        "cmd/internal/sys"
        "cmd/link/internal/sym"
        "encoding/binary"
-       "fmt"
        "log"
        "os"
        "path/filepath"
@@ -256,23 +255,13 @@ func (ctxt *Link) pclntab() {
                        }
                        if r.Type.IsDirectJump() && r.Sym != nil && r.Sym.Name == "runtime.deferreturn" {
                                if ctxt.Arch.Family == sys.Wasm {
-                                       deferreturn = lastWasmAddr - 1
+                                       deferreturn = lastWasmAddr
                                } else {
                                        // Note: the relocation target is in the call instruction, but
                                        // is not necessarily the whole instruction (for instance, on
                                        // x86 the relocation applies to bytes [1:5] of the 5 byte call
                                        // instruction).
                                        deferreturn = uint32(r.Off)
-                                       switch ctxt.Arch.Family {
-                                       case sys.AMD64, sys.I386, sys.MIPS, sys.MIPS64, sys.RISCV64:
-                                               deferreturn--
-                                       case sys.PPC64, sys.ARM, sys.ARM64:
-                                               // no change
-                                       case sys.S390X:
-                                               deferreturn -= 2
-                                       default:
-                                               panic(fmt.Sprint("Unhandled architecture:", ctxt.Arch.Family))
-                                       }
                                }
                                break // only need one
                        }
index b4236a52399da96aada23fed2a0954292dc7fc91..d686a8a476862f963fb33e57264034f8fdcd1377 100644 (file)
@@ -498,8 +498,7 @@ func (ctxt *Link) symtab() {
                case strings.HasPrefix(s.Name, "gcargs."),
                        strings.HasPrefix(s.Name, "gclocals."),
                        strings.HasPrefix(s.Name, "gclocals·"),
-                       strings.HasPrefix(s.Name, "inltree."),
-                       strings.HasSuffix(s.Name, ".opendefer"):
+                       strings.HasPrefix(s.Name, "inltree."):
                        s.Type = sym.SGOFUNC
                        s.Attr |= sym.AttrNotInSymbolTable
                        s.Outer = symgofunc
index cd1421ba910f15085f39bea6a6b9342c9413325a..fcfd10deffe726d0ad267924aa1373ae95b87d3c 100644 (file)
@@ -5,7 +5,6 @@
 package runtime_test
 
 import (
-       "internal/race"
        "reflect"
        "runtime"
        "strings"
@@ -13,19 +12,19 @@ import (
 )
 
 func f1(pan bool) []uintptr {
-       return f2(pan) // line 16
+       return f2(pan) // line 15
 }
 
 func f2(pan bool) []uintptr {
-       return f3(pan) // line 20
+       return f3(pan) // line 19
 }
 
 func f3(pan bool) []uintptr {
        if pan {
-               panic("f3") // line 25
+               panic("f3") // line 24
        }
        ret := make([]uintptr, 20)
-       return ret[:runtime.Callers(0, ret)] // line 28
+       return ret[:runtime.Callers(0, ret)] // line 27
 }
 
 func testCallers(t *testing.T, pcs []uintptr, pan bool) {
@@ -49,16 +48,16 @@ func testCallers(t *testing.T, pcs []uintptr, pan bool) {
 
        var f3Line int
        if pan {
-               f3Line = 25
+               f3Line = 24
        } else {
-               f3Line = 28
+               f3Line = 27
        }
        want := []struct {
                name string
                line int
        }{
-               {"f1", 16},
-               {"f2", 20},
+               {"f1", 15},
+               {"f2", 19},
                {"f3", f3Line},
        }
        for _, w := range want {
@@ -189,36 +188,3 @@ func TestCallersDivZeroPanic(t *testing.T) {
                t.Fatal("did not see divide-by-sizer panic")
        }
 }
-
-// This test will have a slightly different callstack if non-open-coded defers are
-// called (e.g. if race checks enabled), because of a difference in the way the
-// defer function is invoked.
-func TestCallersDeferNilFuncPanic(t *testing.T) {
-       if race.Enabled {
-               t.Skip("skipping TestCallersDeferNilFuncPanic under race detector")
-       }
-       // Make sure we don't have any extra frames on the stack (due to
-       // open-coded defer processing)
-       state := 1
-       want := []string{"runtime.Callers", "runtime_test.TestCallersDeferNilFuncPanic.func1",
-               "runtime.gopanic", "runtime.panicmem", "runtime.sigpanic",
-               "runtime_test.TestCallersDeferNilFuncPanic"}
-
-       defer func() {
-               if r := recover(); r == nil {
-                       t.Fatal("did not panic")
-               }
-               pcs := make([]uintptr, 20)
-               pcs = pcs[:runtime.Callers(0, pcs)]
-               testCallersEqual(t, pcs, want)
-               if state == 1 {
-                       t.Fatal("nil defer func panicked at defer time rather than function exit time")
-               }
-
-       }()
-       var f func()
-       defer f()
-       // Use the value of 'state' to make sure nil defer func f causes panic at
-       // function exit, rather than at the defer statement.
-       state = 2
-}
index d830fc591f0a4d3f619ba0639c7d12f03bae0cb1..0d3e8e9d63270d8c7f428cc8d84021486965044b 100644 (file)
@@ -15,11 +15,11 @@ import (
 // unconditional panic (hence no return from the function)
 func TestUnconditionalPanic(t *testing.T) {
        defer func() {
-               if recover() != "testUnconditional" {
+               if recover() == nil {
                        t.Fatal("expected unconditional panic")
                }
        }()
-       panic("testUnconditional")
+       panic("panic should be recovered")
 }
 
 var glob int = 3
@@ -30,7 +30,7 @@ func TestOpenAndNonOpenDefers(t *testing.T) {
        for {
                // Non-open defer because in a loop
                defer func(n int) {
-                       if recover() != "testNonOpenDefer" {
+                       if recover() == nil {
                                t.Fatal("expected testNonOpen panic")
                        }
                }(3)
@@ -45,7 +45,7 @@ func TestOpenAndNonOpenDefers(t *testing.T) {
 //go:noinline
 func testOpen(t *testing.T, arg int) {
        defer func(n int) {
-               if recover() != "testOpenDefer" {
+               if recover() == nil {
                        t.Fatal("expected testOpen panic")
                }
        }(4)
@@ -61,7 +61,7 @@ func TestNonOpenAndOpenDefers(t *testing.T) {
        for {
                // Non-open defer because in a loop
                defer func(n int) {
-                       if recover() != "testNonOpenDefer" {
+                       if recover() == nil {
                                t.Fatal("expected testNonOpen panic")
                        }
                }(3)
@@ -80,7 +80,7 @@ func TestConditionalDefers(t *testing.T) {
        list = make([]int, 0, 10)
 
        defer func() {
-               if recover() != "testConditional" {
+               if recover() == nil {
                        t.Fatal("expected panic")
                }
                want := []int{4, 2, 1}
@@ -106,7 +106,7 @@ func testConditionalDefers(n int) {
                        defer doappend(4)
                }
        }
-       panic("testConditional")
+       panic("test")
 }
 
 // Test that there is no compile-time or run-time error if an open-coded defer
@@ -174,52 +174,3 @@ func TestRecoverMatching(t *testing.T) {
        }()
        panic("panic1")
 }
-
-type nonSSAable [128]byte
-
-type bigStruct struct {
-       x, y, z, w, p, q int64
-}
-
-func mknonSSAable() nonSSAable {
-       globint1++
-       return nonSSAable{0, 0, 0, 0, 5}
-}
-
-var globint1, globint2 int
-
-//go:noinline
-func sideeffect(n int64) int64 {
-       globint2++
-       return n
-}
-
-// Test that nonSSAable arguments to defer are handled correctly and only evaluated once.
-func TestNonSSAableArgs(t *testing.T) {
-       globint1 = 0
-       globint2 = 0
-       var save1 byte
-       var save2 int64
-
-       defer func() {
-               if globint1 != 1 {
-                       t.Fatal(fmt.Sprintf("globint1:  wanted: 1, got %v", globint1))
-               }
-               if save1 != 5 {
-                       t.Fatal(fmt.Sprintf("save1:  wanted: 5, got %v", save1))
-               }
-               if globint2 != 1 {
-                       t.Fatal(fmt.Sprintf("globint2:  wanted: 1, got %v", globint2))
-               }
-               if save2 != 2 {
-                       t.Fatal(fmt.Sprintf("save2:  wanted: 2, got %v", save2))
-               }
-       }()
-
-       defer func(n nonSSAable) {
-               save1 = n[4]
-       }(mknonSSAable())
-       defer func(b bigStruct) {
-               save2 = b.y
-       }(bigStruct{1, 2, 3, 4, 5, sideeffect(6)})
-}
index 0fb50ddfba5b37af43975b0deaa02d9ec1a96156..d9a35c51a06e887c7147e53d5a3028292212e311 100644 (file)
@@ -17,7 +17,6 @@
 #define FUNCDATA_RegPointerMaps 2
 #define FUNCDATA_StackObjects 3
 #define FUNCDATA_InlTree 4
-#define FUNCDATA_OpenCodedDeferInfo 5 /* info for func with open-coded defers */
 
 // Pseudo-assembly statements.
 
index 291a660b3e06c01ebb8f9d7d5661f5fb210e8c31..5f33cd7c0c394f738459d8aaa6d359dd5e648743 100644 (file)
@@ -10,19 +10,6 @@ import (
        "unsafe"
 )
 
-// We have two different ways of doing defers. The older way involves creating a
-// defer record at the time that a defer statement is executing and adding it to a
-// defer chain. This chain is inspected by the deferreturn call at all function
-// exits in order to run the appropriate defer calls. A cheaper way (which we call
-// open-coded defers) is used for functions in which no defer statements occur in
-// loops. In that case, we simply store the defer function/arg information into
-// specific stack slots at the point of each defer statement, as well as setting a
-// bit in a bitmask. At each function exit, we add inline code to directly make
-// the appropriate defer calls based on the bitmask and fn/arg information stored
-// on the stack. During panic/Goexit processing, the appropriate defer calls are
-// made using extra funcdata info that indicates the exact stack slots that
-// contain the bitmask and defer fn/args.
-
 // Check to make sure we can really generate a panic. If the panic
 // was generated from the runtime, or from inside malloc, then convert
 // to a throw of msg.
@@ -276,24 +263,19 @@ func deferprocStack(d *_defer) {
        // are initialized here.
        d.started = false
        d.heap = false
-       d.openDefer = false
        d.sp = getcallersp()
        d.pc = getcallerpc()
-       d.framepc = 0
-       d.varp = 0
        // The lines below implement:
        //   d.panic = nil
-       //   d.fp = nil
        //   d.link = gp._defer
        //   gp._defer = d
-       // But without write barriers. The first three are writes to
+       // But without write barriers. The first two are writes to
        // the stack so they don't need a write barrier, and furthermore
        // are to uninitialized memory, so they must not use a write barrier.
-       // The fourth write does not require a write barrier because we
+       // The third write does not require a write barrier because we
        // explicitly mark all the defer structures, so we don't need to
        // keep track of pointers to them with a write barrier.
        *(*uintptr)(unsafe.Pointer(&d._panic)) = 0
-       *(*uintptr)(unsafe.Pointer(&d.fd)) = 0
        *(*uintptr)(unsafe.Pointer(&d.link)) = uintptr(unsafe.Pointer(gp._defer))
        *(*uintptr)(unsafe.Pointer(&gp._defer)) = uintptr(unsafe.Pointer(d))
 
@@ -481,12 +463,8 @@ func freedefer(d *_defer) {
        // started causing a nosplit stack overflow via typedmemmove.
        d.siz = 0
        d.started = false
-       d.openDefer = false
        d.sp = 0
        d.pc = 0
-       d.framepc = 0
-       d.varp = 0
-       d.fd = nil
        // d._panic and d.fn must be nil already.
        // If not, we would have called freedeferpanic or freedeferfn above,
        // both of which throw.
@@ -515,11 +493,9 @@ func freedeferfn() {
 // 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.
-//
-// Declared as nosplit, because the function should not be preempted once we start
-// modifying the caller's frame in order to reuse the frame to call the deferred
-// function.
-//
+// Cannot split the stack because we reuse the caller's frame to
+// call the deferred function.
+
 // The single argument isn't actually used - it just has its address
 // taken so it can be matched against pending defers.
 //go:nosplit
@@ -533,15 +509,6 @@ func deferreturn(arg0 uintptr) {
        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)
-               return
-       }
 
        // Moving arguments around.
        //
@@ -577,8 +544,6 @@ func Goexit() {
        // This code is similar to gopanic, see that implementation
        // for detailed comments.
        gp := getg()
-       addOneOpenDeferFrame(gp, getcallerpc(), unsafe.Pointer(getcallersp()))
-
        for {
                d := gp._defer
                if d == nil {
@@ -589,26 +554,13 @@ func Goexit() {
                                d._panic.aborted = true
                                d._panic = nil
                        }
-                       if !d.openDefer {
-                               d.fn = nil
-                               gp._defer = d.link
-                               freedefer(d)
-                               continue
-                       }
+                       d.fn = nil
+                       gp._defer = d.link
+                       freedefer(d)
+                       continue
                }
                d.started = true
-               if d.openDefer {
-                       done := runOpenDeferFrame(gp, d)
-                       if !done {
-                               // We should always run all defers in the frame,
-                               // since there is no panic associated with this
-                               // defer that can be recovered.
-                               throw("unfinished open-coded defers in Goexit")
-                       }
-                       addOneOpenDeferFrame(gp, 0, nil)
-               } else {
-                       reflectcall(nil, unsafe.Pointer(d.fn), deferArgs(d), uint32(d.siz), uint32(d.siz))
-               }
+               reflectcall(nil, unsafe.Pointer(d.fn), deferArgs(d), uint32(d.siz), uint32(d.siz))
                if gp._defer != d {
                        throw("bad defer entry in Goexit")
                }
@@ -655,182 +607,6 @@ func printpanics(p *_panic) {
        print("\n")
 }
 
-// addOneOpenDeferFrame scans the stack for the first frame (if any) with
-// open-coded defers and if it finds one, adds a single record to the defer chain
-// for that frame. If sp is non-nil, it starts the stack scan from the frame
-// specified by sp. If sp is nil, it uses the sp from the current defer record
-// (which has just been finished). Hence, it continues the stack scan from the
-// frame of the defer that just finished. It skips any frame that already has an
-// open-coded _defer record, which would have been been created from a previous
-// (unrecovered) panic.
-//
-// Note: All entries of the defer chain (including this new open-coded entry) have
-// their pointers (including sp) adjusted properly if the stack moves while
-// running deferred functions. Also, it is safe to pass in the sp arg (which is
-// the direct result of calling getcallersp()), because all pointer variables
-// (including arguments) are adjusted as needed during stack copies.
-func addOneOpenDeferFrame(gp *g, pc uintptr, sp unsafe.Pointer) {
-       var prevDefer *_defer
-       if sp == nil {
-               prevDefer = gp._defer
-               pc = prevDefer.framepc
-               sp = unsafe.Pointer(prevDefer.sp)
-       }
-       systemstack(func() {
-               gentraceback(pc, uintptr(sp), 0, gp, 0, nil, 0x7fffffff,
-                       func(frame *stkframe, unused unsafe.Pointer) bool {
-                               if prevDefer != nil && prevDefer.sp == frame.sp {
-                                       // Skip the frame for the previous defer that
-                                       // we just finished (and was used to set
-                                       // where we restarted the stack scan)
-                                       return true
-                               }
-                               f := frame.fn
-                               fd := funcdata(f, _FUNCDATA_OpenCodedDeferInfo)
-                               if fd == nil {
-                                       return true
-                               }
-                               // Insert the open defer record in the
-                               // chain, in order sorted by sp.
-                               d := gp._defer
-                               var prev *_defer
-                               for d != nil {
-                                       dsp := d.sp
-                                       if frame.sp < dsp {
-                                               break
-                                       }
-                                       if frame.sp == dsp {
-                                               if !d.openDefer {
-                                                       throw("duplicated defer entry")
-                                               }
-                                               return true
-                                       }
-                                       prev = d
-                                       d = d.link
-                               }
-                               if frame.fn.deferreturn == 0 {
-                                       throw("missing deferreturn")
-                               }
-
-                               maxargsize, _ := readvarintUnsafe(fd)
-                               d1 := newdefer(int32(maxargsize))
-                               d1.openDefer = true
-                               d1._panic = nil
-                               // These are the pc/sp to set after we've
-                               // run a defer in this frame that did a
-                               // recover. We return to a special
-                               // deferreturn that runs any remaining
-                               // defers and then returns from the
-                               // function.
-                               d1.pc = frame.fn.entry + uintptr(frame.fn.deferreturn)
-                               d1.varp = frame.varp
-                               d1.fd = fd
-                               // Save the SP/PC associated with current frame,
-                               // so we can continue stack trace later if needed.
-                               d1.framepc = frame.pc
-                               d1.sp = frame.sp
-                               d1.link = d
-                               if prev == nil {
-                                       gp._defer = d1
-                               } else {
-                                       prev.link = d1
-                               }
-                               // Stop stack scanning after adding one open defer record
-                               return false
-                       },
-                       nil, 0)
-       })
-}
-
-// readvarintUnsafe reads the uint32 in varint format starting at fd, and returns the
-// uint32 and a pointer to the byte following the varint.
-//
-// There is a similar function runtime.readvarint, which takes a slice of bytes,
-// rather than an unsafe pointer. These functions are duplicated, because one of
-// the two use cases for the functions would get slower if the functions were
-// combined.
-func readvarintUnsafe(fd unsafe.Pointer) (uint32, unsafe.Pointer) {
-       var r uint32
-       var shift int
-       for {
-               b := *(*uint8)((unsafe.Pointer(fd)))
-               fd = add(fd, unsafe.Sizeof(b))
-               if b < 128 {
-                       return r + uint32(b)<<shift, fd
-               }
-               r += ((uint32(b) &^ 128) << shift)
-               shift += 7
-               if shift > 28 {
-                       panic("Bad varint")
-               }
-       }
-}
-
-// runOpenDeferFrame runs the active open-coded defers in the frame specified by
-// d. It normally processes all active defers in the frame, but stops immediately
-// if a defer does a successful recover. It returns true if there are no
-// remaining defers to run in the frame.
-func runOpenDeferFrame(gp *g, d *_defer) bool {
-       done := true
-       fd := d.fd
-
-       // Skip the maxargsize
-       _, fd = readvarintUnsafe(fd)
-       deferBitsOffset, fd := readvarintUnsafe(fd)
-       nDefers, fd := readvarintUnsafe(fd)
-       deferBits := *(*uint8)(unsafe.Pointer(d.varp - uintptr(deferBitsOffset)))
-
-       for i := int(nDefers) - 1; i >= 0; i-- {
-               // read the funcdata info for this defer
-               var argWidth, closureOffset, hasRcvrOffset, rcvrOffset, nArgs uint32
-               argWidth, fd = readvarintUnsafe(fd)
-               closureOffset, fd = readvarintUnsafe(fd)
-               hasRcvrOffset, fd = readvarintUnsafe(fd)
-               if hasRcvrOffset > 0 {
-                       rcvrOffset, fd = readvarintUnsafe(fd)
-               }
-               nArgs, fd = readvarintUnsafe(fd)
-               if deferBits&(1<<i) == 0 {
-                       for j := uint32(0); j < nArgs; j++ {
-                               _, fd = readvarintUnsafe(fd)
-                               _, fd = readvarintUnsafe(fd)
-                               _, fd = readvarintUnsafe(fd)
-                       }
-                       continue
-               }
-               closure := *(**funcval)(unsafe.Pointer(d.varp - uintptr(closureOffset)))
-               d.fn = closure
-               deferArgs := deferArgs(d)
-               if hasRcvrOffset > 0 {
-                       *(*unsafe.Pointer)(deferArgs) = *(*unsafe.Pointer)((unsafe.Pointer)((d.varp - uintptr(rcvrOffset))))
-               }
-               for j := uint32(0); j < nArgs; j++ {
-                       var argOffset, argLen, argCallOffset uint32
-                       argOffset, fd = readvarintUnsafe(fd)
-                       argLen, fd = readvarintUnsafe(fd)
-                       argCallOffset, fd = readvarintUnsafe(fd)
-                       memmove(unsafe.Pointer(uintptr(deferArgs)+uintptr(argCallOffset)),
-                               unsafe.Pointer(d.varp-uintptr(argOffset)),
-                               uintptr(argLen))
-               }
-               deferBits = deferBits &^ (1 << i)
-               *(*uint8)(unsafe.Pointer(d.varp - uintptr(deferBitsOffset))) = deferBits
-               if d._panic != nil {
-                       d._panic.argp = unsafe.Pointer(getargp(0))
-               }
-               reflectcall(nil, unsafe.Pointer(closure), deferArgs, argWidth, argWidth)
-               d.fn = nil
-               // These args are just a copy, so can be cleared immediately
-               memclrNoHeapPointers(deferArgs, uintptr(argWidth))
-               if d._panic != nil && d._panic.recovered {
-                       done = deferBits == 0
-                       break
-               }
-       }
-
-       return done
-}
-
 // The implementation of the predeclared function panic.
 func gopanic(e interface{}) {
        gp := getg()
@@ -870,10 +646,6 @@ func gopanic(e interface{}) {
 
        atomic.Xadd(&runningPanicDefers, 1)
 
-       // By calculating getcallerpc/getcallersp here, we avoid scanning the
-       // gopanic frame (stack scanning is slow...)
-       addOneOpenDeferFrame(gp, getcallerpc(), unsafe.Pointer(getcallersp()))
-
        for {
                d := gp._defer
                if d == nil {
@@ -887,16 +659,10 @@ func gopanic(e interface{}) {
                                d._panic.aborted = true
                        }
                        d._panic = nil
-                       if !d.openDefer {
-                               // For open-coded defers, we need to process the
-                               // defer again, in case there are any other defers
-                               // to call in the frame (not including the defer
-                               // call that caused the panic).
-                               d.fn = nil
-                               gp._defer = d.link
-                               freedefer(d)
-                               continue
-                       }
+                       d.fn = nil
+                       gp._defer = d.link
+                       freedefer(d)
+                       continue
                }
 
                // Mark defer as started, but keep on list, so that traceback
@@ -909,16 +675,8 @@ func gopanic(e interface{}) {
                // will find d in the list and will mark d._panic (this panic) aborted.
                d._panic = (*_panic)(noescape(unsafe.Pointer(&p)))
 
-               done := true
-               if d.openDefer {
-                       done = runOpenDeferFrame(gp, d)
-                       if done && !d._panic.recovered {
-                               addOneOpenDeferFrame(gp, 0, nil)
-                       }
-               } else {
-                       p.argp = unsafe.Pointer(getargp(0))
-                       reflectcall(nil, unsafe.Pointer(d.fn), deferArgs(d), uint32(d.siz), uint32(d.siz))
-               }
+               p.argp = unsafe.Pointer(getargp(0))
+               reflectcall(nil, unsafe.Pointer(d.fn), deferArgs(d), uint32(d.siz), uint32(d.siz))
                p.argp = nil
 
                // reflectcall did not panic. Remove d.
@@ -926,52 +684,18 @@ func gopanic(e interface{}) {
                        throw("bad defer entry in panic")
                }
                d._panic = nil
+               d.fn = nil
+               gp._defer = d.link
 
                // trigger shrinkage to test stack copy. See stack_test.go:TestStackPanic
                //GC()
 
                pc := d.pc
                sp := unsafe.Pointer(d.sp) // must be pointer so it gets adjusted during stack copy
-               if done {
-                       d.fn = nil
-                       gp._defer = d.link
-                       freedefer(d)
-               }
+               freedefer(d)
                if p.recovered {
                        atomic.Xadd(&runningPanicDefers, -1)
 
-                       if done {
-                               // Remove any remaining non-started, open-coded defer
-                               // entry after a recover (there's at most one, if we just
-                               // ran a non-open-coded defer), since the entry will
-                               // become out-dated and the defer will be executed
-                               // normally.
-                               d := gp._defer
-                               var prev *_defer
-                               for d != nil {
-                                       if d.openDefer {
-                                               if d.started {
-                                                       // This defer is started but we
-                                                       // are in the middle of a
-                                                       // defer-panic-recover inside of
-                                                       // it, so don't remove it or any
-                                                       // further defer entries
-                                                       break
-                                               }
-                                               if prev == nil {
-                                                       gp._defer = d.link
-                                               } else {
-                                                       prev.link = d.link
-                                               }
-                                               freedefer(d)
-                                               break
-                                       } else {
-                                               prev = d
-                                               d = d.link
-                                       }
-                               }
-                       }
-
                        gp._panic = p.link
                        // Aborted panics are marked but remain on the g.panic list.
                        // Remove them from the list.
@@ -1079,7 +803,7 @@ func recovery(gp *g) {
        }
 
        // Make the deferproc for this d return again,
-       // this time returning 1. The calling function will
+       // this time returning 1.  The calling function will
        // jump to the standard return epilogue.
        gp.sched.sp = sp
        gp.sched.pc = pc
index 20813d09eb27543788590cdfafa59d30c2864834..dd399e00a69d505f0adc61f417ad2d0d9739a38a 100644 (file)
@@ -701,7 +701,7 @@ type _func struct {
        nameoff int32   // function name
 
        args        int32  // in/out args size
-       deferreturn uint32 // offset of start of a deferreturn call instruction from entry, if any.
+       deferreturn uint32 // offset of a deferreturn block from entry, if any.
 
        pcsp      int32
        pcfile    int32
@@ -774,7 +774,7 @@ func extendRandom(r []byte, n int) {
 }
 
 // A _defer holds an entry on the list of deferred calls.
-// If you add a field here, add code to clear it in freedefer and deferProcStack
+// If you add a field here, add code to clear it in freedefer.
 // This struct must match the code in cmd/compile/internal/gc/reflect.go:deferstruct
 // and cmd/compile/internal/gc/ssa.go:(*state).call.
 // Some defers will be allocated on the stack and some on the heap.
@@ -785,27 +785,11 @@ type _defer struct {
        siz     int32 // includes both arguments and results
        started bool
        heap    bool
-       // openDefer indicates that this _defer is for a frame with open-coded
-       // defers. We have only one defer record for the entire frame (which may
-       // currently have 0, 1, or more defers active).
-       openDefer bool
-       sp        uintptr // sp at time of defer
-       pc        uintptr // pc at time of defer
-       fn        *funcval
-       _panic    *_panic // panic that is running defer
-       link      *_defer
-
-       // If openDefer is true, the fields below record values about the stack
-       // frame and associated function that has the open-coded defer(s). sp
-       // above will be the sp for the frame, and pc will be address of the
-       // deferreturn call in the function.
-       fd   unsafe.Pointer // funcdata for the function associated with the frame
-       varp uintptr        // value of varp for the stack frame
-       // framepc is the current pc associated with the stack frame. Together,
-       // with sp above (which is the sp associated with the stack frame),
-       // framepc/sp can be used as pc/sp pair to continue a stack trace via
-       // gentraceback().
-       framepc uintptr
+       sp      uintptr // sp at time of defer
+       pc      uintptr
+       fn      *funcval
+       _panic  *_panic // panic that is running defer
+       link    *_defer
 }
 
 // A _panic holds information about an active panic.
index a1946d3fcb8b47a3172c86ee9a2f37d3a9527412..ab7a03b2d1608edf554dfc6c93352e6992ddc4f4 100644 (file)
@@ -89,7 +89,7 @@ func BenchmarkDefer(b *testing.B) {
 }
 
 func defer1() {
-       func(x, y, z int) {
+       defer func(x, y, z int) {
                if recover() != nil || x != 1 || y != 2 || z != 3 {
                        panic("bad recover")
                }
index d72582e82e0dbe8c7616856c3dacdf18cb68106c..271b24c58aa2206edd0f12987792b60db391828a 100644 (file)
@@ -91,7 +91,7 @@ const (
 
        // The stack guard is a pointer this many bytes above the
        // bottom of the stack.
-       _StackGuard = 896*sys.StackGuardMultiplier + _StackSystem
+       _StackGuard = 880*sys.StackGuardMultiplier + _StackSystem
 
        // After a stack split check the SP is allowed to be this
        // many bytes below the stack guard. This saves an instruction
@@ -736,8 +736,6 @@ func adjustdefers(gp *g, adjinfo *adjustinfo) {
                adjustpointer(adjinfo, unsafe.Pointer(&d.sp))
                adjustpointer(adjinfo, unsafe.Pointer(&d._panic))
                adjustpointer(adjinfo, unsafe.Pointer(&d.link))
-               adjustpointer(adjinfo, unsafe.Pointer(&d.varp))
-               adjustpointer(adjinfo, unsafe.Pointer(&d.fd))
        }
 
        // Adjust defer argument blocks the same way we adjust active stack frames.
index e99b8cf669592f17492485df5cc57f0bd9344cb9..df6e02f62ad77fe51237f588d68971148dfa699e 100644 (file)
@@ -216,12 +216,11 @@ const (
        _PCDATA_StackMapIndex = 1
        _PCDATA_InlTreeIndex  = 2
 
-       _FUNCDATA_ArgsPointerMaps    = 0
-       _FUNCDATA_LocalsPointerMaps  = 1
-       _FUNCDATA_RegPointerMaps     = 2
-       _FUNCDATA_StackObjects       = 3
-       _FUNCDATA_InlTree            = 4
-       _FUNCDATA_OpenCodedDeferInfo = 5
+       _FUNCDATA_ArgsPointerMaps   = 0
+       _FUNCDATA_LocalsPointerMaps = 1
+       _FUNCDATA_RegPointerMaps    = 2
+       _FUNCDATA_StackObjects      = 3
+       _FUNCDATA_InlTree           = 4
 
        _ArgsSizeUnknown = -0x80000000
 )
diff --git a/test/defererrcheck.go b/test/defererrcheck.go
deleted file mode 100644 (file)
index 5b90e58..0000000
+++ /dev/null
@@ -1,86 +0,0 @@
-// errorcheck -0 -l -d=defer
-
-// Copyright 2019 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-// check that open-coded defers are used in expected situations
-
-package main
-
-import "fmt"
-
-var glob = 3
-
-func f1() {
-
-       for i := 0; i < 10; i++ {
-               fmt.Println("loop")
-       }
-       defer func() { // ERROR "open-coded defer in function f1"
-               fmt.Println("defer")
-       }()
-}
-
-func f2() {
-       for {
-               defer func() { // ERROR "heap-allocated defer in function f2"
-                       fmt.Println("defer1")
-               }()
-               if glob > 2 {
-                       break
-               }
-       }
-       defer func() { // ERROR "stack-allocated defer in function f2"
-               fmt.Println("defer2")
-       }()
-}
-
-func f3() {
-       defer func() { // ERROR "stack-allocated defer in function f3"
-               fmt.Println("defer2")
-       }()
-       for {
-               defer func() { // ERROR "heap-allocated defer in function f3"
-                       fmt.Println("defer1")
-               }()
-               if glob > 2 {
-                       break
-               }
-       }
-}
-
-func f4() {
-       defer func() { // ERROR "open-coded defer in function f4"
-               fmt.Println("defer")
-       }()
-label:
-       fmt.Println("goto loop")
-       if glob > 2 {
-               goto label
-       }
-}
-
-func f5() {
-label:
-       fmt.Println("goto loop")
-       defer func() { // ERROR "heap-allocated defer in function f5"
-               fmt.Println("defer")
-       }()
-       if glob > 2 {
-               goto label
-       }
-}
-
-func f6() {
-label:
-       fmt.Println("goto loop")
-       if glob > 2 {
-               goto label
-       }
-       // The current analysis doesn't end a backward goto loop, so this defer is
-       // considered to be inside a loop
-       defer func() { // ERROR "heap-allocated defer in function f6"
-               fmt.Println("defer")
-       }()
-}
index 32c397f4a99858fc1457ce00ef974047dad4ebba..b6e6d93f5f8fc14c947820e454c77d8153ff5fcd 100644 (file)
@@ -367,19 +367,16 @@ func f24() {
        m2[[2]string{"x", "y"}] = nil
 }
 
-// Non-open-coded defers should not cause autotmps.  (Open-coded defers do create extra autotmps).
+// defer should not cause spurious ambiguously live variables
+
 func f25(b bool) {
-       for i := 0; i < 2; i++ {
-               // Put in loop to make sure defer is not open-coded
-               defer g25()
-       }
+       defer g25()
        if b {
                return
        }
        var x string
        x = g14()
        printstring(x)
-       return
 }
 
 func g25()
@@ -420,8 +417,7 @@ func f27defer(b bool) {
                defer call27(func() { x++ }) // ERROR "stack object .autotmp_[0-9]+ struct \{"
        }
        defer call27(func() { x++ }) // ERROR "stack object .autotmp_[0-9]+ struct \{"
-       printnl()                    // ERROR "live at call to printnl: .autotmp_[0-9]+ .autotmp_[0-9]+"
-       return                       // ERROR "live at call to call27: .autotmp_[0-9]+"
+       printnl()
 }
 
 // and newproc (go) escapes to the heap
@@ -691,12 +687,12 @@ type R struct{ *T } // ERRORAUTO "live at entry to \(\*R\)\.Foo: \.this ptr" "li
 // In particular, at printint r must be live.
 func f41(p, q *int) (r *int) { // ERROR "live at entry to f41: p q$"
        r = p
-       defer func() {
+       defer func() { // ERROR "live at call to deferprocStack: q r$" "live at call to deferreturn: r$"
                recover()
        }()
-       printint(0) // ERROR "live at call to printint: q r .autotmp_[0-9]+$"
+       printint(0) // ERROR "live at call to printint: q r$"
        r = q
-       return // ERROR "live at call to f41.func1: r .autotmp_[0-9]+$"
+       return // ERROR "live at call to deferreturn: r$"
 }
 
 func f42() {
index 3b7e60599998dddae9f4aab0fff7eb6e6a26dd58..266e6077b1f23a025de063aa55ff0d882cb4ea8c 100644 (file)
@@ -309,17 +309,17 @@ TestCases:
                                name := m[1]
                                size, _ := strconv.Atoi(m[2])
 
-                               // The limit was originally 128 but is now 768 (896-128).
+                               // The limit was originally 128 but is now 752 (880-128).
                                // Instead of rewriting the test cases above, adjust
                                // the first stack frame to use up the extra bytes.
                                if i == 0 {
-                                       size += (896 - 128) - 128
+                                       size += (880 - 128) - 128
                                        // Noopt builds have a larger stackguard.
                                        // See ../src/cmd/dist/buildruntime.go:stackGuardMultiplier
                                        // This increase is included in objabi.StackGuard
                                        for _, s := range strings.Split(os.Getenv("GO_GCFLAGS"), " ") {
                                                if s == "-N" {
-                                                       size += 896
+                                                       size += 880
                                                }
                                        }
                                }