< prev index next > src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/Gen.java
Print this page
* If you write code that depends on this, you do so at your own risk.
* This code and its internal interfaces are subject to change or
* deletion without notice.</b>
*/
public class Gen extends JCTree.Visitor {
+ private static final Object[] NO_STATIC_ARGS = new Object[0];
protected static final Context.Key<Gen> genKey = new Context.Key<>();
private final Log log;
private final Symtab syms;
private final Check chk;
private final String accessDollar;
private final Types types;
private final Lower lower;
private final Annotate annotate;
private final StringConcat concat;
+ private final TransValues transValues;
/** Format of stackmap tables to be generated. */
private final Code.StackMapFormat stackMap;
/** A type that serves as the expected type for all method expressions.
concat = StringConcat.instance(context);
methodType = new MethodType(null, null, null, syms.methodClass);
accessDollar = "access" + target.syntheticNameChar();
lower = Lower.instance(context);
+ transValues = TransValues.instance(context);
Options options = Options.instance(context);
lineDebugInfo =
options.isUnset(G_CUSTOM) ||
options.isSet(G_CUSTOM, "lines");
poolWriter = new PoolWriter(types, names);
// ignore cldc because we cannot have both stackmap formats
this.stackMap = StackMapFormat.JSR202;
annotate = Annotate.instance(context);
+ Source source = Source.instance(context);
+ allowPrimitiveClasses = Source.Feature.PRIMITIVE_CLASSES.allowedInSource(source) && options.isSet("enablePrimitiveClasses");
qualifiedSymbolCache = new HashMap<>();
}
/** Switches
*/
List<LocalItem> stackBeforeSwitchExpression;
LocalItem switchResult;
Set<JCMethodInvocation> invocationsWithPatternMatchingCatch = Set.of();
ListBuffer<int[]> patternMatchingInvocationRanges;
+ boolean allowPrimitiveClasses;
+
/** Cache the symbol to reflect the qualifying type.
* key: corresponding type
* value: qualified symbol
*/
Map<Type, Symbol> qualifiedSymbolCache;
return sym;
return sym.clone(site.tsym);
}
+ /** Insert a reference to given type in the constant pool,
+ * checking for an array with too many dimensions;
+ * return the reference's index.
+ * @param type The type for which a reference is inserted.
+ */
+ int makeRef(DiagnosticPosition pos, Type type, boolean emitQtype) {
+ checkDimension(pos, type);
+ if (emitQtype) {
+ return poolWriter.putClass(new ConstantPoolQType(type, types));
+ } else {
+ return poolWriter.putClass(type);
+ }
+ }
+
/** Insert a reference to given type in the constant pool,
* checking for an array with too many dimensions;
* return the reference's index.
* @param type The type for which a reference is inserted.
*/
int makeRef(DiagnosticPosition pos, Type type) {
- return poolWriter.putClass(checkDimension(pos, type));
+ return makeRef(pos, type, false);
}
/** Check if the given type is an array with too many dimensions.
*/
private Type checkDimension(DiagnosticPosition pos, Type t) {
Type site, Name name, List<Type> argtypes,
boolean isStatic) {
Symbol msym = rs.
resolveInternalMethod(pos, attrEnv, site, name, argtypes, null);
if (isStatic) items.makeStaticItem(msym).invoke();
- else items.makeMemberItem(msym, name == names.init).invoke();
+ else items.makeMemberItem(msym, names.isInitOrVNew(name)).invoke();
}
/** Is the given method definition an access method
* resulting from a qualified super? This is signified by an odd
* access code.
* constructor's definition.
* @param initCode The list of instance initializer statements.
* @param initTAs Type annotations from the initializer expression.
*/
void normalizeMethod(JCMethodDecl md, List<JCStatement> initCode, List<TypeCompound> initTAs) {
- if (md.name == names.init && TreeInfo.isInitialConstructor(md)) {
+ if (names.isInitOrVNew(md.name) && TreeInfo.isInitialConstructor(md)) {
// We are seeing a constructor that does not call another
// constructor of the same class.
List<JCStatement> stats = md.body.stats;
ListBuffer<JCStatement> newstats = new ListBuffer<>();
*/
void genMethod(JCMethodDecl tree, Env<GenContext> env, boolean fatcode) {
MethodSymbol meth = tree.sym;
int extras = 0;
// Count up extra parameters
- if (meth.isConstructor()) {
+ if (meth.isInitOrVNew()) {
extras++;
if (meth.enclClass().isInner() &&
!meth.enclClass().isStatic()) {
extras++;
}
if (code.isAlive()) {
code.statBegin(TreeInfo.endPos(tree.body));
if (env.enclMethod == null ||
env.enclMethod.sym.type.getReturnType().hasTag(VOID)) {
code.emitop0(return_);
+ } else if (env.enclMethod.sym.isValueObjectFactory()) {
+ items.makeLocalItem(env.enclMethod.factoryProduct).load();
+ code.emitop0(areturn);
} else {
// sometime dead code seems alive (4415991);
// generate a small loop instead
int startpc = code.entryPoint();
CondItem c = items.makeCondItem(goto_);
debugCode,
genCrt ? new CRTable(tree, env.toplevel.endPositions)
: null,
syms,
types,
- poolWriter);
+ poolWriter,
+ allowPrimitiveClasses);
items = new Items(poolWriter, code, syms, types);
if (code.debugCode) {
System.err.println(meth + " for body " + tree);
}
// If method is not static, create a new local variable address
// for `this'.
if ((tree.mods.flags & STATIC) == 0) {
Type selfType = meth.owner.type;
- if (meth.isConstructor() && selfType != syms.objectType)
+ if (meth.isInitOrVNew() && selfType != syms.objectType)
selfType = UninitializedType.uninitializedThis(selfType);
code.setDefined(
code.newLocal(
new VarSymbol(FINAL, names._this, selfType, meth.owner)));
}
}
} else {
code.newLocal(v);
}
checkDimension(tree.pos(), v.type);
+ Type localType = v.erasure(types);
+ if (localType.requiresPreload(env.enclClass.sym)) {
+ poolWriter.enterPreloadClass((ClassSymbol) localType.tsym);
+ }
}
public void visitSkip(JCSkip tree) {
}
public void visitWhileLoop(JCWhileLoop tree) {
genLoop(tree, tree.body, tree.cond, List.nil(), true);
}
+ public void visitWithField(JCWithField tree) {
+ switch(tree.field.getTag()) {
+ case IDENT:
+ Symbol sym = ((JCIdent) tree.field).sym;
+ items.makeThisItem().load();
+ genExpr(tree.value, tree.field.type).load();
+ sym = binaryQualifier(sym, env.enclClass.type);
+ code.emitop2(withfield, sym, PoolWriter::putMember);
+ result = items.makeStackItem(tree.type);
+ break;
+ case SELECT:
+ JCFieldAccess fieldAccess = (JCFieldAccess) tree.field;
+ sym = TreeInfo.symbol(fieldAccess);
+ // JDK-8207332: To maintain the order of side effects, must compute value ahead of field
+ genExpr(tree.value, tree.field.type).load();
+ genExpr(fieldAccess.selected, fieldAccess.selected.type).load();
+ if (Code.width(tree.field.type) == 2) {
+ code.emitop0(dup_x2);
+ code.emitop0(pop);
+ } else {
+ code.emitop0(swap);
+ }
+ sym = binaryQualifier(sym, fieldAccess.selected.type);
+ code.emitop2(withfield, sym, PoolWriter::putMember);
+ result = items.makeStackItem(tree.type);
+ break;
+ default:
+ Assert.check(false);
+ }
+ }
+
public void visitForLoop(JCForLoop tree) {
int limit = code.nextreg;
genStats(tree.init, env);
genLoop(tree, tree.body, tree.cond, tree.step, true);
code.endScopes(limit);
log.error(pos, Errors.LimitDimensions);
nerrs++;
}
int elemcode = Code.arraycode(elemtype);
if (elemcode == 0 || (elemcode == 1 && ndims == 1)) {
- code.emitAnewarray(makeRef(pos, elemtype), type);
+ code.emitAnewarray(makeRef(pos, elemtype, elemtype.isPrimitiveClass()), type);
} else if (elemcode == 1) {
code.emitMultianewarray(ndims, makeRef(pos, type), type);
} else {
code.emitNewarray(elemcode, type);
}
setTypeAnnotationPositions(tree.pos);
// Additional code is only needed if we cast to a reference type
// which is not statically a supertype of the expression's type.
// For basic types, the coerce(...) in genExpr(...) will do
// the conversion.
+ // 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) &&
- types.asSuper(tree.expr.type, tree.clazz.type.tsym) == null) {
- code.emitop2(checkcast, checkDimension(tree.pos(), tree.clazz.type), PoolWriter::putClass);
+ (!tree.clazz.type.isReferenceProjection() || !types.isSameType(tree.clazz.type.valueProjection(), tree.expr.type) || true) &&
+ !types.isSubtype(tree.expr.type, tree.clazz.type)) {
+ checkDimension(tree.pos(), tree.clazz.type);
+ if (tree.clazz.type.isPrimitiveClass()) {
+ code.emitop2(checkcast, new ConstantPoolQType(tree.clazz.type, types), PoolWriter::putClass);
+ } else {
+ code.emitop2(checkcast, tree.clazz.type, PoolWriter::putClass);
+ }
+
}
}
public void visitWildcard(JCWildcard tree) {
throw new AssertionError(this.getClass().getName());
public void visitSelect(JCFieldAccess tree) {
Symbol sym = tree.sym;
if (tree.name == names._class) {
- code.emitLdc((LoadableConstant)checkDimension(tree.pos(), tree.selected.type));
+ code.emitLdc((LoadableConstant) tree.selected.type, makeRef(tree.pos(), tree.selected.type, tree.selected.type.isPrimitiveClass()));
result = items.makeStackItem(pt);
return;
- }
+ }
Symbol ssym = TreeInfo.symbol(tree.selected);
// Are we selecting via super?
boolean selectSuper =
}
}
}
}
+ public void visitDefaultValue(JCDefaultValue tree) {
+ if (tree.type.isValueClass()) {
+ code.emitop2(aconst_init, checkDimension(tree.pos(), tree.type), PoolWriter::putClass);
+ } else if (tree.type.isReference()) {
+ code.emitop0(aconst_null);
+ } else {
+ code.emitop0(zero(Code.typecode(tree.type)));
+ }
+ result = items.makeStackItem(tree.type);
+ return;
+ }
+
public boolean isInvokeDynamic(Symbol sym) {
return sym.kind == MTH && ((MethodSymbol)sym).isDynamic();
}
public void visitLiteral(JCLiteral tree) {
this.toplevel = env.toplevel;
this.endPosTable = toplevel.endPositions;
/* method normalizeDefs() can add references to external classes into the constant pool
*/
cdef.defs = normalizeDefs(cdef.defs, c);
+ cdef = transValues.translateTopLevelClass(cdef, make);
generateReferencesToPrunedTree(c);
Env<GenContext> localEnv = new Env<>(cdef, new GenContext());
localEnv.toplevel = env.toplevel;
localEnv.enclClass = cdef;
< prev index next >