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:
Claes Redestad 2016-12-11 12:20:45 +01:00
parent 6d2dd6f483
commit f39eef3ab6
2 changed files with 115 additions and 22 deletions

View File

@ -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;
}
/**

View 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.");
}
}