mirror of
https://github.com/golang/go
synced 2024-11-05 18:26:10 -07:00
go.tools/go/pointer: add intrinsic for time.startTimer, which is implemented in C.
Without it, no value appears to be sent on NewTicker/NewTimer channels. + test Also: - add (callgraph.Edge).{Description,Pos} convenience methods to simplify client code when Site==nil. LGTM=gri R=gri, friestein68503 CC=golang-codereviews https://golang.org/cl/112610043
This commit is contained in:
parent
f9612295cb
commit
e5d15a9781
@ -41,6 +41,7 @@ package callgraph
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"go/token"
|
||||||
|
|
||||||
"code.google.com/p/go.tools/go/ssa"
|
"code.google.com/p/go.tools/go/ssa"
|
||||||
)
|
)
|
||||||
@ -99,6 +100,20 @@ func (e Edge) String() string {
|
|||||||
return fmt.Sprintf("%s --> %s", e.Caller, e.Callee)
|
return fmt.Sprintf("%s --> %s", e.Caller, e.Callee)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (e Edge) Description() string {
|
||||||
|
if e.Site == nil {
|
||||||
|
return "synthetic call"
|
||||||
|
}
|
||||||
|
return e.Site.Common().Description()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e Edge) Pos() token.Pos {
|
||||||
|
if e.Site == nil {
|
||||||
|
return token.NoPos
|
||||||
|
}
|
||||||
|
return e.Site.Pos()
|
||||||
|
}
|
||||||
|
|
||||||
// AddEdge adds the edge (caller, site, callee) to the call graph.
|
// AddEdge adds the edge (caller, site, callee) to the call graph.
|
||||||
// Elimination of duplicate edges is the caller's responsibility.
|
// Elimination of duplicate edges is the caller's responsibility.
|
||||||
func AddEdge(caller *Node, site ssa.CallInstruction, callee *Node) {
|
func AddEdge(caller *Node, site ssa.CallInstruction, callee *Node) {
|
||||||
|
@ -174,7 +174,7 @@ func init() {
|
|||||||
"syscall.setenv_c": ext۰NoEffect,
|
"syscall.setenv_c": ext۰NoEffect,
|
||||||
"time.Sleep": ext۰NoEffect,
|
"time.Sleep": ext۰NoEffect,
|
||||||
"time.now": ext۰NoEffect,
|
"time.now": ext۰NoEffect,
|
||||||
"time.startTimer": ext۰NoEffect,
|
"time.startTimer": ext۰time۰startTimer,
|
||||||
"time.stopTimer": ext۰NoEffect,
|
"time.stopTimer": ext۰NoEffect,
|
||||||
} {
|
} {
|
||||||
intrinsicsByName[name] = fn
|
intrinsicsByName[name] = fn
|
||||||
@ -243,13 +243,9 @@ func (a *analysis) isReflect(fn *ssa.Function) bool {
|
|||||||
func ext۰NoEffect(a *analysis, cgn *cgnode) {}
|
func ext۰NoEffect(a *analysis, cgn *cgnode) {}
|
||||||
|
|
||||||
func ext۰NotYetImplemented(a *analysis, cgn *cgnode) {
|
func ext۰NotYetImplemented(a *analysis, cgn *cgnode) {
|
||||||
// TODO(adonovan): enable this warning when we've implemented
|
|
||||||
// enough that it's not unbearably annoying.
|
|
||||||
if true {
|
|
||||||
fn := cgn.fn
|
fn := cgn.fn
|
||||||
a.warnf(fn.Pos(), "unsound: intrinsic treatment of %s not yet implemented", fn)
|
a.warnf(fn.Pos(), "unsound: intrinsic treatment of %s not yet implemented", fn)
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// ---------- func runtime.SetFinalizer(x, f interface{}) ----------
|
// ---------- func runtime.SetFinalizer(x, f interface{}) ----------
|
||||||
|
|
||||||
@ -320,3 +316,65 @@ func ext۰runtime۰SetFinalizer(a *analysis, cgn *cgnode) {
|
|||||||
f: params + 1,
|
f: params + 1,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ---------- func time.startTimer(t *runtimeTimer) ----------
|
||||||
|
|
||||||
|
// time.StartTimer(t)
|
||||||
|
type timeStartTimerConstraint struct {
|
||||||
|
targets nodeid // (indirect)
|
||||||
|
t nodeid // (ptr)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *timeStartTimerConstraint) ptr() nodeid { return c.t }
|
||||||
|
func (c *timeStartTimerConstraint) presolve(h *hvn) {
|
||||||
|
h.markIndirect(onodeid(c.targets), "StartTimer.targets")
|
||||||
|
}
|
||||||
|
func (c *timeStartTimerConstraint) renumber(mapping []nodeid) {
|
||||||
|
c.targets = mapping[c.targets]
|
||||||
|
c.t = mapping[c.t]
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *timeStartTimerConstraint) String() string {
|
||||||
|
return fmt.Sprintf("time.startTimer(n%d)", c.t)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *timeStartTimerConstraint) solve(a *analysis, delta *nodeset) {
|
||||||
|
for _, tObj := range delta.AppendTo(a.deltaSpace) {
|
||||||
|
t := nodeid(tObj)
|
||||||
|
|
||||||
|
// We model startTimer as if it was defined thus:
|
||||||
|
// func startTimer(t *runtimeTimer) { t.f(0, t.arg) }
|
||||||
|
|
||||||
|
// We hard-code the field offsets of time.runtimeTimer:
|
||||||
|
// type runtimeTimer struct {
|
||||||
|
// 0 __identity__
|
||||||
|
// 1 i int32
|
||||||
|
// 2 when int64
|
||||||
|
// 3 period int64
|
||||||
|
// 4 f func(int64, interface{})
|
||||||
|
// 5 arg interface{}
|
||||||
|
// }
|
||||||
|
f := t + 4
|
||||||
|
arg := t + 5
|
||||||
|
|
||||||
|
// store t.arg to t.f.params[1]
|
||||||
|
// (offset 2 => skip identity and int64 param)
|
||||||
|
a.store(f, arg, 2, 1)
|
||||||
|
|
||||||
|
// Add dynamic call target.
|
||||||
|
if a.onlineCopy(c.targets, f) {
|
||||||
|
a.addWork(c.targets)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func ext۰time۰startTimer(a *analysis, cgn *cgnode) {
|
||||||
|
// This is the shared contour, used for dynamic calls.
|
||||||
|
targets := a.addOneNode(tInvalid, "startTimer.targets", nil)
|
||||||
|
cgn.sites = append(cgn.sites, &callsite{targets: targets})
|
||||||
|
params := a.funcParams(cgn.obj)
|
||||||
|
a.addConstraint(&timeStartTimerConstraint{
|
||||||
|
targets: targets,
|
||||||
|
t: params,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
@ -54,6 +54,7 @@ var inputs = []string{
|
|||||||
"testdata/rtti.go",
|
"testdata/rtti.go",
|
||||||
"testdata/structreflect.go",
|
"testdata/structreflect.go",
|
||||||
"testdata/structs.go",
|
"testdata/structs.go",
|
||||||
|
"testdata/timer.go",
|
||||||
}
|
}
|
||||||
|
|
||||||
// Expectation grammar:
|
// Expectation grammar:
|
||||||
|
@ -43,7 +43,7 @@ func (a *analysis) doCallgraph(cg *callgraph.Graph) {
|
|||||||
for _, n := range cg.Nodes {
|
for _, n := range cg.Nodes {
|
||||||
for _, e := range n.Out {
|
for _, e := range n.Out {
|
||||||
if e.Site == nil {
|
if e.Site == nil {
|
||||||
continue // a call from the <root> node
|
continue // a call from a synthetic node such as <root>
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add (site pos, callee) to calledFuncs.
|
// Add (site pos, callee) to calledFuncs.
|
||||||
|
@ -63,25 +63,20 @@ func (r *callersResult) display(printf printfFunc) {
|
|||||||
if edge.Caller == root {
|
if edge.Caller == root {
|
||||||
printf(r.target, "the root of the call graph")
|
printf(r.target, "the root of the call graph")
|
||||||
} else {
|
} else {
|
||||||
printf(edge.Site, "\t%s from %s", edge.Site.Common().Description(), edge.Caller.Func)
|
printf(edge, "\t%s from %s", edge.Description(), edge.Caller.Func)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *callersResult) toSerial(res *serial.Result, fset *token.FileSet) {
|
func (r *callersResult) toSerial(res *serial.Result, fset *token.FileSet) {
|
||||||
root := r.callgraph.Root
|
|
||||||
var callers []serial.Caller
|
var callers []serial.Caller
|
||||||
for _, edge := range r.edges {
|
for _, edge := range r.edges {
|
||||||
var c serial.Caller
|
callers = append(callers, serial.Caller{
|
||||||
c.Caller = edge.Caller.Func.String()
|
Caller: edge.Caller.Func.String(),
|
||||||
if edge.Caller == root {
|
Pos: fset.Position(edge.Pos()).String(),
|
||||||
c.Desc = "synthetic call"
|
Desc: edge.Description(),
|
||||||
} else {
|
})
|
||||||
c.Pos = fset.Position(edge.Site.Pos()).String()
|
|
||||||
c.Desc = edge.Site.Common().Description()
|
|
||||||
}
|
|
||||||
callers = append(callers, c)
|
|
||||||
}
|
}
|
||||||
res.Callers = callers
|
res.Callers = callers
|
||||||
}
|
}
|
||||||
|
@ -71,7 +71,7 @@ func (r *callstackResult) display(printf printfFunc) {
|
|||||||
printf(r.target, "%s", r.target)
|
printf(r.target, "%s", r.target)
|
||||||
for i := len(r.callpath) - 1; i >= 0; i-- {
|
for i := len(r.callpath) - 1; i >= 0; i-- {
|
||||||
edge := r.callpath[i]
|
edge := r.callpath[i]
|
||||||
printf(edge.Site, "%s from %s", edge.Site.Common().Description(), edge.Caller.Func)
|
printf(edge, "%s from %s", edge.Description(), edge.Caller.Func)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
printf(r.target, "%s is unreachable in this analysis scope", r.target)
|
printf(r.target, "%s is unreachable in this analysis scope", r.target)
|
||||||
@ -83,9 +83,9 @@ func (r *callstackResult) toSerial(res *serial.Result, fset *token.FileSet) {
|
|||||||
for i := len(r.callpath) - 1; i >= 0; i-- { // (innermost first)
|
for i := len(r.callpath) - 1; i >= 0; i-- { // (innermost first)
|
||||||
edge := r.callpath[i]
|
edge := r.callpath[i]
|
||||||
callers = append(callers, serial.Caller{
|
callers = append(callers, serial.Caller{
|
||||||
Pos: fset.Position(edge.Site.Pos()).String(),
|
Pos: fset.Position(edge.Pos()).String(),
|
||||||
Caller: edge.Caller.Func.String(),
|
Caller: edge.Caller.Func.String(),
|
||||||
Desc: edge.Site.Common().Description(),
|
Desc: edge.Description(),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
res.Callstack = &serial.CallStack{
|
res.Callstack = &serial.CallStack{
|
||||||
|
Loading…
Reference in New Issue
Block a user