]> Cypherpunks repositories - gostls13.git/commitdiff
cmd/compile: add compiler debug flag to disable range func iterator checking
authorDavid Chase <drchase@google.com>
Sat, 11 Nov 2023 20:32:45 +0000 (15:32 -0500)
committerDavid Chase <drchase@google.com>
Thu, 16 Nov 2023 17:32:05 +0000 (17:32 +0000)
E.g.
`GOEXPERIMENT=rangefunc go test -v -gcflags=-d=rangefunccheck=0 rangefunc_test.go`
will turn off the checking and fail.

The benchmarks, which do not use pathological iterators, run slightly faster.

Change-Id: Ia3e175e86d67ef74bbae9bcc5d2def6a2cdf519d
Reviewed-on: https://go-review.googlesource.com/c/go/+/541995
Run-TryBot: David Chase <drchase@google.com>
Reviewed-by: Matthew Dempsky <mdempsky@google.com>
TryBot-Result: Gopher Robot <gobot@golang.org>

src/cmd/compile/internal/base/debug.go
src/cmd/compile/internal/base/flag.go
src/cmd/compile/internal/rangefunc/rewrite.go

index 390ddf3176a12319648edd8f93658b54cbd9a15e..b9b7d5d565ce0f77b1096fe172e908cb4a4069c7 100644 (file)
@@ -60,6 +60,7 @@ type DebugFlags struct {
        PGOInlineCDFThreshold string `help:"cumulative threshold percentage for determining call sites as hot candidates for inlining" concurrent:"ok"`
        PGOInlineBudget       int    `help:"inline budget for hot functions" concurrent:"ok"`
        PGODevirtualize       int    `help:"enable profile-guided devirtualization" concurrent:"ok"`
+       RangeFuncCheck        int    `help:"insert code to check behavior of range iterator functions" concurrent:"ok"`
        WrapGlobalMapDbg      int    `help:"debug trace output for global map init wrapping"`
        WrapGlobalMapCtl      int    `help:"global map init wrap control (0 => default, 1 => off, 2 => stress mode, no size cutoff)"`
        ZeroCopy              int    `help:"enable zero-copy string->[]byte conversions" concurrent:"ok"`
index dc0952a0f156cda7c876d5b05a443c88da23e27a..d436665129646fb09b03a400f121cfd952845da9 100644 (file)
@@ -182,6 +182,7 @@ func ParseFlags() {
        Debug.PGODevirtualize = 1
        Debug.SyncFrames = -1 // disable sync markers by default
        Debug.ZeroCopy = 1
+       Debug.RangeFuncCheck = 1
 
        Debug.Checkptr = -1 // so we can tell whether it is set explicitly
 
index 460efc69d1bc19ad39822b0a84f4d1f32b227679..7475c570aa3099dff12663bf748ea152f16b51a8 100644 (file)
@@ -554,6 +554,11 @@ func rewriteFunc(pkg *types2.Package, info *types2.Info, typ *syntax.FuncType, b
        }
 }
 
+// checkFuncMisuse reports whether to check for misuse of iterator callbacks functions.
+func (r *rewriter) checkFuncMisuse() bool {
+       return base.Debug.RangeFuncCheck != 0
+}
+
 // inspect is a callback for syntax.Inspect that drives the actual rewriting.
 // If it sees a func literal, it kicks off a separate rewrite for that literal.
 // Otherwise, it maintains a stack of range-over-func loops and
@@ -621,7 +626,10 @@ func (r *rewriter) startLoop(loop *forLoop) {
                r.false = types2.Universe.Lookup("false")
                r.rewritten = make(map[*syntax.ForStmt]syntax.Stmt)
        }
-       loop.exitFlag, loop.exitFlagDecl = r.exitVar(loop.nfor.Pos())
+       if r.checkFuncMisuse() {
+               // declare the exit flag for this loop's body
+               loop.exitFlag, loop.exitFlagDecl = r.exitVar(loop.nfor.Pos())
+       }
 }
 
 // editStmt returns the replacement for the statement x,
