133 lines
		
	
	
		
			3.2 KiB
		
	
	
	
		
			Go
		
	
	
	
			
		
		
	
	
			133 lines
		
	
	
		
			3.2 KiB
		
	
	
	
		
			Go
		
	
	
	
| // 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 implements renumbering, a pre-solver optimization to
 | |
| // improve the efficiency of the solver's points-to set representation.
 | |
| //
 | |
| // TODO(adonovan): rename file "renumber.go"
 | |
| 
 | |
| import "fmt"
 | |
| 
 | |
| // 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.
 | |
| //
 | |
| // Renumbering makes the PTA log inscrutable.  To aid debugging, later
 | |
| // phases (e.g. HVN) must not rely on it having occurred.
 | |
| //
 | |
| func (a *analysis) renumber() {
 | |
| 	if a.log != nil {
 | |
| 		fmt.Fprintf(a.log, "\n\n==== Renumbering\n\n")
 | |
| 	}
 | |
| 
 | |
| 	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
 | |
| 	}
 | |
| 	for _, queries := range a.config.extendedQueries {
 | |
| 		for _, query := range queries {
 | |
| 			if query.ptr != nil {
 | |
| 				query.ptr.n = renumbering[query.ptr.n]
 | |
| 			}
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	// 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
 | |
| }
 |