1
0
mirror of https://github.com/golang/go synced 2024-10-01 03:28:32 -06:00

go.tools/pointer: replace Pointer, PointsToSet interfaces with their sole implementations.

(Elminate premature abstraction.)

The test probes used Pointer!=nil for the "is pointerlike"
predicate. Now that Pointer is a struct, they check the type
of the expression, which is more accurate.  Two probes on
non-pointerlike values have beem removed.

R=crawshaw
CC=golang-dev
https://golang.org/cl/38420043
This commit is contained in:
Alan Donovan 2013-12-06 12:52:04 -05:00
parent 2d324f247c
commit 6b75c15eec
6 changed files with 56 additions and 76 deletions

View File

@ -88,7 +88,7 @@ func peers(o *Oracle, qpos *QueryPos) (queryResult, error) {
var sends, receives []token.Pos
for _, op := range ops {
for _, ptr := range ptares.Queries[op.ch] {
if ptr != nil && ptr.PointsTo().Intersects(queryChanPts) {
if ptr.PointsTo().Intersects(queryChanPts) {
if op.dir == ast.SEND {
sends = append(sends, op.pos)
} else {

View File

@ -40,7 +40,10 @@ type Config struct {
// Pointer p may be saved until the analysis is complete, at
// which point its methods provide access to the analysis
// (The result of callings its methods within the Print
// callback is undefined.) p is nil if x is non-pointerlike.
// callback is undefined.)
//
// CanPoint(site.Args[0].Type()) reports whether p is
// pointerlike.
//
Print func(site *ssa.CallCommon, p Pointer)
@ -117,53 +120,26 @@ type Result struct {
}
// A Pointer is an equivalence class of pointerlike values.
type Pointer interface {
// PointsTo returns the points-to set of this pointer.
PointsTo() PointsToSet
// MayAlias reports whether the receiver pointer may alias
// the argument pointer.
MayAlias(Pointer) bool
// Context returns the context of this pointer,
// if it corresponds to a local variable.
Context() call.GraphNode
String() string
//
// A pointer doesn't have a unique type because pointers of distinct
// types may alias the same object.
//
type Pointer struct {
a *analysis
cgn *cgnode
n nodeid // non-zero
}
// A PointsToSet is a set of labels (locations or allocations).
//
type PointsToSet interface {
// PointsTo returns the set of labels that this points-to set
// contains.
Labels() []*Label
// Intersects reports whether this points-to set and the
// argument points-to set contain common members.
Intersects(PointsToSet) bool
// If this PointsToSet came from a Pointer of interface kind
// or a reflect.Value, DynamicTypes returns the set of dynamic
// types that it may contain. (For an interface, they will
// always be concrete types.)
//
// The result is a mapping whose keys are the dynamic types to
// which it may point. For each pointer-like key type, the
// corresponding map value is a set of pointer abstractions of
// that dynamic type, represented as a []Pointer slice. Use
// PointsToCombined to merge them.
//
// The result is empty unless CanHaveDynamicTypes(T).
//
DynamicTypes() *typemap.M
type PointsToSet struct {
a *analysis // may be nil if pts is nil
pts nodeset
}
// Union returns the set containing all the elements of each set in sets.
func Union(sets ...PointsToSet) PointsToSet {
var union ptset
var union PointsToSet
for _, set := range sets {
set := set.(ptset)
union.a = set.a
union.pts.addAll(set.pts)
}
@ -180,14 +156,7 @@ func PointsToCombined(ptrs []Pointer) PointsToSet {
return Union(ptsets...)
}
// ---- PointsToSet public interface
type ptset struct {
a *analysis // may be nil if pts is nil
pts nodeset
}
func (s ptset) String() string {
func (s PointsToSet) String() string {
var buf bytes.Buffer
fmt.Fprintf(&buf, "[")
sep := ""
@ -199,7 +168,9 @@ func (s ptset) String() string {
return buf.String()
}
func (s ptset) Labels() []*Label {
// PointsTo returns the set of labels that this points-to set
// contains.
func (s PointsToSet) Labels() []*Label {
var labels []*Label
for l := range s.pts {
labels = append(labels, s.a.labelFor(l))
@ -207,7 +178,20 @@ func (s ptset) Labels() []*Label {
return labels
}
func (s ptset) DynamicTypes() *typemap.M {
// If this PointsToSet came from a Pointer of interface kind
// or a reflect.Value, DynamicTypes returns the set of dynamic
// types that it may contain. (For an interface, they will
// always be concrete types.)
//
// The result is a mapping whose keys are the dynamic types to
// which it may point. For each pointer-like key type, the
// corresponding map value is a set of pointer abstractions of
// that dynamic type, represented as a []Pointer slice. Use
// PointsToCombined to merge them.
//
// The result is empty unless CanHaveDynamicTypes(T).
//
func (s PointsToSet) DynamicTypes() *typemap.M {
var tmap typemap.M
tmap.SetHasher(s.a.hasher)
for ifaceObjId := range s.pts {
@ -219,13 +203,14 @@ func (s ptset) DynamicTypes() *typemap.M {
panic("indirect tagged object") // implement later
}
prev, _ := tmap.At(tDyn).([]Pointer)
tmap.Set(tDyn, append(prev, ptr{s.a, nil, v}))
tmap.Set(tDyn, append(prev, Pointer{s.a, nil, v}))
}
return &tmap
}
func (x ptset) Intersects(y_ PointsToSet) bool {
y := y_.(ptset)
// Intersects reports whether this points-to set and the
// argument points-to set contain common members.
func (x PointsToSet) Intersects(y PointsToSet) bool {
for l := range x.pts {
if _, ok := y.pts[l]; ok {
return true
@ -234,31 +219,28 @@ func (x ptset) Intersects(y_ PointsToSet) bool {
return false
}
// ---- Pointer public interface
// ptr adapts a node to the Pointer interface.
type ptr struct {
a *analysis
cgn *cgnode
n nodeid // non-zero
}
func (p ptr) String() string {
func (p Pointer) String() string {
return fmt.Sprintf("n%d", p.n)
}
func (p ptr) Context() call.GraphNode {
// Context returns the context of this pointer,
// if it corresponds to a local variable.
func (p Pointer) Context() call.GraphNode {
return p.cgn
}
func (p ptr) PointsTo() PointsToSet {
return ptset{p.a, p.a.nodes[p.n].pts}
// PointsTo returns the points-to set of this pointer.
func (p Pointer) PointsTo() PointsToSet {
return PointsToSet{p.a, p.a.nodes[p.n].pts}
}
func (p ptr) MayAlias(q Pointer) bool {
// MayAlias reports whether the receiver pointer may alias
// the argument pointer.
func (p Pointer) MayAlias(q Pointer) bool {
return p.PointsTo().Intersects(q.PointsTo())
}
func (p ptr) DynamicTypes() *typemap.M {
// DynamicTypes returns p.PointsTo().DynamicTypes().
func (p Pointer) DynamicTypes() *typemap.M {
return p.PointsTo().DynamicTypes()
}

View File

@ -82,14 +82,14 @@ func (a *analysis) setValueNode(v ssa.Value, id nodeid, cgn *cgnode) {
// Record the (v, id) relation if the client has queried pts(v).
if _, ok := a.config.Queries[v]; ok {
a.result.Queries[v] = append(a.result.Queries[v], ptr{a, cgn, id})
a.result.Queries[v] = append(a.result.Queries[v], Pointer{a, cgn, id})
}
// Record the (*v, id) relation if the client has queried pts(*v).
if _, ok := a.config.IndirectQueries[v]; ok {
indirect := a.addNodes(v.Type(), "query.indirect")
a.genLoad(cgn, indirect, v, 0, a.sizeof(v.Type()))
a.result.IndirectQueries[v] = append(a.result.IndirectQueries[v], ptr{a, cgn, indirect})
a.result.IndirectQueries[v] = append(a.result.IndirectQueries[v], Pointer{a, cgn, indirect})
}
}
@ -539,7 +539,7 @@ func (a *analysis) genBuiltinCall(instr ssa.CallInstruction, cgn *cgnode) {
if probe == 0 {
probe = a.addNodes(t, "print")
a.probes[call] = probe
Print(call, ptr{a, nil, probe}) // notify client
Print(call, Pointer{a, nil, probe}) // notify client
}
a.copy(probe, a.valueNode(call.Args[0]), a.sizeof(t))

View File

@ -309,9 +309,9 @@ func doOneInput(input, filename string) bool {
e.errorf("unreachable print() statement has expectation %s", e)
continue
}
if pr.arg0 == nil {
if tArg := pr.instr.Args[0].Type(); !pointer.CanPoint(tArg) {
ok = false
e.errorf("expectation on non-pointerlike operand: %s", pr.instr.Args[0].Type())
e.errorf("expectation on non-pointerlike operand: %s", tArg)
continue
}
}

View File

@ -31,5 +31,4 @@ func main() {
// labels, even though it may contain pointers that do.
print(i) // @pointsto makeinterface:func(x int) int | makeinterface:func(x int, y int) | makeinterface:func(int, int) | makeinterface:int | makeinterface:main.S
print(i.(func(int) int)) // @pointsto main.incr
print(i.(S)) // @pointsto
}

View File

@ -87,7 +87,6 @@ func structs2() {
var s3 S // @line s2s3
s3.c[2] = new(T) // @line s2s3c
print(s3.c) // @pointsto
print(&s3.c) // @pointsto s3.c@s2s3:6
print(s3.c[1]) // @pointsto new@s2s3c:15
print(&s3.c[1]) // @pointsto s3.c[*]@s2s3:6