fix: correct control flow graph for defer statements

This commit is contained in:
Marc Vertes
2020-03-09 10:52:05 +01:00
committed by GitHub
parent 0ace9244c4
commit 1ae2649655
4 changed files with 53 additions and 48 deletions

23
_test/defer4.go Normal file
View File

@@ -0,0 +1,23 @@
package main
import "sync"
type T struct {
mu sync.RWMutex
name string
}
func (t *T) get() string {
t.mu.RLock()
defer t.mu.RUnlock()
return t.name
}
var d = T{name: "test"}
func main() {
println(d.get())
}
// Output:
// test

View File

@@ -200,7 +200,6 @@ const (
aCase
aCompositeLit
aDec
aDefer
aEqual
aGreater
aGreaterEqual
@@ -258,7 +257,6 @@ var actions = [...]string{
aCase: "case",
aCompositeLit: "compositeLit",
aDec: "--",
aDefer: "defer",
aEqual: "==",
aGreater: ">",
aGetFunc: "getFunc",
@@ -569,7 +567,7 @@ func (interp *Interpreter) ast(src, name string) (string, *node, error) {
st.push(addChild(&root, anc, pos, declStmt, aNop), nod)
case *ast.DeferStmt:
st.push(addChild(&root, anc, pos, deferStmt, aDefer), nod)
st.push(addChild(&root, anc, pos, deferStmt, aNop), nod)
case *ast.Ellipsis:
st.push(addChild(&root, anc, pos, ellipsisExpr, aNop), nod)

View File

@@ -936,7 +936,7 @@ func (interp *Interpreter) cfg(root *node, pkgID string) ([]*node, error) {
sc = sc.pop()
err = genRun(n)
case goStmt:
case deferStmt, goStmt:
wireChild(n)
case identExpr:

View File

@@ -29,7 +29,6 @@ var builtin = [...]bltnGenerator{
aCase: _case,
aCompositeLit: arrayLit,
aDec: dec,
aDefer: _defer,
aEqual: equal,
aGetFunc: getFunc,
aGreater: greater,
@@ -597,47 +596,6 @@ func genInterfaceWrapper(n *node, typ reflect.Type) func(*frame) reflect.Value {
}
}
func _defer(n *node) {
tnext := getExec(n.tnext)
values := make([]func(*frame) reflect.Value, len(n.child[0].child))
var method func(*frame) reflect.Value
for i, c := range n.child[0].child {
if c.typ.cat == funcT {
values[i] = genFunctionWrapper(c)
} else {
if c.recv != nil {
// defer a method on a binary obj
mi := c.val.(int)
m := genValue(c.child[0])
method = func(f *frame) reflect.Value { return m(f).Method(mi) }
}
values[i] = genValue(c)
}
}
if method != nil {
n.exec = func(f *frame) bltn {
val := make([]reflect.Value, len(values))
val[0] = method(f)
for i, v := range values[1:] {
val[i+1] = v(f)
}
f.deferred = append([][]reflect.Value{val}, f.deferred...)
return tnext
}
} else {
n.exec = func(f *frame) bltn {
val := make([]reflect.Value, len(values))
for i, v := range values {
val[i] = v(f)
}
f.deferred = append([][]reflect.Value{val}, f.deferred...)
return tnext
}
}
}
func call(n *node) {
goroutine := n.anc.kind == goStmt
var method bool
@@ -709,6 +667,21 @@ func call(n *node) {
}
}
if n.anc.kind == deferStmt {
// Store function call in frame for deferred execution.
value = genFunctionWrapper(n.child[0])
n.exec = func(f *frame) bltn {
val := make([]reflect.Value, len(values)+1)
val[0] = value(f)
for i, v := range values {
val[i+1] = v(f)
}
f.deferred = append([][]reflect.Value{val}, f.deferred...)
return tnext
}
return
}
n.exec = func(f *frame) bltn {
var def *node
var ok bool
@@ -893,8 +866,19 @@ func callBin(n *node) {
l := len(values)
switch {
case n.anc.kind == deferStmt:
// Store function call in frame for deferred execution.
n.exec = func(f *frame) bltn {
val := make([]reflect.Value, l+1)
val[0] = value(f)
for i, v := range values {
val[i+1] = v(f)
}
f.deferred = append([][]reflect.Value{val}, f.deferred...)
return tnext
}
case n.anc.kind == goStmt:
// Execute function in a goroutine, discard results
// Execute function in a goroutine, discard results.
n.exec = func(f *frame) bltn {
in := make([]reflect.Value, l)
for i, v := range values {
@@ -904,7 +888,7 @@ func callBin(n *node) {
return tnext
}
case fnext != nil:
// Handle branching according to boolean result
// Handle branching according to boolean result.
n.exec = func(f *frame) bltn {
in := make([]reflect.Value, l)
for i, v := range values {