]> Cypherpunks repositories - gostls13.git/commitdiff
cmd/compile, runtime: make room for rangefunc defers
authorRuss Cox <rsc@golang.org>
Fri, 30 Jun 2023 20:18:44 +0000 (16:18 -0400)
committerRuss Cox <rsc@golang.org>
Wed, 16 Aug 2023 16:20:06 +0000 (16:20 +0000)
This is subtle and the compiler and runtime be in sync.
It is easier to develop the rest of the changes (especially when using
toolstash save/restore) if this change is separated out and done first.

Preparation for proposal #61405. The actual logic in the
compiler will be guarded by a GOEXPERIMENT, but it is
easier not to have GOEXPERIMENT-specific data structures
in the runtime, so just make the field always.

Change-Id: I7ec7049b99ae98bf0db365d42966baeec56e3774
Reviewed-on: https://go-review.googlesource.com/c/go/+/510539
TryBot-Result: Gopher Robot <gobot@golang.org>
Run-TryBot: Russ Cox <rsc@golang.org>
Reviewed-by: Matthew Dempsky <mdempsky@google.com>
src/cmd/compile/internal/ssagen/ssa.go
src/runtime/runtime2.go

index 171f99522d9c3eb3fe8c2ff973278ab7c44dd900..74fa6b7fdddf4880add179444f86f9f53d58633d 100644 (file)
@@ -5264,15 +5264,9 @@ func (s *state) call(n *ir.CallExpr, k callKind, returnResultAddr bool) *ssa.Val
                }
                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])
@@ -8101,6 +8095,8 @@ func max8(a, b int8) int8 {
        return b
 }
 
+var deferStructFnField = -1
+
 // deferstruct makes a runtime._defer structure.
 func deferstruct() *types.Type {
        makefield := func(name string, typ *types.Type) *types.Field {
@@ -8114,6 +8110,7 @@ func deferstruct() *types.Type {
        // (*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
@@ -8121,6 +8118,16 @@ func deferstruct() *types.Type {
                // 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
index 54fab050eaa57e44a4f936d15237bf154ed06475..5017a7a80a681f363b412366d0d067ed9f16e71b 100644 (file)
@@ -1001,11 +1001,16 @@ func extendRandom(r []byte, n int) {
 // 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.