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  }