| // 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 | 
 | } |