OLD | NEW |
| (Empty) |
1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file | |
2 // for details. All rights reserved. Use of this source code is governed by a | |
3 // BSD-style license that can be found in the LICENSE file. | |
4 | |
5 part of ssa; | |
6 | |
7 class ValueSet { | |
8 int size = 0; | |
9 List<HInstruction> table; | |
10 ValueSetNode collisions; | |
11 ValueSet() : table = new List<HInstruction>(8); | |
12 | |
13 bool get isEmpty => size == 0; | |
14 int get length => size; | |
15 | |
16 void add(HInstruction instruction) { | |
17 assert(lookup(instruction) == null); | |
18 int hashCode = instruction.gvnHashCode(); | |
19 int capacity = table.length; | |
20 // Resize when half of the hash table is in use. | |
21 if (size >= capacity >> 1) { | |
22 capacity = capacity << 1; | |
23 resize(capacity); | |
24 } | |
25 // Try to insert in the hash table first. | |
26 int index = hashCode % capacity; | |
27 if (table[index] == null) { | |
28 table[index] = instruction; | |
29 } else { | |
30 collisions = new ValueSetNode(instruction, hashCode, collisions); | |
31 } | |
32 size++; | |
33 } | |
34 | |
35 HInstruction lookup(HInstruction instruction) { | |
36 int hashCode = instruction.gvnHashCode(); | |
37 int index = hashCode % table.length; | |
38 // Look in the hash table. | |
39 HInstruction probe = table[index]; | |
40 if (probe != null && probe.gvnEquals(instruction)) return probe; | |
41 // Look in the collisions list. | |
42 for (ValueSetNode node = collisions; node != null; node = node.next) { | |
43 if (node.hashCode == hashCode) { | |
44 HInstruction cached = node.value; | |
45 if (cached.gvnEquals(instruction)) return cached; | |
46 } | |
47 } | |
48 return null; | |
49 } | |
50 | |
51 void kill(int flags) { | |
52 if (flags == 0) return; | |
53 int depends = SideEffects.computeDependsOnFlags(flags); | |
54 // Kill in the hash table. | |
55 for (int index = 0, length = table.length; index < length; index++) { | |
56 HInstruction instruction = table[index]; | |
57 if (instruction != null && instruction.sideEffects.dependsOn(depends)) { | |
58 table[index] = null; | |
59 size--; | |
60 } | |
61 } | |
62 // Kill in the collisions list. | |
63 ValueSetNode previous = null; | |
64 ValueSetNode current = collisions; | |
65 while (current != null) { | |
66 ValueSetNode next = current.next; | |
67 HInstruction cached = current.value; | |
68 if (cached.sideEffects.dependsOn(depends)) { | |
69 if (previous == null) { | |
70 collisions = next; | |
71 } else { | |
72 previous.next = next; | |
73 } | |
74 size--; | |
75 } else { | |
76 previous = current; | |
77 } | |
78 current = next; | |
79 } | |
80 } | |
81 | |
82 ValueSet copy() { | |
83 return copyTo(new ValueSet(), table, collisions); | |
84 } | |
85 | |
86 List<HInstruction> toList() { | |
87 return copyTo(<HInstruction>[], table, collisions); | |
88 } | |
89 | |
90 // Copy the instructions in value set defined by [table] and | |
91 // [collisions] into [other] and returns [other]. The copy is done | |
92 // by iterating through the hash table and the collisions list and | |
93 // calling [:other.add:]. | |
94 static copyTo(var other, List<HInstruction> table, ValueSetNode collisions) { | |
95 // Copy elements from the hash table. | |
96 for (int index = 0, length = table.length; index < length; index++) { | |
97 HInstruction instruction = table[index]; | |
98 if (instruction != null) other.add(instruction); | |
99 } | |
100 // Copy elements from the collision list. | |
101 ValueSetNode current = collisions; | |
102 while (current != null) { | |
103 // TODO(kasperl): Maybe find a way of reusing the hash code | |
104 // rather than recomputing it every time. | |
105 other.add(current.value); | |
106 current = current.next; | |
107 } | |
108 return other; | |
109 } | |
110 | |
111 ValueSet intersection(ValueSet other) { | |
112 if (size > other.size) return other.intersection(this); | |
113 ValueSet result = new ValueSet(); | |
114 // Look in the hash table. | |
115 for (int index = 0, length = table.length; index < length; index++) { | |
116 HInstruction instruction = table[index]; | |
117 if (instruction != null && other.lookup(instruction) != null) { | |
118 result.add(instruction); | |
119 } | |
120 } | |
121 // Look in the collision list. | |
122 ValueSetNode current = collisions; | |
123 while (current != null) { | |
124 HInstruction value = current.value; | |
125 if (other.lookup(value) != null) { | |
126 result.add(value); | |
127 } | |
128 current = current.next; | |
129 } | |
130 return result; | |
131 } | |
132 | |
133 void resize(int capacity) { | |
134 var oldSize = size; | |
135 var oldTable = table; | |
136 var oldCollisions = collisions; | |
137 // Reset the table with a bigger capacity. | |
138 assert(capacity > table.length); | |
139 size = 0; | |
140 table = new List<HInstruction>(capacity); | |
141 collisions = null; | |
142 // Add the old instructions to the new table. | |
143 copyTo(this, oldTable, oldCollisions); | |
144 // Make sure we preserved all elements and that no resizing | |
145 // happened as part of this resizing. | |
146 assert(size == oldSize); | |
147 assert(table.length == capacity); | |
148 } | |
149 } | |
150 | |
151 class ValueSetNode { | |
152 final HInstruction value; | |
153 final int hash; | |
154 int get hashCode => hash; | |
155 ValueSetNode next; | |
156 ValueSetNode(this.value, this.hash, this.next); | |
157 } | |
OLD | NEW |