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

8244227: [lworld] Explore an implementation where the reference projection and value projection types are backed by a single class symbol #375

Closed
wants to merge 11 commits into from
Closed
Changes from 7 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
@@ -1225,7 +1225,7 @@ public TypeMirror getOriginalType(javax.lang.model.type.ErrorType errorType) {
ClassType ct = (ClassType) errorType;
return extraType2OriginalMap.computeIfAbsent(ct, tt ->
new ClassType(ct.getEnclosingType(), ct.typarams_field,
ct.tsym, ct.getMetadata()) {
ct.tsym, ct.getMetadata(), ct.isReferenceProjection()) {
@Override
public Type baseType() { return ct; }
@Override
@@ -234,6 +234,10 @@ public String visitClassType(ClassType t, Locale locale) {
buf.append(printAnnotations(t));
buf.append(className(t, true, locale));
}
if (t.isReferenceProjection()) {
buf.append('.');
buf.append(t.tsym.name.table.names.ref);
}
if (t.getTypeArguments().nonEmpty()) {
buf.append('<');
buf.append(visitTypes(t.getTypeArguments(), locale));
@@ -426,18 +426,10 @@ public boolean isReferenceProjection() {
}

/**
* Return the value projection IFF 'this' happens to be derived reference projection, null
* otherwise.
* If this is the symbol for a reference projection class, what is the class for which
* this is a projection ??
*/
public Symbol valueProjection() {
return null;
}

/**
* Return the reference projection IFF 'this' happens to be inline class, null
* otherwise.
*/
public Symbol referenceProjection() {
public ClassSymbol valueProjection() {
return null;
}

@@ -1328,12 +1320,6 @@ public static class ClassSymbol extends TypeSymbol implements TypeElement {
*/
private List<RecordComponent> recordComponents = List.nil();

/* the 'other' projection: If 'this' is an inline class then 'projection' is its reference projection
and vice versa.
*/
public ClassSymbol projection;


// sealed classes related fields
/** The classes, or interfaces, permitted to extend this class, or interface
*/
@@ -1393,7 +1379,8 @@ public Type erasure(Types types) {
if (erasure_field == null)
erasure_field = new ClassType(types.erasure(type.getEnclosingType()),
List.nil(), this,
type.getMetadata());
type.getMetadata(),
type.isReferenceProjection());
return erasure_field;
}

@@ -1663,65 +1650,6 @@ public boolean isRecord() {
return (flags_field & RECORD) != 0;
}

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

@Override
public ClassSymbol valueProjection() {
return isReferenceProjection() ? projection : null;
}

@Override
public ClassSymbol referenceProjection() {
if (!isPrimitiveClass())
return null;

if (projection != null)
return projection;

ClassType ct = (ClassType) this.type;
ClassType projectedType = new ClassType(ct.getEnclosingType(), ct.typarams_field, null);
projectedType.allparams_field = ct.allparams_field;
projectedType.supertype_field = ct.supertype_field;

projectedType.interfaces_field = ct.interfaces_field;
projectedType.all_interfaces_field = ct.all_interfaces_field;
projectedType.projection = ct;
ct.projection = projectedType;

Name projectionName = this.name.append('$', this.name.table.names.ref);
long projectionFlags = (this.flags() & ~(PRIMITIVE_CLASS | UNATTRIBUTED | FINAL)) | SEALED;

projection = new ClassSymbol(projectionFlags, projectionName, projectedType, this.owner);
projection.members_field = WriteableScope.create(projection);
for (Symbol s : this.members().getSymbols(s->(s.kind == MTH || s.kind == VAR), NON_RECURSIVE)) {
Symbol clone = null;
if (s.kind == MTH) {
MethodSymbol valMethod = (MethodSymbol)s;
MethodSymbol refMethod = valMethod.clone(projection);
valMethod.projection = refMethod;
refMethod.projection = valMethod;
clone = refMethod;
} else if (s.kind == VAR) {
VarSymbol valVar = (VarSymbol)s;
VarSymbol refVar = valVar.clone(projection);
valVar.projection = refVar;
refVar.projection = valVar;
clone = refVar;
}
projection.members_field.enter(clone);
}
projection.completer = Completer.NULL_COMPLETER;
projection.sourcefile = this.sourcefile;
projection.flatname = this.flatname.append('$', this.name.table.names.ref);
projection.permitted = List.of(this);
projection.projection = this;
projectedType.tsym = projection;
return projection;
}

@DefinedBy(Api.LANGUAGE_MODEL)
public List<Type> getPermittedSubclasses() {
return permitted.map(s -> s.type);
@@ -1748,11 +1676,6 @@ public static class VarSymbol extends Symbol implements VariableElement {
*/
public int adr = -1;

/* The 'other' projection: If 'this' is a field of an inline class, then 'projection' is the
its doppleganger in its referene projection class and vice versa.
*/
public VarSymbol projection;

/** Construct a variable symbol, given its flags, name, type and owner.
*/
public VarSymbol(long flags, Name name, Type type, Symbol owner) {
@@ -1785,7 +1708,6 @@ public Object poolKey(Types types) {
v.pos = pos;
v.adr = adr;
v.data = data;
v.projection = projection;
// System.out.println("clone " + v + " in " + newOwner);//DEBUG
return v;
}
@@ -1838,18 +1760,6 @@ public void setLazyConstValue(final Env<AttrContext> env,
setData((Callable<Object>)() -> attr.attribLazyConstantValue(env, variable, type));
}

@Override
public VarSymbol referenceProjection() {
return this.owner.isPrimitiveClass() ?
this.owner.referenceProjection() != null ? projection : null
: null;
}

@Override
public VarSymbol valueProjection() {
return projection != null ? projection.owner.isPrimitiveClass() ? projection : null: null;
}

/**
* The variable's constant value, if this is a constant.
* Before the constant value is evaluated, it points to an
@@ -2026,11 +1936,6 @@ public static class MethodSymbol extends Symbol implements ExecutableElement {
*/
public Attribute defaultValue = null;

/* The 'other' projection: If 'this' is a method of an inline class, then 'projection' is the
its doppleganger in its referene projection class and vice versa.
*/
public MethodSymbol projection;

/** Construct a method symbol, given its flags, name, type and owner.
*/
public MethodSymbol(long flags, Name name, Type type, Symbol owner) {
@@ -2053,7 +1958,6 @@ public Object poolKey(Types types) {
}
};
m.code = code;
m.projection = projection;
return m;
}

@@ -2138,7 +2042,7 @@ public boolean binaryOverrides(Symbol _other, TypeSymbol origin, Types types) {

// check for a direct implementation
if (other.isOverridableIn((TypeSymbol)owner) &&
types.asSuper(owner.type, other.owner) != null &&
types.asSuper(owner.type, other.owner.type) != null &&
types.isSameType(erasure(types), other.erasure(types)))
return true;

@@ -2202,24 +2106,12 @@ public boolean overrides(Symbol _other, TypeSymbol origin, Types types, boolean
boolean requireConcreteIfInherited) {
if (isConstructor() || _other.kind != MTH) return false;


/* If any inline types are involved, ask the same question in the reference universe,
where the hierarchy is navigable
*/
if (origin.isPrimitiveClass())
origin = (TypeSymbol) origin.referenceProjection();

if (this.owner.isPrimitiveClass()) {
return this.projection != null &&
this.projection.overrides(_other, origin, types, checkResult, requireConcreteIfInherited);
}

if (this == _other) return true;
MethodSymbol other = (MethodSymbol)_other;

// check for a direct implementation
if (other.isOverridableIn((TypeSymbol)owner) &&
types.asSuper(owner.type, other.owner) != null) {
types.asSuper(owner.type, other.owner, true) != null) {
Type mt = types.memberType(owner.type, this);
Type ot = types.memberType(owner.type, other);
if (types.isSubSignature(mt, ot)) {
@@ -2269,14 +2161,6 @@ private boolean isOverridableIn(TypeSymbol origin) {
@Override
public boolean isInheritedIn(Symbol clazz, Types types) {

/* If any inline types are involved, ask the same question in the reference universe,
where the hierarchy is navigable
*/
if (clazz.isPrimitiveClass())
clazz = clazz.referenceProjection();
if (this.owner.isPrimitiveClass())
return this.projection.isInheritedIn(clazz, types);

switch ((int)(flags_field & Flags.AccessFlags)) {
case PUBLIC:
return !this.owner.isInterface() ||
@@ -2291,18 +2175,6 @@ public boolean isLambdaMethod() {
return (flags() & LAMBDA_METHOD) == LAMBDA_METHOD;
}

@Override
public MethodSymbol referenceProjection() {
return this.owner.isPrimitiveClass() ?
this.owner.referenceProjection() != null ? projection : null
: null;
}

@Override
public MethodSymbol valueProjection() {
return projection != null ? projection.owner.isPrimitiveClass() ? projection : null : null;
}

/** override this method to point to the original enclosing method if this method symbol represents a synthetic
* lambda method
*/
@@ -277,7 +277,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) {
else return new ClassType(outer1, typarams1, t.tsym, t.metadata, t.isReferenceProjection()) {
@Override
protected boolean needsStripping() {
return true;
@@ -1036,23 +1036,33 @@ public static class ClassType extends Type implements DeclaredType, LoadableCons
*/
public List<Type> all_interfaces_field;

/* The 'other' projection: If 'this' is type of an inline class, then 'projection' is the
its doppleganger in its referene projection world and vice versa.
/** The 'other' projection: If 'this' is type of a primitive class, then 'projection' is the
* reference projection type and vice versa. Lazily initialized, not to be accessed directly.
*/
public ClassType projection;

/** Is this class type a reference projection of a primitive class type ?
*/
private boolean isReferenceProjection;

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

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

Copy link
Collaborator Author

@sadayapalam sadayapalam Mar 31, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have rewired most of the constructor invocations to the new one which handles a reference projection flag parameter. A few call sites are still left in for the old constructors, these seem harmless.

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

public int poolTag() {
@@ -1061,7 +1071,7 @@ public int poolTag() {

@Override
public ClassType cloneWithMetadata(TypeMetadata md) {
return new ClassType(outer_field, typarams_field, tsym, md) {
return new ClassType(outer_field, typarams_field, tsym, md, isReferenceProjection) {
@Override
public Type baseType() { return ClassType.this.baseType(); }
};
@@ -1079,7 +1089,7 @@ public <R,S> R accept(Type.Visitor<R,S> v, S s) {

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

if (isReferenceProjection) {
buf.append('.');
buf.append(tsym.name.table.names.ref);
}

if (getTypeArguments().nonEmpty()) {
buf.append('<');
buf.append(getTypeArguments().toString());
@@ -1167,7 +1182,7 @@ public Type getEnclosingType() {
}

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

public List<Type> allparams() {
@@ -1196,12 +1211,12 @@ public boolean isReference() {

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

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

@Override
@@ -1212,10 +1227,7 @@ public Type valueProjection() {
if (projection != null)
return projection;

// Make a best case effort to cache the other projection.
ClassSymbol valueClass = (ClassSymbol) tsym.valueProjection();

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

@@ -1232,10 +1244,7 @@ public ClassType referenceProjection() {
if (!isPrimitiveClass() || projection != null)
return projection;

// make a best case effort to cache the other projection.
ClassSymbol refClass = (ClassSymbol) tsym.referenceProjection();

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

@@ -1293,7 +1302,7 @@ public <R, P> R accept(TypeVisitor<R, P> v, P p) {
public static class ErasedClassType extends ClassType {
public ErasedClassType(Type outer, TypeSymbol tsym,
TypeMetadata metadata) {
super(outer, List.nil(), tsym, metadata);
super(outer, List.nil(), tsym, metadata, false);
}

@Override