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

8266466: [lworld] Enhance javac to consume unified primitive class files generated under the option -XDunifiedValRefClass #421

Closed
wants to merge 4 commits into from
Closed
Changes from all commits
Commits
File filter
Filter by extension
Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
@@ -1216,7 +1216,7 @@ public TypeMirror getOriginalType(javax.lang.model.type.ErrorType errorType) {
errorType.getKind() == TypeKind.ERROR) {
return extraType2OriginalMap.computeIfAbsent(classType, tt ->
new ClassType(classType.getEnclosingType(), classType.typarams_field,
classType.tsym, classType.getMetadata(), classType.isReferenceProjection()) {
classType.tsym, classType.getMetadata(), classType.getFlavor()) {
@Override
public Type baseType() { return classType; }
@Override
@@ -52,6 +52,7 @@
import javax.tools.JavaFileObject;

import com.sun.tools.javac.code.Kinds.Kind;
import com.sun.tools.javac.code.Type.ClassType.Flavor;
import com.sun.tools.javac.comp.Annotate.AnnotationTypeMetadata;
import com.sun.tools.javac.code.Type.*;
import com.sun.tools.javac.comp.Attr;
@@ -1343,7 +1344,7 @@ public ClassSymbol(long flags, Name name, Symbol owner) {
this(
flags,
name,
new ClassType(Type.noType, null, null),
new ClassType(Type.noType, null, null, TypeMetadata.EMPTY, Flavor.X_Typeof_X),
owner);
this.type.tsym = this;
}
@@ -1381,7 +1382,7 @@ public Type erasure(Types types) {
erasure_field = new ClassType(types.erasure(type.getEnclosingType()),
List.nil(), this,
type.getMetadata(),
type.isReferenceProjection());
type.getFlavor());
return erasure_field;
}

@@ -1450,6 +1451,14 @@ public void complete() throws CompletionFailure {
flags_field |= (PUBLIC|STATIC);
this.type = new ErrorType(this, Type.noType);
throw ex;
} finally {
if (this.type != null && this.type.hasTag(CLASS)) {
ClassType ct = (ClassType) this.type;
ct.flavor = ct.flavor.metamorphose((this.flags_field & PRIMITIVE_CLASS) != 0);
if (this.erasure_field != null && this.erasure_field.hasTag(CLASS)) {
((ClassType) this.erasure_field).flavor = ct.flavor;
}
}
}
}

@@ -1627,6 +1636,7 @@ public void reset() {
classType.supertype_field = null;
classType.interfaces_field = null;
classType.all_interfaces_field = null;
classType.flavor = Flavor.X_Typeof_X;
}
clearAnnotationMetadata();
}
@@ -35,6 +35,7 @@
import javax.lang.model.type.*;

import com.sun.tools.javac.code.Symbol.*;
import com.sun.tools.javac.code.Type.ClassType.Flavor;
import com.sun.tools.javac.code.TypeMetadata.Entry;
import com.sun.tools.javac.code.Types.TypeMapping;
import com.sun.tools.javac.code.Types.UniqueType;
@@ -240,6 +241,14 @@ public boolean isPrimitiveClass() {
return false;
}

/**
* Return the `flavor' associated with a ClassType.
* @see ClassType.Flavor
*/
public Flavor getFlavor() {
throw new AssertionError("Unexpected call to getFlavor() on a Type that is not a ClassType: " + this);
}

