8170595: Optimize Class.isAnonymousClass, isLocalClass, and isMemberClass
Co-authored-by: Christoph Dreis <christoph.dreis@freenet.de> Reviewed-by: mchung, darcy
This commit is contained in:
parent
6d2dd6f483
commit
f39eef3ab6
@ -1277,33 +1277,40 @@ public final class Class<T> implements java.io.Serializable,
|
||||
}
|
||||
|
||||
private static final class EnclosingMethodInfo {
|
||||
private Class<?> enclosingClass;
|
||||
private String name;
|
||||
private String descriptor;
|
||||
private final Class<?> enclosingClass;
|
||||
private final String name;
|
||||
private final String descriptor;
|
||||
|
||||
private EnclosingMethodInfo(Object[] enclosingInfo) {
|
||||
static void validate(Object[] enclosingInfo) {
|
||||
if (enclosingInfo.length != 3)
|
||||
throw new InternalError("Malformed enclosing method information");
|
||||
try {
|
||||
// The array is expected to have three elements:
|
||||
|
||||
// the immediately enclosing class
|
||||
enclosingClass = (Class<?>) enclosingInfo[0];
|
||||
Class<?> enclosingClass = (Class<?>)enclosingInfo[0];
|
||||
assert(enclosingClass != null);
|
||||
|
||||
// the immediately enclosing method or constructor's
|
||||
// name (can be null).
|
||||
name = (String) enclosingInfo[1];
|
||||
String name = (String)enclosingInfo[1];
|
||||
|
||||
// the immediately enclosing method or constructor's
|
||||
// descriptor (null iff name is).
|
||||
descriptor = (String) enclosingInfo[2];
|
||||
String descriptor = (String)enclosingInfo[2];
|
||||
assert((name != null && descriptor != null) || name == descriptor);
|
||||
} catch (ClassCastException cce) {
|
||||
throw new InternalError("Invalid type in enclosing method information", cce);
|
||||
}
|
||||
}
|
||||
|
||||
EnclosingMethodInfo(Object[] enclosingInfo) {
|
||||
validate(enclosingInfo);
|
||||
this.enclosingClass = (Class<?>)enclosingInfo[0];
|
||||
this.name = (String)enclosingInfo[1];
|
||||
this.descriptor = (String)enclosingInfo[2];
|
||||
}
|
||||
|
||||
boolean isPartial() {
|
||||
return enclosingClass == null || name == null || descriptor == null;
|
||||
}
|
||||
@ -1481,7 +1488,7 @@ public final class Class<T> implements java.io.Serializable,
|
||||
|
||||
if (enclosingInfo == null) {
|
||||
// This is a top level or a nested class or an inner class (a, b, or c)
|
||||
enclosingCandidate = getDeclaringClass();
|
||||
enclosingCandidate = getDeclaringClass0();
|
||||
} else {
|
||||
Class<?> enclosingClass = enclosingInfo.getEnclosingClass();
|
||||
// This is a local class or an anonymous class (d or e)
|
||||
@ -1547,14 +1554,6 @@ public final class Class<T> implements java.io.Serializable,
|
||||
return getName();
|
||||
}
|
||||
|
||||
/**
|
||||
* Character.isDigit answers {@code true} to some non-ascii
|
||||
* digits. This one does not.
|
||||
*/
|
||||
private static boolean isAsciiDigit(char c) {
|
||||
return '0' <= c && c <= '9';
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the canonical name of the underlying class as
|
||||
* defined by the Java Language Specification. Returns null if
|
||||
@ -1594,7 +1593,8 @@ public final class Class<T> implements java.io.Serializable,
|
||||
* @since 1.5
|
||||
*/
|
||||
public boolean isAnonymousClass() {
|
||||
return "".equals(getSimpleName());
|
||||
return !isArray() && isLocalOrAnonymousClass() &&
|
||||
getSimpleBinaryName0() == null;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -1605,7 +1605,8 @@ public final class Class<T> implements java.io.Serializable,
|
||||
* @since 1.5
|
||||
*/
|
||||
public boolean isLocalClass() {
|
||||
return isLocalOrAnonymousClass() && !isAnonymousClass();
|
||||
return isLocalOrAnonymousClass() &&
|
||||
(isArray() || getSimpleBinaryName0() != null);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -1616,7 +1617,7 @@ public final class Class<T> implements java.io.Serializable,
|
||||
* @since 1.5
|
||||
*/
|
||||
public boolean isMemberClass() {
|
||||
return getSimpleBinaryName() != null && !isLocalOrAnonymousClass();
|
||||
return !isLocalOrAnonymousClass() && getDeclaringClass0() != null;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -1626,8 +1627,7 @@ public final class Class<T> implements java.io.Serializable,
|
||||
* class.
|
||||
*/
|
||||
private String getSimpleBinaryName() {
|
||||
Class<?> enclosingClass = getEnclosingClass();
|
||||
if (enclosingClass == null) // top level class
|
||||
if (isTopLevelClass())
|
||||
return null;
|
||||
String name = getSimpleBinaryName0();
|
||||
if (name == null) // anonymous class
|
||||
@ -1637,6 +1637,14 @@ public final class Class<T> implements java.io.Serializable,
|
||||
|
||||
private native String getSimpleBinaryName0();
|
||||
|
||||
/**
|
||||
* Returns {@code true} if this is a top level class. Returns {@code false}
|
||||
* otherwise.
|
||||
*/
|
||||
private boolean isTopLevelClass() {
|
||||
return !isLocalOrAnonymousClass() && getDeclaringClass0() == null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns {@code true} if this is a local class or an anonymous
|
||||
* class. Returns {@code false} otherwise.
|
||||
@ -1645,7 +1653,16 @@ public final class Class<T> implements java.io.Serializable,
|
||||
// JVM Spec 4.7.7: A class must have an EnclosingMethod
|
||||
// attribute if and only if it is a local class or an
|
||||
// anonymous class.
|
||||
return getEnclosingMethodInfo() != null;
|
||||
return hasEnclosingMethodInfo();
|
||||
}
|
||||
|
||||
private boolean hasEnclosingMethodInfo() {
|
||||
Object[] enclosingInfo = getEnclosingMethod0();
|
||||
if (enclosingInfo != null) {
|
||||
EnclosingMethodInfo.validate(enclosingInfo);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
|
76
jdk/test/java/lang/Class/attributes/ClassAttributesTest.java
Normal file
76
jdk/test/java/lang/Class/attributes/ClassAttributesTest.java
Normal file
@ -0,0 +1,76 @@
|
||||
/*
|
||||
* Copyright (c) 2016, 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.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
/*
|
||||
* @test
|
||||
* @bug 8170595
|
||||
* @summary Checks Class.isAnonymousClass, isMemberClass and isLocalClass
|
||||
* attributes
|
||||
*/
|
||||
|
||||
public class ClassAttributesTest {
|
||||
|
||||
class NestedClass {}
|
||||
|
||||
static int test(Class<?> clazz, boolean anonymous, boolean local, boolean member) {
|
||||
if (clazz.isAnonymousClass() != anonymous) {
|
||||
System.err.println("Unexpected isAnonymousClass value for " +
|
||||
clazz.getName() + " expected: " + anonymous +
|
||||
" got: " + (!anonymous));
|
||||
return 1;
|
||||
}
|
||||
if (clazz.isLocalClass() != local) {
|
||||
System.err.println("Unexpected isLocalClass value for " +
|
||||
clazz.getName() + " expected: " + local +
|
||||
" got: " + (!local));
|
||||
return 1;
|
||||
}
|
||||
if (clazz.isMemberClass() != member) {
|
||||
System.err.println("Unexpected isMemberClass status for " +
|
||||
clazz.getName() + " expected: " + member +
|
||||
" got: " + (!member));
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
public static void main(String argv[]) {
|
||||
int failures = 0;
|
||||
|
||||
class LocalClass {}
|
||||
Cloneable clone = new Cloneable() {};
|
||||
Runnable lambda = () -> System.out.println("run");
|
||||
|
||||
failures += test(ClassAttributesTest.class, false, false, false);
|
||||
failures += test(NestedClass.class, false, false, true);
|
||||
failures += test(LocalClass.class, false, true, false);
|
||||
failures += test(clone.getClass(), true, false, false);
|
||||
|
||||
// Lambdas may be VM anonymous classes, but are named, non-local classes
|
||||
// in this sense
|
||||
failures += test(lambda.getClass(), false, false, false);
|
||||
|
||||
if (failures != 0)
|
||||
throw new RuntimeException("Test failed with " + failures + " failures.");
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user