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:
parent
52c6f24392
commit
98ed3d3c76
|
|
@ -102,91 +102,6 @@ type node struct {
|
||||||
complex constraintset
|
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.
|
// An analysis instance holds the state of a single pointer analysis problem.
|
||||||
type analysis struct {
|
type analysis struct {
|
||||||
config *Config // the client's control/observer interface
|
config *Config // the client's control/observer interface
|
||||||
|
|
@ -200,7 +115,6 @@ type analysis struct {
|
||||||
cgnodes []*cgnode // all cgnodes
|
cgnodes []*cgnode // all cgnodes
|
||||||
genq []*cgnode // queue of functions to generate constraints for
|
genq []*cgnode // queue of functions to generate constraints for
|
||||||
intrinsics map[*ssa.Function]intrinsic // non-nil values are summaries for intrinsic fns
|
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
|
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
|
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
|
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.
|
// always succeed. An error can occur only due to an internal bug.
|
||||||
//
|
//
|
||||||
func Analyze(config *Config) (result *Result, err error) {
|
func Analyze(config *Config) (result *Result, err error) {
|
||||||
stage := "setup"
|
|
||||||
defer func() {
|
defer func() {
|
||||||
if p := recover(); p != nil {
|
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:")
|
fmt.Fprintln(os.Stderr, "Internal panic in pointer analysis:")
|
||||||
debug.PrintStack()
|
debug.PrintStack()
|
||||||
}
|
}
|
||||||
|
|
@ -360,7 +273,6 @@ func Analyze(config *Config) (result *Result, err error) {
|
||||||
}
|
}
|
||||||
a.computeTrackBits()
|
a.computeTrackBits()
|
||||||
|
|
||||||
stage = "constraint generation"
|
|
||||||
a.generate()
|
a.generate()
|
||||||
|
|
||||||
if a.log != nil {
|
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))
|
fmt.Fprintf(a.log, "# nodes:\t%d\n", len(a.nodes))
|
||||||
}
|
}
|
||||||
|
|
||||||
// stage = "constraint optimization"
|
a.optimize()
|
||||||
// a.optimize()
|
|
||||||
|
|
||||||
stage = "solver"
|
|
||||||
a.solve()
|
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.
|
// Create callgraph.Nodes in deterministic order.
|
||||||
stage = "callgraph construction"
|
|
||||||
if cg := a.result.CallGraph; cg != nil {
|
if cg := a.result.CallGraph; cg != nil {
|
||||||
for _, caller := range a.cgnodes {
|
for _, caller := range a.cgnodes {
|
||||||
cg.CreateNode(caller.fn)
|
cg.CreateNode(caller.fn)
|
||||||
|
|
|
||||||
|
|
@ -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]
|
||||||
|
}
|
||||||
|
|
@ -1260,4 +1260,10 @@ func (a *analysis) generate() {
|
||||||
a.endObject(obj, nil, "<command-line args>")
|
a.endObject(obj, nil, "<command-line args>")
|
||||||
a.addressOf(T, a.objectNode(nil, os.Var("Args")), obj)
|
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
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -30,124 +30,13 @@ type intrinsic func(a *analysis, cgn *cgnode)
|
||||||
|
|
||||||
// Initialized in explicit init() to defeat (spurious) initialization
|
// Initialized in explicit init() to defeat (spurious) initialization
|
||||||
// cycle error.
|
// cycle error.
|
||||||
var intrinsicsByName map[string]intrinsic
|
var intrinsicsByName = make(map[string]intrinsic)
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
// Key strings are from Function.String().
|
// Key strings are from Function.String().
|
||||||
// That little dot ۰ is an Arabic zero numeral (U+06F0),
|
// That little dot ۰ is an Arabic zero numeral (U+06F0),
|
||||||
// categories [Nd].
|
// categories [Nd].
|
||||||
intrinsicsByName = map[string]intrinsic{
|
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,
|
|
||||||
|
|
||||||
// Other packages.
|
// Other packages.
|
||||||
"bytes.Equal": ext۰NoEffect,
|
"bytes.Equal": ext۰NoEffect,
|
||||||
"bytes.IndexByte": ext۰NoEffect,
|
"bytes.IndexByte": ext۰NoEffect,
|
||||||
|
|
@ -287,6 +176,8 @@ func init() {
|
||||||
"time.now": ext۰NoEffect,
|
"time.now": ext۰NoEffect,
|
||||||
"time.startTimer": ext۰NoEffect,
|
"time.startTimer": ext۰NoEffect,
|
||||||
"time.stopTimer": ext۰NoEffect,
|
"time.stopTimer": ext۰NoEffect,
|
||||||
|
} {
|
||||||
|
intrinsicsByName[name] = fn
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -369,12 +260,16 @@ type runtimeSetFinalizerConstraint struct {
|
||||||
x nodeid
|
x nodeid
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *runtimeSetFinalizerConstraint) String() string {
|
func (c *runtimeSetFinalizerConstraint) ptr() nodeid { return c.f }
|
||||||
return fmt.Sprintf("runtime.SetFinalizer(n%d, n%d)", c.x, 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 {
|
func (c *runtimeSetFinalizerConstraint) String() string {
|
||||||
return c.f
|
return fmt.Sprintf("runtime.SetFinalizer(n%d, n%d)", c.x, c.f)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *runtimeSetFinalizerConstraint) solve(a *analysis, _ *node, delta nodeset) {
|
func (c *runtimeSetFinalizerConstraint) solve(a *analysis, _ *node, delta nodeset) {
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
}
|
||||||
|
|
@ -32,6 +32,123 @@ import (
|
||||||
"code.google.com/p/go.tools/go/types"
|
"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) --------------------
|
// -------------------- (reflect.Value) --------------------
|
||||||
|
|
||||||
func ext۰reflect۰Value۰Addr(a *analysis, cgn *cgnode) {}
|
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()
|
// result = v.Bytes()
|
||||||
type rVBytesConstraint struct {
|
type rVBytesConstraint struct {
|
||||||
v nodeid // (ptr)
|
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 {
|
func (c *rVBytesConstraint) String() string {
|
||||||
return fmt.Sprintf("n%d = reflect n%d.Bytes()", c.result, c.v)
|
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) {
|
func (c *rVBytesConstraint) solve(a *analysis, _ *node, delta nodeset) {
|
||||||
changed := false
|
changed := false
|
||||||
for vObj := range delta {
|
for vObj := range delta {
|
||||||
|
|
@ -89,18 +209,30 @@ type rVCallConstraint struct {
|
||||||
targets nodeid
|
targets nodeid
|
||||||
v nodeid // (ptr)
|
v nodeid // (ptr)
|
||||||
arg nodeid // = in[*]
|
arg nodeid // = in[*]
|
||||||
result nodeid
|
result nodeid // (indirect)
|
||||||
dotdotdot bool // interpret last arg as a "..." slice
|
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 {
|
func (c *rVCallConstraint) String() string {
|
||||||
return fmt.Sprintf("n%d = reflect n%d.Call(n%d)", c.result, c.v, c.arg)
|
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) {
|
func (c *rVCallConstraint) solve(a *analysis, _ *node, delta nodeset) {
|
||||||
if c.targets == 0 {
|
if c.targets == 0 {
|
||||||
panic("no targets")
|
panic("no targets")
|
||||||
|
|
@ -228,17 +360,20 @@ func ext۰reflect۰Value۰Convert(a *analysis, cgn *cgnode) {}
|
||||||
type rVElemConstraint struct {
|
type rVElemConstraint struct {
|
||||||
cgn *cgnode
|
cgn *cgnode
|
||||||
v nodeid // (ptr)
|
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 {
|
func (c *rVElemConstraint) String() string {
|
||||||
return fmt.Sprintf("n%d = reflect n%d.Elem()", c.result, c.v)
|
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) {
|
func (c *rVElemConstraint) solve(a *analysis, _ *node, delta nodeset) {
|
||||||
changed := false
|
changed := false
|
||||||
for vObj := range delta {
|
for vObj := range delta {
|
||||||
|
|
@ -287,17 +422,20 @@ func ext۰reflect۰Value۰FieldByNameFunc(a *analysis, cgn *cgnode) {}
|
||||||
type rVIndexConstraint struct {
|
type rVIndexConstraint struct {
|
||||||
cgn *cgnode
|
cgn *cgnode
|
||||||
v nodeid // (ptr)
|
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 {
|
func (c *rVIndexConstraint) String() string {
|
||||||
return fmt.Sprintf("n%d = reflect n%d.Index()", c.result, c.v)
|
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) {
|
func (c *rVIndexConstraint) solve(a *analysis, _ *node, delta nodeset) {
|
||||||
changed := false
|
changed := false
|
||||||
for vObj := range delta {
|
for vObj := range delta {
|
||||||
|
|
@ -345,19 +483,21 @@ func ext۰reflect۰Value۰Index(a *analysis, cgn *cgnode) {
|
||||||
// result = v.Interface()
|
// result = v.Interface()
|
||||||
type rVInterfaceConstraint struct {
|
type rVInterfaceConstraint struct {
|
||||||
v nodeid // (ptr)
|
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 {
|
func (c *rVInterfaceConstraint) String() string {
|
||||||
return fmt.Sprintf("n%d = reflect n%d.Interface()", c.result, c.v)
|
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) {
|
func (c *rVInterfaceConstraint) solve(a *analysis, _ *node, delta nodeset) {
|
||||||
resultPts := &a.nodes[c.result].pts
|
|
||||||
changed := false
|
changed := false
|
||||||
for vObj := range delta {
|
for vObj := range delta {
|
||||||
tDyn, payload, indirect := a.taggedValue(vObj)
|
tDyn, payload, indirect := a.taggedValue(vObj)
|
||||||
|
|
@ -372,7 +512,7 @@ func (c *rVInterfaceConstraint) solve(a *analysis, _ *node, delta nodeset) {
|
||||||
a.addWork(c.result)
|
a.addWork(c.result)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if resultPts.add(vObj) {
|
if a.addLabel(c.result, vObj) {
|
||||||
changed = true
|
changed = true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -395,17 +535,20 @@ func ext۰reflect۰Value۰Interface(a *analysis, cgn *cgnode) {
|
||||||
type rVMapIndexConstraint struct {
|
type rVMapIndexConstraint struct {
|
||||||
cgn *cgnode
|
cgn *cgnode
|
||||||
v nodeid // (ptr)
|
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 {
|
func (c *rVMapIndexConstraint) String() string {
|
||||||
return fmt.Sprintf("n%d = reflect n%d.MapIndex(_)", c.result, c.v)
|
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) {
|
func (c *rVMapIndexConstraint) solve(a *analysis, _ *node, delta nodeset) {
|
||||||
changed := false
|
changed := false
|
||||||
for vObj := range delta {
|
for vObj := range delta {
|
||||||
|
|
@ -445,17 +588,20 @@ func ext۰reflect۰Value۰MapIndex(a *analysis, cgn *cgnode) {
|
||||||
type rVMapKeysConstraint struct {
|
type rVMapKeysConstraint struct {
|
||||||
cgn *cgnode
|
cgn *cgnode
|
||||||
v nodeid // (ptr)
|
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 {
|
func (c *rVMapKeysConstraint) String() string {
|
||||||
return fmt.Sprintf("n%d = reflect n%d.MapKeys()", c.result, c.v)
|
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) {
|
func (c *rVMapKeysConstraint) solve(a *analysis, _ *node, delta nodeset) {
|
||||||
changed := false
|
changed := false
|
||||||
for vObj := range delta {
|
for vObj := range delta {
|
||||||
|
|
@ -505,17 +651,20 @@ func ext۰reflect۰Value۰MethodByName(a *analysis, cgn *cgnode) {}
|
||||||
type rVRecvConstraint struct {
|
type rVRecvConstraint struct {
|
||||||
cgn *cgnode
|
cgn *cgnode
|
||||||
v nodeid // (ptr)
|
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 {
|
func (c *rVRecvConstraint) String() string {
|
||||||
return fmt.Sprintf("n%d = reflect n%d.Recv()", c.result, c.v)
|
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) {
|
func (c *rVRecvConstraint) solve(a *analysis, _ *node, delta nodeset) {
|
||||||
changed := false
|
changed := false
|
||||||
for vObj := range delta {
|
for vObj := range delta {
|
||||||
|
|
@ -559,12 +708,15 @@ type rVSendConstraint struct {
|
||||||
x nodeid
|
x nodeid
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *rVSendConstraint) String() string {
|
func (c *rVSendConstraint) ptr() nodeid { return c.v }
|
||||||
return fmt.Sprintf("reflect n%d.Send(n%d)", c.v, c.x)
|
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 {
|
func (c *rVSendConstraint) String() string {
|
||||||
return c.v
|
return fmt.Sprintf("reflect n%d.Send(n%d)", c.v, c.x)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *rVSendConstraint) solve(a *analysis, _ *node, delta nodeset) {
|
func (c *rVSendConstraint) solve(a *analysis, _ *node, delta nodeset) {
|
||||||
|
|
@ -608,12 +760,15 @@ type rVSetBytesConstraint struct {
|
||||||
x nodeid
|
x nodeid
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *rVSetBytesConstraint) String() string {
|
func (c *rVSetBytesConstraint) ptr() nodeid { return c.v }
|
||||||
return fmt.Sprintf("reflect n%d.SetBytes(n%d)", c.v, c.x)
|
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 {
|
func (c *rVSetBytesConstraint) String() string {
|
||||||
return c.v
|
return fmt.Sprintf("reflect n%d.SetBytes(n%d)", c.v, c.x)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *rVSetBytesConstraint) solve(a *analysis, _ *node, delta nodeset) {
|
func (c *rVSetBytesConstraint) solve(a *analysis, _ *node, delta nodeset) {
|
||||||
|
|
@ -653,12 +808,16 @@ type rVSetMapIndexConstraint struct {
|
||||||
val nodeid
|
val nodeid
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *rVSetMapIndexConstraint) String() string {
|
func (c *rVSetMapIndexConstraint) ptr() nodeid { return c.v }
|
||||||
return fmt.Sprintf("reflect n%d.SetMapIndex(n%d, n%d)", c.v, c.key, c.val)
|
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 {
|
func (c *rVSetMapIndexConstraint) String() string {
|
||||||
return c.v
|
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) {
|
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 {
|
type rVSliceConstraint struct {
|
||||||
cgn *cgnode
|
cgn *cgnode
|
||||||
v nodeid // (ptr)
|
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 {
|
func (c *rVSliceConstraint) String() string {
|
||||||
return fmt.Sprintf("n%d = reflect n%d.Slice(_, _)", c.result, c.v)
|
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) {
|
func (c *rVSliceConstraint) solve(a *analysis, _ *node, delta nodeset) {
|
||||||
changed := false
|
changed := false
|
||||||
for vObj := range delta {
|
for vObj := range delta {
|
||||||
|
|
@ -780,18 +942,21 @@ func ext۰reflect۰Copy(a *analysis, cgn *cgnode) {}
|
||||||
type reflectChanOfConstraint struct {
|
type reflectChanOfConstraint struct {
|
||||||
cgn *cgnode
|
cgn *cgnode
|
||||||
t nodeid // (ptr)
|
t nodeid // (ptr)
|
||||||
result nodeid
|
result nodeid // (indirect)
|
||||||
dirs []types.ChanDir
|
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 {
|
func (c *reflectChanOfConstraint) String() string {
|
||||||
return fmt.Sprintf("n%d = reflect.ChanOf(n%d)", c.result, c.t)
|
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) {
|
func (c *reflectChanOfConstraint) solve(a *analysis, _ *node, delta nodeset) {
|
||||||
changed := false
|
changed := false
|
||||||
for tObj := range delta {
|
for tObj := range delta {
|
||||||
|
|
@ -845,17 +1010,20 @@ func ext۰reflect۰ChanOf(a *analysis, cgn *cgnode) {
|
||||||
type reflectIndirectConstraint struct {
|
type reflectIndirectConstraint struct {
|
||||||
cgn *cgnode
|
cgn *cgnode
|
||||||
v nodeid // (ptr)
|
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 {
|
func (c *reflectIndirectConstraint) String() string {
|
||||||
return fmt.Sprintf("n%d = reflect.Indirect(n%d)", c.result, c.v)
|
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) {
|
func (c *reflectIndirectConstraint) solve(a *analysis, _ *node, delta nodeset) {
|
||||||
changed := false
|
changed := false
|
||||||
for vObj := range delta {
|
for vObj := range delta {
|
||||||
|
|
@ -893,17 +1061,20 @@ func ext۰reflect۰Indirect(a *analysis, cgn *cgnode) {
|
||||||
type reflectMakeChanConstraint struct {
|
type reflectMakeChanConstraint struct {
|
||||||
cgn *cgnode
|
cgn *cgnode
|
||||||
typ nodeid // (ptr)
|
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 {
|
func (c *reflectMakeChanConstraint) String() string {
|
||||||
return fmt.Sprintf("n%d = reflect.MakeChan(n%d)", c.result, c.typ)
|
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) {
|
func (c *reflectMakeChanConstraint) solve(a *analysis, _ *node, delta nodeset) {
|
||||||
changed := false
|
changed := false
|
||||||
for typObj := range delta {
|
for typObj := range delta {
|
||||||
|
|
@ -947,17 +1118,20 @@ func ext۰reflect۰MakeFunc(a *analysis, cgn *cgnode) {}
|
||||||
type reflectMakeMapConstraint struct {
|
type reflectMakeMapConstraint struct {
|
||||||
cgn *cgnode
|
cgn *cgnode
|
||||||
typ nodeid // (ptr)
|
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 {
|
func (c *reflectMakeMapConstraint) String() string {
|
||||||
return fmt.Sprintf("n%d = reflect.MakeMap(n%d)", c.result, c.typ)
|
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) {
|
func (c *reflectMakeMapConstraint) solve(a *analysis, _ *node, delta nodeset) {
|
||||||
changed := false
|
changed := false
|
||||||
for typObj := range delta {
|
for typObj := range delta {
|
||||||
|
|
@ -1000,17 +1174,20 @@ func ext۰reflect۰MakeMap(a *analysis, cgn *cgnode) {
|
||||||
type reflectMakeSliceConstraint struct {
|
type reflectMakeSliceConstraint struct {
|
||||||
cgn *cgnode
|
cgn *cgnode
|
||||||
typ nodeid // (ptr)
|
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 {
|
func (c *reflectMakeSliceConstraint) String() string {
|
||||||
return fmt.Sprintf("n%d = reflect.MakeSlice(n%d)", c.result, c.typ)
|
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) {
|
func (c *reflectMakeSliceConstraint) solve(a *analysis, _ *node, delta nodeset) {
|
||||||
changed := false
|
changed := false
|
||||||
for typObj := range delta {
|
for typObj := range delta {
|
||||||
|
|
@ -1053,17 +1230,20 @@ func ext۰reflect۰MapOf(a *analysis, cgn *cgnode) {}
|
||||||
type reflectNewConstraint struct {
|
type reflectNewConstraint struct {
|
||||||
cgn *cgnode
|
cgn *cgnode
|
||||||
typ nodeid // (ptr)
|
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 {
|
func (c *reflectNewConstraint) String() string {
|
||||||
return fmt.Sprintf("n%d = reflect.New(n%d)", c.result, c.typ)
|
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) {
|
func (c *reflectNewConstraint) solve(a *analysis, _ *node, delta nodeset) {
|
||||||
changed := false
|
changed := false
|
||||||
for typObj := range delta {
|
for typObj := range delta {
|
||||||
|
|
@ -1111,17 +1291,20 @@ func ext۰reflect۰NewAt(a *analysis, cgn *cgnode) {
|
||||||
type reflectPtrToConstraint struct {
|
type reflectPtrToConstraint struct {
|
||||||
cgn *cgnode
|
cgn *cgnode
|
||||||
t nodeid // (ptr)
|
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 {
|
func (c *reflectPtrToConstraint) String() string {
|
||||||
return fmt.Sprintf("n%d = reflect.PtrTo(n%d)", c.result, c.t)
|
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) {
|
func (c *reflectPtrToConstraint) solve(a *analysis, _ *node, delta nodeset) {
|
||||||
changed := false
|
changed := false
|
||||||
for tObj := range delta {
|
for tObj := range delta {
|
||||||
|
|
@ -1152,17 +1335,20 @@ func ext۰reflect۰Select(a *analysis, cgn *cgnode) {}
|
||||||
type reflectSliceOfConstraint struct {
|
type reflectSliceOfConstraint struct {
|
||||||
cgn *cgnode
|
cgn *cgnode
|
||||||
t nodeid // (ptr)
|
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 {
|
func (c *reflectSliceOfConstraint) String() string {
|
||||||
return fmt.Sprintf("n%d = reflect.SliceOf(n%d)", c.result, c.t)
|
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) {
|
func (c *reflectSliceOfConstraint) solve(a *analysis, _ *node, delta nodeset) {
|
||||||
changed := false
|
changed := false
|
||||||
for tObj := range delta {
|
for tObj := range delta {
|
||||||
|
|
@ -1191,17 +1377,20 @@ func ext۰reflect۰SliceOf(a *analysis, cgn *cgnode) {
|
||||||
type reflectTypeOfConstraint struct {
|
type reflectTypeOfConstraint struct {
|
||||||
cgn *cgnode
|
cgn *cgnode
|
||||||
i nodeid // (ptr)
|
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 {
|
func (c *reflectTypeOfConstraint) String() string {
|
||||||
return fmt.Sprintf("n%d = reflect.TypeOf(n%d)", c.result, c.i)
|
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) {
|
func (c *reflectTypeOfConstraint) solve(a *analysis, _ *node, delta nodeset) {
|
||||||
changed := false
|
changed := false
|
||||||
for iObj := range delta {
|
for iObj := range delta {
|
||||||
|
|
@ -1238,17 +1427,20 @@ func ext۰reflect۰ValueOf(a *analysis, cgn *cgnode) {
|
||||||
type reflectZeroConstraint struct {
|
type reflectZeroConstraint struct {
|
||||||
cgn *cgnode
|
cgn *cgnode
|
||||||
typ nodeid // (ptr)
|
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 {
|
func (c *reflectZeroConstraint) String() string {
|
||||||
return fmt.Sprintf("n%d = reflect.Zero(n%d)", c.result, c.typ)
|
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) {
|
func (c *reflectZeroConstraint) solve(a *analysis, _ *node, delta nodeset) {
|
||||||
changed := false
|
changed := false
|
||||||
for typObj := range delta {
|
for typObj := range delta {
|
||||||
|
|
@ -1294,17 +1486,20 @@ func ext۰reflect۰Zero(a *analysis, cgn *cgnode) {
|
||||||
type rtypeElemConstraint struct {
|
type rtypeElemConstraint struct {
|
||||||
cgn *cgnode
|
cgn *cgnode
|
||||||
t nodeid // (ptr)
|
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 {
|
func (c *rtypeElemConstraint) String() string {
|
||||||
return fmt.Sprintf("n%d = (*reflect.rtype).Elem(n%d)", c.result, c.t)
|
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) {
|
func (c *rtypeElemConstraint) solve(a *analysis, _ *node, delta nodeset) {
|
||||||
// Implemented by *types.{Map,Chan,Array,Slice,Pointer}.
|
// Implemented by *types.{Map,Chan,Array,Slice,Pointer}.
|
||||||
type hasElem interface {
|
type hasElem interface {
|
||||||
|
|
@ -1341,17 +1536,20 @@ type rtypeFieldByNameConstraint struct {
|
||||||
cgn *cgnode
|
cgn *cgnode
|
||||||
name string // name of field; "" for unknown
|
name string // name of field; "" for unknown
|
||||||
t nodeid // (ptr)
|
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 {
|
func (c *rtypeFieldByNameConstraint) String() string {
|
||||||
return fmt.Sprintf("n%d = (*reflect.rtype).FieldByName(n%d, %q)", c.result, c.t, c.name)
|
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) {
|
func (c *rtypeFieldByNameConstraint) solve(a *analysis, _ *node, delta nodeset) {
|
||||||
// type StructField struct {
|
// type StructField struct {
|
||||||
// 0 __identity__
|
// 0 __identity__
|
||||||
|
|
@ -1424,17 +1622,20 @@ func ext۰reflect۰rtype۰FieldByNameFunc(a *analysis, cgn *cgnode) {}
|
||||||
type rtypeInOutConstraint struct {
|
type rtypeInOutConstraint struct {
|
||||||
cgn *cgnode
|
cgn *cgnode
|
||||||
t nodeid // (ptr)
|
t nodeid // (ptr)
|
||||||
result nodeid
|
result nodeid // (indirect)
|
||||||
out bool
|
out bool
|
||||||
i int // -ve if not a constant
|
i int // -ve if not a constant
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *rtypeInOutConstraint) String() string {
|
func (c *rtypeInOutConstraint) ptr() nodeid { return c.t }
|
||||||
return fmt.Sprintf("n%d = (*reflect.rtype).InOut(n%d, %d)", c.result, c.t, c.i)
|
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 {
|
func (c *rtypeInOutConstraint) String() string {
|
||||||
return c.t
|
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) {
|
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 {
|
type rtypeKeyConstraint struct {
|
||||||
cgn *cgnode
|
cgn *cgnode
|
||||||
t nodeid // (ptr)
|
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 {
|
func (c *rtypeKeyConstraint) String() string {
|
||||||
return fmt.Sprintf("n%d = (*reflect.rtype).Key(n%d)", c.result, c.t)
|
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) {
|
func (c *rtypeKeyConstraint) solve(a *analysis, _ *node, delta nodeset) {
|
||||||
changed := false
|
changed := false
|
||||||
for tObj := range delta {
|
for tObj := range delta {
|
||||||
|
|
@ -1540,17 +1744,22 @@ type rtypeMethodByNameConstraint struct {
|
||||||
cgn *cgnode
|
cgn *cgnode
|
||||||
name string // name of method; "" for unknown
|
name string // name of method; "" for unknown
|
||||||
t nodeid // (ptr)
|
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 {
|
func (c *rtypeMethodByNameConstraint) String() string {
|
||||||
return fmt.Sprintf("n%d = (*reflect.rtype).MethodByName(n%d, %q)", c.result, c.t, c.name)
|
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().
|
// changeRecv returns sig with Recv prepended to Params().
|
||||||
func changeRecv(sig *types.Signature) *types.Signature {
|
func changeRecv(sig *types.Signature) *types.Signature {
|
||||||
params := sig.Params()
|
params := sig.Params()
|
||||||
|
|
|
||||||
|
|
@ -56,6 +56,13 @@ func (a *analysis) solve() {
|
||||||
|
|
||||||
if a.log != nil {
|
if a.log != nil {
|
||||||
fmt.Fprintf(a.log, "Solver done\n")
|
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
|
// onlineCopy adds a copy edge. It is called online, i.e. during
|
||||||
// solving, so it adds edges and pts members directly rather than by
|
// solving, so it adds edges and pts members directly rather than by
|
||||||
// instantiating a 'constraint'.
|
// instantiating a 'constraint'.
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue