Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

JDK-8251986: [lworld] implement Class::valueType and Class::referenceType in Java #152

Closed
wants to merge 11 commits into from
104 changes: 79 additions & 25 deletions src/java.base/share/classes/java/lang/Class.java
Expand Up @@ -583,8 +583,8 @@ public Optional<Class<?>> valueType() {
if (isPrimitive() || isInterface() || isArray())
return Optional.empty();

ensureProjectionTypesInited();
return projectionTypes.length > 0 ? Optional.of(projectionTypes[0]) : Optional.empty();
Class<?>[] valRefTypes = getProjectionTypes();
return valRefTypes.length > 0 ? Optional.of(valRefTypes[0]) : Optional.empty();
}

/**
Expand Down Expand Up @@ -615,50 +615,85 @@ public Optional<Class<?>> referenceType() {
if (isPrimitive()) return Optional.empty();
if (isInterface() || isArray()) return Optional.of(this);

ensureProjectionTypesInited();
return projectionTypes.length == 2 ? Optional.of(projectionTypes[1]) : Optional.empty();
Class<?>[] valRefTypes = getProjectionTypes();
return valRefTypes.length == 2 ? Optional.of(valRefTypes[1]) : Optional.empty();
}

/*
* Returns true if this Class object represents a reference projection
* type for an inline class.
*
* A reference projection type must be a sealed abstract class that
* permits the inline projection type to extend. The inline projection
* type and reference projection type for an inline type must be of
* the same package.
*/
private boolean isReferenceProjectionType() {
if (isPrimitive() || isArray() || isInterface() || isInlineClass())
return false;

int mods = getModifiers();
if (!Modifier.isAbstract(mods)) {
return false;
}

Class<?>[] valRefTypes = getProjectionTypes();
return valRefTypes.length == 2 && valRefTypes[1] == this;
}

private transient Class<?>[] projectionTypes;
private Class<?>[] getProjectionTypes() {
ensureProjectionTypesInited();
return projectionTypes;
}

private synchronized void ensureProjectionTypesInited() {
/*
* Returns an array of Class object whose element at index 0 represents the
* value projection type and element at index 1 represents the reference
* projection type if present.
*
* If this Class object is neither a value projection type nor
* a reference projection type for an inline class, then an empty array
* is returned.
*/
private Class<?>[] newProjectionTypeArray() {
if (isPrimitive() || isArray() || isInterface())
return;

if (projectionTypes != null)
return;
return null;

if (isInlineClass()) {
Class<?> superClass = getSuperclass();
if (superClass != Object.class && superClass.isReferenceProjectionType()) {
projectionTypes = new Class<?>[] { this, superClass };
return new Class<?>[] { this, superClass };
} else {
projectionTypes = new Class<?>[] { this };
return new Class<?>[] { this };
}
} else if (isReferenceProjectionType()) {
projectionTypes = new Class<?>[] { valueProjectionType(), this };
} else {
projectionTypes = EMPTY_CLASS_ARRAY;
Class<?> valType = valueProjectionType();
if (valType != null) {
return new Class<?>[] { valType, this};
} else {
return EMPTY_CLASS_ARRAY;
}
}
}

private boolean isReferenceProjectionType() {
if (isPrimitive() || isInterface() || isArray() || isInlineClass())
return false;
/*
* Returns the value projection type if this Class represents
* a reference projection type. If this class is an inline class
* then this method returns this class. Otherwise, returns null.
*/
private Class<?> valueProjectionType() {
if (isPrimitive() || isArray() || isInterface())
return null;

if (projectionTypes != null) {
return projectionTypes.length == 2 && projectionTypes[1] == this;
}
if (isInlineClass())
return this;

int mods = getModifiers();
if (!Modifier.isAbstract(mods)) {
return false;
return null;
}

return valueProjectionType() != null;
}

private Class<?> valueProjectionType() {
// A reference projection type must be a sealed abstract class
// that permits the inline projection type to extend.
// The inline projection type and reference projection type for
Expand All @@ -680,6 +715,25 @@ private Class<?> valueProjectionType() {
return null;
}

private void ensureProjectionTypesInited() {
if (isPrimitive() || isArray() || isInterface())
return;

Class<?>[] valRefTypes = projectionTypes;
if (valRefTypes == null) {
// C.ensureProjectionTypesInited calls initProjectionTypes that may
// call D.ensureProjectionTypesInited where D is its superclass.
// So initProjectionTypes is called without holding any lock to
// avoid deadlock when multiple threads attempt to ensure
valRefTypes = newProjectionTypeArray();
}
synchronized (this) {
if (projectionTypes == null) {
projectionTypes = valRefTypes;
}
}
}

/**
* Creates a new instance of the class represented by this {@code Class}
* object. The class is instantiated as if by a {@code new}
Expand Down