8005232: (JEP-149) Class Instance size reduction

Moved the fields for cached reflection objects into a seperate ReflectionData object to reduce dynamic footprint.

Reviewed-by: dholmes, mchung, shade
This commit is contained in:
Peter Levart 2013-01-13 19:57:06 -05:00 committed by David Holmes
parent 7a8ddfee99
commit e912773451

View File

@ -1,5 +1,5 @@
/*
* 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
@ -2214,39 +2214,89 @@ public final
// 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;
// Intermediate results for getFields and getMethods
private volatile transient SoftReference<Field[]> declaredPublicFields;
private volatile transient SoftReference<Method[]> declaredPublicMethods;
// 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
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;
}
}
}
@ -2289,27 +2339,19 @@ public final
// 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();
}
}
Field[] res;
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;
@ -2320,12 +2362,10 @@ public final
// via ReflectionFactory.copyField.
private Field[] privateGetPublicFields(Set<Class<?>> traversedInterfaces) {
checkInitted();
Field[] res = null;
if (useCaches) {
clearCachesOnClassRedefinition();
if (publicFields != null) {
res = publicFields.get();
}
Field[] res;
ReflectionData<T> rd = reflectionData();
if (rd != null) {
res = rd.publicFields;
if (res != null) return res;
}
@ -2358,8 +2398,8 @@ public final
res = new Field[fields.size()];
fields.toArray(res);
if (useCaches) {
publicFields = new SoftReference<>(res);
if (rd != null) {
rd.publicFields = res;
}
return res;
}
@ -2382,18 +2422,10 @@ public final
// 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();
}
}
Constructor<T>[] res;
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
@ -2404,11 +2436,11 @@ public final
} 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;
@ -2425,27 +2457,19 @@ public final
// 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();
}
}
Method[] res;
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;
@ -2547,12 +2571,10 @@ public final
// via ReflectionFactory.copyMethod.
private Method[] privateGetPublicMethods() {
checkInitted();
Method[] res = null;
if (useCaches) {
clearCachesOnClassRedefinition();
if (publicMethods != null) {
res = publicMethods.get();
}
Method[] res;
ReflectionData<T> rd = reflectionData();
if (rd != null) {
res = rd.publicMethods;
if (res != null) return res;
}
@ -2560,7 +2582,7 @@ public final
// Start by fetching public declared methods
MethodArray methods = new MethodArray();
{
Method[] tmp = privateGetDeclaredMethods(true);
Method[] tmp = privateGetDeclaredMethods(true);
methods.addAll(tmp);
}
// Now recur over superclass and direct superinterfaces.
@ -2600,8 +2622,8 @@ public final
methods.addAllIfNotPresent(inheritedMethods);
methods.compactAndTrim();
res = methods.getArray();
if (useCaches) {
publicMethods = new SoftReference<>(res);
if (rd != null) {
rd.publicMethods = res;
}
return res;
}
@ -2611,7 +2633,7 @@ public final
// Helpers for fetchers of one field, method, or constructor
//
private Field searchFields(Field[] fields, String name) {
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) {
@ -2629,7 +2651,7 @@ public final
// 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;
Field res;
// Search declared public fields
if ((res = searchFields(privateGetDeclaredFields(true), name)) != null) {
return res;
@ -2681,7 +2703,7 @@ public final
// 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;
Method res;
// Search declared public methods
if ((res = searchMethods(privateGetDeclaredMethods(true),
name,
@ -3125,9 +3147,20 @@ public final
// 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(