mirror of
https://github.com/golang/go
synced 2024-09-28 18:14:29 -06:00
cmd/compile: add compiler debug flag to disable range func iterator checking
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>
This commit is contained in:
parent
d6ef98b8fa
commit
d411b3197c
@ -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"`
|
||||
|
@ -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
|
||||
|
||||
|
@ -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...)
|
||||
|
Loading…
Reference in New Issue
Block a user