github.com/cockroachdb/tools@v0.0.0-20230222021103-a6d27438930d/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 func (a *analysis) renumber() { 31 if a.log != nil { 32 fmt.Fprintf(a.log, "\n\n==== Renumbering\n\n") 33 } 34 35 N := nodeid(len(a.nodes)) 36 newNodes := make([]*node, N) 37 renumbering := make([]nodeid, N) // maps old to new 38 39 var i, j nodeid 40 41 // The zero node is special. 42 newNodes[j] = a.nodes[i] 43 renumbering[i] = j 44 i++ 45 j++ 46 47 // Pass 1: object nodes. 48 for i < N { 49 obj := a.nodes[i].obj 50 if obj == nil { 51 i++ 52 continue 53 } 54 55 end := i + nodeid(obj.size) 56 for i < end { 57 newNodes[j] = a.nodes[i] 58 renumbering[i] = j 59 i++ 60 j++ 61 } 62 } 63 nobj := j 64 65 // Pass 2: non-object nodes. 66 for i = 1; i < N; { 67 obj := a.nodes[i].obj 68 if obj != nil { 69 i += nodeid(obj.size) 70 continue 71 } 72 73 newNodes[j] = a.nodes[i] 74 renumbering[i] = j 75 i++ 76 j++ 77 } 78 79 if j != N { 80 panic(fmt.Sprintf("internal error: j=%d, N=%d", j, N)) 81 } 82 83 // Log the remapping table. 84 if a.log != nil { 85 fmt.Fprintf(a.log, "Renumbering nodes to improve density:\n") 86 fmt.Fprintf(a.log, "(%d object nodes of %d total)\n", nobj, N) 87 for old, new := range renumbering { 88 fmt.Fprintf(a.log, "\tn%d -> n%d\n", old, new) 89 } 90 } 91 92 // Now renumber all existing nodeids to use the new node permutation. 93 // It is critical that all reachable nodeids are accounted for! 94 95 // Renumber nodeids in queried Pointers. 96 for v, ptr := range a.result.Queries { 97 ptr.n = renumbering[ptr.n] 98 a.result.Queries[v] = ptr 99 } 100 for v, ptr := range a.result.IndirectQueries { 101 ptr.n = renumbering[ptr.n] 102 a.result.IndirectQueries[v] = ptr 103 } 104 for _, queries := range a.config.extendedQueries { 105 for _, query := range queries { 106 if query.ptr != nil { 107 query.ptr.n = renumbering[query.ptr.n] 108 } 109 } 110 } 111 112 // Renumber nodeids in global objects. 113 for v, id := range a.globalobj { 114 a.globalobj[v] = renumbering[id] 115 } 116 117 // Renumber nodeids in constraints. 118 for _, c := range a.constraints { 119 c.renumber(renumbering) 120 } 121 122 // Renumber nodeids in the call graph. 123 for _, cgn := range a.cgnodes { 124 cgn.obj = renumbering[cgn.obj] 125 for _, site := range cgn.sites { 126 site.targets = renumbering[site.targets] 127 } 128 } 129 130 a.nodes = newNodes 131 }