/**
* @return true IFF the receiver is a reference projection of an inline type and false
* for primitives or plain references
@@ -286,7 +295,7 @@ public Type visitClassType(ClassType t, S s) {
List<Type> typarams = t.getTypeArguments();
List<Type> typarams1 = visit(typarams, s);
if (outer1 == outer && typarams1 == typarams) return t;
else return new ClassType(outer1, typarams1, t.tsym, t.metadata, t.isReferenceProjection()) {
else return new ClassType(outer1, typarams1, t.tsym, t.metadata, t.getFlavor()) {
@Override
protected boolean needsStripping() {
return true;
@@ -1017,6 +1026,85 @@ public String toString() {
public static class ClassType extends Type implements DeclaredType, LoadableConstant,
javax.lang.model.type.ErrorType {

/**
* The 'flavor' of a ClassType indicates its reference/primitive projectionness
* viewed against the default nature of the associated class.
*/
public enum Flavor {

This comment has been minimized.

@mcimadamore

mcimadamore May 21, 2021
Collaborator

Perhaps you could add a method which "upgrades" a flavor to a new one, given new info.

e.g.

L_TypeOf_X.update(sym.isPrimitiveClass()) ->  L_TypeOf_Q/L_TypeOf_L (depending on isPrimitiveClass)

This would allow you to rule out (e.g. throw) bad updates. E.g. X flavors can be updated, all the other "leaf" flavors can only be updated to self.

I think a method such as this would remove a lot of conditional logic in the clients.

This comment has been minimized.

@sadayapalam

sadayapalam May 21, 2021
Author Collaborator

I'll take a look ...

This comment has been minimized.

@sadayapalam

sadayapalam May 24, 2021
Author Collaborator

Perhaps you could add a method which "upgrades" a flavor to a new one, given new info.

e.g.

L_TypeOf_X.update(sym.isPrimitiveClass()) ->  L_TypeOf_Q/L_TypeOf_L (depending on isPrimitiveClass)

This would allow you to rule out (e.g. throw) bad updates. E.g. X flavors can be updated, all the other "leaf" flavors can only be updated to self.

I think a method such as this would remove a lot of conditional logic in the clients.

Thanks, this turned out to be a nice suggestion and helped simplify the code at 3 or 4 places.


/**
* Classic reference type. Also reference projection type of a reference-favoring aka
* reference-default primitive class type
*/
L_TypeOf_L,

/**
* Reference projection type of a primitive-favoring aka primitive-default
* plain vanilla primitive class type,
*/
L_TypeOf_Q,

/**
* Value projection type of a primitive-favoring aka primitive-default
* plain vanilla primitive class type,
*/
Q_TypeOf_Q,

/**
* Value projection type of a reference-favoring aka
* reference-default primitive class type
*/
Q_TypeOf_L,

/**
* Reference projection type of a class type of an as yet unknown default provenance, 'X' will be
* discovered to be 'L' or 'Q' in "due course" and mutated suitably.
*/
L_TypeOf_X,

/**
* Value projection type of a class type of an as yet unknown default provenance, 'X' will be
* discovered to be 'L' or 'Q' in "due course" and mutated suitably.
*/
Q_TypeOf_X,

/**
* As yet unknown projection type of an as yet unknown default provenance class.
*/
X_Typeof_X,

/**
* An error type - we don't care to discriminate them any further.
*/
E_Typeof_X;

// We don't seem to need X_Typeof_L or X_Typeof_Q so far.

// Transform a larval form into a more evolved form
public Flavor metamorphose(boolean isPrimtiveClass) {

switch (this) {

case E_Typeof_X: // stunted form
case L_TypeOf_L:
case L_TypeOf_Q:
case Q_TypeOf_L:
case Q_TypeOf_Q:
// These are fully evolved sealed forms or stunted - no futher transformation
return this;
case L_TypeOf_X:
return isPrimtiveClass ? L_TypeOf_Q : L_TypeOf_L;
case Q_TypeOf_X:
return isPrimtiveClass ? Q_TypeOf_Q : Q_TypeOf_L;
case X_Typeof_X:
// TODO: Discriminate between ref-val defaultness
return isPrimtiveClass ? Q_TypeOf_Q : L_TypeOf_L;
default:
throw new AssertionError("Unexpected class type flavor");
}
}
}

/** The enclosing type of this type. If this is the type of an inner
* class, outer_field refers to the type of its enclosing
* instance class, in all other cases it refers to noType.
@@ -1050,28 +1138,27 @@ public String toString() {
*/
public ClassType projection;

/** Is this class type a reference projection of a primitive class type ?
/** Is this L of default {L, Q, X} or Q of default {L, Q, X} ?
*/
private boolean isReferenceProjection;
public Flavor flavor;

/*
* Use of this constructor is kinda sorta deprecated, use the other constructor
* that forces the call site to consider and include the class type flavor.
*/
public ClassType(Type outer, List<Type> typarams, TypeSymbol tsym) {
this(outer, typarams, tsym, TypeMetadata.EMPTY, false);
this(outer, typarams, tsym, TypeMetadata.EMPTY, Flavor.L_TypeOf_L);
}

public ClassType(Type outer, List<Type> typarams, TypeSymbol tsym,
TypeMetadata metadata) {
this(outer, typarams, tsym, metadata, false);
}

public ClassType(Type outer, List<Type> typarams, TypeSymbol tsym,
TypeMetadata metadata, boolean isReferenceProjection) {
TypeMetadata metadata, Flavor flavor) {
super(tsym, metadata);
this.outer_field = outer != null && outer.isReferenceProjection() ? outer.valueProjection() : outer;
this.outer_field = outer;
this.typarams_field = typarams;
this.allparams_field = null;
this.supertype_field = null;
this.interfaces_field = null;
this.isReferenceProjection = isReferenceProjection;
this.flavor = flavor;
}

