--- old/src/java.base/share/classes/java/lang/Class.java 2014-10-30 16:11:40.000000000 -0400 +++ new/src/java.base/share/classes/java/lang/Class.java 2014-10-30 16:11:39.000000000 -0400 @@ -67,8 +67,10 @@ import sun.reflect.generics.repository.ConstructorRepository; import sun.reflect.generics.scope.ClassScope; import sun.security.util.SecurityConstants; + import java.lang.annotation.Annotation; import java.lang.reflect.Proxy; + import sun.reflect.annotation.*; import sun.reflect.misc.ReflectUtil; @@ -2462,6 +2464,153 @@ } /** + * ClassData + */ + private static class ClassData { + /** + * This needs to be a simple data structure because we need to access + * and update its elements from the JVM. Note that the Java side controls + * the allocation and order of elements in the array; the JVM modifies + * fields of those elements during class redefinition. + */ + private volatile Comparable[] elementData; + private volatile int size; + + /** + * Interns a member name in the member name table. + * Returns null if a race with the jvm occurred. Races are detected + * by checking for changes in the class redefinition count that occur + * before an intern is complete. + * + * @param klass class whose redefinition count is checked. + * @param memberName member name to be interned + * @param redefined_count the value of classRedefinedCount() observed before + * creation of the MemberName that is being interned. + * @return null if a race occurred, otherwise the interned MemberName. + */ + @SuppressWarnings({"unchecked","rawtypes"}) + public > E intern(Class klass, E memberName, int redefined_count) { + if (elementData == null) { + synchronized (this) { + if (elementData == null) { + elementData = new Comparable[1]; + } + } + } + synchronized (elementData) { + final int index = Arrays.binarySearch(elementData, 0, size, memberName); + if (index >= 0) { + return (E) elementData[index]; + } + // Not found, add carefully. + return add(klass, ~index, memberName, redefined_count); + } + } + + /** + * Appends the specified element at the specified index. + * + * @param klass the klass for this ClassData. + * @param index index at which insertion should occur + * @param e element to be insert into this list + * @param redefined_count value of klass.classRedefinedCount() before e was created. + * @return null if insertion failed because of redefinition race, otherwise e. + */ + private > E add(Class klass, int index, E e, int redefined_count) { + int oldCapacity = size; + Comparable[] element_data = elementData; + if (oldCapacity + 1 > element_data.length ) { + // Replacing array with a copy is safe; elements are identical. + grow(oldCapacity + 1); + element_data = elementData; + } + /* + * Careful dance to insert an element. + * + * Wish to ensure that we do not hide an element of + * the array; must also ensure that visible-to-jvm + * portion of array never contains nulls; also ensure + * that array remains sorted. + * + * Note that taking a safepoint is also a barrier. + */ + if (oldCapacity > 0) { + element_data[oldCapacity] = element_data[oldCapacity - 1]; + // all array elements are non-null and sorted, increase size. + // if store to element_data above floats below + // store to size on the next line, that will be + // inconsistent to the VM if a safepoint occurs here. + size += 1; + for (int i = oldCapacity; i > index; i--) { + // pre: element_data[i] is duplicated at [i+1] + element_data[i] = element_data[i - 1]; + // post: element_data[i-1] is duplicated at [i] + } + // element_data[index] is duplicated at [index+1] + element_data[index] = (Comparable) e; + } else { + element_data[index] = (Comparable) e; + // Don't want store to element_data[index] above + // to float past store to size below, otherwise + // VM might see inconsistent state. + size += 1; + } + if (redefined_count == klass.classRedefinedCount()) { + return e; + } + /* The race was lost, must undo insertion and retry the intern + * with a new resolution. + */ + for (int i = index; i < oldCapacity; i++) { + element_data[i] = element_data[i+1]; + } + size -= 1; + return null; + } + + /** + * Increases the capacity to ensure that it can hold at least the + * number of elements specified by the minimum capacity argument. + * + * @param minCapacity the desired minimum capacity + */ + private void grow(int minCapacity) { + // overflow-conscious code + int oldCapacity = elementData.length; + int newCapacity = oldCapacity + (oldCapacity >> 1); + if (newCapacity - minCapacity < 0) + newCapacity = minCapacity; + // minCapacity is usually close to size, so this is a win: + elementData = Arrays.copyOf(elementData, newCapacity); + } + } + + private volatile transient ClassData classData; + + /** + * Lazily create {@link ClassData}. + */ + private ClassData classData() { + if (this.classData != null) { + return this.classData; + } + synchronized (this) { + if (this.classData == null) { + this.classData = new ClassData<>(); + } + } + return this.classData; + } + + /* package */ > E internMemberName(E memberName, int redefined_count) { + return classData().intern(this, memberName, redefined_count); + } + + /* package */ int classRedefinedCount() { + return classRedefinedCount; + } + + /** * Reflection support. */