src/share/classes/java/lang/Class.java
Index Unified diffs Context diffs Sdiffs Wdiffs Patch New Old Previous File Next File
*** old/src/share/classes/java/lang/Class.java	Sun Jan  6 17:36:18 2013
--- new/src/share/classes/java/lang/Class.java	Sun Jan  6 17:36:16 2013

*** 1,7 **** --- 1,7 ---- /* ! * Copyright (c) 1994, 2012, Oracle and/or its affiliates. All rights reserved. ! * Copyright (c) 1994, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as * published by the Free Software Foundation. Oracle designates this
*** 2212,2256 **** --- 2212,2306 ---- * Reflection support. */ // Caches for certain reflective results private static boolean useCaches = true; private volatile transient SoftReference<Field[]> declaredFields; private volatile transient SoftReference<Field[]> publicFields; private volatile transient SoftReference<Method[]> declaredMethods; ! private volatile transient SoftReference<Method[]> publicMethods; ! private volatile transient SoftReference<Constructor<T>[]> declaredConstructors; ! private volatile transient SoftReference<Constructor<T>[]> publicConstructors; + + // reflection data that might get invalidated when JVM TI RedefineClasses() is called + static class ReflectionData<T> { ! volatile Field[] declaredFields; ! volatile Field[] publicFields; ! volatile Method[] declaredMethods; + volatile Method[] publicMethods; + volatile Constructor<T>[] declaredConstructors; + volatile Constructor<T>[] publicConstructors; // Intermediate results for getFields and getMethods ! private volatile transient SoftReference<Field[]> declaredPublicFields; ! private volatile transient SoftReference<Method[]> declaredPublicMethods; ! volatile Field[] declaredPublicFields; ! volatile Method[] declaredPublicMethods; + // Value of classRedefinedCount when we created this ReflectionData instance + final int redefinedCount; + ReflectionData(int redefinedCount) { + this.redefinedCount = redefinedCount; + } + + // initialize Unsafe machinery here, since we need to call Class.class instance method + // and have to avoid calling it in the static initializer of the Class class... + private static final Unsafe unsafe; + // offset of Class.reflectionData instance field + private static final long reflectionDataOffset; + + static { + unsafe = Unsafe.getUnsafe(); + // bypass caches + Field reflectionDataField = searchFields(Class.class.getDeclaredFields0(false), + "reflectionData"); + if (reflectionDataField == null) { + throw new Error("No reflectionData field found in java.lang.Class"); + } + reflectionDataOffset = unsafe.objectFieldOffset(reflectionDataField); + } + + static <T> boolean compareAndSwap(Class<?> clazz, + SoftReference<ReflectionData<T>> oldData, + SoftReference<ReflectionData<T>> newData) { + return unsafe.compareAndSwapObject(clazz, reflectionDataOffset, oldData, newData); + } + } + + private volatile transient SoftReference<ReflectionData<T>> reflectionData; + // Incremented by the VM on each call to JVM TI RedefineClasses() // that redefines this class or a superclass. private volatile transient int classRedefinedCount = 0; // Value of classRedefinedCount when we last cleared the cached values // that are sensitive to class redefinition. ! private volatile transient int lastRedefinedCount = 0; + // Lazily create and cache ReflectionData + private ReflectionData<T> reflectionData() { ! SoftReference<ReflectionData<T>> reflectionData = this.reflectionData; + int classRedefinedCount = this.classRedefinedCount; + ReflectionData<T> rd; + if (useCaches && + reflectionData != null && + (rd = reflectionData.get()) != null && + rd.redefinedCount == classRedefinedCount) { + return rd; + } + // else no SoftReference or cleared SoftReference or stale ReflectionData + // -> create and replace new instance + return newReflectionData(reflectionData, classRedefinedCount); + } // Clears cached values that might possibly have been obsoleted by // a class redefinition. private void clearCachesOnClassRedefinition() { if (lastRedefinedCount != classRedefinedCount) { declaredFields = publicFields = declaredPublicFields = null; declaredMethods = publicMethods = declaredPublicMethods = null; declaredConstructors = publicConstructors = null; annotations = declaredAnnotations = null; + private ReflectionData<T> newReflectionData(SoftReference<ReflectionData<T>> oldReflectionData, + int classRedefinedCount) { + if (!useCaches) return null; // Use of "volatile" (and synchronization by caller in the case // of annotations) ensures that no thread sees the update to ! // lastRedefinedCount before seeing the caches cleared. // We do not guard against brief windows during which multiple // threads might redundantly work to fill an empty cache. lastRedefinedCount = classRedefinedCount; + while (true) { + ReflectionData<T> rd = new ReflectionData<>(classRedefinedCount); ! // try to CAS it... + if (ReflectionData.compareAndSwap(this, oldReflectionData, new SoftReference<>(rd))) { + return rd; } + // else retry + oldReflectionData = this.reflectionData; + classRedefinedCount = this.classRedefinedCount; + if (oldReflectionData != null && + (rd = oldReflectionData.get()) != null && + rd.redefinedCount == classRedefinedCount) { + return rd; } + } + } // Generic signature handling private native String getGenericSignature(); // Generic info repository; lazily initialized
*** 2287,2317 **** --- 2337,2359 ---- // Returns an array of "root" fields. These Field objects must NOT // be propagated to the outside world, but must instead be copied // via ReflectionFactory.copyField. private Field[] privateGetDeclaredFields(boolean publicOnly) { checkInitted(); - Field[] res = null; if (useCaches) { clearCachesOnClassRedefinition(); if (publicOnly) { if (declaredPublicFields != null) { res = declaredPublicFields.get(); } } else { if (declaredFields != null) { res = declaredFields.get(); } } + ReflectionData<T> rd = reflectionData(); + if (rd != null) { + res = publicOnly ? rd.declaredPublicFields : rd.declaredFields; if (res != null) return res; } // No cached value available; request value from VM res = Reflection.filterFields(this, getDeclaredFields0(publicOnly)); ! if (useCaches) { ! if (rd != null) { if (publicOnly) { ! declaredPublicFields = new SoftReference<>(res); ! rd.declaredPublicFields = res; } else { ! declaredFields = new SoftReference<>(res); ! rd.declaredFields = res; } } return res; }
*** 2318,2333 **** --- 2360,2373 ---- // Returns an array of "root" fields. These Field objects must NOT // be propagated to the outside world, but must instead be copied // via ReflectionFactory.copyField. private Field[] privateGetPublicFields(Set<Class<?>> traversedInterfaces) { checkInitted(); - Field[] res = null; if (useCaches) { clearCachesOnClassRedefinition(); if (publicFields != null) { res = publicFields.get(); } + ReflectionData<T> rd = reflectionData(); + if (rd != null) { + res = rd.publicFields; if (res != null) return res; } // No cached value available; compute value recursively. // Traverse in correct order for getField().
*** 2356,2367 **** --- 2396,2407 ---- } } res = new Field[fields.size()]; fields.toArray(res); ! if (useCaches) { ! publicFields = new SoftReference<>(res); ! if (rd != null) { ! rd.publicFields = res; } return res; } private static void addAll(Collection<Field> c, Field[] o) {
*** 2380,2401 **** --- 2420,2433 ---- // Returns an array of "root" constructors. These Constructor // objects must NOT be propagated to the outside world, but must // instead be copied via ReflectionFactory.copyConstructor. private Constructor<T>[] privateGetDeclaredConstructors(boolean publicOnly) { checkInitted(); - Constructor<T>[] res = null; if (useCaches) { clearCachesOnClassRedefinition(); if (publicOnly) { if (publicConstructors != null) { res = publicConstructors.get(); } } else { if (declaredConstructors != null) { res = declaredConstructors.get(); } } + ReflectionData<T> rd = reflectionData(); + if (rd != null) { + res = publicOnly ? rd.publicConstructors : rd.declaredConstructors; if (res != null) return res; } // No cached value available; request value from VM if (isInterface()) { @SuppressWarnings("unchecked")
*** 2402,2416 **** --- 2434,2448 ---- Constructor<T>[] temporaryRes = (Constructor<T>[]) new Constructor<?>[0]; res = temporaryRes; } else { res = getDeclaredConstructors0(publicOnly); } ! if (useCaches) { ! if (rd != null) { if (publicOnly) { ! publicConstructors = new SoftReference<>(res); ! rd.publicConstructors = res; } else { ! declaredConstructors = new SoftReference<>(res); ! rd.declaredConstructors = res; } } return res; }
*** 2423,2453 **** --- 2455,2477 ---- // Returns an array of "root" methods. These Method objects must NOT // be propagated to the outside world, but must instead be copied // via ReflectionFactory.copyMethod. private Method[] privateGetDeclaredMethods(boolean publicOnly) { checkInitted(); - Method[] res = null; if (useCaches) { clearCachesOnClassRedefinition(); if (publicOnly) { if (declaredPublicMethods != null) { res = declaredPublicMethods.get(); } } else { if (declaredMethods != null) { res = declaredMethods.get(); } } + ReflectionData<T> rd = reflectionData(); + if (rd != null) { + res = publicOnly ? rd.declaredPublicMethods : rd.declaredMethods; if (res != null) return res; } // No cached value available; request value from VM res = Reflection.filterMethods(this, getDeclaredMethods0(publicOnly)); ! if (useCaches) { ! if (rd != null) { if (publicOnly) { ! declaredPublicMethods = new SoftReference<>(res); ! rd.declaredPublicMethods = res; } else { ! declaredMethods = new SoftReference<>(res); ! rd.declaredMethods = res; } } return res; }
*** 2545,2560 **** --- 2569,2582 ---- // Returns an array of "root" methods. These Method objects must NOT // be propagated to the outside world, but must instead be copied // via ReflectionFactory.copyMethod. private Method[] privateGetPublicMethods() { checkInitted(); - Method[] res = null; if (useCaches) { clearCachesOnClassRedefinition(); if (publicMethods != null) { res = publicMethods.get(); } + ReflectionData<T> rd = reflectionData(); + if (rd != null) { + res = rd.publicMethods; if (res != null) return res; } // No cached value available; compute value recursively. // Start by fetching public declared methods
*** 2598,2619 **** --- 2620,2641 ---- inheritedMethods.removeByNameAndSignature(m); } methods.addAllIfNotPresent(inheritedMethods); methods.compactAndTrim(); res = methods.getArray(); ! if (useCaches) { ! publicMethods = new SoftReference<>(res); ! if (rd != null) { ! rd.publicMethods = res; } return res; } // // Helpers for fetchers of one field, method, or constructor // ! private static Field searchFields(Field[] fields, String name) { String internedName = name.intern(); for (int i = 0; i < fields.length; i++) { if (fields[i].getName() == internedName) { return getReflectionFactory().copyField(fields[i]); }
*** 2627,2637 **** --- 2649,2659 ---- // privateGetPublicFields(). It fetches only the declared // public fields for each class, however, to reduce the number // of Field objects which have to be created for the common // case where the field being requested is declared in the // class which is being queried. - Field res = null; // Search declared public fields if ((res = searchFields(privateGetDeclaredFields(true), name)) != null) { return res; } // Direct superinterfaces, recursively
*** 2679,2689 **** --- 2701,2711 ---- // privateGetPublicMethods(). It fetches only the declared // public methods for each class, however, to reduce the // number of Method objects which have to be created for the // common case where the method being requested is declared in // the class which is being queried. - Method res = null; // Search declared public methods if ((res = searchMethods(privateGetDeclaredMethods(true), name, parameterTypes)) != null) { return res;
*** 3123,3135 **** --- 3145,3168 ---- } // Annotations cache private transient Map<Class<? extends Annotation>, Annotation> annotations; private transient Map<Class<? extends Annotation>, 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; + } + } + private synchronized void initAnnotationsIfNecessary() { ! clearCachesOnClassRedefinition(); ! clearAnnotationCachesOnClassRedefinition(); if (annotations != null) return; declaredAnnotations = AnnotationParser.parseAnnotations( getRawAnnotations(), getConstantPool(), this); Class<?> superClass = getSuperclass();

src/share/classes/java/lang/Class.java
Index Unified diffs Context diffs Sdiffs Wdiffs Patch New Old Previous File Next File