go.tools/go/pointer: node renumbering
This change renumbers nodes so that addressable ones
(that may appear in a points-to set) all have lower
numbers than non-addressable ones----initially at least:
reflection, SetFinalizer, etc add new nodes during
solving.
This improves the efficiency of sparse PTS
representations (to be added later). The largest int in
a PTS is now about 20% of the previous max.
Overview:
- move constraint stuff into constraint.go.
- add two methods to constraint:
(1) renumber(): renumbers all nodeids. The
implementations are very repetitive but simple. I
thought hard about other ways (mixins, reflection)
but decided this one was fine.
(2) indirect(): report the set of nodeids whose
points-to relations depend on the solver, not just
the initial constraint graph.
(This method is currently unused and is logically
part of a forthcoming change to implement PE/LE
presolver optimizations. (Perhaps I should comment
it out/remove it for now.)
- split up the population of the intrinsics map by file.
- delete analysis.probes (unused field)
- remove state="..." from panic message; unnecessary.
LGTM=crawshaw
R=crawshaw
CC=golang-codereviews
https://golang.org/cl/73320043
diff --git a/go/pointer/analysis.go b/go/pointer/analysis.go
index 1464982..42deb0b 100644
--- a/go/pointer/analysis.go
+++ b/go/pointer/analysis.go
@@ -102,91 +102,6 @@
complex constraintset
}
-type constraint interface {
- String() string
-
- // For a complex constraint, returns the nodeid of the pointer
- // to which it is attached.
- ptr() nodeid
-
- // solve is called for complex constraints when the pts for
- // the node to which they are attached has changed.
- solve(a *analysis, n *node, delta nodeset)
-}
-
-// dst = &src
-// pts(dst) ⊇ {src}
-// A base constraint used to initialize the solver's pt sets
-type addrConstraint struct {
- dst nodeid // (ptr)
- src nodeid
-}
-
-// dst = src
-// A simple constraint represented directly as a copyTo graph edge.
-type copyConstraint struct {
- dst nodeid
- src nodeid // (ptr)
-}
-
-// dst = src[offset]
-// A complex constraint attached to src (the pointer)
-type loadConstraint struct {
- offset uint32
- dst nodeid
- src nodeid // (ptr)
-}
-
-// dst[offset] = src
-// A complex constraint attached to dst (the pointer)
-type storeConstraint struct {
- offset uint32
- dst nodeid // (ptr)
- src nodeid
-}
-
-// dst = &src.f or dst = &src[0]
-// A complex constraint attached to dst (the pointer)
-type offsetAddrConstraint struct {
- offset uint32
- dst nodeid
- src nodeid // (ptr)
-}
-
-// dst = src.(typ) where typ is an interface
-// A complex constraint attached to src (the interface).
-// No representation change: pts(dst) and pts(src) contains tagged objects.
-type typeFilterConstraint struct {
- typ types.Type // an interface type
- dst nodeid
- src nodeid // (ptr)
-}
-
-// dst = src.(typ) where typ is a concrete type
-// A complex constraint attached to src (the interface).
-//
-// If exact, only tagged objects identical to typ are untagged.
-// If !exact, tagged objects assignable to typ are untagged too.
-// The latter is needed for various reflect operators, e.g. Send.
-//
-// This entails a representation change:
-// pts(src) contains tagged objects,
-// pts(dst) contains their payloads.
-type untagConstraint struct {
- typ types.Type // a concrete type
- dst nodeid
- src nodeid // (ptr)
- exact bool
-}
-
-// src.method(params...)
-// A complex constraint attached to iface.
-type invokeConstraint struct {
- method *types.Func // the abstract method
- iface nodeid // (ptr) the interface
- params nodeid // the first parameter in the params/results block
-}
-
// An analysis instance holds the state of a single pointer analysis problem.
type analysis struct {
config *Config // the client's control/observer interface
@@ -200,7 +115,6 @@
cgnodes []*cgnode // all cgnodes
genq []*cgnode // queue of functions to generate constraints for
intrinsics map[*ssa.Function]intrinsic // non-nil values are summaries for intrinsic fns
- probes map[*ssa.CallCommon]nodeid // maps call to print() to argument variable
globalval map[ssa.Value]nodeid // node for each global ssa.Value
globalobj map[ssa.Value]nodeid // maps v to sole member of pts(v), if singleton
localval map[ssa.Value]nodeid // node for each local ssa.Value
@@ -291,10 +205,9 @@
// always succeed. An error can occur only due to an internal bug.
//
func Analyze(config *Config) (result *Result, err error) {
- stage := "setup"
defer func() {
if p := recover(); p != nil {
- err = fmt.Errorf("internal error in pointer analysis %s: %v (please report this bug)", stage, p)
+ err = fmt.Errorf("internal error in pointer analysis: %v (please report this bug)", p)
fmt.Fprintln(os.Stderr, "Internal panic in pointer analysis:")
debug.PrintStack()
}
@@ -360,7 +273,6 @@
}
a.computeTrackBits()
- stage = "constraint generation"
a.generate()
if a.log != nil {
@@ -376,23 +288,11 @@
fmt.Fprintf(a.log, "# nodes:\t%d\n", len(a.nodes))
}
- // stage = "constraint optimization"
- // a.optimize()
+ a.optimize()
- stage = "solver"
a.solve()
- if a.log != nil {
- // Dump solution.
- for i, n := range a.nodes {
- if n.pts != nil {
- fmt.Fprintf(a.log, "pts(n%d) = %s : %s\n", i, n.pts, n.typ)
- }
- }
- }
-
// Create callgraph.Nodes in deterministic order.
- stage = "callgraph construction"
if cg := a.result.CallGraph; cg != nil {
for _, caller := range a.cgnodes {
cg.CreateNode(caller.fn)
diff --git a/go/pointer/constraint.go b/go/pointer/constraint.go
new file mode 100644
index 0000000..f7603cb
--- /dev/null
+++ b/go/pointer/constraint.go
@@ -0,0 +1,167 @@
+// Copyright 2013 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package pointer
+
+import (
+ "code.google.com/p/go.tools/go/types"
+)
+
+type constraint interface {
+ // For a complex constraint, returns the nodeid of the pointer
+ // to which it is attached.
+ ptr() nodeid
+
+ // indirect returns (by appending to the argument) the constraint's
+ // "indirect" nodes as defined in (Hardekopf 2007b):
+ // nodes whose points-to relations are not completely
+ // represented in the initial constraint graph.
+ //
+ // TODO(adonovan): I think we need >1 results in some obscure
+ // cases. If not, just return a nodeid, like ptr().
+ //
+ indirect(nodes []nodeid) []nodeid
+
+ // renumber replaces each nodeid n in the constraint by mapping[n].
+ renumber(mapping []nodeid)
+
+ // solve is called for complex constraints when the pts for
+ // the node to which they are attached has changed.
+ solve(a *analysis, n *node, delta nodeset)
+
+ String() string
+}
+
+// dst = &src
+// pts(dst) ⊇ {src}
+// A base constraint used to initialize the solver's pt sets
+type addrConstraint struct {
+ dst nodeid // (ptr)
+ src nodeid
+}
+
+func (c *addrConstraint) ptr() nodeid { panic("addrConstraint: not a complex constraint") }
+func (c *addrConstraint) indirect(nodes []nodeid) []nodeid {
+ panic("addrConstraint: not a complex constraint")
+}
+func (c *addrConstraint) renumber(mapping []nodeid) {
+ c.dst = mapping[c.dst]
+ c.src = mapping[c.src]
+}
+
+// dst = src
+// A simple constraint represented directly as a copyTo graph edge.
+type copyConstraint struct {
+ dst nodeid
+ src nodeid // (ptr)
+}
+
+func (c *copyConstraint) ptr() nodeid { panic("copyConstraint: not a complex constraint") }
+func (c *copyConstraint) indirect(nodes []nodeid) []nodeid {
+ panic("copyConstraint: not a complex constraint")
+}
+func (c *copyConstraint) renumber(mapping []nodeid) {
+ c.dst = mapping[c.dst]
+ c.src = mapping[c.src]
+}
+
+// dst = src[offset]
+// A complex constraint attached to src (the pointer)
+type loadConstraint struct {
+ offset uint32
+ dst nodeid // (indirect)
+ src nodeid // (ptr)
+}
+
+func (c *loadConstraint) ptr() nodeid { return c.src }
+func (c *loadConstraint) indirect(nodes []nodeid) []nodeid { return append(nodes, c.dst) }
+func (c *loadConstraint) renumber(mapping []nodeid) {
+ c.dst = mapping[c.dst]
+ c.src = mapping[c.src]
+}
+
+// dst[offset] = src
+// A complex constraint attached to dst (the pointer)
+type storeConstraint struct {
+ offset uint32
+ dst nodeid // (ptr)
+ src nodeid
+}
+
+func (c *storeConstraint) ptr() nodeid { return c.dst }
+func (c *storeConstraint) indirect(nodes []nodeid) []nodeid { return nodes }
+func (c *storeConstraint) renumber(mapping []nodeid) {
+ c.dst = mapping[c.dst]
+ c.src = mapping[c.src]
+}
+
+// dst = &src.f or dst = &src[0]
+// A complex constraint attached to dst (the pointer)
+type offsetAddrConstraint struct {
+ offset uint32
+ dst nodeid // (indirect)
+ src nodeid // (ptr)
+}
+
+func (c *offsetAddrConstraint) ptr() nodeid { return c.src }
+func (c *offsetAddrConstraint) indirect(nodes []nodeid) []nodeid { return append(nodes, c.dst) }
+func (c *offsetAddrConstraint) renumber(mapping []nodeid) {
+ c.dst = mapping[c.dst]
+ c.src = mapping[c.src]
+}
+
+// dst = src.(typ) where typ is an interface
+// A complex constraint attached to src (the interface).
+// No representation change: pts(dst) and pts(src) contains tagged objects.
+type typeFilterConstraint struct {
+ typ types.Type // an interface type
+ dst nodeid // (indirect)
+ src nodeid // (ptr)
+}
+
+func (c *typeFilterConstraint) ptr() nodeid { return c.src }
+func (c *typeFilterConstraint) indirect(nodes []nodeid) []nodeid { return append(nodes, c.dst) }
+func (c *typeFilterConstraint) renumber(mapping []nodeid) {
+ c.dst = mapping[c.dst]
+ c.src = mapping[c.src]
+}
+
+// dst = src.(typ) where typ is a concrete type
+// A complex constraint attached to src (the interface).
+//
+// If exact, only tagged objects identical to typ are untagged.
+// If !exact, tagged objects assignable to typ are untagged too.
+// The latter is needed for various reflect operators, e.g. Send.
+//
+// This entails a representation change:
+// pts(src) contains tagged objects,
+// pts(dst) contains their payloads.
+type untagConstraint struct {
+ typ types.Type // a concrete type
+ dst nodeid // (indirect)
+ src nodeid // (ptr)
+ exact bool
+}
+
+func (c *untagConstraint) ptr() nodeid { return c.src }
+func (c *untagConstraint) indirect(nodes []nodeid) []nodeid { return append(nodes, c.dst) }
+func (c *untagConstraint) renumber(mapping []nodeid) {
+ c.dst = mapping[c.dst]
+ c.src = mapping[c.src]
+}
+
+// src.method(params...)
+// A complex constraint attached to iface.
+type invokeConstraint struct {
+ method *types.Func // the abstract method
+ iface nodeid // (ptr) the interface
+ params nodeid // (indirect) the first param in the params/results block
+}
+
+func (c *invokeConstraint) ptr() nodeid { return c.iface }
+func (c *invokeConstraint) indirect(nodes []nodeid) []nodeid { return append(nodes, c.params) }
+func (c *invokeConstraint) renumber(mapping []nodeid) {
+ c.iface = mapping[c.iface]
+ c.params = mapping[c.params]
+}
diff --git a/go/pointer/gen.go b/go/pointer/gen.go
index fdd2370..c451c8d 100644
--- a/go/pointer/gen.go
+++ b/go/pointer/gen.go
@@ -1260,4 +1260,10 @@
a.endObject(obj, nil, "<command-line args>")
a.addressOf(T, a.objectNode(nil, os.Var("Args")), obj)
}
+
+ // Discard generation state, to avoid confusion after node renumbering.
+ a.panicNode = 0
+ a.globalval = nil
+ a.localval = nil
+ a.localobj = nil
}
diff --git a/go/pointer/intrinsics.go b/go/pointer/intrinsics.go
index 69ce878..a2257fe 100644
--- a/go/pointer/intrinsics.go
+++ b/go/pointer/intrinsics.go
@@ -30,124 +30,13 @@
// Initialized in explicit init() to defeat (spurious) initialization
// cycle error.
-var intrinsicsByName map[string]intrinsic
+var intrinsicsByName = make(map[string]intrinsic)
func init() {
// Key strings are from Function.String().
// That little dot ۰ is an Arabic zero numeral (U+06F0),
// categories [Nd].
- intrinsicsByName = map[string]intrinsic{
- // reflect.Value methods.
- "(reflect.Value).Addr": ext۰reflect۰Value۰Addr,
- "(reflect.Value).Bool": ext۰NoEffect,
- "(reflect.Value).Bytes": ext۰reflect۰Value۰Bytes,
- "(reflect.Value).Call": ext۰reflect۰Value۰Call,
- "(reflect.Value).CallSlice": ext۰reflect۰Value۰CallSlice,
- "(reflect.Value).CanAddr": ext۰NoEffect,
- "(reflect.Value).CanInterface": ext۰NoEffect,
- "(reflect.Value).CanSet": ext۰NoEffect,
- "(reflect.Value).Cap": ext۰NoEffect,
- "(reflect.Value).Close": ext۰NoEffect,
- "(reflect.Value).Complex": ext۰NoEffect,
- "(reflect.Value).Convert": ext۰reflect۰Value۰Convert,
- "(reflect.Value).Elem": ext۰reflect۰Value۰Elem,
- "(reflect.Value).Field": ext۰reflect۰Value۰Field,
- "(reflect.Value).FieldByIndex": ext۰reflect۰Value۰FieldByIndex,
- "(reflect.Value).FieldByName": ext۰reflect۰Value۰FieldByName,
- "(reflect.Value).FieldByNameFunc": ext۰reflect۰Value۰FieldByNameFunc,
- "(reflect.Value).Float": ext۰NoEffect,
- "(reflect.Value).Index": ext۰reflect۰Value۰Index,
- "(reflect.Value).Int": ext۰NoEffect,
- "(reflect.Value).Interface": ext۰reflect۰Value۰Interface,
- "(reflect.Value).InterfaceData": ext۰NoEffect,
- "(reflect.Value).IsNil": ext۰NoEffect,
- "(reflect.Value).IsValid": ext۰NoEffect,
- "(reflect.Value).Kind": ext۰NoEffect,
- "(reflect.Value).Len": ext۰NoEffect,
- "(reflect.Value).MapIndex": ext۰reflect۰Value۰MapIndex,
- "(reflect.Value).MapKeys": ext۰reflect۰Value۰MapKeys,
- "(reflect.Value).Method": ext۰reflect۰Value۰Method,
- "(reflect.Value).MethodByName": ext۰reflect۰Value۰MethodByName,
- "(reflect.Value).NumField": ext۰NoEffect,
- "(reflect.Value).NumMethod": ext۰NoEffect,
- "(reflect.Value).OverflowComplex": ext۰NoEffect,
- "(reflect.Value).OverflowFloat": ext۰NoEffect,
- "(reflect.Value).OverflowInt": ext۰NoEffect,
- "(reflect.Value).OverflowUint": ext۰NoEffect,
- "(reflect.Value).Pointer": ext۰NoEffect,
- "(reflect.Value).Recv": ext۰reflect۰Value۰Recv,
- "(reflect.Value).Send": ext۰reflect۰Value۰Send,
- "(reflect.Value).Set": ext۰reflect۰Value۰Set,
- "(reflect.Value).SetBool": ext۰NoEffect,
- "(reflect.Value).SetBytes": ext۰reflect۰Value۰SetBytes,
- "(reflect.Value).SetComplex": ext۰NoEffect,
- "(reflect.Value).SetFloat": ext۰NoEffect,
- "(reflect.Value).SetInt": ext۰NoEffect,
- "(reflect.Value).SetLen": ext۰NoEffect,
- "(reflect.Value).SetMapIndex": ext۰reflect۰Value۰SetMapIndex,
- "(reflect.Value).SetPointer": ext۰reflect۰Value۰SetPointer,
- "(reflect.Value).SetString": ext۰NoEffect,
- "(reflect.Value).SetUint": ext۰NoEffect,
- "(reflect.Value).Slice": ext۰reflect۰Value۰Slice,
- "(reflect.Value).String": ext۰NoEffect,
- "(reflect.Value).TryRecv": ext۰reflect۰Value۰Recv,
- "(reflect.Value).TrySend": ext۰reflect۰Value۰Send,
- "(reflect.Value).Type": ext۰NoEffect,
- "(reflect.Value).Uint": ext۰NoEffect,
- "(reflect.Value).UnsafeAddr": ext۰NoEffect,
-
- // Standalone reflect.* functions.
- "reflect.Append": ext۰reflect۰Append,
- "reflect.AppendSlice": ext۰reflect۰AppendSlice,
- "reflect.Copy": ext۰reflect۰Copy,
- "reflect.ChanOf": ext۰reflect۰ChanOf,
- "reflect.DeepEqual": ext۰NoEffect,
- "reflect.Indirect": ext۰reflect۰Indirect,
- "reflect.MakeChan": ext۰reflect۰MakeChan,
- "reflect.MakeFunc": ext۰reflect۰MakeFunc,
- "reflect.MakeMap": ext۰reflect۰MakeMap,
- "reflect.MakeSlice": ext۰reflect۰MakeSlice,
- "reflect.MapOf": ext۰reflect۰MapOf,
- "reflect.New": ext۰reflect۰New,
- "reflect.NewAt": ext۰reflect۰NewAt,
- "reflect.PtrTo": ext۰reflect۰PtrTo,
- "reflect.Select": ext۰reflect۰Select,
- "reflect.SliceOf": ext۰reflect۰SliceOf,
- "reflect.TypeOf": ext۰reflect۰TypeOf,
- "reflect.ValueOf": ext۰reflect۰ValueOf,
- "reflect.Zero": ext۰reflect۰Zero,
- "reflect.init": ext۰NoEffect,
-
- // *reflect.rtype methods
- "(*reflect.rtype).Align": ext۰NoEffect,
- "(*reflect.rtype).AssignableTo": ext۰NoEffect,
- "(*reflect.rtype).Bits": ext۰NoEffect,
- "(*reflect.rtype).ChanDir": ext۰NoEffect,
- "(*reflect.rtype).ConvertibleTo": ext۰NoEffect,
- "(*reflect.rtype).Elem": ext۰reflect۰rtype۰Elem,
- "(*reflect.rtype).Field": ext۰reflect۰rtype۰Field,
- "(*reflect.rtype).FieldAlign": ext۰NoEffect,
- "(*reflect.rtype).FieldByIndex": ext۰reflect۰rtype۰FieldByIndex,
- "(*reflect.rtype).FieldByName": ext۰reflect۰rtype۰FieldByName,
- "(*reflect.rtype).FieldByNameFunc": ext۰reflect۰rtype۰FieldByNameFunc,
- "(*reflect.rtype).Implements": ext۰NoEffect,
- "(*reflect.rtype).In": ext۰reflect۰rtype۰In,
- "(*reflect.rtype).IsVariadic": ext۰NoEffect,
- "(*reflect.rtype).Key": ext۰reflect۰rtype۰Key,
- "(*reflect.rtype).Kind": ext۰NoEffect,
- "(*reflect.rtype).Len": ext۰NoEffect,
- "(*reflect.rtype).Method": ext۰reflect۰rtype۰Method,
- "(*reflect.rtype).MethodByName": ext۰reflect۰rtype۰MethodByName,
- "(*reflect.rtype).Name": ext۰NoEffect,
- "(*reflect.rtype).NumField": ext۰NoEffect,
- "(*reflect.rtype).NumIn": ext۰NoEffect,
- "(*reflect.rtype).NumMethod": ext۰NoEffect,
- "(*reflect.rtype).NumOut": ext۰NoEffect,
- "(*reflect.rtype).Out": ext۰reflect۰rtype۰Out,
- "(*reflect.rtype).PkgPath": ext۰NoEffect,
- "(*reflect.rtype).Size": ext۰NoEffect,
- "(*reflect.rtype).String": ext۰NoEffect,
-
+ for name, fn := range map[string]intrinsic{
// Other packages.
"bytes.Equal": ext۰NoEffect,
"bytes.IndexByte": ext۰NoEffect,
@@ -287,6 +176,8 @@
"time.now": ext۰NoEffect,
"time.startTimer": ext۰NoEffect,
"time.stopTimer": ext۰NoEffect,
+ } {
+ intrinsicsByName[name] = fn
}
}
@@ -369,12 +260,16 @@
x nodeid
}
-func (c *runtimeSetFinalizerConstraint) String() string {
- return fmt.Sprintf("runtime.SetFinalizer(n%d, n%d)", c.x, c.f)
+func (c *runtimeSetFinalizerConstraint) ptr() nodeid { return c.f }
+func (c *runtimeSetFinalizerConstraint) indirect(nodes []nodeid) []nodeid { return nodes }
+func (c *runtimeSetFinalizerConstraint) renumber(mapping []nodeid) {
+ c.targets = mapping[c.targets]
+ c.f = mapping[c.f]
+ c.x = mapping[c.x]
}
-func (c *runtimeSetFinalizerConstraint) ptr() nodeid {
- return c.f
+func (c *runtimeSetFinalizerConstraint) String() string {
+ return fmt.Sprintf("runtime.SetFinalizer(n%d, n%d)", c.x, c.f)
}
func (c *runtimeSetFinalizerConstraint) solve(a *analysis, _ *node, delta nodeset) {
diff --git a/go/pointer/opt.go b/go/pointer/opt.go
new file mode 100644
index 0000000..e27508a
--- /dev/null
+++ b/go/pointer/opt.go
@@ -0,0 +1,124 @@
+// Copyright 2013 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package pointer
+
+// This file defines the constraint optimiser ("pre-solver").
+
+import (
+ "fmt"
+)
+
+func (a *analysis) optimize() {
+ a.renumber()
+
+ // TODO(adonovan): opt:
+ // PE, LE, HVN, HRU, sparse bitsets, etc.
+}
+
+// renumber permutes a.nodes so that all nodes within an addressable
+// object appear before all non-addressable nodes, maintaining the
+// order of nodes within the same object (as required by offsetAddr).
+//
+// renumber must update every nodeid in the analysis (constraints,
+// Pointers, callgraph, etc) to reflect the new ordering.
+//
+// This is an optimisation to increase the locality and efficiency of
+// sparse representations of points-to sets. (Typically only about
+// 20% of nodes are within an object.)
+//
+// NB: nodes added during solving (e.g. for reflection, SetFinalizer)
+// will be appended to the end.
+//
+func (a *analysis) renumber() {
+ N := nodeid(len(a.nodes))
+ newNodes := make([]*node, N, N)
+ renumbering := make([]nodeid, N, N) // maps old to new
+
+ var i, j nodeid
+
+ // The zero node is special.
+ newNodes[j] = a.nodes[i]
+ renumbering[i] = j
+ i++
+ j++
+
+ // Pass 1: object nodes.
+ for i < N {
+ obj := a.nodes[i].obj
+ if obj == nil {
+ i++
+ continue
+ }
+
+ end := i + nodeid(obj.size)
+ for i < end {
+ newNodes[j] = a.nodes[i]
+ renumbering[i] = j
+ i++
+ j++
+ }
+ }
+ nobj := j
+
+ // Pass 2: non-object nodes.
+ for i = 1; i < N; {
+ obj := a.nodes[i].obj
+ if obj != nil {
+ i += nodeid(obj.size)
+ continue
+ }
+
+ newNodes[j] = a.nodes[i]
+ renumbering[i] = j
+ i++
+ j++
+ }
+
+ if j != N {
+ panic(fmt.Sprintf("internal error: j=%d, N=%d", j, N))
+ }
+
+ // Log the remapping table.
+ if a.log != nil {
+ fmt.Fprintf(a.log, "Renumbering nodes to improve density:\n")
+ fmt.Fprintf(a.log, "(%d object nodes of %d total)\n", nobj, N)
+ for old, new := range renumbering {
+ fmt.Fprintf(a.log, "\tn%d -> n%d\n", old, new)
+ }
+ }
+
+ // Now renumber all existing nodeids to use the new node permutation.
+ // It is critical that all reachable nodeids are accounted for!
+
+ // Renumber nodeids in queried Pointers.
+ for v, ptr := range a.result.Queries {
+ ptr.n = renumbering[ptr.n]
+ a.result.Queries[v] = ptr
+ }
+ for v, ptr := range a.result.IndirectQueries {
+ ptr.n = renumbering[ptr.n]
+ a.result.IndirectQueries[v] = ptr
+ }
+
+ // Renumber nodeids in global objects.
+ for v, id := range a.globalobj {
+ a.globalobj[v] = renumbering[id]
+ }
+
+ // Renumber nodeids in constraints.
+ for _, c := range a.constraints {
+ c.renumber(renumbering)
+ }
+
+ // Renumber nodeids in the call graph.
+ for _, cgn := range a.cgnodes {
+ cgn.obj = renumbering[cgn.obj]
+ for _, site := range cgn.sites {
+ site.targets = renumbering[site.targets]
+ }
+ }
+
+ a.nodes = newNodes
+}
diff --git a/go/pointer/reflect.go b/go/pointer/reflect.go
index b0dd9d0..ed45177 100644
--- a/go/pointer/reflect.go
+++ b/go/pointer/reflect.go
@@ -32,6 +32,123 @@
"code.google.com/p/go.tools/go/types"
)
+func init() {
+ for name, fn := range map[string]intrinsic{
+ // reflect.Value methods.
+ "(reflect.Value).Addr": ext۰reflect۰Value۰Addr,
+ "(reflect.Value).Bool": ext۰NoEffect,
+ "(reflect.Value).Bytes": ext۰reflect۰Value۰Bytes,
+ "(reflect.Value).Call": ext۰reflect۰Value۰Call,
+ "(reflect.Value).CallSlice": ext۰reflect۰Value۰CallSlice,
+ "(reflect.Value).CanAddr": ext۰NoEffect,
+ "(reflect.Value).CanInterface": ext۰NoEffect,
+ "(reflect.Value).CanSet": ext۰NoEffect,
+ "(reflect.Value).Cap": ext۰NoEffect,
+ "(reflect.Value).Close": ext۰NoEffect,
+ "(reflect.Value).Complex": ext۰NoEffect,
+ "(reflect.Value).Convert": ext۰reflect۰Value۰Convert,
+ "(reflect.Value).Elem": ext۰reflect۰Value۰Elem,
+ "(reflect.Value).Field": ext۰reflect۰Value۰Field,
+ "(reflect.Value).FieldByIndex": ext۰reflect۰Value۰FieldByIndex,
+ "(reflect.Value).FieldByName": ext۰reflect۰Value۰FieldByName,
+ "(reflect.Value).FieldByNameFunc": ext۰reflect۰Value۰FieldByNameFunc,
+ "(reflect.Value).Float": ext۰NoEffect,
+ "(reflect.Value).Index": ext۰reflect۰Value۰Index,
+ "(reflect.Value).Int": ext۰NoEffect,
+ "(reflect.Value).Interface": ext۰reflect۰Value۰Interface,
+ "(reflect.Value).InterfaceData": ext۰NoEffect,
+ "(reflect.Value).IsNil": ext۰NoEffect,
+ "(reflect.Value).IsValid": ext۰NoEffect,
+ "(reflect.Value).Kind": ext۰NoEffect,
+ "(reflect.Value).Len": ext۰NoEffect,
+ "(reflect.Value).MapIndex": ext۰reflect۰Value۰MapIndex,
+ "(reflect.Value).MapKeys": ext۰reflect۰Value۰MapKeys,
+ "(reflect.Value).Method": ext۰reflect۰Value۰Method,
+ "(reflect.Value).MethodByName": ext۰reflect۰Value۰MethodByName,
+ "(reflect.Value).NumField": ext۰NoEffect,
+ "(reflect.Value).NumMethod": ext۰NoEffect,
+ "(reflect.Value).OverflowComplex": ext۰NoEffect,
+ "(reflect.Value).OverflowFloat": ext۰NoEffect,
+ "(reflect.Value).OverflowInt": ext۰NoEffect,
+ "(reflect.Value).OverflowUint": ext۰NoEffect,
+ "(reflect.Value).Pointer": ext۰NoEffect,
+ "(reflect.Value).Recv": ext۰reflect۰Value۰Recv,
+ "(reflect.Value).Send": ext۰reflect۰Value۰Send,
+ "(reflect.Value).Set": ext۰reflect۰Value۰Set,
+ "(reflect.Value).SetBool": ext۰NoEffect,
+ "(reflect.Value).SetBytes": ext۰reflect۰Value۰SetBytes,
+ "(reflect.Value).SetComplex": ext۰NoEffect,
+ "(reflect.Value).SetFloat": ext۰NoEffect,
+ "(reflect.Value).SetInt": ext۰NoEffect,
+ "(reflect.Value).SetLen": ext۰NoEffect,
+ "(reflect.Value).SetMapIndex": ext۰reflect۰Value۰SetMapIndex,
+ "(reflect.Value).SetPointer": ext۰reflect۰Value۰SetPointer,
+ "(reflect.Value).SetString": ext۰NoEffect,
+ "(reflect.Value).SetUint": ext۰NoEffect,
+ "(reflect.Value).Slice": ext۰reflect۰Value۰Slice,
+ "(reflect.Value).String": ext۰NoEffect,
+ "(reflect.Value).TryRecv": ext۰reflect۰Value۰Recv,
+ "(reflect.Value).TrySend": ext۰reflect۰Value۰Send,
+ "(reflect.Value).Type": ext۰NoEffect,
+ "(reflect.Value).Uint": ext۰NoEffect,
+ "(reflect.Value).UnsafeAddr": ext۰NoEffect,
+
+ // Standalone reflect.* functions.
+ "reflect.Append": ext۰reflect۰Append,
+ "reflect.AppendSlice": ext۰reflect۰AppendSlice,
+ "reflect.Copy": ext۰reflect۰Copy,
+ "reflect.ChanOf": ext۰reflect۰ChanOf,
+ "reflect.DeepEqual": ext۰NoEffect,
+ "reflect.Indirect": ext۰reflect۰Indirect,
+ "reflect.MakeChan": ext۰reflect۰MakeChan,
+ "reflect.MakeFunc": ext۰reflect۰MakeFunc,
+ "reflect.MakeMap": ext۰reflect۰MakeMap,
+ "reflect.MakeSlice": ext۰reflect۰MakeSlice,
+ "reflect.MapOf": ext۰reflect۰MapOf,
+ "reflect.New": ext۰reflect۰New,
+ "reflect.NewAt": ext۰reflect۰NewAt,
+ "reflect.PtrTo": ext۰reflect۰PtrTo,
+ "reflect.Select": ext۰reflect۰Select,
+ "reflect.SliceOf": ext۰reflect۰SliceOf,
+ "reflect.TypeOf": ext۰reflect۰TypeOf,
+ "reflect.ValueOf": ext۰reflect۰ValueOf,
+ "reflect.Zero": ext۰reflect۰Zero,
+ "reflect.init": ext۰NoEffect,
+
+ // *reflect.rtype methods
+ "(*reflect.rtype).Align": ext۰NoEffect,
+ "(*reflect.rtype).AssignableTo": ext۰NoEffect,
+ "(*reflect.rtype).Bits": ext۰NoEffect,
+ "(*reflect.rtype).ChanDir": ext۰NoEffect,
+ "(*reflect.rtype).ConvertibleTo": ext۰NoEffect,
+ "(*reflect.rtype).Elem": ext۰reflect۰rtype۰Elem,
+ "(*reflect.rtype).Field": ext۰reflect۰rtype۰Field,
+ "(*reflect.rtype).FieldAlign": ext۰NoEffect,
+ "(*reflect.rtype).FieldByIndex": ext۰reflect۰rtype۰FieldByIndex,
+ "(*reflect.rtype).FieldByName": ext۰reflect۰rtype۰FieldByName,
+ "(*reflect.rtype).FieldByNameFunc": ext۰reflect۰rtype۰FieldByNameFunc,
+ "(*reflect.rtype).Implements": ext۰NoEffect,
+ "(*reflect.rtype).In": ext۰reflect۰rtype۰In,
+ "(*reflect.rtype).IsVariadic": ext۰NoEffect,
+ "(*reflect.rtype).Key": ext۰reflect۰rtype۰Key,
+ "(*reflect.rtype).Kind": ext۰NoEffect,
+ "(*reflect.rtype).Len": ext۰NoEffect,
+ "(*reflect.rtype).Method": ext۰reflect۰rtype۰Method,
+ "(*reflect.rtype).MethodByName": ext۰reflect۰rtype۰MethodByName,
+ "(*reflect.rtype).Name": ext۰NoEffect,
+ "(*reflect.rtype).NumField": ext۰NoEffect,
+ "(*reflect.rtype).NumIn": ext۰NoEffect,
+ "(*reflect.rtype).NumMethod": ext۰NoEffect,
+ "(*reflect.rtype).NumOut": ext۰NoEffect,
+ "(*reflect.rtype).Out": ext۰reflect۰rtype۰Out,
+ "(*reflect.rtype).PkgPath": ext۰NoEffect,
+ "(*reflect.rtype).Size": ext۰NoEffect,
+ "(*reflect.rtype).String": ext۰NoEffect,
+ } {
+ intrinsicsByName[name] = fn
+ }
+}
+
// -------------------- (reflect.Value) --------------------
func ext۰reflect۰Value۰Addr(a *analysis, cgn *cgnode) {}
@@ -41,17 +158,20 @@
// result = v.Bytes()
type rVBytesConstraint struct {
v nodeid // (ptr)
- result nodeid
+ result nodeid // (indirect)
+}
+
+func (c *rVBytesConstraint) ptr() nodeid { return c.v }
+func (c *rVBytesConstraint) indirect(nodes []nodeid) []nodeid { return append(nodes, c.result) }
+func (c *rVBytesConstraint) renumber(mapping []nodeid) {
+ c.v = mapping[c.v]
+ c.result = mapping[c.result]
}
func (c *rVBytesConstraint) String() string {
return fmt.Sprintf("n%d = reflect n%d.Bytes()", c.result, c.v)
}
-func (c *rVBytesConstraint) ptr() nodeid {
- return c.v
-}
-
func (c *rVBytesConstraint) solve(a *analysis, _ *node, delta nodeset) {
changed := false
for vObj := range delta {
@@ -89,18 +209,30 @@
targets nodeid
v nodeid // (ptr)
arg nodeid // = in[*]
- result nodeid
- dotdotdot bool // interpret last arg as a "..." slice
+ result nodeid // (indirect)
+ dotdotdot bool // interpret last arg as a "..." slice
+}
+
+func (c *rVCallConstraint) ptr() nodeid { return c.v }
+func (c *rVCallConstraint) indirect(nodes []nodeid) []nodeid {
+ nodes = append(nodes, c.result)
+ // TODO(adonovan): we may be able to handle 'targets' out-of-band
+ // so that all implementations indirect() return a single value.
+ // We can then dispense with the slice.
+ nodes = append(nodes, c.targets)
+ return nodes
+}
+func (c *rVCallConstraint) renumber(mapping []nodeid) {
+ c.targets = mapping[c.targets]
+ c.v = mapping[c.v]
+ c.arg = mapping[c.arg]
+ c.result = mapping[c.result]
}
func (c *rVCallConstraint) String() string {
return fmt.Sprintf("n%d = reflect n%d.Call(n%d)", c.result, c.v, c.arg)
}
-func (c *rVCallConstraint) ptr() nodeid {
- return c.v
-}
-
func (c *rVCallConstraint) solve(a *analysis, _ *node, delta nodeset) {
if c.targets == 0 {
panic("no targets")
@@ -228,17 +360,20 @@
type rVElemConstraint struct {
cgn *cgnode
v nodeid // (ptr)
- result nodeid
+ result nodeid // (indirect)
+}
+
+func (c *rVElemConstraint) ptr() nodeid { return c.v }
+func (c *rVElemConstraint) indirect(nodes []nodeid) []nodeid { return append(nodes, c.result) }
+func (c *rVElemConstraint) renumber(mapping []nodeid) {
+ c.v = mapping[c.v]
+ c.result = mapping[c.result]
}
func (c *rVElemConstraint) String() string {
return fmt.Sprintf("n%d = reflect n%d.Elem()", c.result, c.v)
}
-func (c *rVElemConstraint) ptr() nodeid {
- return c.v
-}
-
func (c *rVElemConstraint) solve(a *analysis, _ *node, delta nodeset) {
changed := false
for vObj := range delta {
@@ -287,17 +422,20 @@
type rVIndexConstraint struct {
cgn *cgnode
v nodeid // (ptr)
- result nodeid
+ result nodeid // (indirect)
+}
+
+func (c *rVIndexConstraint) ptr() nodeid { return c.v }
+func (c *rVIndexConstraint) indirect(nodes []nodeid) []nodeid { return append(nodes, c.result) }
+func (c *rVIndexConstraint) renumber(mapping []nodeid) {
+ c.v = mapping[c.v]
+ c.result = mapping[c.result]
}
func (c *rVIndexConstraint) String() string {
return fmt.Sprintf("n%d = reflect n%d.Index()", c.result, c.v)
}
-func (c *rVIndexConstraint) ptr() nodeid {
- return c.v
-}
-
func (c *rVIndexConstraint) solve(a *analysis, _ *node, delta nodeset) {
changed := false
for vObj := range delta {
@@ -345,19 +483,21 @@
// result = v.Interface()
type rVInterfaceConstraint struct {
v nodeid // (ptr)
- result nodeid
+ result nodeid // (indirect)
+}
+
+func (c *rVInterfaceConstraint) ptr() nodeid { return c.v }
+func (c *rVInterfaceConstraint) indirect(nodes []nodeid) []nodeid { return append(nodes, c.result) }
+func (c *rVInterfaceConstraint) renumber(mapping []nodeid) {
+ c.v = mapping[c.v]
+ c.result = mapping[c.result]
}
func (c *rVInterfaceConstraint) String() string {
return fmt.Sprintf("n%d = reflect n%d.Interface()", c.result, c.v)
}
-func (c *rVInterfaceConstraint) ptr() nodeid {
- return c.v
-}
-
func (c *rVInterfaceConstraint) solve(a *analysis, _ *node, delta nodeset) {
- resultPts := &a.nodes[c.result].pts
changed := false
for vObj := range delta {
tDyn, payload, indirect := a.taggedValue(vObj)
@@ -372,7 +512,7 @@
a.addWork(c.result)
}
} else {
- if resultPts.add(vObj) {
+ if a.addLabel(c.result, vObj) {
changed = true
}
}
@@ -395,17 +535,20 @@
type rVMapIndexConstraint struct {
cgn *cgnode
v nodeid // (ptr)
- result nodeid
+ result nodeid // (indirect)
+}
+
+func (c *rVMapIndexConstraint) ptr() nodeid { return c.v }
+func (c *rVMapIndexConstraint) indirect(nodes []nodeid) []nodeid { return append(nodes, c.result) }
+func (c *rVMapIndexConstraint) renumber(mapping []nodeid) {
+ c.v = mapping[c.v]
+ c.result = mapping[c.result]
}
func (c *rVMapIndexConstraint) String() string {
return fmt.Sprintf("n%d = reflect n%d.MapIndex(_)", c.result, c.v)
}
-func (c *rVMapIndexConstraint) ptr() nodeid {
- return c.v
-}
-
func (c *rVMapIndexConstraint) solve(a *analysis, _ *node, delta nodeset) {
changed := false
for vObj := range delta {
@@ -445,17 +588,20 @@
type rVMapKeysConstraint struct {
cgn *cgnode
v nodeid // (ptr)
- result nodeid
+ result nodeid // (indirect)
+}
+
+func (c *rVMapKeysConstraint) ptr() nodeid { return c.v }
+func (c *rVMapKeysConstraint) indirect(nodes []nodeid) []nodeid { return append(nodes, c.result) }
+func (c *rVMapKeysConstraint) renumber(mapping []nodeid) {
+ c.v = mapping[c.v]
+ c.result = mapping[c.result]
}
func (c *rVMapKeysConstraint) String() string {
return fmt.Sprintf("n%d = reflect n%d.MapKeys()", c.result, c.v)
}
-func (c *rVMapKeysConstraint) ptr() nodeid {
- return c.v
-}
-
func (c *rVMapKeysConstraint) solve(a *analysis, _ *node, delta nodeset) {
changed := false
for vObj := range delta {
@@ -505,17 +651,20 @@
type rVRecvConstraint struct {
cgn *cgnode
v nodeid // (ptr)
- result nodeid
+ result nodeid // (indirect)
+}
+
+func (c *rVRecvConstraint) ptr() nodeid { return c.v }
+func (c *rVRecvConstraint) indirect(nodes []nodeid) []nodeid { return append(nodes, c.result) }
+func (c *rVRecvConstraint) renumber(mapping []nodeid) {
+ c.v = mapping[c.v]
+ c.result = mapping[c.result]
}
func (c *rVRecvConstraint) String() string {
return fmt.Sprintf("n%d = reflect n%d.Recv()", c.result, c.v)
}
-func (c *rVRecvConstraint) ptr() nodeid {
- return c.v
-}
-
func (c *rVRecvConstraint) solve(a *analysis, _ *node, delta nodeset) {
changed := false
for vObj := range delta {
@@ -559,12 +708,15 @@
x nodeid
}
-func (c *rVSendConstraint) String() string {
- return fmt.Sprintf("reflect n%d.Send(n%d)", c.v, c.x)
+func (c *rVSendConstraint) ptr() nodeid { return c.v }
+func (c *rVSendConstraint) indirect(nodes []nodeid) []nodeid { return nodes }
+func (c *rVSendConstraint) renumber(mapping []nodeid) {
+ c.v = mapping[c.v]
+ c.x = mapping[c.x]
}
-func (c *rVSendConstraint) ptr() nodeid {
- return c.v
+func (c *rVSendConstraint) String() string {
+ return fmt.Sprintf("reflect n%d.Send(n%d)", c.v, c.x)
}
func (c *rVSendConstraint) solve(a *analysis, _ *node, delta nodeset) {
@@ -608,12 +760,15 @@
x nodeid
}
-func (c *rVSetBytesConstraint) String() string {
- return fmt.Sprintf("reflect n%d.SetBytes(n%d)", c.v, c.x)
+func (c *rVSetBytesConstraint) ptr() nodeid { return c.v }
+func (c *rVSetBytesConstraint) indirect(nodes []nodeid) []nodeid { return nodes }
+func (c *rVSetBytesConstraint) renumber(mapping []nodeid) {
+ c.v = mapping[c.v]
+ c.x = mapping[c.x]
}
-func (c *rVSetBytesConstraint) ptr() nodeid {
- return c.v
+func (c *rVSetBytesConstraint) String() string {
+ return fmt.Sprintf("reflect n%d.SetBytes(n%d)", c.v, c.x)
}
func (c *rVSetBytesConstraint) solve(a *analysis, _ *node, delta nodeset) {
@@ -653,12 +808,16 @@
val nodeid
}
-func (c *rVSetMapIndexConstraint) String() string {
- return fmt.Sprintf("reflect n%d.SetMapIndex(n%d, n%d)", c.v, c.key, c.val)
+func (c *rVSetMapIndexConstraint) ptr() nodeid { return c.v }
+func (c *rVSetMapIndexConstraint) indirect(nodes []nodeid) []nodeid { return nodes }
+func (c *rVSetMapIndexConstraint) renumber(mapping []nodeid) {
+ c.v = mapping[c.v]
+ c.key = mapping[c.key]
+ c.val = mapping[c.val]
}
-func (c *rVSetMapIndexConstraint) ptr() nodeid {
- return c.v
+func (c *rVSetMapIndexConstraint) String() string {
+ return fmt.Sprintf("reflect n%d.SetMapIndex(n%d, n%d)", c.v, c.key, c.val)
}
func (c *rVSetMapIndexConstraint) solve(a *analysis, _ *node, delta nodeset) {
@@ -706,17 +865,20 @@
type rVSliceConstraint struct {
cgn *cgnode
v nodeid // (ptr)
- result nodeid
+ result nodeid // (indirect)
+}
+
+func (c *rVSliceConstraint) ptr() nodeid { return c.v }
+func (c *rVSliceConstraint) indirect(nodes []nodeid) []nodeid { return append(nodes, c.result) }
+func (c *rVSliceConstraint) renumber(mapping []nodeid) {
+ c.v = mapping[c.v]
+ c.result = mapping[c.result]
}
func (c *rVSliceConstraint) String() string {
return fmt.Sprintf("n%d = reflect n%d.Slice(_, _)", c.result, c.v)
}
-func (c *rVSliceConstraint) ptr() nodeid {
- return c.v
-}
-
func (c *rVSliceConstraint) solve(a *analysis, _ *node, delta nodeset) {
changed := false
for vObj := range delta {
@@ -780,18 +942,21 @@
type reflectChanOfConstraint struct {
cgn *cgnode
t nodeid // (ptr)
- result nodeid
+ result nodeid // (indirect)
dirs []types.ChanDir
}
+func (c *reflectChanOfConstraint) ptr() nodeid { return c.t }
+func (c *reflectChanOfConstraint) indirect(nodes []nodeid) []nodeid { return append(nodes, c.result) }
+func (c *reflectChanOfConstraint) renumber(mapping []nodeid) {
+ c.t = mapping[c.t]
+ c.result = mapping[c.result]
+}
+
func (c *reflectChanOfConstraint) String() string {
return fmt.Sprintf("n%d = reflect.ChanOf(n%d)", c.result, c.t)
}
-func (c *reflectChanOfConstraint) ptr() nodeid {
- return c.t
-}
-
func (c *reflectChanOfConstraint) solve(a *analysis, _ *node, delta nodeset) {
changed := false
for tObj := range delta {
@@ -845,17 +1010,20 @@
type reflectIndirectConstraint struct {
cgn *cgnode
v nodeid // (ptr)
- result nodeid
+ result nodeid // (indirect)
+}
+
+func (c *reflectIndirectConstraint) ptr() nodeid { return c.v }
+func (c *reflectIndirectConstraint) indirect(nodes []nodeid) []nodeid { return append(nodes, c.result) }
+func (c *reflectIndirectConstraint) renumber(mapping []nodeid) {
+ c.v = mapping[c.v]
+ c.result = mapping[c.result]
}
func (c *reflectIndirectConstraint) String() string {
return fmt.Sprintf("n%d = reflect.Indirect(n%d)", c.result, c.v)
}
-func (c *reflectIndirectConstraint) ptr() nodeid {
- return c.v
-}
-
func (c *reflectIndirectConstraint) solve(a *analysis, _ *node, delta nodeset) {
changed := false
for vObj := range delta {
@@ -893,17 +1061,20 @@
type reflectMakeChanConstraint struct {
cgn *cgnode
typ nodeid // (ptr)
- result nodeid
+ result nodeid // (indirect)
+}
+
+func (c *reflectMakeChanConstraint) ptr() nodeid { return c.typ }
+func (c *reflectMakeChanConstraint) indirect(nodes []nodeid) []nodeid { return append(nodes, c.result) }
+func (c *reflectMakeChanConstraint) renumber(mapping []nodeid) {
+ c.typ = mapping[c.typ]
+ c.result = mapping[c.result]
}
func (c *reflectMakeChanConstraint) String() string {
return fmt.Sprintf("n%d = reflect.MakeChan(n%d)", c.result, c.typ)
}
-func (c *reflectMakeChanConstraint) ptr() nodeid {
- return c.typ
-}
-
func (c *reflectMakeChanConstraint) solve(a *analysis, _ *node, delta nodeset) {
changed := false
for typObj := range delta {
@@ -947,17 +1118,20 @@
type reflectMakeMapConstraint struct {
cgn *cgnode
typ nodeid // (ptr)
- result nodeid
+ result nodeid // (indirect)
+}
+
+func (c *reflectMakeMapConstraint) ptr() nodeid { return c.typ }
+func (c *reflectMakeMapConstraint) indirect(nodes []nodeid) []nodeid { return append(nodes, c.result) }
+func (c *reflectMakeMapConstraint) renumber(mapping []nodeid) {
+ c.typ = mapping[c.typ]
+ c.result = mapping[c.result]
}
func (c *reflectMakeMapConstraint) String() string {
return fmt.Sprintf("n%d = reflect.MakeMap(n%d)", c.result, c.typ)
}
-func (c *reflectMakeMapConstraint) ptr() nodeid {
- return c.typ
-}
-
func (c *reflectMakeMapConstraint) solve(a *analysis, _ *node, delta nodeset) {
changed := false
for typObj := range delta {
@@ -1000,17 +1174,20 @@
type reflectMakeSliceConstraint struct {
cgn *cgnode
typ nodeid // (ptr)
- result nodeid
+ result nodeid // (indirect)
+}
+
+func (c *reflectMakeSliceConstraint) ptr() nodeid { return c.typ }
+func (c *reflectMakeSliceConstraint) indirect(nodes []nodeid) []nodeid { return append(nodes, c.result) }
+func (c *reflectMakeSliceConstraint) renumber(mapping []nodeid) {
+ c.typ = mapping[c.typ]
+ c.result = mapping[c.result]
}
func (c *reflectMakeSliceConstraint) String() string {
return fmt.Sprintf("n%d = reflect.MakeSlice(n%d)", c.result, c.typ)
}
-func (c *reflectMakeSliceConstraint) ptr() nodeid {
- return c.typ
-}
-
func (c *reflectMakeSliceConstraint) solve(a *analysis, _ *node, delta nodeset) {
changed := false
for typObj := range delta {
@@ -1053,17 +1230,20 @@
type reflectNewConstraint struct {
cgn *cgnode
typ nodeid // (ptr)
- result nodeid
+ result nodeid // (indirect)
+}
+
+func (c *reflectNewConstraint) ptr() nodeid { return c.typ }
+func (c *reflectNewConstraint) indirect(nodes []nodeid) []nodeid { return append(nodes, c.result) }
+func (c *reflectNewConstraint) renumber(mapping []nodeid) {
+ c.typ = mapping[c.typ]
+ c.result = mapping[c.result]
}
func (c *reflectNewConstraint) String() string {
return fmt.Sprintf("n%d = reflect.New(n%d)", c.result, c.typ)
}
-func (c *reflectNewConstraint) ptr() nodeid {
- return c.typ
-}
-
func (c *reflectNewConstraint) solve(a *analysis, _ *node, delta nodeset) {
changed := false
for typObj := range delta {
@@ -1111,17 +1291,20 @@
type reflectPtrToConstraint struct {
cgn *cgnode
t nodeid // (ptr)
- result nodeid
+ result nodeid // (indirect)
+}
+
+func (c *reflectPtrToConstraint) ptr() nodeid { return c.t }
+func (c *reflectPtrToConstraint) indirect(nodes []nodeid) []nodeid { return append(nodes, c.result) }
+func (c *reflectPtrToConstraint) renumber(mapping []nodeid) {
+ c.t = mapping[c.t]
+ c.result = mapping[c.result]
}
func (c *reflectPtrToConstraint) String() string {
return fmt.Sprintf("n%d = reflect.PtrTo(n%d)", c.result, c.t)
}
-func (c *reflectPtrToConstraint) ptr() nodeid {
- return c.t
-}
-
func (c *reflectPtrToConstraint) solve(a *analysis, _ *node, delta nodeset) {
changed := false
for tObj := range delta {
@@ -1152,17 +1335,20 @@
type reflectSliceOfConstraint struct {
cgn *cgnode
t nodeid // (ptr)
- result nodeid
+ result nodeid // (indirect)
+}
+
+func (c *reflectSliceOfConstraint) ptr() nodeid { return c.t }
+func (c *reflectSliceOfConstraint) indirect(nodes []nodeid) []nodeid { return append(nodes, c.result) }
+func (c *reflectSliceOfConstraint) renumber(mapping []nodeid) {
+ c.t = mapping[c.t]
+ c.result = mapping[c.result]
}
func (c *reflectSliceOfConstraint) String() string {
return fmt.Sprintf("n%d = reflect.SliceOf(n%d)", c.result, c.t)
}
-func (c *reflectSliceOfConstraint) ptr() nodeid {
- return c.t
-}
-
func (c *reflectSliceOfConstraint) solve(a *analysis, _ *node, delta nodeset) {
changed := false
for tObj := range delta {
@@ -1191,17 +1377,20 @@
type reflectTypeOfConstraint struct {
cgn *cgnode
i nodeid // (ptr)
- result nodeid
+ result nodeid // (indirect)
+}
+
+func (c *reflectTypeOfConstraint) ptr() nodeid { return c.i }
+func (c *reflectTypeOfConstraint) indirect(nodes []nodeid) []nodeid { return append(nodes, c.result) }
+func (c *reflectTypeOfConstraint) renumber(mapping []nodeid) {
+ c.i = mapping[c.i]
+ c.result = mapping[c.result]
}
func (c *reflectTypeOfConstraint) String() string {
return fmt.Sprintf("n%d = reflect.TypeOf(n%d)", c.result, c.i)
}
-func (c *reflectTypeOfConstraint) ptr() nodeid {
- return c.i
-}
-
func (c *reflectTypeOfConstraint) solve(a *analysis, _ *node, delta nodeset) {
changed := false
for iObj := range delta {
@@ -1238,17 +1427,20 @@
type reflectZeroConstraint struct {
cgn *cgnode
typ nodeid // (ptr)
- result nodeid
+ result nodeid // (indirect)
+}
+
+func (c *reflectZeroConstraint) ptr() nodeid { return c.typ }
+func (c *reflectZeroConstraint) indirect(nodes []nodeid) []nodeid { return append(nodes, c.result) }
+func (c *reflectZeroConstraint) renumber(mapping []nodeid) {
+ c.typ = mapping[c.typ]
+ c.result = mapping[c.result]
}
func (c *reflectZeroConstraint) String() string {
return fmt.Sprintf("n%d = reflect.Zero(n%d)", c.result, c.typ)
}
-func (c *reflectZeroConstraint) ptr() nodeid {
- return c.typ
-}
-
func (c *reflectZeroConstraint) solve(a *analysis, _ *node, delta nodeset) {
changed := false
for typObj := range delta {
@@ -1294,17 +1486,20 @@
type rtypeElemConstraint struct {
cgn *cgnode
t nodeid // (ptr)
- result nodeid
+ result nodeid // (indirect)
+}
+
+func (c *rtypeElemConstraint) ptr() nodeid { return c.t }
+func (c *rtypeElemConstraint) indirect(nodes []nodeid) []nodeid { return append(nodes, c.result) }
+func (c *rtypeElemConstraint) renumber(mapping []nodeid) {
+ c.t = mapping[c.t]
+ c.result = mapping[c.result]
}
func (c *rtypeElemConstraint) String() string {
return fmt.Sprintf("n%d = (*reflect.rtype).Elem(n%d)", c.result, c.t)
}
-func (c *rtypeElemConstraint) ptr() nodeid {
- return c.t
-}
-
func (c *rtypeElemConstraint) solve(a *analysis, _ *node, delta nodeset) {
// Implemented by *types.{Map,Chan,Array,Slice,Pointer}.
type hasElem interface {
@@ -1341,17 +1536,20 @@
cgn *cgnode
name string // name of field; "" for unknown
t nodeid // (ptr)
- result nodeid
+ result nodeid // (indirect)
+}
+
+func (c *rtypeFieldByNameConstraint) ptr() nodeid { return c.t }
+func (c *rtypeFieldByNameConstraint) indirect(nodes []nodeid) []nodeid { return append(nodes, c.result) }
+func (c *rtypeFieldByNameConstraint) renumber(mapping []nodeid) {
+ c.t = mapping[c.t]
+ c.result = mapping[c.result]
}
func (c *rtypeFieldByNameConstraint) String() string {
return fmt.Sprintf("n%d = (*reflect.rtype).FieldByName(n%d, %q)", c.result, c.t, c.name)
}
-func (c *rtypeFieldByNameConstraint) ptr() nodeid {
- return c.t
-}
-
func (c *rtypeFieldByNameConstraint) solve(a *analysis, _ *node, delta nodeset) {
// type StructField struct {
// 0 __identity__
@@ -1424,17 +1622,20 @@
type rtypeInOutConstraint struct {
cgn *cgnode
t nodeid // (ptr)
- result nodeid
+ result nodeid // (indirect)
out bool
i int // -ve if not a constant
}
-func (c *rtypeInOutConstraint) String() string {
- return fmt.Sprintf("n%d = (*reflect.rtype).InOut(n%d, %d)", c.result, c.t, c.i)
+func (c *rtypeInOutConstraint) ptr() nodeid { return c.t }
+func (c *rtypeInOutConstraint) indirect(nodes []nodeid) []nodeid { return append(nodes, c.result) }
+func (c *rtypeInOutConstraint) renumber(mapping []nodeid) {
+ c.t = mapping[c.t]
+ c.result = mapping[c.result]
}
-func (c *rtypeInOutConstraint) ptr() nodeid {
- return c.t
+func (c *rtypeInOutConstraint) String() string {
+ return fmt.Sprintf("n%d = (*reflect.rtype).InOut(n%d, %d)", c.result, c.t, c.i)
}
func (c *rtypeInOutConstraint) solve(a *analysis, _ *node, delta nodeset) {
@@ -1497,17 +1698,20 @@
type rtypeKeyConstraint struct {
cgn *cgnode
t nodeid // (ptr)
- result nodeid
+ result nodeid // (indirect)
+}
+
+func (c *rtypeKeyConstraint) ptr() nodeid { return c.t }
+func (c *rtypeKeyConstraint) indirect(nodes []nodeid) []nodeid { return append(nodes, c.result) }
+func (c *rtypeKeyConstraint) renumber(mapping []nodeid) {
+ c.t = mapping[c.t]
+ c.result = mapping[c.result]
}
func (c *rtypeKeyConstraint) String() string {
return fmt.Sprintf("n%d = (*reflect.rtype).Key(n%d)", c.result, c.t)
}
-func (c *rtypeKeyConstraint) ptr() nodeid {
- return c.t
-}
-
func (c *rtypeKeyConstraint) solve(a *analysis, _ *node, delta nodeset) {
changed := false
for tObj := range delta {
@@ -1540,17 +1744,22 @@
cgn *cgnode
name string // name of method; "" for unknown
t nodeid // (ptr)
- result nodeid
+ result nodeid // (indirect)
+}
+
+func (c *rtypeMethodByNameConstraint) ptr() nodeid { return c.t }
+func (c *rtypeMethodByNameConstraint) indirect(nodes []nodeid) []nodeid {
+ return append(nodes, c.result)
+}
+func (c *rtypeMethodByNameConstraint) renumber(mapping []nodeid) {
+ c.t = mapping[c.t]
+ c.result = mapping[c.result]
}
func (c *rtypeMethodByNameConstraint) String() string {
return fmt.Sprintf("n%d = (*reflect.rtype).MethodByName(n%d, %q)", c.result, c.t, c.name)
}
-func (c *rtypeMethodByNameConstraint) ptr() nodeid {
- return c.t
-}
-
// changeRecv returns sig with Recv prepended to Params().
func changeRecv(sig *types.Signature) *types.Signature {
params := sig.Params()
diff --git a/go/pointer/solve.go b/go/pointer/solve.go
index 458e66c..6a6a5ee 100644
--- a/go/pointer/solve.go
+++ b/go/pointer/solve.go
@@ -56,6 +56,13 @@
if a.log != nil {
fmt.Fprintf(a.log, "Solver done\n")
+
+ // Dump solution.
+ for i, n := range a.nodes {
+ if n.pts != nil {
+ fmt.Fprintf(a.log, "pts(n%d) = %s : %s\n", i, n.pts, n.typ)
+ }
+ }
}
}
@@ -160,34 +167,6 @@
}
}
-func (c *addrConstraint) ptr() nodeid {
- panic("addrConstraint: not a complex constraint")
-}
-func (c *copyConstraint) ptr() nodeid {
- panic("addrConstraint: not a complex constraint")
-}
-
-// Complex constraints attach themselves to the relevant pointer node.
-
-func (c *storeConstraint) ptr() nodeid {
- return c.dst
-}
-func (c *loadConstraint) ptr() nodeid {
- return c.src
-}
-func (c *offsetAddrConstraint) ptr() nodeid {
- return c.src
-}
-func (c *typeFilterConstraint) ptr() nodeid {
- return c.src
-}
-func (c *untagConstraint) ptr() nodeid {
- return c.src
-}
-func (c *invokeConstraint) ptr() nodeid {
- return c.iface
-}
-
// onlineCopy adds a copy edge. It is called online, i.e. during
// solving, so it adds edges and pts members directly rather than by
// instantiating a 'constraint'.