You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

132 lines
3.2 KiB

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