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 static final class EnclosingMethodInfo {
|
||||||
private Class<?> enclosingClass;
|
private final Class<?> enclosingClass;
|
||||||
private String name;
|
private final String name;
|
||||||
private String descriptor;
|
private final String descriptor;
|
||||||
|
|
||||||
private EnclosingMethodInfo(Object[] enclosingInfo) {
|
static void validate(Object[] enclosingInfo) {
|
||||||
if (enclosingInfo.length != 3)
|
if (enclosingInfo.length != 3)
|
||||||
throw new InternalError("Malformed enclosing method information");
|
throw new InternalError("Malformed enclosing method information");
|
||||||
try {
|
try {
|
||||||
// The array is expected to have three elements:
|
// The array is expected to have three elements:
|
||||||
|
|
||||||
// the immediately enclosing class
|
// the immediately enclosing class
|
||||||
enclosingClass = (Class<?>) enclosingInfo[0];
|
Class<?> enclosingClass = (Class<?>)enclosingInfo[0];
|
||||||
assert(enclosingClass != null);
|
assert(enclosingClass != null);
|
||||||
|
|
||||||
// the immediately enclosing method or constructor's
|
// the immediately enclosing method or constructor's
|
||||||
// name (can be null).
|
// name (can be null).
|
||||||
name = (String) enclosingInfo[1];
|
String name = (String)enclosingInfo[1];
|
||||||
|
|
||||||
// the immediately enclosing method or constructor's
|
// the immediately enclosing method or constructor's
|
||||||
// descriptor (null iff name is).
|
// descriptor (null iff name is).
|
||||||
descriptor = (String) enclosingInfo[2];
|
String descriptor = (String)enclosingInfo[2];
|
||||||
assert((name != null && descriptor != null) || name == descriptor);
|
assert((name != null && descriptor != null) || name == descriptor);
|
||||||
} catch (ClassCastException cce) {
|
} catch (ClassCastException cce) {
|
||||||
throw new InternalError("Invalid type in enclosing method information", 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() {
|
boolean isPartial() {
|
||||||
return enclosingClass == null || name == null || descriptor == null;
|
return enclosingClass == null || name == null || descriptor == null;
|
||||||
}
|
}
|
||||||
@ -1481,7 +1488,7 @@ public final class Class<T> implements java.io.Serializable,
|
|||||||
|
|
||||||
if (enclosingInfo == null) {
|
if (enclosingInfo == null) {
|
||||||
// This is a top level or a nested class or an inner class (a, b, or c)
|
// This is a top level or a nested class or an inner class (a, b, or c)
|
||||||
enclosingCandidate = getDeclaringClass();
|
enclosingCandidate = getDeclaringClass0();
|
||||||
} else {
|
} else {
|
||||||
Class<?> enclosingClass = enclosingInfo.getEnclosingClass();
|
Class<?> enclosingClass = enclosingInfo.getEnclosingClass();
|
||||||
// This is a local class or an anonymous class (d or e)
|
// 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();
|
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
|
* Returns the canonical name of the underlying class as
|
||||||
* defined by the Java Language Specification. Returns null if
|
* 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
|
* @since 1.5
|
||||||
*/
|
*/
|
||||||
public boolean isAnonymousClass() {
|
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
|
* @since 1.5
|
||||||
*/
|
*/
|
||||||
public boolean isLocalClass() {
|
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
|
* @since 1.5
|
||||||
*/
|
*/
|
||||||
public boolean isMemberClass() {
|
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.
|
* class.
|
||||||
*/
|
*/
|
||||||
private String getSimpleBinaryName() {
|
private String getSimpleBinaryName() {
|
||||||
Class<?> enclosingClass = getEnclosingClass();
|
if (isTopLevelClass())
|
||||||
if (enclosingClass == null) // top level class
|
|
||||||
return null;
|
return null;
|
||||||
String name = getSimpleBinaryName0();
|
String name = getSimpleBinaryName0();
|
||||||
if (name == null) // anonymous class
|
if (name == null) // anonymous class
|
||||||
@ -1637,6 +1637,14 @@ public final class Class<T> implements java.io.Serializable,
|
|||||||
|
|
||||||
private native String getSimpleBinaryName0();
|
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
|
* Returns {@code true} if this is a local class or an anonymous
|
||||||
* class. Returns {@code false} otherwise.
|
* 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
|
// JVM Spec 4.7.7: A class must have an EnclosingMethod
|
||||||
// attribute if and only if it is a local class or an
|
// attribute if and only if it is a local class or an
|
||||||
// anonymous class.
|
// 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