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
This commit is contained in:
Alan Donovan 2014-03-11 18:37:19 -04:00
parent 52c6f24392
commit 98ed3d3c76
7 changed files with 662 additions and 382 deletions

View File

@ -102,91 +102,6 @@ type node struct {
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 @@ type analysis struct {
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 @@ func (a *analysis) computeTrackBits() {
// 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 @@ func Analyze(config *Config) (result *Result, err error) {
}
a.computeTrackBits()
stage = "constraint generation"
a.generate()
if a.log != nil {
@ -376,23 +288,11 @@ func Analyze(config *Config) (result *Result, err error) {
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)

167
go/pointer/constraint.go Normal file
View File

@ -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]
}

View File

@ -1260,4 +1260,10 @@ func (a *analysis) generate() {
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
}

View File

@ -30,124 +30,13 @@ type intrinsic func(a *analysis, cgn *cgnode)
// 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 @@ func init() {
"time.now": ext۰NoEffect,
"time.startTimer": ext۰NoEffect,
"time.stopTimer": ext۰NoEffect,
} {
intrinsicsByName[name] = fn
}
}
@ -369,12 +260,16 @@ type runtimeSetFinalizerConstraint struct {
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) {

124
go/pointer/opt.go Normal file
View File

@ -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
}

View File

@ -32,6 +32,123 @@ import (
"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 @@ func ext۰reflect۰Value۰Addr(a *analysis, cgn *cgnode) {}
// 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 @@ type rVCallConstraint struct {
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 @@ func ext۰reflect۰Value۰Convert(a *analysis, cgn *cgnode) {}
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 @@ func ext۰reflect۰Value۰FieldByNameFunc(a *analysis, cgn *cgnode) {}
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 @@ func ext۰reflect۰Value۰Index(a *analysis, cgn *cgnode) {
// 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 @@ func (c *rVInterfaceConstraint) solve(a *analysis, _ *node, delta nodeset) {
a.addWork(c.result)
}
} else {
if resultPts.add(vObj) {
if a.addLabel(c.result, vObj) {
changed = true
}
}
@ -395,17 +535,20 @@ func ext۰reflect۰Value۰Interface(a *analysis, cgn *cgnode) {
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 @@ func ext۰reflect۰Value۰MapIndex(a *analysis, cgn *cgnode) {
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 @@ func ext۰reflect۰Value۰MethodByName(a *analysis, cgn *cgnode) {}
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 @@ type rVSendConstraint struct {
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 @@ type rVSetBytesConstraint struct {
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 @@ type rVSetMapIndexConstraint struct {
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 @@ func ext۰reflect۰Value۰SetPointer(a *analysis, cgn *cgnode) {}
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 @@ func ext۰reflect۰Copy(a *analysis, cgn *cgnode) {}
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 @@ func ext۰reflect۰ChanOf(a *analysis, cgn *cgnode) {
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 @@ func ext۰reflect۰Indirect(a *analysis, cgn *cgnode) {
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 @@ func ext۰reflect۰MakeFunc(a *analysis, cgn *cgnode) {}
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 @@ func ext۰reflect۰MakeMap(a *analysis, cgn *cgnode) {
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 @@ func ext۰reflect۰MapOf(a *analysis, cgn *cgnode) {}
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 @@ func ext۰reflect۰NewAt(a *analysis, cgn *cgnode) {
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 @@ func ext۰reflect۰Select(a *analysis, cgn *cgnode) {}
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 @@ func ext۰reflect۰SliceOf(a *analysis, cgn *cgnode) {
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 @@ func ext۰reflect۰ValueOf(a *analysis, cgn *cgnode) {
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 @@ func ext۰reflect۰Zero(a *analysis, cgn *cgnode) {
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 @@ type rtypeFieldByNameConstraint struct {
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 @@ func ext۰reflect۰rtype۰FieldByNameFunc(a *analysis, cgn *cgnode) {}
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 @@ func ext۰reflect۰rtype۰Out(a *analysis, cgn *cgnode) {
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 @@ type rtypeMethodByNameConstraint struct {
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()

View File

@ -56,6 +56,13 @@ func (a *analysis) solve() {
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 (a *analysis) addWork(id nodeid) {
}
}
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'.