From 98ed3d3c76ce6d0cd22d94cfaee0f555ca6244a3 Mon Sep 17 00:00:00 2001 From: Alan Donovan Date: Tue, 11 Mar 2014 18:37:19 -0400 Subject: [PATCH] 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 --- go/pointer/analysis.go | 104 +-------- go/pointer/constraint.go | 167 ++++++++++++++ go/pointer/gen.go | 6 + go/pointer/intrinsics.go | 129 +---------- go/pointer/opt.go | 124 ++++++++++ go/pointer/reflect.go | 479 ++++++++++++++++++++++++++++----------- go/pointer/solve.go | 35 +-- 7 files changed, 662 insertions(+), 382 deletions(-) create mode 100644 go/pointer/constraint.go create mode 100644 go/pointer/opt.go diff --git a/go/pointer/analysis.go b/go/pointer/analysis.go index 14649821..42deb0bf 100644 --- a/go/pointer/analysis.go +++ b/go/pointer/analysis.go @@ -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) diff --git a/go/pointer/constraint.go b/go/pointer/constraint.go new file mode 100644 index 00000000..f7603cbc --- /dev/null +++ b/go/pointer/constraint.go @@ -0,0 +1,167 @@ +// Copyright 2013 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package pointer + +import ( + "code.google.com/p/go.tools/go/types" +) + +type constraint interface { + // For a complex constraint, returns the nodeid of the pointer + // to which it is attached. + ptr() nodeid + + // indirect returns (by appending to the argument) the constraint's + // "indirect" nodes as defined in (Hardekopf 2007b): + // nodes whose points-to relations are not completely + // represented in the initial constraint graph. + // + // TODO(adonovan): I think we need >1 results in some obscure + // cases. If not, just return a nodeid, like ptr(). + // + indirect(nodes []nodeid) []nodeid + + // renumber replaces each nodeid n in the constraint by mapping[n]. + renumber(mapping []nodeid) + + // solve is called for complex constraints when the pts for + // the node to which they are attached has changed. + solve(a *analysis, n *node, delta nodeset) + + String() string +} + +// dst = &src +// pts(dst) ⊇ {src} +// A base constraint used to initialize the solver's pt sets +type addrConstraint struct { + dst nodeid // (ptr) + src nodeid +} + +func (c *addrConstraint) ptr() nodeid { panic("addrConstraint: not a complex constraint") } +func (c *addrConstraint) indirect(nodes []nodeid) []nodeid { + panic("addrConstraint: not a complex constraint") +} +func (c *addrConstraint) renumber(mapping []nodeid) { + c.dst = mapping[c.dst] + c.src = mapping[c.src] +} + +// dst = src +// A simple constraint represented directly as a copyTo graph edge. +type copyConstraint struct { + dst nodeid + src nodeid // (ptr) +} + +func (c *copyConstraint) ptr() nodeid { panic("copyConstraint: not a complex constraint") } +func (c *copyConstraint) indirect(nodes []nodeid) []nodeid { + panic("copyConstraint: not a complex constraint") +} +func (c *copyConstraint) renumber(mapping []nodeid) { + c.dst = mapping[c.dst] + c.src = mapping[c.src] +} + +// dst = src[offset] +// A complex constraint attached to src (the pointer) +type loadConstraint struct { + offset uint32 + dst nodeid // (indirect) + src nodeid // (ptr) +} + +func (c *loadConstraint) ptr() nodeid { return c.src } +func (c *loadConstraint) indirect(nodes []nodeid) []nodeid { return append(nodes, c.dst) } +func (c *loadConstraint) renumber(mapping []nodeid) { + c.dst = mapping[c.dst] + c.src = mapping[c.src] +} + +// dst[offset] = src +// A complex constraint attached to dst (the pointer) +type storeConstraint struct { + offset uint32 + dst nodeid // (ptr) + src nodeid +} + +func (c *storeConstraint) ptr() nodeid { return c.dst } +func (c *storeConstraint) indirect(nodes []nodeid) []nodeid { return nodes } +func (c *storeConstraint) renumber(mapping []nodeid) { + c.dst = mapping[c.dst] + c.src = mapping[c.src] +} + +// dst = &src.f or dst = &src[0] +// A complex constraint attached to dst (the pointer) +type offsetAddrConstraint struct { + offset uint32 + dst nodeid // (indirect) + src nodeid // (ptr) +} + +func (c *offsetAddrConstraint) ptr() nodeid { return c.src } +func (c *offsetAddrConstraint) indirect(nodes []nodeid) []nodeid { return append(nodes, c.dst) } +func (c *offsetAddrConstraint) renumber(mapping []nodeid) { + c.dst = mapping[c.dst] + c.src = mapping[c.src] +} + +// dst = src.(typ) where typ is an interface +// A complex constraint attached to src (the interface). +// No representation change: pts(dst) and pts(src) contains tagged objects. +type typeFilterConstraint struct { + typ types.Type // an interface type + dst nodeid // (indirect) + src nodeid // (ptr) +} + +func (c *typeFilterConstraint) ptr() nodeid { return c.src } +func (c *typeFilterConstraint) indirect(nodes []nodeid) []nodeid { return append(nodes, c.dst) } +func (c *typeFilterConstraint) renumber(mapping []nodeid) { + c.dst = mapping[c.dst] + c.src = mapping[c.src] +} + +// dst = src.(typ) where typ is a concrete type +// A complex constraint attached to src (the interface). +// +// If exact, only tagged objects identical to typ are untagged. +// If !exact, tagged objects assignable to typ are untagged too. +// The latter is needed for various reflect operators, e.g. Send. +// +// This entails a representation change: +// pts(src) contains tagged objects, +// pts(dst) contains their payloads. +type untagConstraint struct { + typ types.Type // a concrete type + dst nodeid // (indirect) + src nodeid // (ptr) + exact bool +} + +func (c *untagConstraint) ptr() nodeid { return c.src } +func (c *untagConstraint) indirect(nodes []nodeid) []nodeid { return append(nodes, c.dst) } +func (c *untagConstraint) renumber(mapping []nodeid) { + c.dst = mapping[c.dst] + c.src = mapping[c.src] +} + +// src.method(params...) +// A complex constraint attached to iface. +type invokeConstraint struct { + method *types.Func // the abstract method + iface nodeid // (ptr) the interface + params nodeid // (indirect) the first param in the params/results block +} + +func (c *invokeConstraint) ptr() nodeid { return c.iface } +func (c *invokeConstraint) indirect(nodes []nodeid) []nodeid { return append(nodes, c.params) } +func (c *invokeConstraint) renumber(mapping []nodeid) { + c.iface = mapping[c.iface] + c.params = mapping[c.params] +} diff --git a/go/pointer/gen.go b/go/pointer/gen.go index fdd2370e..c451c8d9 100644 --- a/go/pointer/gen.go +++ b/go/pointer/gen.go @@ -1260,4 +1260,10 @@ func (a *analysis) generate() { a.endObject(obj, nil, "") a.addressOf(T, a.objectNode(nil, os.Var("Args")), obj) } + + // Discard generation state, to avoid confusion after node renumbering. + a.panicNode = 0 + a.globalval = nil + a.localval = nil + a.localobj = nil } diff --git a/go/pointer/intrinsics.go b/go/pointer/intrinsics.go index 69ce8780..a2257fec 100644 --- a/go/pointer/intrinsics.go +++ b/go/pointer/intrinsics.go @@ -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) { diff --git a/go/pointer/opt.go b/go/pointer/opt.go new file mode 100644 index 00000000..e27508af --- /dev/null +++ b/go/pointer/opt.go @@ -0,0 +1,124 @@ +// Copyright 2013 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package pointer + +// This file defines the constraint optimiser ("pre-solver"). + +import ( + "fmt" +) + +func (a *analysis) optimize() { + a.renumber() + + // TODO(adonovan): opt: + // PE, LE, HVN, HRU, sparse bitsets, etc. +} + +// renumber permutes a.nodes so that all nodes within an addressable +// object appear before all non-addressable nodes, maintaining the +// order of nodes within the same object (as required by offsetAddr). +// +// renumber must update every nodeid in the analysis (constraints, +// Pointers, callgraph, etc) to reflect the new ordering. +// +// This is an optimisation to increase the locality and efficiency of +// sparse representations of points-to sets. (Typically only about +// 20% of nodes are within an object.) +// +// NB: nodes added during solving (e.g. for reflection, SetFinalizer) +// will be appended to the end. +// +func (a *analysis) renumber() { + N := nodeid(len(a.nodes)) + newNodes := make([]*node, N, N) + renumbering := make([]nodeid, N, N) // maps old to new + + var i, j nodeid + + // The zero node is special. + newNodes[j] = a.nodes[i] + renumbering[i] = j + i++ + j++ + + // Pass 1: object nodes. + for i < N { + obj := a.nodes[i].obj + if obj == nil { + i++ + continue + } + + end := i + nodeid(obj.size) + for i < end { + newNodes[j] = a.nodes[i] + renumbering[i] = j + i++ + j++ + } + } + nobj := j + + // Pass 2: non-object nodes. + for i = 1; i < N; { + obj := a.nodes[i].obj + if obj != nil { + i += nodeid(obj.size) + continue + } + + newNodes[j] = a.nodes[i] + renumbering[i] = j + i++ + j++ + } + + if j != N { + panic(fmt.Sprintf("internal error: j=%d, N=%d", j, N)) + } + + // Log the remapping table. + if a.log != nil { + fmt.Fprintf(a.log, "Renumbering nodes to improve density:\n") + fmt.Fprintf(a.log, "(%d object nodes of %d total)\n", nobj, N) + for old, new := range renumbering { + fmt.Fprintf(a.log, "\tn%d -> n%d\n", old, new) + } + } + + // Now renumber all existing nodeids to use the new node permutation. + // It is critical that all reachable nodeids are accounted for! + + // Renumber nodeids in queried Pointers. + for v, ptr := range a.result.Queries { + ptr.n = renumbering[ptr.n] + a.result.Queries[v] = ptr + } + for v, ptr := range a.result.IndirectQueries { + ptr.n = renumbering[ptr.n] + a.result.IndirectQueries[v] = ptr + } + + // Renumber nodeids in global objects. + for v, id := range a.globalobj { + a.globalobj[v] = renumbering[id] + } + + // Renumber nodeids in constraints. + for _, c := range a.constraints { + c.renumber(renumbering) + } + + // Renumber nodeids in the call graph. + for _, cgn := range a.cgnodes { + cgn.obj = renumbering[cgn.obj] + for _, site := range cgn.sites { + site.targets = renumbering[site.targets] + } + } + + a.nodes = newNodes +} diff --git a/go/pointer/reflect.go b/go/pointer/reflect.go index b0dd9d05..ed451774 100644 --- a/go/pointer/reflect.go +++ b/go/pointer/reflect.go @@ -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() diff --git a/go/pointer/solve.go b/go/pointer/solve.go index 458e66c5..6a6a5ee9 100644 --- a/go/pointer/solve.go +++ b/go/pointer/solve.go @@ -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'.