}
addr := s.addr(d)
- // Must match deferstruct() below and src/runtime/runtime2.go:_defer.
- // 0: heap, set in deferprocStack
- // 1: sp, set in deferprocStack
- // 2: pc, set in deferprocStack
- // 3: fn
s.store(closure.Type,
- s.newValue1I(ssa.OpOffPtr, closure.Type.PtrTo(), t.FieldOff(3), addr),
+ s.newValue1I(ssa.OpOffPtr, closure.Type.PtrTo(), t.FieldOff(deferStructFnField), addr),
closure)
- // 4: link, set in deferprocStack
// Call runtime.deferprocStack with pointer to _defer record.
ACArgs = append(ACArgs, types.Types[types.TUINTPTR])
return b
}
+var deferStructFnField = -1
+
// deferstruct makes a runtime._defer structure.
func deferstruct() *types.Type {
makefield := func(name string, typ *types.Type) *types.Field {
// (*state).call above.
fields := []*types.Field{
makefield("heap", types.Types[types.TBOOL]),
+ makefield("rangefunc", types.Types[types.TBOOL]),
makefield("sp", types.Types[types.TUINTPTR]),
makefield("pc", types.Types[types.TUINTPTR]),
// Note: the types here don't really matter. Defer structures
// so we make them uintptr type even though they are real pointers.
makefield("fn", types.Types[types.TUINTPTR]),
makefield("link", types.Types[types.TUINTPTR]),
+ makefield("head", types.Types[types.TUINTPTR]),
+ }
+ for i, f := range fields {
+ if f.Sym.Name == "fn" {
+ deferStructFnField = i
+ break
+ }
+ }
+ if deferStructFnField < 0 {
+ base.Fatalf("deferstruct has no fn field")
}
// build struct holding the above fields
// initialize them are not required. All defers must be manually scanned,
// and for heap defers, marked.
type _defer struct {
- heap bool
- sp uintptr // sp at time of defer
- pc uintptr // pc at time of defer
- fn func() // can be nil for open-coded defers
- link *_defer // next defer on G; can point to either heap or stack!
+ heap bool
+ rangefunc bool // true for rangefunc list
+ sp uintptr // sp at time of defer
+ pc uintptr // pc at time of defer
+ fn func() // can be nil for open-coded defers
+ link *_defer // next defer on G; can point to either heap or stack!
+
+ // If rangefunc is true, *head is the head of the atomic linked list
+ // during a range-over-func execution.
+ head *atomic.Pointer[_defer]
}
// A _panic holds information about an active panic.