8187123: (reflect) Class#getCanonicalName and Class#getSimpleName is a part of performance issue
Reviewed-by: psandoz, dholmes, mchung
--- a/src/java.base/share/classes/java/lang/Class.java Tue Apr 24 18:06:32 2018 +0200
+++ b/src/java.base/share/classes/java/lang/Class.java Fri May 04 09:29:14 2018 +0200
@@ -1524,13 +1524,22 @@
* @since 1.5
*/
public String getSimpleName() {
- if (isArray())
- return getComponentType().getSimpleName()+"[]";
-
+ ReflectionData<T> rd = reflectionData();
+ String simpleName = rd.simpleName;
+ if (simpleName == null) {
+ rd.simpleName = simpleName = getSimpleName0();
+ }
+ return simpleName;
+ }
+
+ private String getSimpleName0() {
+ if (isArray()) {
+ return getComponentType().getSimpleName() + "[]";
+ }
String simpleName = getSimpleBinaryName();
if (simpleName == null) { // top level class
simpleName = getName();
- return simpleName.substring(simpleName.lastIndexOf('.')+1); // strip the package name
+ simpleName = simpleName.substring(simpleName.lastIndexOf('.') + 1); // strip the package name
}
return simpleName;
}
@@ -1546,10 +1555,10 @@
try {
Class<?> cl = this;
int dimensions = 0;
- while (cl.isArray()) {
+ do {
dimensions++;
cl = cl.getComponentType();
- }
+ } while (cl.isArray());
StringBuilder sb = new StringBuilder();
sb.append(cl.getName());
for (int i = 0; i < dimensions; i++) {
@@ -1572,22 +1581,31 @@
* @since 1.5
*/
public String getCanonicalName() {
+ ReflectionData<T> rd = reflectionData();
+ String canonicalName = rd.canonicalName;
+ if (canonicalName == null) {
+ rd.canonicalName = canonicalName = getCanonicalName0();
+ }
+ return canonicalName == ReflectionData.NULL_SENTINEL? null : canonicalName;
+ }
+
+ private String getCanonicalName0() {
if (isArray()) {
String canonicalName = getComponentType().getCanonicalName();
if (canonicalName != null)
return canonicalName + "[]";
else
- return null;
+ return ReflectionData.NULL_SENTINEL;
}
if (isLocalOrAnonymousClass())
- return null;
+ return ReflectionData.NULL_SENTINEL;
Class<?> enclosingClass = getEnclosingClass();
if (enclosingClass == null) { // top level class
return getName();
} else {
String enclosingName = enclosingClass.getCanonicalName();
if (enclosingName == null)
- return null;
+ return ReflectionData.NULL_SENTINEL;
return enclosingName + "." + getSimpleName();
}
}
@@ -2895,7 +2913,8 @@
* Reflection support.
*/
- // reflection data that might get invalidated when JVM TI RedefineClasses() is called
+ // Reflection data caches various derived names and reflective members. Cached
+ // values may be invalidated when JVM TI RedefineClasses() is called
private static class ReflectionData<T> {
volatile Field[] declaredFields;
volatile Field[] publicFields;
@@ -2908,6 +2927,11 @@
volatile Method[] declaredPublicMethods;
volatile Class<?>[] interfaces;
+ // Cached names
+ String simpleName;
+ String canonicalName;
+ static final String NULL_SENTINEL = new String();
+
// Value of classRedefinedCount when we created this ReflectionData instance
final int redefinedCount;