mirror of
https://github.com/golang/go
synced 2024-11-05 11:36: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 (
|
||||
"fmt"
|
||||
"go/token"
|
||||
|
||||
"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)
|
||||
}
|
||||
|
||||
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.
|
||||
// Elimination of duplicate edges is the caller's responsibility.
|
||||
func AddEdge(caller *Node, site ssa.CallInstruction, callee *Node) {
|
||||
|
@ -174,7 +174,7 @@ func init() {
|
||||
"syscall.setenv_c": ext۰NoEffect,
|
||||
"time.Sleep": ext۰NoEffect,
|
||||
"time.now": ext۰NoEffect,
|
||||
"time.startTimer": ext۰NoEffect,
|
||||
"time.startTimer": ext۰time۰startTimer,
|
||||
"time.stopTimer": ext۰NoEffect,
|
||||
} {
|
||||
intrinsicsByName[name] = fn
|
||||
@ -243,12 +243,8 @@ func (a *analysis) isReflect(fn *ssa.Function) bool {
|
||||
func ext۰NoEffect(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
|
||||
a.warnf(fn.Pos(), "unsound: intrinsic treatment of %s not yet implemented", fn)
|
||||
}
|
||||
fn := cgn.fn
|
||||
a.warnf(fn.Pos(), "unsound: intrinsic treatment of %s not yet implemented", fn)
|
||||
}
|
||||
|
||||
// ---------- func runtime.SetFinalizer(x, f interface{}) ----------
|
||||
@ -320,3 +316,65 @@ func ext۰runtime۰SetFinalizer(a *analysis, cgn *cgnode) {
|
||||
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/structreflect.go",
|
||||
"testdata/structs.go",
|
||||
"testdata/timer.go",
|
||||
}
|
||||
|
||||
// Expectation grammar:
|
||||
|
@ -43,7 +43,7 @@ func (a *analysis) doCallgraph(cg *callgraph.Graph) {
|
||||
for _, n := range cg.Nodes {
|
||||
for _, e := range n.Out {
|
||||
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.
|
||||
|
@ -63,25 +63,20 @@ func (r *callersResult) display(printf printfFunc) {
|
||||
if edge.Caller == root {
|
||||
printf(r.target, "the root of the call graph")
|
||||
} 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) {
|
||||
root := r.callgraph.Root
|
||||
var callers []serial.Caller
|
||||
for _, edge := range r.edges {
|
||||
var c serial.Caller
|
||||
c.Caller = edge.Caller.Func.String()
|
||||
if edge.Caller == root {
|
||||
c.Desc = "synthetic call"
|
||||
} else {
|
||||
c.Pos = fset.Position(edge.Site.Pos()).String()
|
||||
c.Desc = edge.Site.Common().Description()
|
||||
}
|
||||
callers = append(callers, c)
|
||||
callers = append(callers, serial.Caller{
|
||||
Caller: edge.Caller.Func.String(),
|
||||
Pos: fset.Position(edge.Pos()).String(),
|
||||
Desc: edge.Description(),
|
||||
})
|
||||
}
|
||||
res.Callers = callers
|
||||
}
|
||||
|
@ -71,7 +71,7 @@ func (r *callstackResult) display(printf printfFunc) {
|
||||
printf(r.target, "%s", r.target)
|
||||
for i := len(r.callpath) - 1; i >= 0; 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 {
|
||||
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)
|
||||
edge := r.callpath[i]
|
||||
callers = append(callers, serial.Caller{
|
||||
Pos: fset.Position(edge.Site.Pos()).String(),
|
||||
Pos: fset.Position(edge.Pos()).String(),
|
||||
Caller: edge.Caller.Func.String(),
|
||||
Desc: edge.Site.Common().Description(),
|
||||
Desc: edge.Description(),
|
||||
})
|
||||
}
|
||||
res.Callstack = &serial.CallStack{
|
||||
|
Loading…
Reference in New Issue
Block a user