@@ -714,8 +722,11 @@ func (r *rewriter) editReturn(x *syntax.ReturnStmt) syntax.Stmt {
                bl.List = append(bl.List, &syntax.AssignStmt{Lhs: r.useList(r.retVars), Rhs: x.Results})
        }
        bl.List = append(bl.List, &syntax.AssignStmt{Lhs: r.next(), Rhs: r.intConst(next)})
-       for i := 0; i < len(r.forStack); i++ {
-               bl.List = append(bl.List, r.setExitedAt(i))
+       if r.checkFuncMisuse() {
+               // mark all enclosing loop bodies as exited
+               for i := 0; i < len(r.forStack); i++ {
+                       bl.List = append(bl.List, r.setExitedAt(i))
+               }
        }
        bl.List = append(bl.List, &syntax.ReturnStmt{Results: r.useVar(r.false)})
        setPos(bl, x.Pos())
@@ -811,8 +822,14 @@ func (r *rewriter) editBranch(x *syntax.BranchStmt) syntax.Stmt {
                // If this is a simple break, mark this loop as exited and return false.
                // No adjustments to #next.
                if depth == 0 {
+                       var stmts []syntax.Stmt
+                       if r.checkFuncMisuse() {
+                               stmts = []syntax.Stmt{r.setExited(), ret}
+                       } else {
+                               stmts = []syntax.Stmt{ret}
+                       }
                        bl := &syntax.BlockStmt{
-                               List: []syntax.Stmt{r.setExited(), ret},
+                               List: stmts,
                        }
                        setPos(bl, x.Pos())
                        return bl
@@ -846,9 +863,11 @@ func (r *rewriter) editBranch(x *syntax.BranchStmt) syntax.Stmt {
                List: []syntax.Stmt{as},
        }
 
-       // Set #exitK for this loop and those exited by the control flow.
-       for i := exitFrom; i < len(r.forStack); i++ {
-               bl.List = append(bl.List, r.setExitedAt(i))
+       if r.checkFuncMisuse() {
+               // Set #exitK for this loop and those exited by the control flow.
+               for i := exitFrom; i < len(r.forStack); i++ {
+                       bl.List = append(bl.List, r.setExitedAt(i))
+               }
        }
 
        bl.List = append(bl.List, ret)
@@ -953,12 +972,18 @@ func (r *rewriter) endLoop(loop *forLoop) {
        }
 
        // declare the exitFlag here so it has proper scope and zeroing
-       exitFlagDecl := &syntax.DeclStmt{DeclList: []syntax.Decl{loop.exitFlagDecl}}
-       block.List = append(block.List, exitFlagDecl)
+       if r.checkFuncMisuse() {
+               exitFlagDecl := &syntax.DeclStmt{DeclList: []syntax.Decl{loop.exitFlagDecl}}
+               block.List = append(block.List, exitFlagDecl)
+       }
 
+       // iteratorFunc(bodyFunc)
        block.List = append(block.List, call)
 
-       block.List = append(block.List, r.setExited())
+       if r.checkFuncMisuse() {
+               // iteratorFunc has exited, mark the exit flag for the body
+               block.List = append(block.List, r.setExited())
+       }
        block.List = append(block.List, checks...)
 
        if len(r.forStack) == 1 { // ending an outermost loop
@@ -1037,7 +1062,9 @@ func (r *rewriter) bodyFunc(body []syntax.Stmt, lhs []syntax.Expr, def bool, fty
 
        loop := r.forStack[len(r.forStack)-1]
 
-       bodyFunc.Body.List = append(bodyFunc.Body.List, r.assertNotExited(start, loop))
+       if r.checkFuncMisuse() {
+               bodyFunc.Body.List = append(bodyFunc.Body.List, r.assertNotExited(start, loop))
+       }
 
        // Original loop body (already rewritten by editStmt during inspect).
        bodyFunc.Body.List = append(bodyFunc.Body.List, body...)