jdk/src/share/classes/java/lang/invoke/MethodType.java
changeset 18180 e0b8c923f35d
parent 13610 28122b96858e
child 18569 0e46c17766b7
equal deleted inserted replaced
18179:9b6ad451b521 18180:e0b8c923f35d
    25 
    25 
    26 package java.lang.invoke;
    26 package java.lang.invoke;
    27 
    27 
    28 import sun.invoke.util.Wrapper;
    28 import sun.invoke.util.Wrapper;
    29 import java.lang.ref.WeakReference;
    29 import java.lang.ref.WeakReference;
       
    30 import java.lang.ref.Reference;
    30 import java.lang.ref.ReferenceQueue;
    31 import java.lang.ref.ReferenceQueue;
    31 import java.util.Arrays;
    32 import java.util.Arrays;
    32 import java.util.Collections;
    33 import java.util.Collections;
    33 import java.util.List;
    34 import java.util.List;
       
    35 import java.util.concurrent.ConcurrentMap;
       
    36 import java.util.concurrent.ConcurrentHashMap;
    34 import sun.invoke.util.BytecodeDescriptor;
    37 import sun.invoke.util.BytecodeDescriptor;
    35 import static java.lang.invoke.MethodHandleStatics.*;
    38 import static java.lang.invoke.MethodHandleStatics.*;
    36 import sun.invoke.util.VerifyType;
    39 import sun.invoke.util.VerifyType;
    37 
    40 
    38 /**
    41 /**
   169     private static IndexOutOfBoundsException newIndexOutOfBoundsException(Object num) {
   172     private static IndexOutOfBoundsException newIndexOutOfBoundsException(Object num) {
   170         if (num instanceof Integer)  num = "bad index: "+num;
   173         if (num instanceof Integer)  num = "bad index: "+num;
   171         return new IndexOutOfBoundsException(num.toString());
   174         return new IndexOutOfBoundsException(num.toString());
   172     }
   175     }
   173 
   176 
   174     static final WeakInternSet internTable = new WeakInternSet();
   177     static final ConcurrentWeakInternSet<MethodType> internTable = new ConcurrentWeakInternSet<>();
   175 
   178 
   176     static final Class<?>[] NO_PTYPES = {};
   179     static final Class<?>[] NO_PTYPES = {};
   177 
   180 
   178     /**
   181     /**
   179      * Finds or creates an instance of the given method type.
   182      * Finds or creates an instance of the given method type.
  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 }