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