--- old/src/share/classes/java/lang/Class.java 2013-08-27 14:32:58.873302926 +0200 +++ new/src/share/classes/java/lang/Class.java 2013-08-27 14:32:58.777304719 +0200 @@ -48,6 +48,7 @@ import java.util.Arrays; import java.util.Collection; import java.util.HashSet; +import java.util.LinkedHashMap; import java.util.List; import java.util.Set; import java.util.Map; @@ -2318,11 +2319,14 @@ private static final long reflectionDataOffset; // offset of Class.annotationType instance field private static final long annotationTypeOffset; + // offset of Class.annotationData instance field + private static final long annotationDataOffset; static { Field[] fields = Class.class.getDeclaredFields0(false); // bypass caches reflectionDataOffset = objectFieldOffset(fields, "reflectionData"); annotationTypeOffset = objectFieldOffset(fields, "annotationType"); + annotationDataOffset = objectFieldOffset(fields, "annotationData"); } private static long objectFieldOffset(Field[] fields, String fieldName) { @@ -2344,6 +2348,12 @@ AnnotationType newType) { return unsafe.compareAndSwapObject(clazz, annotationTypeOffset, oldType, newType); } + + static boolean casAnnotationData(Class clazz, + AnnotationData oldData, + AnnotationData newData) { + return unsafe.compareAndSwapObject(clazz, annotationDataOffset, oldData, newData); + } } /** @@ -2354,7 +2364,7 @@ private static boolean useCaches = true; // reflection data that might get invalidated when JVM TI RedefineClasses() is called - static class ReflectionData { + private static class ReflectionData { volatile Field[] declaredFields; volatile Field[] publicFields; volatile Method[] declaredMethods; @@ -3201,8 +3211,7 @@ public A getAnnotation(Class annotationClass) { Objects.requireNonNull(annotationClass); - initAnnotationsIfNecessary(); - return (A) annotations.get(annotationClass); + return (A) annotationData().annotations.get(annotationClass); } /** @@ -3223,16 +3232,14 @@ public A[] getAnnotationsByType(Class annotationClass) { Objects.requireNonNull(annotationClass); - initAnnotationsIfNecessary(); - return AnnotationSupport.getMultipleAnnotations(annotations, annotationClass); + return AnnotationSupport.getMultipleAnnotations(annotationData().annotations, annotationClass); } /** * @since 1.5 */ public Annotation[] getAnnotations() { - initAnnotationsIfNecessary(); - return AnnotationParser.toArray(annotations); + return AnnotationParser.toArray(annotationData().annotations); } /** @@ -3244,8 +3251,7 @@ public A getDeclaredAnnotation(Class annotationClass) { Objects.requireNonNull(annotationClass); - initAnnotationsIfNecessary(); - return (A) declaredAnnotations.get(annotationClass); + return (A) annotationData().declaredAnnotations.get(annotationClass); } /** @@ -3256,52 +3262,85 @@ public A[] getDeclaredAnnotationsByType(Class annotationClass) { Objects.requireNonNull(annotationClass); - initAnnotationsIfNecessary(); - return AnnotationSupport.getMultipleAnnotations(declaredAnnotations, annotationClass); + return AnnotationSupport.getMultipleAnnotations(annotationData().declaredAnnotations, annotationClass); } /** * @since 1.5 */ public Annotation[] getDeclaredAnnotations() { - initAnnotationsIfNecessary(); - return AnnotationParser.toArray(declaredAnnotations); + return AnnotationParser.toArray(annotationData().declaredAnnotations); + } + + // annotation data that might get invalidated when JVM TI RedefineClasses() is called + private static class AnnotationData { + final Map, Annotation> annotations; + final Map, Annotation> declaredAnnotations; + + // Value of classRedefinedCount when we created this AnnotationData instance + final int redefinedCount; + + AnnotationData(Map, Annotation> annotations, + Map, Annotation> declaredAnnotations, + int redefinedCount) { + this.annotations = annotations; + this.declaredAnnotations = declaredAnnotations; + this.redefinedCount = redefinedCount; + } } // Annotations cache - private transient Map, Annotation> annotations; - private transient Map, Annotation> declaredAnnotations; - // Value of classRedefinedCount when we last cleared the cached annotations and declaredAnnotations fields - private transient int lastAnnotationsRedefinedCount = 0; - - // Clears cached values that might possibly have been obsoleted by - // a class redefinition. - private void clearAnnotationCachesOnClassRedefinition() { - if (lastAnnotationsRedefinedCount != classRedefinedCount) { - annotations = declaredAnnotations = null; - lastAnnotationsRedefinedCount = classRedefinedCount; + @SuppressWarnings("UnusedDeclaration") + private volatile transient AnnotationData annotationData; + + private AnnotationData annotationData() { + while (true) { // retry loop + AnnotationData annotationData = this.annotationData; + int classRedefinedCount = this.classRedefinedCount; + if (annotationData != null && + annotationData.redefinedCount == classRedefinedCount) { + return annotationData; + } + // null or stale annotationData -> optimistically create new instance + AnnotationData newAnnotationData = createAnnotationData(classRedefinedCount); + // try to install it + if (Atomic.casAnnotationData(this, annotationData, newAnnotationData)) { + // successfully installed new AnnotationData + return newAnnotationData; + } } } - private synchronized void initAnnotationsIfNecessary() { - clearAnnotationCachesOnClassRedefinition(); - if (annotations != null) - return; - declaredAnnotations = AnnotationParser.parseAnnotations( - getRawAnnotations(), getConstantPool(), this); + private AnnotationData createAnnotationData(int classRedefinedCount) { + Map, Annotation> declaredAnnotations = + AnnotationParser.parseAnnotations(getRawAnnotations(), getConstantPool(), this); Class superClass = getSuperclass(); - if (superClass == null) { - annotations = declaredAnnotations; - } else { - annotations = new HashMap<>(); - superClass.initAnnotationsIfNecessary(); - for (Map.Entry, Annotation> e : superClass.annotations.entrySet()) { + Map, Annotation> annotations = null; + if (superClass != null) { + Map, Annotation> superAnnotations = + superClass.annotationData().annotations; + for (Map.Entry, Annotation> e : superAnnotations.entrySet()) { Class annotationClass = e.getKey(); - if (AnnotationType.getInstance(annotationClass).isInherited()) + if (AnnotationType.getInstance(annotationClass).isInherited()) { + if (annotations == null) { // lazy construction + annotations = new LinkedHashMap<>((Math.max( + declaredAnnotations.size(), + Math.min(12, declaredAnnotations.size() + superAnnotations.size()) + ) * 4 + 2) / 3 + ); + } annotations.put(annotationClass, e.getValue()); + } } + } + if (annotations == null) { + // no inherited annotations -> share the Map with declaredAnnotations + annotations = declaredAnnotations; + } else { + // at least one inherited annotation -> declared may override inherited annotations.putAll(declaredAnnotations); } + return new AnnotationData(annotations, declaredAnnotations, classRedefinedCount); } // Annotation types cache their internal (AnnotationType) form