1011 // Verify all operands, and make sure ptypes is unshared: |
1014 // Verify all operands, and make sure ptypes is unshared: |
1012 return methodType(rtype, ptypes); |
1015 return methodType(rtype, ptypes); |
1013 } |
1016 } |
1014 |
1017 |
1015 /** |
1018 /** |
1016 * Weak intern set based on implementation of the <tt>HashSet</tt> and |
1019 * Simple implementation of weak concurrent intern set. |
1017 * <tt>WeakHashMap</tt>, with <em>weak values</em>. Note: <tt>null</tt> |
|
1018 * values will yield <tt>NullPointerException</tt> |
|
1019 * Refer to implementation of WeakInternSet for details. |
|
1020 * |
1020 * |
1021 * @see java.util.HashMap |
1021 * @param <T> interned type |
1022 * @see java.util.HashSet |
1022 */ |
1023 * @see java.util.WeakHashMap |
1023 private static class ConcurrentWeakInternSet<T> { |
1024 * @see java.lang.ref.WeakReference |
1024 |
1025 */ |
1025 private final ConcurrentMap<WeakEntry<T>, WeakEntry<T>> map; |
1026 private static class WeakInternSet { |
1026 private final ReferenceQueue<T> stale; |
1027 // The default initial capacity -- MUST be a power of two. |
1027 |
1028 private static final int DEFAULT_INITIAL_CAPACITY = 16; |
1028 public ConcurrentWeakInternSet() { |
1029 |
1029 this.map = new ConcurrentHashMap<>(); |
1030 // The maximum capacity, used if a higher value is implicitly specified |
1030 this.stale = new ReferenceQueue<>(); |
1031 // by either of the constructors with arguments. |
|
1032 // MUST be a power of two <= 1<<30. |
|
1033 private static final int MAXIMUM_CAPACITY = 1 << 30; |
|
1034 |
|
1035 // The load factor used when none specified in constructor. |
|
1036 private static final float DEFAULT_LOAD_FACTOR = 0.75f; |
|
1037 |
|
1038 // The table, resized as necessary. Length MUST Always be a power of two. |
|
1039 private Entry[] table; |
|
1040 |
|
1041 // The number of entries contained in this set. |
|
1042 private int size; |
|
1043 |
|
1044 // The next size value at which to resize (capacity * load factor). |
|
1045 private int threshold; |
|
1046 |
|
1047 // The load factor for the hash table. |
|
1048 private final float loadFactor; |
|
1049 |
|
1050 // Reference queue for cleared WeakEntries |
|
1051 private final ReferenceQueue<Object> queue = new ReferenceQueue<>(); |
|
1052 |
|
1053 private Entry[] newTable(int n) { |
|
1054 return new Entry[n]; |
|
1055 } |
1031 } |
1056 |
1032 |
1057 /** |
1033 /** |
1058 * Constructs a new, empty <tt>WeakInternSet</tt> with the default initial |
1034 * Get the existing interned element. |
1059 * capacity (16) and load factor (0.75). |
1035 * This method returns null if no element is interned. |
|
1036 * |
|
1037 * @param elem element to look up |
|
1038 * @return the interned element |
1060 */ |
1039 */ |
1061 WeakInternSet() { |
1040 public T get(T elem) { |
1062 this.loadFactor = DEFAULT_LOAD_FACTOR; |
1041 if (elem == null) throw new NullPointerException(); |
1063 threshold = DEFAULT_INITIAL_CAPACITY; |
1042 expungeStaleElements(); |
1064 table = newTable(DEFAULT_INITIAL_CAPACITY); |
1043 |
1065 } |
1044 WeakEntry<T> value = map.get(new WeakEntry<>(elem)); |
1066 |
1045 if (value != null) { |
1067 /** |
1046 T res = value.get(); |
1068 * Applies a supplemental hash function to a given hashCode, which |
1047 if (res != null) { |
1069 * defends against poor quality hash functions. This is critical |
1048 return res; |
1070 * because hashing uses power-of-two length hash tables, that |
|
1071 * otherwise encounter collisions for hashCodes that do not differ |
|
1072 * in lower bits. |
|
1073 * @param h preliminary hash code value |
|
1074 * @return supplemental hash code value |
|
1075 */ |
|
1076 private static int hash(int h) { |
|
1077 // This function ensures that hashCodes that differ only by |
|
1078 // constant multiples at each bit position have a bounded |
|
1079 // number of collisions (approximately 8 at default load factor). |
|
1080 h ^= (h >>> 20) ^ (h >>> 12); |
|
1081 return h ^ (h >>> 7) ^ (h >>> 4); |
|
1082 } |
|
1083 |
|
1084 /** |
|
1085 * Checks for equality of non-null reference x and possibly-null y. By |
|
1086 * default uses Object.equals. |
|
1087 * @param x first object to compare |
|
1088 * @param y second object to compare |
|
1089 * @return <tt>true</tt> if objects are equal |
|
1090 */ |
|
1091 private static boolean eq(Object x, Object y) { |
|
1092 return x == y || x.equals(y); |
|
1093 } |
|
1094 |
|
1095 /** |
|
1096 * Returns index for hash code h. |
|
1097 * @param h raw hash code |
|
1098 * @param length length of table (power of 2) |
|
1099 * @return index in table |
|
1100 */ |
|
1101 private static int indexFor(int h, int length) { |
|
1102 return h & (length-1); |
|
1103 } |
|
1104 |
|
1105 /** |
|
1106 * Expunges stale entries from the table. |
|
1107 */ |
|
1108 private void expungeStaleEntries() { |
|
1109 for (Object x; (x = queue.poll()) != null; ) { |
|
1110 synchronized (queue) { |
|
1111 Entry entry = (Entry) x; |
|
1112 int i = indexFor(entry.hash, table.length); |
|
1113 Entry prev = table[i]; |
|
1114 Entry p = prev; |
|
1115 while (p != null) { |
|
1116 Entry next = p.next; |
|
1117 if (p == entry) { |
|
1118 if (prev == entry) |
|
1119 table[i] = next; |
|
1120 else |
|
1121 prev.next = next; |
|
1122 entry.next = null; |
|
1123 size--; |
|
1124 break; |
|
1125 } |
|
1126 prev = p; |
|
1127 p = next; |
|
1128 } |
|
1129 } |
1049 } |
1130 } |
1050 } |
|
1051 return null; |
1131 } |
1052 } |
1132 |
1053 |
1133 /** |
1054 /** |
1134 * Returns the table after first expunging stale entries. |
1055 * Interns the element. |
1135 * @return an expunged hash table |
1056 * Always returns non-null element, matching the one in the intern set. |
|
1057 * Under the race against another add(), it can return <i>different</i> |
|
1058 * element, if another thread beats us to interning it. |
|
1059 * |
|
1060 * @param elem element to add |
|
1061 * @return element that was actually added |
1136 */ |
1062 */ |
1137 private Entry[] getTable() { |
1063 public T add(T elem) { |
1138 expungeStaleEntries(); |
1064 if (elem == null) throw new NullPointerException(); |
1139 return table; |
1065 |
1140 } |
1066 // Playing double race here, and so spinloop is required. |
1141 |
1067 // First race is with two concurrent updaters. |
1142 /** |
1068 // Second race is with GC purging weak ref under our feet. |
1143 * Returns the entry to which the specified value is mapped, |
1069 // Hopefully, we almost always end up with a single pass. |
1144 * or {@code null} if this set contains no entry for the value. |
1070 T interned; |
1145 * |
1071 WeakEntry<T> e = new WeakEntry<>(elem, stale); |
1146 * <p>More formally, if this set contains an entry for value |
1072 do { |
1147 * {@code entry} to a value {@code value} such that |
1073 expungeStaleElements(); |
1148 * {@code entry.equals(value)}, then this method returns {@code entry}; |
1074 WeakEntry<T> exist = map.putIfAbsent(e, e); |
1149 * otherwise it returns {@code null}. |
1075 interned = (exist == null) ? elem : exist.get(); |
1150 * |
1076 } while (interned == null); |
1151 * @param value value to search for in set |
1077 return interned; |
1152 * @return interned value if in set, otherwise <tt>null</tt> |
1078 } |
1153 */ |
1079 |
1154 synchronized MethodType get(MethodType value) { |
1080 private void expungeStaleElements() { |
1155 int h = hash(value.hashCode()); |
1081 Reference<? extends T> reference; |
1156 Entry[] tab = getTable(); |
1082 while ((reference = stale.poll()) != null) { |
1157 int index = indexFor(h, tab.length); |
1083 map.remove(reference); |
1158 Entry e = tab[index]; |
|
1159 MethodType g; |
|
1160 while (e != null) { |
|
1161 if (e.hash == h && eq(value, g = e.get())) |
|
1162 return g; |
|
1163 e = e.next; |
|
1164 } |
1084 } |
1165 return null; |
1085 } |
1166 } |
1086 |
1167 |
1087 private static class WeakEntry<T> extends WeakReference<T> { |
1168 /** |
1088 |
1169 * Attempts to add the specified value to the set and returns same value. |
1089 public final int hashcode; |
1170 * If the set previously contained an entry for this value, the old |
1090 |
1171 * value is left untouched and returned as the result. |
1091 public WeakEntry(T key, ReferenceQueue<T> queue) { |
1172 * |
1092 super(key, queue); |
1173 * @param value value to be added |
1093 hashcode = key.hashCode(); |
1174 * @return the previous entry associated with <tt>value</tt>, or |
1094 } |
1175 * <tt>value</tt> if there was no previous entry found |
1095 |
1176 */ |
1096 public WeakEntry(T key) { |
1177 synchronized MethodType add(MethodType value) { |
1097 super(key); |
1178 int h = hash(value.hashCode()); |
1098 hashcode = key.hashCode(); |
1179 Entry[] tab = getTable(); |
1099 } |
1180 int i = indexFor(h, tab.length); |
1100 |
1181 MethodType g; |
1101 @Override |
1182 for (Entry e = tab[i]; e != null; e = e.next) { |
1102 public boolean equals(Object obj) { |
1183 if (h == e.hash && eq(value, g = e.get())) { |
1103 if (obj instanceof WeakEntry) { |
1184 return g; |
1104 Object that = ((WeakEntry) obj).get(); |
|
1105 Object mine = get(); |
|
1106 return (that == null || mine == null) ? (this == obj) : mine.equals(that); |
1185 } |
1107 } |
|
1108 return false; |
1186 } |
1109 } |
1187 Entry e = tab[i]; |
1110 |
1188 tab[i] = new Entry(value, queue, h, e); |
1111 @Override |
1189 if (++size >= threshold) |
1112 public int hashCode() { |
1190 resize(tab.length * 2); |
1113 return hashcode; |
1191 return value; |
|
1192 } |
|
1193 |
|
1194 /** |
|
1195 * Rehashes the contents of this set into a new array with a |
|
1196 * larger capacity. This method is called automatically when the |
|
1197 * number of keys in this set reaches its threshold. |
|
1198 * |
|
1199 * If current capacity is MAXIMUM_CAPACITY, this method does not |
|
1200 * resize the set, but sets threshold to Integer.MAX_VALUE. |
|
1201 * This has the effect of preventing future calls. |
|
1202 * |
|
1203 * @param newCapacity the new capacity, MUST be a power of two; |
|
1204 * must be greater than current capacity unless current |
|
1205 * capacity is MAXIMUM_CAPACITY (in which case value |
|
1206 * is irrelevant) |
|
1207 */ |
|
1208 private void resize(int newCapacity) { |
|
1209 Entry[] oldTable = getTable(); |
|
1210 int oldCapacity = oldTable.length; |
|
1211 if (oldCapacity == MAXIMUM_CAPACITY) { |
|
1212 threshold = Integer.MAX_VALUE; |
|
1213 return; |
|
1214 } |
1114 } |
1215 |
1115 |
1216 Entry[] newTable = newTable(newCapacity); |
1116 } |
1217 transfer(oldTable, newTable); |
1117 } |
1218 table = newTable; |
1118 |
1219 |
|
1220 /* |
|
1221 * If ignoring null elements and processing ref queue caused massive |
|
1222 * shrinkage, then restore old table. This should be rare, but avoids |
|
1223 * unbounded expansion of garbage-filled tables. |
|
1224 */ |
|
1225 if (size >= threshold / 2) { |
|
1226 threshold = (int)(newCapacity * loadFactor); |
|
1227 } else { |
|
1228 expungeStaleEntries(); |
|
1229 transfer(newTable, oldTable); |
|
1230 table = oldTable; |
|
1231 } |
|
1232 } |
|
1233 |
|
1234 /** |
|
1235 * Transfers all entries from src to dest tables |
|
1236 * @param src original table |
|
1237 * @param dest new table |
|
1238 */ |
|
1239 private void transfer(Entry[] src, Entry[] dest) { |
|
1240 for (int j = 0; j < src.length; ++j) { |
|
1241 Entry e = src[j]; |
|
1242 src[j] = null; |
|
1243 while (e != null) { |
|
1244 Entry next = e.next; |
|
1245 MethodType key = e.get(); |
|
1246 if (key == null) { |
|
1247 e.next = null; // Help GC |
|
1248 size--; |
|
1249 } else { |
|
1250 int i = indexFor(e.hash, dest.length); |
|
1251 e.next = dest[i]; |
|
1252 dest[i] = e; |
|
1253 } |
|
1254 e = next; |
|
1255 } |
|
1256 } |
|
1257 } |
|
1258 |
|
1259 /** |
|
1260 * The entries in this hash table extend WeakReference, using its main ref |
|
1261 * field as the key. |
|
1262 */ |
|
1263 private static class Entry extends WeakReference<MethodType> { |
|
1264 final int hash; |
|
1265 Entry next; |
|
1266 |
|
1267 /** |
|
1268 * Creates new entry. |
|
1269 */ |
|
1270 Entry(MethodType key, |
|
1271 ReferenceQueue<Object> queue, |
|
1272 int hash, Entry next) { |
|
1273 super(key, queue); |
|
1274 this.hash = hash; |
|
1275 this.next = next; |
|
1276 } |
|
1277 } |
|
1278 } |
|
1279 } |
1119 } |