github.com/powerman/golang-tools@v0.1.11-0.20220410185822-5ad214d8d803/go/pointer/opt.go (about) 1 // Copyright 2013 The Go Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 package pointer 6 7 // This file implements renumbering, a pre-solver optimization to 8 // improve the efficiency of the solver's points-to set representation. 9 // 10 // TODO(adonovan): rename file "renumber.go" 11 12 import "fmt" 13 14 // renumber permutes a.nodes so that all nodes within an addressable 15 // object appear before all non-addressable nodes, maintaining the 16 // order of nodes within the same object (as required by offsetAddr). 17 // 18 // renumber must update every nodeid in the analysis (constraints, 19 // Pointers, callgraph, etc) to reflect the new ordering. 20 // 21 // This is an optimisation to increase the locality and efficiency of 22 // sparse representations of points-to sets. (Typically only about 23 // 20% of nodes are within an object.) 24 // 25 // NB: nodes added during solving (e.g. for reflection, SetFinalizer) 26 // will be appended to the end. 27 // 28 // Renumbering makes the PTA log inscrutable. To aid debugging, later 29 // phases (e.g. HVN) must not rely on it having occurred. 30 // 31 func (a *analysis) renumber() { 32 if a.log != nil { 33 fmt.Fprintf(a.log, "\n\n==== Renumbering\n\n") 34 } 35 36 N := nodeid(len(a.nodes)) 37 newNodes := make([]*node, N) 38 renumbering := make([]nodeid, N) // maps old to new 39 40 var i, j nodeid 41 42 // The zero node is special. 43 newNodes[j] = a.nodes[i] 44 renumbering[i] = j 45 i++ 46 j++ 47 48 // Pass 1: object nodes. 49 for i < N { 50 obj := a.nodes[i].obj 51 if obj == nil { 52 i++ 53 continue 54 } 55 56 end := i + nodeid(obj.size) 57 for i < end { 58 newNodes[j] = a.nodes[i] 59 renumbering[i] = j 60 i++ 61 j++ 62 } 63 } 64 nobj := j 65 66 // Pass 2: non-object nodes. 67 for i = 1; i < N; { 68 obj := a.nodes[i].obj 69 if obj != nil { 70 i += nodeid(obj.size) 71 continue 72 } 73 74 newNodes[j] = a.nodes[i] 75 renumbering[i] = j 76 i++ 77 j++ 78 } 79 80 if j != N { 81 panic(fmt.Sprintf("internal error: j=%d, N=%d", j, N)) 82 } 83 84 // Log the remapping table. 85 if a.log != nil { 86 fmt.Fprintf(a.log, "Renumbering nodes to improve density:\n") 87 fmt.Fprintf(a.log, "(%d object nodes of %d total)\n", nobj, N) 88 for old, new := range renumbering { 89 fmt.Fprintf(a.log, "\tn%d -> n%d\n", old, new) 90 } 91 } 92 93 // Now renumber all existing nodeids to use the new node permutation. 94 // It is critical that all reachable nodeids are accounted for! 95 96 // Renumber nodeids in queried Pointers. 97 for v, ptr := range a.result.Queries { 98 ptr.n = renumbering[ptr.n] 99 a.result.Queries[v] = ptr 100 } 101 for v, ptr := range a.result.IndirectQueries { 102 ptr.n = renumbering[ptr.n] 103 a.result.IndirectQueries[v] = ptr 104 } 105 for _, queries := range a.config.extendedQueries { 106 for _, query := range queries { 107 if query.ptr != nil { 108 query.ptr.n = renumbering[query.ptr.n] 109 } 110 } 111 } 112 113 // Renumber nodeids in global objects. 114 for v, id := range a.globalobj { 115 a.globalobj[v] = renumbering[id] 116 } 117 118 // Renumber nodeids in constraints. 119 for _, c := range a.constraints { 120 c.renumber(renumbering) 121 } 122 123 // Renumber nodeids in the call graph. 124 for _, cgn := range a.cgnodes { 125 cgn.obj = renumbering[cgn.obj] 126 for _, site := range cgn.sites { 127 site.targets = renumbering[site.targets] 128 } 129 } 130 131 a.nodes = newNodes 132 }