public int poolTag() {
@@ -1080,7 +1167,7 @@ public int poolTag() {

@Override
public ClassType cloneWithMetadata(TypeMetadata md) {
return new ClassType(outer_field, typarams_field, tsym, md, isReferenceProjection) {
return new ClassType(outer_field, typarams_field, tsym, md, flavor) {
@Override
public Type baseType() { return ClassType.this.baseType(); }
};
@@ -1098,7 +1185,7 @@ public TypeTag getTag() {

public Type constType(Object constValue) {
final Object value = constValue;
return new ClassType(getEnclosingType(), typarams_field, tsym, metadata, isReferenceProjection) {
return new ClassType(getEnclosingType(), typarams_field, tsym, metadata, flavor) {
@Override
public Object constValue() {
return value;
@@ -1125,6 +1212,12 @@ public String toString() {
buf.append(className(tsym, true));
}

boolean isReferenceProjection;
try {
isReferenceProjection = isReferenceProjection();
} catch (CompletionFailure cf) {
isReferenceProjection = false; // handle missing types gracefully.
}
if (isReferenceProjection) {
buf.append('.');
buf.append(tsym.name.table.names.ref);
@@ -1171,6 +1264,10 @@ private String className(Symbol sym, boolean longform) {
return s;
}

public Flavor getFlavor() {
return flavor;
}

@DefinedBy(Api.LANGUAGE_MODEL)
public List<Type> getTypeArguments() {
if (typarams_field == null) {
@@ -1187,11 +1284,14 @@ public boolean hasErasedSupertypes() {

@DefinedBy(Api.LANGUAGE_MODEL)
public Type getEnclosingType() {
if (outer_field != null && outer_field.isReferenceProjection()) {
outer_field = outer_field.valueProjection();
}
return outer_field;
}

public void setEnclosingType(Type outer) {
outer_field = outer != null && outer.isReferenceProjection() ? outer.valueProjection() : outer;
outer_field = outer;
}

public List<Type> allparams() {
@@ -1220,12 +1320,18 @@ public boolean isReference() {

@Override
public boolean isPrimitiveClass() {
return !isReferenceProjection && tsym != null && tsym.isPrimitiveClass();
return !isReferenceProjection() && tsym != null && tsym.isPrimitiveClass();
}

@Override
public boolean isReferenceProjection() {
return isReferenceProjection;
// gaurd against over-eager and/or inopportune completion
if (tsym != null) {
if (flavor == Flavor.L_TypeOf_X || tsym.isCompleted()) {
flavor = flavor.metamorphose(tsym.isPrimitiveClass());
}
}
return flavor == Flavor.L_TypeOf_Q;
}

@Override
@@ -1236,7 +1342,7 @@ public Type valueProjection() {
if (projection != null)
return projection;

projection = new ClassType(outer_field, typarams_field, tsym, getMetadata(), false);
projection = new ClassType(outer_field, typarams_field, tsym, getMetadata(), Flavor.Q_TypeOf_Q);
projection.allparams_field = allparams_field;
projection.supertype_field = supertype_field;

@@ -1256,7 +1362,7 @@ public ClassType referenceProjection() {
if (projection != null)
return projection;

projection = new ClassType(outer_field, typarams_field, tsym, getMetadata(), true);
projection = new ClassType(outer_field, typarams_field, tsym, getMetadata(), Flavor.L_TypeOf_Q);
projection.allparams_field = allparams_field;
projection.supertype_field = supertype_field;

@@ -1314,7 +1420,7 @@ public TypeKind getKind() {
public static class ErasedClassType extends ClassType {
public ErasedClassType(Type outer, TypeSymbol tsym,
TypeMetadata metadata) {
super(outer, List.nil(), tsym, metadata, false);
super(outer, List.nil(), tsym, metadata, tsym.type.getFlavor());
}

@Override
@@ -2479,21 +2585,20 @@ public ErrorType(ClassSymbol c, Type originalType) {
}

public ErrorType(Type originalType, TypeSymbol tsym) {
super(noType, List.nil(), null);
this.tsym = tsym;
super(noType, List.nil(), tsym, TypeMetadata.EMPTY, Flavor.E_Typeof_X);
this.originalType = (originalType == null ? noType : originalType);
}

private ErrorType(Type originalType, TypeSymbol tsym,
TypeMetadata metadata) {
super(noType, List.nil(), null, metadata);
TypeMetadata metadata, Flavor flavor) {
super(noType, List.nil(), null, metadata, flavor);
this.tsym = tsym;
this.originalType = (originalType == null ? noType : originalType);
}

@Override
public ErrorType cloneWithMetadata(TypeMetadata md) {
return new ErrorType(originalType, tsym, md) {
return new ErrorType(originalType, tsym, md, getFlavor()) {
@Override
public Type baseType() { return ErrorType.this.baseType(); }
};
@@ -627,7 +627,7 @@ public Type visitClassType(ClassType t, List<TypeCompound> s) {
} else {
ClassType ret = new ClassType(t.getEnclosingType().accept(this, s),
t.typarams_field, t.tsym,
t.getMetadata(), t.isReferenceProjection());
t.getMetadata(), t.getFlavor());
ret.all_interfaces_field = t.all_interfaces_field;
ret.allparams_field = t.allparams_field;
ret.interfaces_field = t.interfaces_field;