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 var sends, receives []token.Pos
for _, op := range ops { for _, op := range ops {
for _, ptr := range ptares.Queries[op.ch] { for _, ptr := range ptares.Queries[op.ch] {
if ptr != nil && ptr.PointsTo().Intersects(queryChanPts) { if ptr.PointsTo().Intersects(queryChanPts) {
if op.dir == ast.SEND { if op.dir == ast.SEND {
sends = append(sends, op.pos) sends = append(sends, op.pos)
} else { } else {

View File

@ -40,7 +40,10 @@ type Config struct {
// Pointer p may be saved until the analysis is complete, at // Pointer p may be saved until the analysis is complete, at
// which point its methods provide access to the analysis // which point its methods provide access to the analysis
// (The result of callings its methods within the Print // (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) Print func(site *ssa.CallCommon, p Pointer)
@ -117,53 +120,26 @@ type Result struct {
} }
// A Pointer is an equivalence class of pointerlike values. // A Pointer is an equivalence class of pointerlike values.
type Pointer interface { //
// PointsTo returns the points-to set of this pointer. // A pointer doesn't have a unique type because pointers of distinct
PointsTo() PointsToSet // types may alias the same object.
//
// MayAlias reports whether the receiver pointer may alias type Pointer struct {
// the argument pointer. a *analysis
MayAlias(Pointer) bool cgn *cgnode
n nodeid // non-zero
// Context returns the context of this pointer,
// if it corresponds to a local variable.
Context() call.GraphNode
String() string
} }
// A PointsToSet is a set of labels (locations or allocations). // A PointsToSet is a set of labels (locations or allocations).
// type PointsToSet struct {
type PointsToSet interface { a *analysis // may be nil if pts is nil
// PointsTo returns the set of labels that this points-to set pts nodeset
// 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
} }
// Union returns the set containing all the elements of each set in sets. // Union returns the set containing all the elements of each set in sets.
func Union(sets ...PointsToSet) PointsToSet { func Union(sets ...PointsToSet) PointsToSet {
var union ptset var union PointsToSet
for _, set := range sets { for _, set := range sets {
set := set.(ptset)
union.a = set.a union.a = set.a
union.pts.addAll(set.pts) union.pts.addAll(set.pts)
} }
@ -180,14 +156,7 @@ func PointsToCombined(ptrs []Pointer) PointsToSet {
return Union(ptsets...) return Union(ptsets...)
} }
// ---- PointsToSet public interface func (s PointsToSet) String() string {
type ptset struct {
a *analysis // may be nil if pts is nil
pts nodeset
}
func (s ptset) String() string {
var buf bytes.Buffer var buf bytes.Buffer
fmt.Fprintf(&buf, "[") fmt.Fprintf(&buf, "[")
sep := "" sep := ""
@ -199,7 +168,9 @@ func (s ptset) String() string {
return buf.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 var labels []*Label
for l := range s.pts { for l := range s.pts {
labels = append(labels, s.a.labelFor(l)) labels = append(labels, s.a.labelFor(l))
@ -207,7 +178,20 @@ func (s ptset) Labels() []*Label {
return labels 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 var tmap typemap.M
tmap.SetHasher(s.a.hasher) tmap.SetHasher(s.a.hasher)
for ifaceObjId := range s.pts { for ifaceObjId := range s.pts {
@ -219,13 +203,14 @@ func (s ptset) DynamicTypes() *typemap.M {
panic("indirect tagged object") // implement later panic("indirect tagged object") // implement later
} }
prev, _ := tmap.At(tDyn).([]Pointer) 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 return &tmap
} }
func (x ptset) Intersects(y_ PointsToSet) bool { // Intersects reports whether this points-to set and the
y := y_.(ptset) // argument points-to set contain common members.
func (x PointsToSet) Intersects(y PointsToSet) bool {
for l := range x.pts { for l := range x.pts {
if _, ok := y.pts[l]; ok { if _, ok := y.pts[l]; ok {
return true return true
@ -234,31 +219,28 @@ func (x ptset) Intersects(y_ PointsToSet) bool {
return false return false
} }
// ---- Pointer public interface func (p Pointer) String() string {
// ptr adapts a node to the Pointer interface.
type ptr struct {
a *analysis
cgn *cgnode
n nodeid // non-zero
}
func (p ptr) String() string {
return fmt.Sprintf("n%d", p.n) 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 return p.cgn
} }
func (p ptr) PointsTo() PointsToSet { // PointsTo returns the points-to set of this pointer.
return ptset{p.a, p.a.nodes[p.n].pts} 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()) 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() 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). // Record the (v, id) relation if the client has queried pts(v).
if _, ok := a.config.Queries[v]; ok { 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). // Record the (*v, id) relation if the client has queried pts(*v).
if _, ok := a.config.IndirectQueries[v]; ok { if _, ok := a.config.IndirectQueries[v]; ok {
indirect := a.addNodes(v.Type(), "query.indirect") indirect := a.addNodes(v.Type(), "query.indirect")
a.genLoad(cgn, indirect, v, 0, a.sizeof(v.Type())) 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 { if probe == 0 {
probe = a.addNodes(t, "print") probe = a.addNodes(t, "print")
a.probes[call] = probe 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)) 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) e.errorf("unreachable print() statement has expectation %s", e)
continue continue
} }
if pr.arg0 == nil { if tArg := pr.instr.Args[0].Type(); !pointer.CanPoint(tArg) {
ok = false 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 continue
} }
} }

View File

@ -31,5 +31,4 @@ func main() {
// labels, even though it may contain pointers that do. // 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) // @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.(func(int) int)) // @pointsto main.incr
print(i.(S)) // @pointsto
} }

View File

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