]> Cypherpunks.ru repositories - gostls13.git/commitdiff
runtime, cmd: rationalize StackLimit and StackGuard
authorAustin Clements <austin@google.com>
Wed, 19 Apr 2023 18:01:05 +0000 (14:01 -0400)
committerAustin Clements <austin@google.com>
Thu, 20 Apr 2023 16:05:21 +0000 (16:05 +0000)
The current definitions of StackLimit and StackGuard only indirectly
specify the NOSPLIT stack limit and duplicate a literal constant
(928). Currently, they define the stack guard delta, and from there
compute the NOSPLIT limit.

Rationalize these by defining a new constant, abi.StackNosplitBase,
which consolidates and directly specifies the NOSPLIT stack limit (in
the default case). From this we then compute the stack guard delta,
inverting the relationship between these two constants. While we're
here, we rename StackLimit to StackNosplit to make it clearer what's
being limited.

This change does not affect the values of these constants in the
default configuration. It does slightly change how
StackGuardMultiplier values other than 1 affect the constants, but
this multiplier is a pretty rough heuristic anyway.

                    before after
stackNosplit           800   800
_StackGuard            928   928
stackNosplit -race    1728  1600
_StackGuard -race     1856  1728

For #59670.

Change-Id: Ibe20825ebe0076bbd7b0b7501177b16c9dbcb79e
Reviewed-on: https://go-review.googlesource.com/c/go/+/486380
Run-TryBot: Austin Clements <austin@google.com>
Reviewed-by: Cherry Mui <cherryyz@google.com>
TryBot-Result: Gopher Robot <gobot@golang.org>

src/cmd/internal/objabi/stack.go
src/cmd/link/internal/ld/stackcheck.go
src/internal/abi/stack.go
src/runtime/preempt.go
src/runtime/stack.go
test/nosplit.go

index 5a2f641a751dc2e86b3c9403fcdb0cda16210ecf..7c7ff4e0586851e2ae79f35150d7fe017f76fc59 100644 (file)
@@ -9,18 +9,9 @@ import (
        "internal/buildcfg"
 )
 
-// For the linkers. Must match Go definitions.
-
-const (
-       STACKSYSTEM = 0
-       StackSystem = STACKSYSTEM
-)
-
-func StackLimit(race bool) int {
-       // This arithmetic must match that in runtime/stack.go:{_StackGuard,_StackLimit}.
-       stackGuard := 928*stackGuardMultiplier(race) + StackSystem
-       stackLimit := stackGuard - StackSystem - abi.StackSmall
-       return stackLimit
+func StackNosplit(race bool) int {
+       // This arithmetic must match that in runtime/stack.go:stackNosplit.
+       return abi.StackNosplitBase * stackGuardMultiplier(race)
 }
 
 // stackGuardMultiplier returns a multiplier to apply to the default
index c82dafe51edbf02b7710e78f0180d9e6cead9761..24a96fb996810e5f92a763240b04f1747ba10d91 100644 (file)
@@ -61,7 +61,7 @@ func (ctxt *Link) doStackCheck() {
        // The call to morestack in every splittable function ensures
        // that there are at least StackLimit bytes available below SP
        // when morestack returns.
-       limit := objabi.StackLimit(*flagRace) - sc.callSize
+       limit := objabi.StackNosplit(*flagRace) - sc.callSize
        if buildcfg.GOARCH == "arm64" {
                // Need an extra 8 bytes below SP to save FP.
                limit -= 8
index 9efd21b167551f7decf254249b305e5b8818fc57..8e3327ee48ff67351a0abba85f5b103ef896562c 100644 (file)
@@ -5,6 +5,14 @@
 package abi
 
 const (
+       // StackNosplitBase is the base maximum number of bytes that a chain of
+       // NOSPLIT functions can use.
+       //
+       // This value must be multiplied by the stack guard multiplier, so do not
+       // use it directly. See runtime/stack.go:stackNosplit and
+       // cmd/internal/objabi/stack.go:StackNosplit.
+       StackNosplitBase = 800
+
        // We have three different sequences for stack bounds checks, depending on
        // whether the stack frame of a function is small, big, or huge.
 
index a6623c0ec2d86a6a18122d0a158e1fb9d1379702..e19e6d3d7a937ae03f52fa5631f419bfd468db8e 100644 (file)
@@ -320,7 +320,7 @@ func init() {
        total += funcMaxSPDelta(f)
        // Add some overhead for return PCs, etc.
        asyncPreemptStack = uintptr(total) + 8*goarch.PtrSize
-       if asyncPreemptStack > _StackLimit {
+       if asyncPreemptStack > stackNosplit {
                // We need more than the nosplit limit. This isn't
                // unsafe, but it may limit asynchronous preemption.
                //
index 39dbed5114351ba359a2d1b1f072ef92e15f3af6..708a6ee2e5be264416ced37c71159c638835c36c 100644 (file)
@@ -85,19 +85,18 @@ const (
        _FixedStack6 = _FixedStack5 | (_FixedStack5 >> 16)
        _FixedStack  = _FixedStack6 + 1
 
+       // stackNosplit is the maximum number of bytes that a chain of NOSPLIT
+       // functions can use.
+       // This arithmetic must match that in cmd/internal/objabi/stack.go:StackNosplit.
+       stackNosplit = abi.StackNosplitBase * sys.StackGuardMultiplier
+
        // The stack guard is a pointer this many bytes above the
        // bottom of the stack.
        //
-       // The guard leaves enough room for one _StackSmall frame plus
-       // a _StackLimit chain of NOSPLIT calls plus _StackSystem
-       // bytes for the OS.
-       // This arithmetic must match that in cmd/internal/objabi/stack.go:StackLimit.
-       _StackGuard = 928*sys.StackGuardMultiplier + _StackSystem
-
-       // The maximum number of bytes that a chain of NOSPLIT
-       // functions can use.
+       // The guard leaves enough room for a stackNosplit chain of NOSPLIT calls
+       // plus one stackSmall frame plus stackSystem bytes for the OS.
        // This arithmetic must match that in cmd/internal/objabi/stack.go:StackLimit.
-       _StackLimit = _StackGuard - _StackSystem - abi.StackSmall
+       _StackGuard = stackNosplit + _StackSystem + abi.StackSmall
 )
 
 const (
@@ -1211,7 +1210,7 @@ func shrinkstack(gp *g) {
        // down to the SP plus the stack guard space that ensures
        // there's room for nosplit functions.
        avail := gp.stack.hi - gp.stack.lo
-       if used := gp.stack.hi - gp.sched.sp + _StackLimit; used >= avail/4 {
+       if used := gp.stack.hi - gp.sched.sp + stackNosplit; used >= avail/4 {
                return
        }
 
index a695654eaf131f0228c4630123a4fa3570959f6e..2b1bb5492db64b115e686055aa76eed77932ce0a 100644 (file)
@@ -342,22 +342,15 @@ TestCases:
                                nosplit := m[3]
                                body := m[4]
 
-                               // The limit was originally 128 but is now 800 (928-128).
+                               // The limit was originally 128 but is now 800.
                                // Instead of rewriting the test cases above, adjust
                                // the first nosplit frame to use up the extra bytes.
                                // This isn't exactly right because we could have
                                // nosplit -> split -> nosplit, but it's good enough.
                                if !adjusted && nosplit != "" {
+                                       const stackNosplitBase = 800 // internal/abi.StackNosplitBase
                                        adjusted = true
-                                       size += (928 - 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 += 928
-                                               }
-                                       }
+                                       size += stackNosplitBase - 128
                                }
 
                                if nosplit != "" {