< prev index next > src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/ClassReader.java
Print this page
import javax.lang.model.element.NestingKind;
import javax.tools.JavaFileManager;
import javax.tools.JavaFileObject;
import com.sun.tools.javac.code.Source.Feature;
+ import com.sun.tools.javac.code.Type.ClassType.Flavor;
import com.sun.tools.javac.comp.Annotate;
import com.sun.tools.javac.comp.Annotate.AnnotationTypeCompleter;
import com.sun.tools.javac.code.*;
import com.sun.tools.javac.code.Directive.*;
import com.sun.tools.javac.code.Lint.LintCategory;
/** Switch: allow modules.
*/
boolean allowModules;
+ /** Switch: allow primitive classes.
+ */
+ boolean allowPrimitiveClasses;
+
+ /** Switch: allow value classes.
+ */
+ boolean allowValueClasses;
+
/** Switch: allow sealed
*/
boolean allowSealedTypes;
/** Switch: allow records
verbose = options.isSet(Option.VERBOSE);
Source source = Source.instance(context);
preview = Preview.instance(context);
allowModules = Feature.MODULES.allowedInSource(source);
+ allowPrimitiveClasses = (!preview.isPreview(Feature.PRIMITIVE_CLASSES) || preview.isEnabled()) &&
+ Feature.PRIMITIVE_CLASSES.allowedInSource(source);
+ allowValueClasses = (!preview.isPreview(Feature.VALUE_CLASSES) || preview.isEnabled()) &&
+ Feature.VALUE_CLASSES.allowedInSource(source);
allowRecords = Feature.RECORDS.allowedInSource(source);
allowSealedTypes = Feature.SEALED_CLASSES.allowedInSource(source);
saveParameterNames = options.isSet(PARAMETERS);
sigp++;
return syms.intType;
case 'J':
sigp++;
return syms.longType;
+ case 'Q':
case 'L':
{
// int oldsigp = sigp;
Type t = classSigToType();
if (sigp < siglimit && signature[sigp] == '.')
byte[] signatureBuffer = new byte[0];
int sbp = 0;
/** Convert class signature to type, where signature is implicit.
*/
Type classSigToType() {
! if (signature[sigp] != 'L')
throw badClassFile("bad.class.signature",
Convert.utf2string(signature, sigp, 10));
sigp++;
Type outer = Type.noType;
int startSbp = sbp;
while (true) {
final byte c = signature[sigp++];
switch (c) {
byte[] signatureBuffer = new byte[0];
int sbp = 0;
/** Convert class signature to type, where signature is implicit.
*/
Type classSigToType() {
! byte prefix = signature[sigp];
+ if (prefix != 'L' && prefix != 'Q')
throw badClassFile("bad.class.signature",
Convert.utf2string(signature, sigp, 10));
sigp++;
Type outer = Type.noType;
+ Name name;
+ ClassType.Flavor flavor;
int startSbp = sbp;
while (true) {
final byte c = signature[sigp++];
switch (c) {
case ';': { // end
ClassSymbol t = enterClass(names.fromUtf(signatureBuffer,
startSbp,
sbp - startSbp));
try {
! return (outer == Type.noType) ?
! t.erasure(types) :
! new ClassType(outer, List.nil(), t);
} finally {
sbp = startSbp;
}
}
case '<': // generic arguments
ClassSymbol t = enterClass(names.fromUtf(signatureBuffer,
startSbp,
sbp - startSbp));
! outer = new ClassType(outer, sigToTypes('>'), t) {
boolean completed = false;
@Override @DefinedBy(Api.LANGUAGE_MODEL)
public Type getEnclosingType() {
if (!completed) {
completed = true;
case ';': { // end
ClassSymbol t = enterClass(names.fromUtf(signatureBuffer,
startSbp,
sbp - startSbp));
+ // We are seeing QFoo; or LFoo; The name itself does not shine any light on default val-refness
+ flavor = prefix == 'L' ? Flavor.L_TypeOf_X : Flavor.Q_TypeOf_X;
try {
! if (outer == Type.noType) {
! ClassType et = (ClassType) t.erasure(types);
! // Todo: This spews out more objects than before, i.e no reuse with identical flavor
+ return new ClassType(et.getEnclosingType(), List.nil(), et.tsym, et.getMetadata(), flavor);
+ }
+ return new ClassType(outer, List.nil(), t, TypeMetadata.EMPTY, flavor);
} finally {
sbp = startSbp;
}
}
case '<': // generic arguments
ClassSymbol t = enterClass(names.fromUtf(signatureBuffer,
startSbp,
sbp - startSbp));
! // We are seeing QFoo; or LFoo; The name itself does not shine any light on default val-refness
+ flavor = prefix == 'L' ? Flavor.L_TypeOf_X : Flavor.Q_TypeOf_X;
+ outer = new ClassType(outer, sigToTypes('>'), t, TypeMetadata.EMPTY, flavor) {
boolean completed = false;
@Override @DefinedBy(Api.LANGUAGE_MODEL)
public Type getEnclosingType() {
if (!completed) {
completed = true;
//we have seen an enclosing non-generic class
if (outer != Type.noType) {
t = enterClass(names.fromUtf(signatureBuffer,
startSbp,
sbp - startSbp));
! outer = new ClassType(outer, List.nil(), t);
}
signatureBuffer[sbp++] = (byte)'$';
continue;
case '/':
signatureBuffer[sbp++] = (byte)'.';
//we have seen an enclosing non-generic class
if (outer != Type.noType) {
t = enterClass(names.fromUtf(signatureBuffer,
startSbp,
sbp - startSbp));
! // We are seeing QFoo; or LFoo; The name itself does not shine any light on default val-refness
+ flavor = prefix == 'L' ? Flavor.L_TypeOf_X : Flavor.Q_TypeOf_X;
+ outer = new ClassType(outer, List.nil(), t, TypeMetadata.EMPTY, flavor);
}
signatureBuffer[sbp++] = (byte)'$';
continue;
case '/':
signatureBuffer[sbp++] = (byte)'.';
AttributeReader[] readers = {
// v45.3 attributes
new AttributeReader(names.Code, V45_3, MEMBER_ATTRIBUTE) {
protected void read(Symbol sym, int attrLen) {
+ if (allowPrimitiveClasses) {
+ if (sym.isConstructor() && ((MethodSymbol) sym).type.getParameterTypes().size() == 0) {
+ int code_length = buf.getInt(bp + 4);
+ if ((code_length == 1 && buf.getByte( bp + 8) == (byte) ByteCodes.return_) ||
+ (code_length == 5 && buf.getByte(bp + 8) == ByteCodes.aload_0 &&
+ buf.getByte( bp + 9) == (byte) ByteCodes.invokespecial &&
+ buf.getByte( bp + 12) == (byte) ByteCodes.return_)) {
+ sym.flags_field |= EMPTYNOARGCONSTR;
+ }
+ }
+ }
if (saveParameterNames)
((MethodSymbol)sym).code = readCode(sym);
else
bp = bp + attrLen;
}
List<Type> thrown = sym.type.getThrownTypes();
sym.type = poolReader.getType(nextChar());
//- System.err.println(" # " + sym.type);
if (sym.kind == MTH && sym.type.getThrownTypes().isEmpty())
sym.type.asMethodType().thrown = thrown;
+ // Map value class factory methods back to constructors for the benefit of earlier pipeline stages
+ if (sym.kind == MTH && sym.name == names.init && !sym.type.getReturnType().hasTag(TypeTag.VOID)) {
+ sym.type = new MethodType(sym.type.getParameterTypes(),
+ syms.voidType,
+ sym.type.getThrownTypes(),
+ syms.methodClass);
+ }
}
}
},
throw badClassFile((flags & STATIC) == 0 ? "invalid.default.interface" : "invalid.static.interface",
Integer.toString(majorVersion),
Integer.toString(minorVersion));
}
}
+ if (name == names.init && ((flags & STATIC) != 0)) {
+ flags &= ~STATIC;
+ type = new MethodType(type.getParameterTypes(),
+ syms.voidType,
+ type.getThrownTypes(),
+ syms.methodClass);
+ }
validateMethodType(name, type);
if (name == names.init && currentOwner.hasOuterInstance()) {
// Sometimes anonymous classes don't have an outer
// instance, however, there is no reliable way to tell so
// we never strip this$n
long adjustClassFlags(long flags) {
if ((flags & ACC_MODULE) != 0) {
flags &= ~ACC_MODULE;
flags |= MODULE;
}
! return flags & ~ACC_SUPER; // SUPER and SYNCHRONIZED bits overloaded
}
/**
* A subclass of JavaFileObject for the sourcefile attribute found in a classfile.
* The attribute is only the last component of the original filename, so is unlikely
long adjustClassFlags(long flags) {
if ((flags & ACC_MODULE) != 0) {
flags &= ~ACC_MODULE;
flags |= MODULE;
}
! if ((flags & ACC_PRIMITIVE) != 0) {
+ flags &= ~ACC_PRIMITIVE;
+ if (allowPrimitiveClasses) {
+ flags |= PRIMITIVE_CLASS;
+ }
+ }
+ if ((flags & ACC_VALUE) != 0) {
+ flags &= ~ACC_VALUE;
+ if (allowValueClasses) {
+ flags |= VALUE_CLASS;
+ }
+ }
+ if ((flags & ACC_IDENTITY) != 0) {
+ flags &= ~ACC_IDENTITY;
+ flags |= IDENTITY_TYPE;
+ }
+ return flags;
}
/**
* A subclass of JavaFileObject for the sourcefile attribute found in a classfile.
* The attribute is only the last component of the original filename, so is unlikely
< prev index next >