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