mirror of
https://github.com/golang/go.git
synced 2025-05-31 23:25:39 +00:00
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
|
||||
}
|
||||
|
||||
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
167
go/pointer/constraint.go
Normal 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]
|
||||
}
|
@ -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
|
||||
}
|
||||
|
@ -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
124
go/pointer/opt.go
Normal 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
|
||||
}
|
@ -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()
|
||||
|
@ -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'.
|
||||
|
Loading…
x
Reference in New Issue
Block a user