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

8267824: [lworld] Lots of lingering references to inline/value types in Javac code base #455

Closed
wants to merge 1 commit 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
@@ -479,9 +479,9 @@ public boolean isConstructor() {
return name == name.table.names.init && (flags() & STATIC) == 0;
}

/** Is this symbol a value factory?
/** Is this symbol a primitive object factory?
*/
public boolean isValueFactory() {
public boolean isPrimitiveObjectFactory() {
return ((name == name.table.names.init && this.type.getReturnType().tsym == this.owner));
}

@@ -269,7 +269,7 @@ public VarSymbol getClassField(Type type, Types types) {
new UniqueType(type, types), k -> {
Type arg = null;
if (type.getTag() == ARRAY || type.getTag() == CLASS) {
/* Temporary treatment for inline class: Given an inline class V that implements
/* Temporary treatment for primitive class: Given a primitive class V that implements
I1, I2, ... In, V.class is typed to be Class<? extends Object & I1 & I2 .. & In>
*/
if (type.isPrimitiveClass()) {
@@ -250,15 +250,15 @@ public Flavor getFlavor() {
}

/**
* @return true IFF the receiver is a reference projection of an inline type and false
* @return true IFF the receiver is a reference projection of a primitive class type and false
* for primitives or plain references
*/
public boolean isReferenceProjection() {
return false;
}

/**
* @return the value projection type IFF the receiver is a reference projection of an inline type
* @return the value projection type IFF the receiver is a reference projection of a primitive class type
* and null otherwise
*/
public Type valueProjection() {
@@ -1645,7 +1645,7 @@ public Boolean visitWildcardType(WildcardType t, Type s) {

// ----------------------------------- Unspecified behavior ----------------

/* If a value class V implements an interface I, then does "? extends I" contain V?
/* If a primitive class V implements an interface I, then does "? extends I" contain V?
It seems widening must be applied here to answer yes to compile some common code
patterns.
*/
@@ -2374,7 +2374,7 @@ private boolean implicitIdentityType(Type t) {
return true;
}

// No instance fields and no arged constructors both mean inner classes cannot be inline supers.
// No instance fields and no arged constructors both mean inner classes cannot be primitive class supers.
Type encl = t.getEnclosingType();
if (encl != null && encl.hasTag(CLASS)) {
return true;
@@ -2476,7 +2476,7 @@ public Type memberType(Type t, Symbol sym) {
if ((sym.flags() & STATIC) != 0)
return sym.type;

/* If any inline types are involved, switch over to the reference universe,
/* If any primitive class types are involved, switch over to the reference universe,
where the hierarchy is navigable. V and V.ref have identical membership
with no bridging needs.
*/
@@ -318,7 +318,7 @@ void checkAssignable(DiagnosticPosition pos, VarSymbol v, JCTree base, Env<AttrC
log.error(pos, Errors.TryResourceMayNotBeAssigned(v));
} else {
boolean complain = true;
/* Allow updates to instance fields of value classes by any method in the same nest via the
/* Allow updates to instance fields of primitive classes by any method in the same nest via the
withfield operator -This does not result in mutation of final fields; the code generator
would implement `copy on write' semantics via the opcode `withfield'.
*/
@@ -1320,7 +1320,7 @@ public void visitVarDef(JCVariableDecl tree) {
deferredLintHandler.flush(tree.pos());
chk.checkDeprecatedAnnotation(tree.pos(), v);

/* Don't want constant propagation/folding for instance fields of value classes,
/* Don't want constant propagation/folding for instance fields of primitive classes,
as these can undergo updates via copy on write.
*/
if (tree.init != null) {
@@ -2205,8 +2205,8 @@ Type condType(List<DiagnosticPosition> positions, List<Type> condTypes) {
}
}

// Those were all the cases that could result in a primitive. See if primitive boxing and inline
// narrowing conversions bring about a convergence.
// Those were all the cases that could result in a primitive. See if primitive boxing and primitive
// value conversions bring about a convergence.
condTypes = condTypes.stream()
.map(t -> t.isPrimitive() ? types.boxedClass(t).type
: t.isReferenceProjection() ? t.valueProjection() : t)
@@ -2650,13 +2650,13 @@ public void visitApply(JCMethodInvocation tree) {

final Symbol symbol = TreeInfo.symbol(tree.meth);
if (symbol != null) {
/* Is this an ill conceived attempt to invoke jlO methods not available on value types ??
/* Is this an ill conceived attempt to invoke jlO methods not available on primitive class types ??
*/
boolean superCallOnValueReceiver = types.isPrimitiveClass(env.enclClass.sym.type)
boolean superCallOnPrimitiveReceiver = types.isPrimitiveClass(env.enclClass.sym.type)
&& (tree.meth.hasTag(SELECT))
&& ((JCFieldAccess)tree.meth).selected.hasTag(IDENT)
&& TreeInfo.name(((JCFieldAccess)tree.meth).selected) == names._super;
if (types.isPrimitiveClass(qualifier) || superCallOnValueReceiver) {
if (types.isPrimitiveClass(qualifier) || superCallOnPrimitiveReceiver) {
int argSize = argtypes.size();
Name name = symbol.name;
switch (name.toString()) {
@@ -2692,7 +2692,7 @@ Type adjustMethodReturnType(Symbol msym, Type qualifierType, Name methodName, Li
methodName == names.getClass &&
argtypes.isEmpty()) {
// as a special case, x.getClass() has type Class<? extends |X|>
// Temporary treatment for inline class: Given an inline class V that implements
// Temporary treatment for primitive classes: Given a primitive class V that implements
// I1, I2, ... In, v.getClass() is typed to be Class<? extends Object & I1 & I2 .. & In>
Type wcb;
if (qualifierType.isPrimitiveClass()) {
@@ -3056,7 +3056,7 @@ private void visitAnonymousClassDefinition(JCNewClass tree, JCExpression clazz,
for (Type t : clazztype.getTypeArguments()) {
rs.checkAccessibleType(env, t);
}
chk.checkParameterizationWithValues(tree, clazztype);
chk.checkParameterizationByPrimitiveClass(tree, clazztype);
}

// If we already errored, be careful to avoid a further avalanche. ErrorType answers
@@ -3129,7 +3129,7 @@ public JCExpression makeNullCheck(JCExpression arg) {
// optimization: new Outer() can never be null; skip null check
if (arg.getTag() == NEWCLASS)
return arg;
// Likewise arg can't be null if it is a value.
// Likewise arg can't be null if it is a primitive class instance.
if (types.isPrimitiveClass(arg.type))
return arg;
// optimization: X.this is never null; skip null check
@@ -5537,7 +5537,7 @@ void attribClass(ClassSymbol c) throws CompletionFailure {
env.info.isSerializable = true;
}

if ((c.flags() & (PRIMITIVE_CLASS | ABSTRACT)) == PRIMITIVE_CLASS) { // for non-intersection, concrete values.
if ((c.flags() & (PRIMITIVE_CLASS | ABSTRACT)) == PRIMITIVE_CLASS) { // for non-intersection, concrete primitive classes.
Assert.check(env.tree.hasTag(CLASSDEF));
JCClassDecl classDecl = (JCClassDecl) env.tree;
if (classDecl.extending != null) {
@@ -605,7 +605,7 @@ Type checkType(final DiagnosticPosition pos, final Type found, final Type req, f
} else {
if (found.hasTag(CLASS)) {
if (inferenceContext != infer.emptyContext)
checkParameterizationWithValues(pos, found);
checkParameterizationByPrimitiveClass(pos, found);
}
}
if (req.hasTag(ERROR))
@@ -749,7 +749,8 @@ void checkSuperConstraintsOfPrimitiveClass(DiagnosticPosition pos, ClassSymbol c
if ((st.tsym.flags() & HASINITBLOCK) != 0) {
log.error(pos, Errors.SuperClassDeclaresInitBlock(c, st));
}
// No instance fields and no arged constructors both mean inner classes cannot be inline supers.
// No instance fields and no arged constructors both mean inner classes
// cannot be super classes for primitive classes.
Type encl = st.getEnclosingType();
if (encl != null && encl.hasTag(CLASS)) {
log.error(pos, Errors.SuperClassCannotBeInner(c, st));
@@ -836,10 +837,10 @@ Type checkClassType(DiagnosticPosition pos, Type t, boolean noBounds) {
* or a type variable.
* @param pos Position to be used for error reporting.
* @param t The type to be checked.
* @param valueOK If false, a value class does not qualify
* @param primitiveClassOK If false, a primitive class does not qualify
*/
Type checkRefType(DiagnosticPosition pos, Type t, boolean valueOK) {
if (t.isReference() && (valueOK || !types.isPrimitiveClass(t)))
Type checkRefType(DiagnosticPosition pos, Type t, boolean primitiveClassOK) {
if (t.isReference() && (primitiveClassOK || !types.isPrimitiveClass(t)))
return t;
else
return typeTagError(pos,
@@ -923,14 +924,15 @@ boolean checkDisjoint(DiagnosticPosition pos, long flags, long set1, long set2)
return true;
}

void checkParameterizationWithValues(DiagnosticPosition pos, Type t) {
valueParameterizationChecker.visit(t, pos);
void checkParameterizationByPrimitiveClass(DiagnosticPosition pos, Type t) {
parameterizationByPrimitiveClassChecker.visit(t, pos);
}

/** valueParameterizationChecker: A type visitor that descends down the given type looking for instances of value types
/** parameterizationByPrimitiveClassChecker: A type visitor that descends down the given type looking for instances of primitive classes
* being used as type arguments and issues error against those usages.
*/
private final Types.SimpleVisitor<Void, DiagnosticPosition> valueParameterizationChecker = new Types.SimpleVisitor<Void, DiagnosticPosition>() {
private final Types.SimpleVisitor<Void, DiagnosticPosition> parameterizationByPrimitiveClassChecker =
new Types.SimpleVisitor<Void, DiagnosticPosition>() {

@Override
public Void visitType(Type t, DiagnosticPosition pos) {
@@ -1121,7 +1123,7 @@ Type checkLocalVarType(DiagnosticPosition pos, Type t, Name name) {
//upward project the initializer type
Type varType = types.upward(t, types.captures(t));
if (varType.hasTag(CLASS)) {
checkParameterizationWithValues(pos, varType);
checkParameterizationByPrimitiveClass(pos, varType);
}
return varType;
}
@@ -1387,7 +1389,7 @@ else if ((sym.owner.flags_field & INTERFACE) != 0)
} else if ((sym.owner.flags_field & RECORD) != 0) {
mask = RecordMethodFlags;
} else {
// instance methods of value types do not have a monitor associated with their `this'
// instance methods of primitive classes do not have a monitor associated with their `this'
mask = ((sym.owner.flags_field & PRIMITIVE_CLASS) != 0 && (flags & Flags.STATIC) == 0) ?
MethodFlags & ~SYNCHRONIZED : MethodFlags;
}
@@ -1426,7 +1428,7 @@ else if ((sym.owner.flags_field & INTERFACE) != 0)
if ((flags & INTERFACE) != 0) implicit |= ABSTRACT;

if ((flags & ENUM) != 0) {
// enums can't be declared abstract, final, sealed or non-sealed or value type
// enums can't be declared abstract, final, sealed or non-sealed or primitive
mask &= ~(ABSTRACT | FINAL | SEALED | NON_SEALED | PRIMITIVE_CLASS);
implicit |= implicitEnumFinalFlag(tree);
}
@@ -2448,7 +2450,7 @@ void checkAllDefined(DiagnosticPosition pos, ClassSymbol c) {
}
}

// A value class cannot contain a field of its own type either or indirectly.
// A primitive class cannot contain a field of its own type either or indirectly.
void checkNonCyclicMembership(JCClassDecl tree) {
Assert.check((tree.sym.flags_field & LOCKED) == 0);
try {
@@ -1677,8 +1677,8 @@ public void visitClassDef(JCClassDecl tree) {
all instance fields are DA.
*/
enum ThisExposability {
ALLOWED, // Normal Object classes - NOP
BANNED, // Value types - Error
ALLOWED, // identity Object classes - NOP
BANNED, // primitive classes - Error
}

/**
@@ -2273,8 +2273,8 @@ boolean receiverAccessible() {
return tree.ownerAccessible;
}

/* Per our interim inline class translation scheme, the reference projection classes
are completely empty, so we want the methods in the value class to be invoked instead.
/* Per our interim primitive class translation scheme, the reference projection classes
are completely empty, so we want the methods in the primitive class to be invoked instead.
As the lambda meta factory isn't clued into this, it will try to invoke the method in
C$ref.class and fail with a NoSuchMethodError. we need to workaround it ourselves.
*/
@@ -287,7 +287,7 @@ public void visitVarDef(JCVariableDecl tree) {
VarSymbol v = new VarSymbol(0, tree.name, vartype, enclScope.owner);
v.flags_field = chk.checkFlags(tree.pos(), tree.mods.flags, v, tree);
tree.sym = v;
/* Don't want constant propagation/folding for instance fields of value classes,
/* Don't want constant propagation/folding for instance fields of primitive classes,
as these can undergo updates via copy on write.
*/
if (tree.init != null) {
@@ -420,7 +420,7 @@ public boolean isAccessible(Env<AttrContext> env, Type site, Symbol sym, boolean

ClassSymbol enclosingCsym = env.enclClass.sym;
if (sym.kind == MTH || sym.kind == VAR) {
/* If any inline types are involved, ask the same question in the reference universe,
/* If any primitive class types are involved, ask the same question in the reference universe,
where the hierarchy is navigable
*/
if (site.isPrimitiveClass())
@@ -485,7 +485,7 @@ private boolean notOverriddenIn(Type site, Symbol sym) {
if (sym.kind != MTH || sym.isConstructor() || sym.isStatic())
return true;

/* If any inline types are involved, ask the same question in the reference universe,
/* If any primitive class types are involved, ask the same question in the reference universe,
where the hierarchy is navigable
*/
if (site.isPrimitiveClass())
@@ -243,7 +243,7 @@
jsr_w = 201,
breakpoint = 202,

// value-type bytecodes
// primitive classes related bytecodes
defaultvalue = 203,
withfield = 204,

@@ -2736,7 +2736,7 @@ public void readClassFile(ClassSymbol c) {
/* http://cr.openjdk.java.net/~briangoetz/valhalla/sov/04-translation.html
The relationship of value and reference projections differs between the language model
and the VM model. In the language, the value projection is not a subtype of the
reference projection; instead, the two are related by inline narrowing and widening
reference projection; instead, the two are related by primitive reference and value
conversions, whereas in the VM, the two are related by actual subtyping.
Sever the subtyping relationship by rewiring the supertypes here and now.
*/
@@ -79,7 +79,7 @@
private final Lower lower;
private final Annotate annotate;
private final StringConcat concat;
private final TransValues transValues;
private final TransPrimitiveClass transPrimitiveClass;

/** Format of stackmap tables to be generated. */
private final Code.StackMapFormat stackMap;
@@ -116,7 +116,7 @@ protected Gen(Context context) {
accessDollar = names.
fromString("access" + target.syntheticNameChar());
lower = Lower.instance(context);
transValues = TransValues.instance(context);
transPrimitiveClass = TransPrimitiveClass.instance(context);

Options options = Options.instance(context);
lineDebugInfo =
@@ -1001,7 +1001,7 @@ else if (tree.body != null) {
if (env.enclMethod == null ||
env.enclMethod.sym.type.getReturnType().hasTag(VOID)) {
code.emitop0(return_);
} else if (env.enclMethod.sym.isValueFactory()) {
} else if (env.enclMethod.sym.isPrimitiveObjectFactory()) {
items.makeLocalItem(env.enclMethod.factoryProduct).load();
code.emitop0(areturn);
} else {
@@ -2279,7 +2279,7 @@ public void visitTypeCast(JCTypeCast tree) {
// which is not statically a supertype of the expression's type.
// For basic types, the coerce(...) in genExpr(...) will do
// the conversion.
// inline widening conversion is a nop when we bifurcate the primitive class, as the VM sees a subtyping relationship.
// primitive reference conversion is a nop when we bifurcate the primitive class, as the VM sees a subtyping relationship.
if (!tree.clazz.type.isPrimitive() &&
!types.isSameType(tree.expr.type, tree.clazz.type) &&
(!tree.clazz.type.isReferenceProjection() || !types.splitPrimitiveClass || !types.isSameType(tree.clazz.type.valueProjection(), tree.expr.type)) &&
@@ -2479,7 +2479,7 @@ public boolean genClass(Env<AttrContext> env, JCClassDecl cdef) {
/* method normalizeDefs() can add references to external classes into the constant pool
*/
cdef.defs = normalizeDefs(cdef.defs, c);
cdef = transValues.translateTopLevelClass(cdef, make);
cdef = transPrimitiveClass.translateTopLevelClass(cdef, make);
generateReferencesToPrunedTree(c);
Env<GenContext> localEnv = new Env<>(cdef, new GenContext());
localEnv.toplevel = env.toplevel;