Method from com.sun.tools.javac.comp.Lower Detail: |
JCTree abstractLval(JCTree lval,
TreeBuilder builder) {
lval = TreeInfo.skipParens(lval);
switch (lval.getTag()) {
case JCTree.IDENT:
return builder.build(lval);
case JCTree.SELECT: {
final JCFieldAccess s = (JCFieldAccess)lval;
JCTree selected = TreeInfo.skipParens(s.selected);
Symbol lid = TreeInfo.symbol(s.selected);
if (lid != null && lid.kind == TYP) return builder.build(lval);
return abstractRval(s.selected, new TreeBuilder() {
public JCTree build(final JCTree selected) {
return builder.build(make.Select((JCExpression)selected, s.sym));
}
});
}
case JCTree.INDEXED: {
final JCArrayAccess i = (JCArrayAccess)lval;
return abstractRval(i.indexed, new TreeBuilder() {
public JCTree build(final JCTree indexed) {
return abstractRval(i.index, syms.intType, new TreeBuilder() {
public JCTree build(final JCTree index) {
JCTree newLval = make.Indexed((JCExpression)indexed,
(JCExpression)index);
newLval.setType(i.type);
return builder.build(newLval);
}
});
}
});
}
case JCTree.TYPECAST: {
return abstractLval(((JCTypeCast)lval).expr, builder);
}
}
throw new AssertionError(lval);
}
|
JCTree abstractRval(JCTree rval,
TreeBuilder builder) {
return abstractRval(rval, rval.type, builder);
}
|
JCTree abstractRval(JCTree rval,
Type type,
TreeBuilder builder) {
rval = TreeInfo.skipParens(rval);
switch (rval.getTag()) {
case JCTree.LITERAL:
return builder.build(rval);
case JCTree.IDENT:
JCIdent id = (JCIdent) rval;
if ((id.sym.flags() & FINAL) != 0 && id.sym.owner.kind == MTH)
return builder.build(rval);
}
VarSymbol var =
new VarSymbol(FINAL|SYNTHETIC,
names.fromString(
target.syntheticNameChar()
+ "" + rval.hashCode()),
type,
currentMethodSym);
rval = convert(rval,type);
JCVariableDecl def = make.VarDef(var, (JCExpression)rval); // XXX cast
JCTree built = builder.build(make.Ident(var));
JCTree res = make.LetExpr(def, built);
res.type = built.type;
return res;
}
Construct an expression using the builder, with the given rval
expression as an argument to the builder. However, the rval
expression must be computed only once, even if used multiple
times in the result of the builder. We do that by
constructing a "let" expression that saves the rvalue into a
temporary variable and then uses the temporary variable in
place of the expression built by the builder. The complete
resulting expression is of the form
(let TYPE TEMP = RVAL;
in (BUILDER(TEMP)))
where TEMP is a newly declared variable
in the let expression. |
JCExpression access(JCExpression tree) {
Symbol sym = TreeInfo.symbol(tree);
return sym == null ? tree : access(sym, tree, null, false);
}
Ensure that identifier is accessible, return tree accessing the identifier. |
JCExpression access(Symbol sym,
JCExpression tree,
JCExpression enclOp,
boolean refSuper) {
// Access a free variable via its proxy, or its proxy's proxy
while (sym.kind == VAR && sym.owner.kind == MTH &&
sym.owner.enclClass() != currentClass) {
// A constant is replaced by its constant value.
Object cv = ((VarSymbol)sym).getConstValue();
if (cv != null) {
make.at(tree.pos);
return makeLit(sym.type, cv);
}
// Otherwise replace the variable by its proxy.
sym = proxies.lookup(proxyName(sym.name)).sym;
Assert.check(sym != null && (sym.flags_field & FINAL) != 0);
tree = make.at(tree.pos).Ident(sym);
}
JCExpression base = (tree.getTag() == JCTree.SELECT) ? ((JCFieldAccess) tree).selected : null;
switch (sym.kind) {
case TYP:
if (sym.owner.kind != PCK) {
// Convert type idents to
// < flat name > or < package name > . < flat name >
Name flatname = Convert.shortName(sym.flatName());
while (base != null &&
TreeInfo.symbol(base) != null &&
TreeInfo.symbol(base).kind != PCK) {
base = (base.getTag() == JCTree.SELECT)
? ((JCFieldAccess) base).selected
: null;
}
if (tree.getTag() == JCTree.IDENT) {
((JCIdent) tree).name = flatname;
} else if (base == null) {
tree = make.at(tree.pos).Ident(sym);
((JCIdent) tree).name = flatname;
} else {
((JCFieldAccess) tree).selected = base;
((JCFieldAccess) tree).name = flatname;
}
}
break;
case MTH: case VAR:
if (sym.owner.kind == TYP) {
// Access methods are required for
// - private members,
// - protected members in a superclass of an
// enclosing class contained in another package.
// - all non-private members accessed via a qualified super.
boolean protAccess = refSuper && !needsPrivateAccess(sym)
|| needsProtectedAccess(sym, tree);
boolean accReq = protAccess || needsPrivateAccess(sym);
// A base has to be supplied for
// - simple identifiers accessing variables in outer classes.
boolean baseReq =
base == null &&
sym.owner != syms.predefClass &&
!sym.isMemberOf(currentClass, types);
if (accReq || baseReq) {
make.at(tree.pos);
// Constants are replaced by their constant value.
if (sym.kind == VAR) {
Object cv = ((VarSymbol)sym).getConstValue();
if (cv != null) return makeLit(sym.type, cv);
}
// Private variables and methods are replaced by calls
// to their access methods.
if (accReq) {
List< JCExpression > args = List.nil();
if ((sym.flags() & STATIC) == 0) {
// Instance access methods get instance
// as first parameter.
if (base == null)
base = makeOwnerThis(tree.pos(), sym, true);
args = args.prepend(base);
base = null; // so we don't duplicate code
}
Symbol access = accessSymbol(sym, tree,
enclOp, protAccess,
refSuper);
JCExpression receiver = make.Select(
base != null ? base : make.QualIdent(access.owner),
access);
return make.App(receiver, args);
// Other accesses to members of outer classes get a
// qualifier.
} else if (baseReq) {
return make.at(tree.pos).Select(
accessBase(tree.pos(), sym), sym).setType(tree.type);
}
}
}
}
return tree;
}
Ensure that identifier is accessible, return tree accessing the identifier. |
JCExpression accessBase(DiagnosticPosition pos,
Symbol sym) {
return (sym.flags() & STATIC) != 0
? access(make.at(pos.getStartPosition()).QualIdent(sym.owner))
: makeOwnerThis(pos, sym, true);
}
The qualifier to be used for accessing a symbol in an outer class.
This is either C.sym or C.this.sym, depending on whether or not
sym is static. |
ClassSymbol accessClass(Symbol sym,
boolean protAccess,
JCTree tree) {
if (protAccess) {
Symbol qualifier = null;
ClassSymbol c = currentClass;
if (tree.getTag() == JCTree.SELECT && (sym.flags() & STATIC) == 0) {
qualifier = ((JCFieldAccess) tree).selected.type.tsym;
while (!qualifier.isSubClass(c, types)) {
c = c.owner.enclClass();
}
return c;
} else {
while (!c.isSubClass(sym.owner, types)) {
c = c.owner.enclClass();
}
}
return c;
} else {
// the symbol is private
return sym.owner.enclClass();
}
}
The class in which an access method for given symbol goes. |
Symbol accessConstructor(DiagnosticPosition pos,
Symbol constr) {
if (needsPrivateAccess(constr)) {
ClassSymbol accOwner = constr.owner.enclClass();
MethodSymbol aconstr = accessConstrs.get(constr);
if (aconstr == null) {
List< Type > argtypes = constr.type.getParameterTypes();
if ((accOwner.flags_field & ENUM) != 0)
argtypes = argtypes
.prepend(syms.intType)
.prepend(syms.stringType);
aconstr = new MethodSymbol(
SYNTHETIC,
names.init,
new MethodType(
argtypes.append(
accessConstructorTag().erasure(types)),
constr.type.getReturnType(),
constr.type.getThrownTypes(),
syms.methodClass),
accOwner);
enterSynthetic(pos, aconstr, accOwner.members());
accessConstrs.put(constr, aconstr);
accessed.append(constr);
}
return aconstr;
} else {
return constr;
}
}
Return access constructor for a private constructor,
or the constructor itself, if no access constructor is needed. |
JCTree accessConstructorDef(int pos,
Symbol constr,
MethodSymbol accessor) {
make.at(pos);
JCMethodDecl md = make.MethodDef(accessor,
accessor.externalType(types),
null);
JCIdent callee = make.Ident(names._this);
callee.sym = constr;
callee.type = constr.type;
md.body =
make.Block(0, List.< JCStatement >of(
make.Call(
make.App(
callee,
make.Idents(md.params.reverse().tail.reverse())))));
return md;
}
Construct definition of an access constructor. |
ClassSymbol accessConstructorTag() {
ClassSymbol topClass = currentClass.outermostClass();
Name flatname = names.fromString("" + topClass.getQualifiedName() +
target.syntheticNameChar() +
"1");
ClassSymbol ctag = chk.compiled.get(flatname);
if (ctag == null)
ctag = makeEmptyClass(STATIC | SYNTHETIC, topClass);
// keep a record of all tags, to verify that all are generated as required
accessConstrTags = accessConstrTags.prepend(ctag);
return ctag;
}
Return an anonymous class nested in this toplevel class. |
JCTree accessDef(int pos,
Symbol vsym,
MethodSymbol accessor,
int acode) {
// System.err.println("access " + vsym + " with " + accessor);//DEBUG
currentClass = vsym.owner.enclClass();
make.at(pos);
JCMethodDecl md = make.MethodDef(accessor, null);
// Find actual symbol
Symbol sym = actualSymbols.get(vsym);
if (sym == null) sym = vsym;
JCExpression ref; // The tree referencing the private symbol.
List< JCExpression > args; // Any additional arguments to be passed along.
if ((sym.flags() & STATIC) != 0) {
ref = make.Ident(sym);
args = make.Idents(md.params);
} else {
ref = make.Select(make.Ident(md.params.head), sym);
args = make.Idents(md.params.tail);
}
JCStatement stat; // The statement accessing the private symbol.
if (sym.kind == VAR) {
// Normalize out all odd access codes by taking floor modulo 2:
int acode1 = acode - (acode & 1);
JCExpression expr; // The access method's return value.
switch (acode1) {
case DEREFcode:
expr = ref;
break;
case ASSIGNcode:
expr = make.Assign(ref, args.head);
break;
case PREINCcode: case POSTINCcode: case PREDECcode: case POSTDECcode:
expr = makeUnary(
((acode1 - PREINCcode) > > 1) + JCTree.PREINC, ref);
break;
default:
expr = make.Assignop(
treeTag(binaryAccessOperator(acode1)), ref, args.head);
((JCAssignOp) expr).operator = binaryAccessOperator(acode1);
}
stat = make.Return(expr.setType(sym.type));
} else {
stat = make.Call(make.App(ref, args));
}
md.body = make.Block(0, List.of(stat));
// Make sure all parameters, result types and thrown exceptions
// are accessible.
for (List< JCVariableDecl > l = md.params; l.nonEmpty(); l = l.tail)
l.head.vartype = access(l.head.vartype);
md.restype = access(md.restype);
for (List< JCExpression > l = md.thrown; l.nonEmpty(); l = l.tail)
l.head = access(l.head);
return md;
}
Construct definition of an access method. |
Name accessName(int anum,
int acode) {
return names.fromString(
"access" + target.syntheticNameChar() + anum + acode / 10 + acode % 10);
}
The name of the access method with number `anum' and access code `acode'. |
MethodSymbol accessSymbol(Symbol sym,
JCTree tree,
JCTree enclOp,
boolean protAccess,
boolean refSuper) {
ClassSymbol accOwner = refSuper && protAccess
// For access via qualified super (T.super.x), place the
// access symbol on T.
? (ClassSymbol)((JCFieldAccess) tree).selected.type.tsym
// Otherwise pretend that the owner of an accessed
// protected symbol is the enclosing class of the current
// class which is a subclass of the symbol's owner.
: accessClass(sym, protAccess, tree);
Symbol vsym = sym;
if (sym.owner != accOwner) {
vsym = sym.clone(accOwner);
actualSymbols.put(vsym, sym);
}
Integer anum // The access number of the access method.
= accessNums.get(vsym);
if (anum == null) {
anum = accessed.length();
accessNums.put(vsym, anum);
accessSyms.put(vsym, new MethodSymbol[NCODES]);
accessed.append(vsym);
// System.out.println("accessing " + vsym + " in " + vsym.location());
}
int acode; // The access code of the access method.
List< Type > argtypes; // The argument types of the access method.
Type restype; // The result type of the access method.
List< Type > thrown; // The thrown exceptions of the access method.
switch (vsym.kind) {
case VAR:
acode = accessCode(tree, enclOp);
if (acode >= FIRSTASGOPcode) {
OperatorSymbol operator = binaryAccessOperator(acode);
if (operator.opcode == string_add)
argtypes = List.of(syms.objectType);
else
argtypes = operator.type.getParameterTypes().tail;
} else if (acode == ASSIGNcode)
argtypes = List.of(vsym.erasure(types));
else
argtypes = List.nil();
restype = vsym.erasure(types);
thrown = List.nil();
break;
case MTH:
acode = DEREFcode;
argtypes = vsym.erasure(types).getParameterTypes();
restype = vsym.erasure(types).getReturnType();
thrown = vsym.type.getThrownTypes();
break;
default:
throw new AssertionError();
}
// For references via qualified super, increment acode by one,
// making it odd.
if (protAccess && refSuper) acode++;
// Instance access methods get instance as first parameter.
// For protected symbols this needs to be the instance as a member
// of the type containing the accessed symbol, not the class
// containing the access method.
if ((vsym.flags() & STATIC) == 0) {
argtypes = argtypes.prepend(vsym.owner.erasure(types));
}
MethodSymbol[] accessors = accessSyms.get(vsym);
MethodSymbol accessor = accessors[acode];
if (accessor == null) {
accessor = new MethodSymbol(
STATIC | SYNTHETIC,
accessName(anum.intValue(), acode),
new MethodType(argtypes, restype, thrown, syms.methodClass),
accOwner);
enterSynthetic(tree.pos(), accessor, accOwner.members());
accessors[acode] = accessor;
}
return accessor;
}
Return access symbol for a private or protected symbol from an inner class. |
List<JCExpression> boxArgs(List<Type> parameters,
List<JCExpression> _args,
Type varargsElement) {
List< JCExpression > args = _args;
if (parameters.isEmpty()) return args;
boolean anyChanges = false;
ListBuffer< JCExpression > result = new ListBuffer< JCExpression >();
while (parameters.tail.nonEmpty()) {
JCExpression arg = translate(args.head, parameters.head);
anyChanges |= (arg != args.head);
result.append(arg);
args = args.tail;
parameters = parameters.tail;
}
Type parameter = parameters.head;
if (varargsElement != null) {
anyChanges = true;
ListBuffer< JCExpression > elems = new ListBuffer< JCExpression >();
while (args.nonEmpty()) {
JCExpression arg = translate(args.head, varargsElement);
elems.append(arg);
args = args.tail;
}
JCNewArray boxedArgs = make.NewArray(make.Type(varargsElement),
List.< JCExpression >nil(),
elems.toList());
boxedArgs.type = new ArrayType(varargsElement, syms.arrayClass);
result.append(boxedArgs);
} else {
if (args.length() != 1) throw new AssertionError(args);
JCExpression arg = translate(args.head, parameter);
anyChanges |= (arg != args.head);
result.append(arg);
if (!anyChanges) return _args;
}
return result.toList();
}
|
T boxIfNeeded(T tree,
Type type) {
boolean havePrimitive = tree.type.isPrimitive();
if (havePrimitive == type.isPrimitive())
return tree;
if (havePrimitive) {
Type unboxedTarget = types.unboxedType(type);
if (unboxedTarget.tag != NONE) {
if (!types.isSubtype(tree.type, unboxedTarget)) //e.g. Character c = 89;
tree.type = unboxedTarget.constType(tree.type.constValue());
return (T)boxPrimitive((JCExpression)tree, type);
} else {
tree = (T)boxPrimitive((JCExpression)tree);
}
} else {
tree = (T)unbox((JCExpression)tree, type);
}
return tree;
}
Expand a boxing or unboxing conversion if needed. |
JCExpression boxPrimitive(JCExpression tree) {
return boxPrimitive(tree, types.boxedClass(tree.type).type);
}
Box up a single primitive expression. |
JCExpression boxPrimitive(JCExpression tree,
Type box) {
make_at(tree.pos());
if (target.boxWithConstructors()) {
Symbol ctor = lookupConstructor(tree.pos(),
box,
List.< Type >nil()
.prepend(tree.type));
return make.Create(ctor, List.of(tree));
} else {
Symbol valueOfSym = lookupMethod(tree.pos(),
names.valueOf,
box,
List.< Type >nil()
.prepend(tree.type));
return make.App(make.QualIdent(valueOfSym), List.of(tree));
}
}
Box up a single primitive expression. |
void checkConflicts(List<JCTree> translatedTrees) {
for (JCTree t : translatedTrees) {
t.accept(conflictsChecker);
}
}
Check whether synthetic symbols generated during lowering conflict
with user-defined symbols. |
JCClassDecl classDef(ClassSymbol c) {
// First lookup the class in the classdefs table.
JCClassDecl def = classdefs.get(c);
if (def == null && outermostMemberDef != null) {
// If this fails, traverse outermost member definition, entering all
// local classes into classdefs, and try again.
classMap.scan(outermostMemberDef);
def = classdefs.get(c);
}
if (def == null) {
// If this fails, traverse outermost class definition, entering all
// local classes into classdefs, and try again.
classMap.scan(outermostClassDef);
def = classdefs.get(c);
}
return def;
}
Map a class symbol to its definition. |
JCBlock classDollarSymBody(DiagnosticPosition pos,
JCMethodDecl md) {
MethodSymbol classDollarSym = md.sym;
ClassSymbol outerCacheClass = (ClassSymbol)classDollarSym.owner;
JCBlock returnResult;
// in 1.4.2 and above, we use
// Class.forName(String name, boolean init, ClassLoader loader);
// which requires we cache the current loader in cl$
if (target.classLiteralsNoInit()) {
// clsym = "private static ClassLoader cl$"
VarSymbol clsym = new VarSymbol(STATIC|SYNTHETIC,
names.fromString("cl" + target.syntheticNameChar()),
syms.classLoaderType,
outerCacheClass);
enterSynthetic(pos, clsym, outerCacheClass.members());
// emit "private static ClassLoader cl$;"
JCVariableDecl cldef = make.VarDef(clsym, null);
JCClassDecl outerCacheClassDef = classDef(outerCacheClass);
outerCacheClassDef.defs = outerCacheClassDef.defs.prepend(cldef);
// newcache := "new cache$1[0]"
JCNewArray newcache = make.
NewArray(make.Type(outerCacheClass.type),
List.< JCExpression >of(make.Literal(INT, 0).setType(syms.intType)),
null);
newcache.type = new ArrayType(types.erasure(outerCacheClass.type),
syms.arrayClass);
// forNameSym := java.lang.Class.forName(
// String s,boolean init,ClassLoader loader)
Symbol forNameSym = lookupMethod(make_pos, names.forName,
types.erasure(syms.classType),
List.of(syms.stringType,
syms.booleanType,
syms.classLoaderType));
// clvalue := "(cl$ == null) ?
// $newcache.getClass().getComponentType().getClassLoader() : cl$"
JCExpression clvalue =
make.Conditional(
makeBinary(JCTree.EQ, make.Ident(clsym), makeNull()),
make.Assign(
make.Ident(clsym),
makeCall(
makeCall(makeCall(newcache,
names.getClass,
List.< JCExpression >nil()),
names.getComponentType,
List.< JCExpression >nil()),
names.getClassLoader,
List.< JCExpression >nil())).setType(syms.classLoaderType),
make.Ident(clsym)).setType(syms.classLoaderType);
// returnResult := "{ return Class.forName(param1, false, cl$); }"
List< JCExpression > args = List.of(make.Ident(md.params.head.sym),
makeLit(syms.booleanType, 0),
clvalue);
returnResult = make.
Block(0, List.< JCStatement >of(make.
Call(make. // return
App(make.
Ident(forNameSym), args))));
} else {
// forNameSym := java.lang.Class.forName(String s)
Symbol forNameSym = lookupMethod(make_pos,
names.forName,
types.erasure(syms.classType),
List.of(syms.stringType));
// returnResult := "{ return Class.forName(param1); }"
returnResult = make.
Block(0, List.of(make.
Call(make. // return
App(make.
QualIdent(forNameSym),
List.< JCExpression >of(make.
Ident(md.params.
head.sym))))));
}
// catchParam := ClassNotFoundException e1
VarSymbol catchParam =
new VarSymbol(0, make.paramName(1),
syms.classNotFoundExceptionType,
classDollarSym);
JCStatement rethrow;
if (target.hasInitCause()) {
// rethrow = "throw new NoClassDefFoundError().initCause(e);
JCTree throwExpr =
makeCall(makeNewClass(syms.noClassDefFoundErrorType,
List.< JCExpression >nil()),
names.initCause,
List.< JCExpression >of(make.Ident(catchParam)));
rethrow = make.Throw(throwExpr);
} else {
// getMessageSym := ClassNotFoundException.getMessage()
Symbol getMessageSym = lookupMethod(make_pos,
names.getMessage,
syms.classNotFoundExceptionType,
List.< Type >nil());
// rethrow = "throw new NoClassDefFoundError(e.getMessage());"
rethrow = make.
Throw(makeNewClass(syms.noClassDefFoundErrorType,
List.< JCExpression >of(make.App(make.Select(make.Ident(catchParam),
getMessageSym),
List.< JCExpression >nil()))));
}
// rethrowStmt := "( $rethrow )"
JCBlock rethrowStmt = make.Block(0, List.of(rethrow));
// catchBlock := "catch ($catchParam) $rethrowStmt"
JCCatch catchBlock = make.Catch(make.VarDef(catchParam, null),
rethrowStmt);
// tryCatch := "try $returnResult $catchBlock"
JCStatement tryCatch = make.Try(returnResult,
List.of(catchBlock), null);
return make.Block(0, List.of(tryCatch));
}
Generate code for class$(String name). |
List<JCVariableDecl> freevarDefs(int pos,
List<VarSymbol> freevars,
Symbol owner) {
long flags = FINAL | SYNTHETIC;
if (owner.kind == TYP &&
target.usePrivateSyntheticFields())
flags |= PRIVATE;
List< JCVariableDecl > defs = List.nil();
for (List< VarSymbol > l = freevars; l.nonEmpty(); l = l.tail) {
VarSymbol v = l.head;
VarSymbol proxy = new VarSymbol(
flags, proxyName(v.name), v.erasure(types), owner);
proxies.enter(proxy);
JCVariableDecl vd = make.at(pos).VarDef(proxy, null);
vd.vartype = access(vd.vartype);
defs = defs.prepend(vd);
}
return defs;
}
Proxy definitions for all free variables in given list, in reverse order. |
List<VarSymbol> freevars(ClassSymbol c) {
if ((c.owner.kind & (VAR | MTH)) != 0) {
List< VarSymbol > fvs = freevarCache.get(c);
if (fvs == null) {
FreeVarCollector collector = new FreeVarCollector(c);
collector.scan(classDef(c));
fvs = collector.fvs;
freevarCache.put(c, fvs);
}
return fvs;
} else {
return List.nil();
}
}
Return the variables accessed from within a local class, which
are declared in the local class' owner.
(in reverse order of first access). |
JCStatement initField(int pos,
Name name) {
Scope.Entry e = proxies.lookup(name);
Symbol rhs = e.sym;
Assert.check(rhs.owner.kind == MTH);
Symbol lhs = e.next().sym;
Assert.check(rhs.owner.owner == lhs.owner);
make.at(pos);
return
make.Exec(
make.Assign(
make.Select(make.This(lhs.owner.erasure(types)), lhs),
make.Ident(rhs)).setType(lhs.erasure(types)));
}
Return tree simulating the assignment , where
name is the name of a free variable. |
JCStatement initOuterThis(int pos) {
VarSymbol rhs = outerThisStack.head;
Assert.check(rhs.owner.kind == MTH);
VarSymbol lhs = outerThisStack.tail.head;
Assert.check(rhs.owner.owner == lhs.owner);
make.at(pos);
return
make.Exec(
make.Assign(
make.Select(make.This(lhs.owner.erasure(types)), lhs),
make.Ident(rhs)).setType(lhs.erasure(types)));
}
Return tree simulating the assignment . |
public static Lower instance(Context context) {
Lower instance = context.get(lowerKey);
if (instance == null)
instance = new Lower(context);
return instance;
}
|
JCExpression loadFreevar(DiagnosticPosition pos,
VarSymbol v) {
return access(v, make.at(pos).Ident(v), null, false);
}
|
List<JCExpression> loadFreevars(DiagnosticPosition pos,
List<VarSymbol> freevars) {
List< JCExpression > args = List.nil();
for (List< VarSymbol > l = freevars; l.nonEmpty(); l = l.tail)
args = args.prepend(loadFreevar(pos, l.head));
return args;
}
Return a list of trees that load the free variables in given list,
in reverse order. |
JCTree lowerBoxedPostop(JCUnary tree) {
// translate to tmp1=lval(e); tmp2=tmp1; tmp1 OP 1; tmp2
// or
// translate to tmp1=lval(e); tmp2=tmp1; (typeof tree)tmp1 OP 1; tmp2
// where OP is += or -=
final boolean cast = TreeInfo.skipParens(tree.arg).getTag() == JCTree.TYPECAST;
return abstractLval(tree.arg, new TreeBuilder() {
public JCTree build(final JCTree tmp1) {
return abstractRval(tmp1, tree.arg.type, new TreeBuilder() {
public JCTree build(final JCTree tmp2) {
int opcode = (tree.getTag() == JCTree.POSTINC)
? JCTree.PLUS_ASG : JCTree.MINUS_ASG;
JCTree lhs = cast
? make.TypeCast(tree.arg.type, (JCExpression)tmp1)
: tmp1;
JCTree update = makeAssignop(opcode,
lhs,
make.Literal(1));
return makeComma(update, tmp2);
}
});
}
});
}
Lower a tree of the form e++ or e-- where e is an object type |
void makeAccessible(Symbol sym) {
JCClassDecl cdef = classDef(sym.owner.enclClass());
if (cdef == null) Assert.error("class def not found: " + sym + " in " + sym.owner);
if (sym.name == names.init) {
cdef.defs = cdef.defs.prepend(
accessConstructorDef(cdef.pos, sym, accessConstrs.get(sym)));
} else {
MethodSymbol[] accessors = accessSyms.get(sym);
for (int i = 0; i < NCODES; i++) {
if (accessors[i] != null)
cdef.defs = cdef.defs.prepend(
accessDef(cdef.pos, sym, accessors[i], i));
}
}
}
Add all required access methods for a private symbol to enclosing class. |
JCAssignOp makeAssignop(int optag,
JCTree lhs,
JCTree rhs) {
JCAssignOp tree = make.Assignop(optag, lhs, rhs);
tree.operator = rs.resolveBinaryOperator(
make_pos, tree.getTag() - JCTree.ASGOffset, attrEnv, lhs.type, rhs.type);
tree.type = lhs.type;
return tree;
}
Make an attributed assignop expression. |
JCBinary makeBinary(int optag,
JCExpression lhs,
JCExpression rhs) {
JCBinary tree = make.Binary(optag, lhs, rhs);
tree.operator = rs.resolveBinaryOperator(
make_pos, optag, attrEnv, lhs.type, rhs.type);
tree.type = tree.operator.type.getReturnType();
return tree;
}
Make an attributed binary expression. |
JCTree makeComma(JCTree expr1,
JCTree expr2) {
return abstractRval(expr1, new TreeBuilder() {
public JCTree build(final JCTree discarded) {
return expr2;
}
});
}
|
ClassSymbol makeEmptyClass(long flags,
ClassSymbol owner) {
// Create class symbol.
ClassSymbol c = reader.defineClass(names.empty, owner);
c.flatname = chk.localClassName(c);
c.sourcefile = owner.sourcefile;
c.completer = null;
c.members_field = new Scope(c);
c.flags_field = flags;
ClassType ctype = (ClassType) c.type;
ctype.supertype_field = syms.objectType;
ctype.interfaces_field = List.nil();
JCClassDecl odef = classDef(owner);
// Enter class symbol in owner scope and compiled table.
enterSynthetic(odef.pos(), c, owner.members());
chk.compiled.put(c.flatname, c);
// Create class definition tree.
JCClassDecl cdef = make.ClassDef(
make.Modifiers(flags), names.empty,
List.< JCTypeParameter >nil(),
null, List.< JCExpression >nil(), List.< JCTree >nil());
cdef.sym = c;
cdef.type = c.type;
// Append class definition tree to owner's definitions.
odef.defs = odef.defs.prepend(cdef);
return c;
}
Create an empty anonymous class definition and enter and complete
its symbol. Return the class definition's symbol.
and create |
JCExpression makeLit(Type type,
Object value) {
return make.Literal(type.tag, value).setType(type.constType(value));
}
Make an attributed tree representing a literal. This will be an
Ident node in the case of boolean literals, a Literal node in all
other cases. |
JCNewClass makeNewClass(Type ctype,
List<JCExpression> args) {
JCNewClass tree = make.NewClass(null,
null, make.QualIdent(ctype.tsym), args, null);
tree.constructor = rs.resolveConstructor(
make_pos, attrEnv, ctype, TreeInfo.types(args), null, false, false);
tree.type = ctype;
return tree;
}
Make an attributed class instance creation expression. |
JCExpression makeNull() {
return makeLit(syms.botType, null);
}
Make an attributed tree representing null. |
JCExpression makeOuterThis(DiagnosticPosition pos,
TypeSymbol c) {
List< VarSymbol > ots = outerThisStack;
if (ots.isEmpty()) {
log.error(pos, "no.encl.instance.of.type.in.scope", c);
Assert.error();
return makeNull();
}
VarSymbol ot = ots.head;
JCExpression tree = access(make.at(pos).Ident(ot));
TypeSymbol otc = ot.type.tsym;
while (otc != c) {
do {
ots = ots.tail;
if (ots.isEmpty()) {
log.error(pos,
"no.encl.instance.of.type.in.scope",
c);
Assert.error(); // should have been caught in Attr
return tree;
}
ot = ots.head;
} while (ot.owner != otc);
if (otc.owner.kind != PCK && !otc.hasOuterInstance()) {
chk.earlyRefError(pos, c);
Assert.error(); // should have been caught in Attr
return makeNull();
}
tree = access(make.at(pos).Select(tree, ot));
otc = ot.type.tsym;
}
return tree;
}
Construct a tree that represents the outer instance
. Never pick the current `this'. |
JCExpression makeOwnerThis(DiagnosticPosition pos,
Symbol sym,
boolean preciseMatch) {
Symbol c = sym.owner;
if (preciseMatch ? sym.isMemberOf(currentClass, types)
: currentClass.isSubClass(sym.owner, types)) {
// in this case, `this' works fine
return make.at(pos).This(c.erasure(types));
} else {
// need to go via this$n
return makeOwnerThisN(pos, sym, preciseMatch);
}
}
Construct a tree that represents the closest outer instance
such that the given symbol is a member of C. |
JCExpression makeOwnerThisN(DiagnosticPosition pos,
Symbol sym,
boolean preciseMatch) {
Symbol c = sym.owner;
List< VarSymbol > ots = outerThisStack;
if (ots.isEmpty()) {
log.error(pos, "no.encl.instance.of.type.in.scope", c);
Assert.error();
return makeNull();
}
VarSymbol ot = ots.head;
JCExpression tree = access(make.at(pos).Ident(ot));
TypeSymbol otc = ot.type.tsym;
while (!(preciseMatch ? sym.isMemberOf(otc, types) : otc.isSubClass(sym.owner, types))) {
do {
ots = ots.tail;
if (ots.isEmpty()) {
log.error(pos,
"no.encl.instance.of.type.in.scope",
c);
Assert.error();
return tree;
}
ot = ots.head;
} while (ot.owner != otc);
tree = access(make.at(pos).Select(tree, ot));
otc = ot.type.tsym;
}
return tree;
}
Similar to makeOwnerThis but will never pick "this". |
JCExpression makeString(JCExpression tree) {
if (tree.type.tag >= CLASS) {
return tree;
} else {
Symbol valueOfSym = lookupMethod(tree.pos(),
names.valueOf,
syms.stringType,
List.of(tree.type));
return make.App(make.QualIdent(valueOfSym), List.of(tree));
}
}
Convert tree into string object, unless it has already a
reference type.. |
JCExpression makeThis(DiagnosticPosition pos,
TypeSymbol c) {
if (currentClass == c) {
// in this case, `this' works fine
return make.at(pos).This(c.erasure(types));
} else {
// need to go via this$n
return makeOuterThis(pos, c);
}
}
Construct a tree simulating the expression . |
JCTree makeTwrTry(JCTry tree) {
make_at(tree.pos());
twrVars = twrVars.dup();
JCBlock twrBlock = makeTwrBlock(tree.resources, tree.body, 0);
if (tree.catchers.isEmpty() && tree.finalizer == null)
result = translate(twrBlock);
else
result = translate(make.Try(twrBlock, tree.catchers, tree.finalizer));
twrVars = twrVars.leave();
return result;
}
Optionally replace a try statement with the desugaring of a
try-with-resources statement. The canonical desugaring of
try ResourceSpecification
Block
is
{
final VariableModifiers_minus_final R #resource = Expression;
Throwable #primaryException = null;
try ResourceSpecificationtail
Block
catch (Throwable #t) {
#primaryException = t;
throw #t;
} finally {
if (#resource != null) {
if (#primaryException != null) {
try {
#resource.close();
} catch(Throwable #suppressedException) {
#primaryException.addSuppressed(#suppressedException);
}
} else {
#resource.close();
}
}
} |
JCUnary makeUnary(int optag,
JCExpression arg) {
JCUnary tree = make.Unary(optag, arg);
tree.operator = rs.resolveUnaryOperator(
make_pos, optag, attrEnv, arg.type);
tree.type = tree.operator.type.getReturnType();
return tree;
}
Make an attributed unary expression. |
TreeMaker make_at(DiagnosticPosition pos) {
make_pos = pos;
return make.at(pos);
}
Equivalent to make.at(pos.getStartPosition()) with side effect of caching
pos as make_pos, for use in diagnostics.
* |
EnumMapping mapForEnum(DiagnosticPosition pos,
TypeSymbol enumClass) {
EnumMapping map = enumSwitchMap.get(enumClass);
if (map == null)
enumSwitchMap.put(enumClass, map = new EnumMapping(pos, enumClass));
return map;
}
|
boolean needsPrivateAccess(Symbol sym) {
if ((sym.flags() & PRIVATE) == 0 || sym.owner == currentClass) {
return false;
} else if (sym.name == names.init && (sym.owner.owner.kind & (VAR | MTH)) != 0) {
// private constructor in local class: relax protection
sym.flags_field &= ~PRIVATE;
return false;
} else {
return true;
}
}
Do we need an access method to reference private symbol? |
boolean needsProtectedAccess(Symbol sym,
JCTree tree) {
if ((sym.flags() & PROTECTED) == 0 ||
sym.owner.owner == currentClass.owner || // fast special case
sym.packge() == currentClass.packge())
return false;
if (!currentClass.isSubClass(sym.owner, types))
return true;
if ((sym.flags() & STATIC) != 0 ||
tree.getTag() != JCTree.SELECT ||
TreeInfo.name(((JCFieldAccess) tree).selected) == names._super)
return false;
return !((JCFieldAccess) tree).selected.type.tsym.isSubClass(currentClass, types);
}
Do we need an access method to reference symbol in other package? |
JCVariableDecl outerThisDef(int pos,
Symbol owner) {
long flags = FINAL | SYNTHETIC;
if (owner.kind == TYP &&
target.usePrivateSyntheticFields())
flags |= PRIVATE;
Type target = types.erasure(owner.enclClass().type.getEnclosingType());
VarSymbol outerThis = new VarSymbol(
flags, outerThisName(target, owner), target, owner);
outerThisStack = outerThisStack.prepend(outerThis);
JCVariableDecl vd = make.at(pos).VarDef(outerThis, null);
vd.vartype = access(vd.vartype);
return vd;
}
Definition for this$n field. |
Name outerThisName(Type type,
Symbol owner) {
Type t = type.getEnclosingType();
int nestingLevel = 0;
while (t.tag == CLASS) {
t = t.getEnclosingType();
nestingLevel++;
}
Name result = names.fromString("this" + target.syntheticNameChar() + nestingLevel);
while (owner.kind == TYP && ((ClassSymbol)owner).members().lookup(result).scope != null)
result = names.fromString(result.toString() + target.syntheticNameChar());
return result;
}
The name of a this$n field |
Name proxyName(Name name) {
return names.fromString("val" + target.syntheticNameChar() + name);
}
The name of a free variable proxy. |
public T translate(T tree) {
if (tree == null) {
return null;
} else {
make_at(tree.pos());
T result = super.translate(tree);
if (endPositions != null && result != tree) {
Integer endPos = endPositions.remove(tree);
if (endPos != null) endPositions.put(result, endPos);
}
return result;
}
}
Visitor method: Translate a single node.
Attach the source position from the old tree to its replacement tree. |
public T translate(T tree,
Type type) {
return (tree == null) ? null : boxIfNeeded(translate(tree), type);
}
Visitor method: Translate a single node, boxing or unboxing if needed. |
public T translate(T tree,
JCExpression enclOp) {
JCExpression prevEnclOp = this.enclOp;
this.enclOp = enclOp;
T res = translate(tree);
this.enclOp = prevEnclOp;
return res;
}
Visitor method: Translate tree. |
public List<T> translate(List<T> trees,
JCExpression enclOp) {
JCExpression prevEnclOp = this.enclOp;
this.enclOp = enclOp;
List< T > res = translate(trees);
this.enclOp = prevEnclOp;
return res;
}
Visitor method: Translate list of trees. |
public List<T> translate(List<T> trees,
Type type) {
if (trees == null) return null;
for (List< T > l = trees; l.nonEmpty(); l = l.tail)
l.head = translate(l.head, type);
return trees;
}
Visitor method: Translate list of trees. |
public List<JCTree> translateTopLevelClass(Env<AttrContext> env,
JCTree cdef,
TreeMaker make) {
ListBuffer< JCTree > translated = null;
try {
attrEnv = env;
this.make = make;
endPositions = env.toplevel.endPositions;
currentClass = null;
currentMethodDef = null;
outermostClassDef = (cdef.getTag() == JCTree.CLASSDEF) ? (JCClassDecl)cdef : null;
outermostMemberDef = null;
this.translated = new ListBuffer< JCTree >();
classdefs = new HashMap< ClassSymbol,JCClassDecl >();
actualSymbols = new HashMap< Symbol,Symbol >();
freevarCache = new HashMap< ClassSymbol,List< VarSymbol > >();
proxies = new Scope(syms.noSymbol);
twrVars = new Scope(syms.noSymbol);
outerThisStack = List.nil();
accessNums = new HashMap< Symbol,Integer >();
accessSyms = new HashMap< Symbol,MethodSymbol[] >();
accessConstrs = new HashMap< Symbol,MethodSymbol >();
accessConstrTags = List.nil();
accessed = new ListBuffer< Symbol >();
translate(cdef, (JCExpression)null);
for (List< Symbol > l = accessed.toList(); l.nonEmpty(); l = l.tail)
makeAccessible(l.head);
for (EnumMapping map : enumSwitchMap.values())
map.translate();
checkConflicts(this.translated.toList());
checkAccessConstructorTags();
translated = this.translated;
} finally {
// note that recursive invocations of this method fail hard
attrEnv = null;
this.make = null;
endPositions = null;
currentClass = null;
currentMethodDef = null;
outermostClassDef = null;
outermostMemberDef = null;
this.translated = null;
classdefs = null;
actualSymbols = null;
freevarCache = null;
proxies = null;
outerThisStack = null;
accessNums = null;
accessSyms = null;
accessConstrs = null;
accessConstrTags = null;
accessed = null;
enumSwitchMap.clear();
}
return translated.toList();
}
Translate a toplevel class and return a list consisting of
the translated class and translated versions of all inner classes. |
JCExpression unbox(JCExpression tree,
Type primitive) {
Type unboxedType = types.unboxedType(tree.type);
if (unboxedType.tag == NONE) {
unboxedType = primitive;
if (!unboxedType.isPrimitive())
throw new AssertionError(unboxedType);
make_at(tree.pos());
tree = make.TypeCast(types.boxedClass(unboxedType).type, tree);
} else {
// There must be a conversion from unboxedType to primitive.
if (!types.isSubtype(unboxedType, primitive))
throw new AssertionError(tree);
}
make_at(tree.pos());
Symbol valueSym = lookupMethod(tree.pos(),
unboxedType.tsym.name.append(names.Value), // x.intValue()
tree.type,
List.< Type >nil());
return make.App(make.Select(tree, valueSym));
}
Unbox an object to a primitive value. |
public void visitAnnotation(JCAnnotation tree) {
result = tree;
}
|
public void visitApply(JCMethodInvocation tree) {
Symbol meth = TreeInfo.symbol(tree.meth);
List< Type > argtypes = meth.type.getParameterTypes();
if (allowEnums &&
meth.name==names.init &&
meth.owner == syms.enumSym)
argtypes = argtypes.tail.tail;
tree.args = boxArgs(argtypes, tree.args, tree.varargsElement);
tree.varargsElement = null;
Name methName = TreeInfo.name(tree.meth);
if (meth.name==names.init) {
// We are seeing a this(...) or super(...) constructor call.
// If an access constructor is used, append null as a last argument.
Symbol constructor = accessConstructor(tree.pos(), meth);
if (constructor != meth) {
tree.args = tree.args.append(makeNull());
TreeInfo.setSymbol(tree.meth, constructor);
}
// If we are calling a constructor of a local class, add
// free variables after explicit constructor arguments.
ClassSymbol c = (ClassSymbol)constructor.owner;
if ((c.owner.kind & (VAR | MTH)) != 0) {
tree.args = tree.args.appendList(loadFreevars(tree.pos(), freevars(c)));
}
// If we are calling a constructor of an enum class, pass
// along the name and ordinal arguments
if ((c.flags_field&ENUM) != 0 || c.getQualifiedName() == names.java_lang_Enum) {
List< JCVariableDecl > params = currentMethodDef.params;
if (currentMethodSym.owner.hasOuterInstance())
params = params.tail; // drop this$n
tree.args = tree.args
.prepend(make_at(tree.pos()).Ident(params.tail.head.sym)) // ordinal
.prepend(make.Ident(params.head.sym)); // name
}
// If we are calling a constructor of a class with an outer
// instance, and the call
// is qualified, pass qualifier as first argument in front of
// the explicit constructor arguments. If the call
// is not qualified, pass the correct outer instance as
// first argument.
if (c.hasOuterInstance()) {
JCExpression thisArg;
if (tree.meth.getTag() == JCTree.SELECT) {
thisArg = attr.
makeNullCheck(translate(((JCFieldAccess) tree.meth).selected));
tree.meth = make.Ident(constructor);
((JCIdent) tree.meth).name = methName;
} else if ((c.owner.kind & (MTH | VAR)) != 0 || methName == names._this){
// local class or this() call
thisArg = makeThis(tree.meth.pos(), c.type.getEnclosingType().tsym);
} else {
// super() call of nested class - never pick 'this'
thisArg = makeOwnerThisN(tree.meth.pos(), c, false);
}
tree.args = tree.args.prepend(thisArg);
}
} else {
// We are seeing a normal method invocation; translate this as usual.
tree.meth = translate(tree.meth);
// If the translated method itself is an Apply tree, we are
// seeing an access method invocation. In this case, append
// the method arguments to the arguments of the access method.
if (tree.meth.getTag() == JCTree.APPLY) {
JCMethodInvocation app = (JCMethodInvocation)tree.meth;
app.args = tree.args.prependList(app.args);
result = app;
return;
}
}
result = tree;
}
|
public void visitAssert(JCAssert tree) {
DiagnosticPosition detailPos = (tree.detail == null) ? tree.pos() : tree.detail.pos();
tree.cond = translate(tree.cond, syms.booleanType);
if (!tree.cond.type.isTrue()) {
JCExpression cond = assertFlagTest(tree.pos());
List< JCExpression > exnArgs = (tree.detail == null) ?
List.< JCExpression >nil() : List.of(translate(tree.detail));
if (!tree.cond.type.isFalse()) {
cond = makeBinary
(JCTree.AND,
cond,
makeUnary(JCTree.NOT, tree.cond));
}
result =
make.If(cond,
make_at(detailPos).
Throw(makeNewClass(syms.assertionErrorType, exnArgs)),
null);
} else {
result = make.Skip();
}
}
Visitor method for assert statements. Translate them away. |
public void visitAssign(JCAssign tree) {
tree.lhs = translate(tree.lhs, tree);
tree.rhs = translate(tree.rhs, tree.lhs.type);
// If translated left hand side is an Apply, we are
// seeing an access method invocation. In this case, append
// right hand side as last argument of the access method.
if (tree.lhs.getTag() == JCTree.APPLY) {
JCMethodInvocation app = (JCMethodInvocation)tree.lhs;
app.args = List.of(tree.rhs).prependList(app.args);
result = app;
} else {
result = tree;
}
}
|
public void visitAssignop(JCAssignOp tree) {
if (!tree.lhs.type.isPrimitive() &&
tree.operator.type.getReturnType().isPrimitive()) {
// boxing required; need to rewrite as x = (unbox typeof x)(x op y);
// or if x == (typeof x)z then z = (unbox typeof x)((typeof x)z op y)
// (but without recomputing x)
JCTree newTree = abstractLval(tree.lhs, new TreeBuilder() {
public JCTree build(final JCTree lhs) {
int newTag = tree.getTag() - JCTree.ASGOffset;
// Erasure (TransTypes) can change the type of
// tree.lhs. However, we can still get the
// unerased type of tree.lhs as it is stored
// in tree.type in Attr.
Symbol newOperator = rs.resolveBinaryOperator(tree.pos(),
newTag,
attrEnv,
tree.type,
tree.rhs.type);
JCExpression expr = (JCExpression)lhs;
if (expr.type != tree.type)
expr = make.TypeCast(tree.type, expr);
JCBinary opResult = make.Binary(newTag, expr, tree.rhs);
opResult.operator = newOperator;
opResult.type = newOperator.type.getReturnType();
JCTypeCast newRhs = make.TypeCast(types.unboxedType(tree.type),
opResult);
return make.Assign((JCExpression)lhs, newRhs).setType(tree.type);
}
});
result = translate(newTree);
return;
}
tree.lhs = translate(tree.lhs, tree);
tree.rhs = translate(tree.rhs, tree.operator.type.getParameterTypes().tail.head);
// If translated left hand side is an Apply, we are
// seeing an access method invocation. In this case, append
// right hand side as last argument of the access method.
if (tree.lhs.getTag() == JCTree.APPLY) {
JCMethodInvocation app = (JCMethodInvocation)tree.lhs;
// if operation is a += on strings,
// make sure to convert argument to string
JCExpression rhs = (((OperatorSymbol)tree.operator).opcode == string_add)
? makeString(tree.rhs)
: tree.rhs;
app.args = List.of(rhs).prependList(app.args);
result = app;
} else {
result = tree;
}
}
|
public void visitBinary(JCBinary tree) {
List< Type > formals = tree.operator.type.getParameterTypes();
JCTree lhs = tree.lhs = translate(tree.lhs, formals.head);
switch (tree.getTag()) {
case JCTree.OR:
if (lhs.type.isTrue()) {
result = lhs;
return;
}
if (lhs.type.isFalse()) {
result = translate(tree.rhs, formals.tail.head);
return;
}
break;
case JCTree.AND:
if (lhs.type.isFalse()) {
result = lhs;
return;
}
if (lhs.type.isTrue()) {
result = translate(tree.rhs, formals.tail.head);
return;
}
break;
}
tree.rhs = translate(tree.rhs, formals.tail.head);
result = tree;
}
|
public void visitBlock(JCBlock tree) {
MethodSymbol oldMethodSym = currentMethodSym;
if (currentMethodSym == null) {
// Block is a static or instance initializer.
currentMethodSym =
new MethodSymbol(tree.flags | BLOCK,
names.empty, null,
currentClass);
}
super.visitBlock(tree);
currentMethodSym = oldMethodSym;
}
|
public void visitClassDef(JCClassDecl tree) {
ClassSymbol currentClassPrev = currentClass;
MethodSymbol currentMethodSymPrev = currentMethodSym;
currentClass = tree.sym;
currentMethodSym = null;
classdefs.put(currentClass, tree);
proxies = proxies.dup(currentClass);
List< VarSymbol > prevOuterThisStack = outerThisStack;
// If this is an enum definition
if ((tree.mods.flags & ENUM) != 0 &&
(types.supertype(currentClass.type).tsym.flags() & ENUM) == 0)
visitEnumDef(tree);
// If this is a nested class, define a this$n field for
// it and add to proxies.
JCVariableDecl otdef = null;
if (currentClass.hasOuterInstance())
otdef = outerThisDef(tree.pos, currentClass);
// If this is a local class, define proxies for all its free variables.
List< JCVariableDecl > fvdefs = freevarDefs(
tree.pos, freevars(currentClass), currentClass);
// Recursively translate superclass, interfaces.
tree.extending = translate(tree.extending);
tree.implementing = translate(tree.implementing);
// Recursively translate members, taking into account that new members
// might be created during the translation and prepended to the member
// list `tree.defs'.
List< JCTree > seen = List.nil();
while (tree.defs != seen) {
List< JCTree > unseen = tree.defs;
for (List< JCTree > l = unseen; l.nonEmpty() && l != seen; l = l.tail) {
JCTree outermostMemberDefPrev = outermostMemberDef;
if (outermostMemberDefPrev == null) outermostMemberDef = l.head;
l.head = translate(l.head);
outermostMemberDef = outermostMemberDefPrev;
}
seen = unseen;
}
// Convert a protected modifier to public, mask static modifier.
if ((tree.mods.flags & PROTECTED) != 0) tree.mods.flags |= PUBLIC;
tree.mods.flags &= ClassFlags;
// Convert name to flat representation, replacing '.' by '$'.
tree.name = Convert.shortName(currentClass.flatName());
// Add this$n and free variables proxy definitions to class.
for (List< JCVariableDecl > l = fvdefs; l.nonEmpty(); l = l.tail) {
tree.defs = tree.defs.prepend(l.head);
enterSynthetic(tree.pos(), l.head.sym, currentClass.members());
}
if (currentClass.hasOuterInstance()) {
tree.defs = tree.defs.prepend(otdef);
enterSynthetic(tree.pos(), otdef.sym, currentClass.members());
}
proxies = proxies.leave();
outerThisStack = prevOuterThisStack;
// Append translated tree to `translated' queue.
translated.append(tree);
currentClass = currentClassPrev;
currentMethodSym = currentMethodSymPrev;
// Return empty block {} as a placeholder for an inner class.
result = make_at(tree.pos()).Block(0, List.< JCStatement >nil());
}
|
public void visitConditional(JCConditional tree) {
JCTree cond = tree.cond = translate(tree.cond, syms.booleanType);
if (cond.type.isTrue()) {
result = convert(translate(tree.truepart, tree.type), tree.type);
} else if (cond.type.isFalse()) {
result = convert(translate(tree.falsepart, tree.type), tree.type);
} else {
// Condition is not a compile-time constant.
tree.truepart = translate(tree.truepart, tree.type);
tree.falsepart = translate(tree.falsepart, tree.type);
result = tree;
}
}
Visitor method for conditional expressions. |
public void visitDoLoop(JCDoWhileLoop tree) {
tree.body = translate(tree.body);
tree.cond = translate(tree.cond, syms.booleanType);
result = tree;
}
|
public JCTree visitEnumSwitch(JCSwitch tree) {
TypeSymbol enumSym = tree.selector.type.tsym;
EnumMapping map = mapForEnum(tree.pos(), enumSym);
make_at(tree.pos());
Symbol ordinalMethod = lookupMethod(tree.pos(),
names.ordinal,
tree.selector.type,
List.< Type >nil());
JCArrayAccess selector = make.Indexed(map.mapVar,
make.App(make.Select(tree.selector,
ordinalMethod)));
ListBuffer< JCCase > cases = new ListBuffer< JCCase >();
for (JCCase c : tree.cases) {
if (c.pat != null) {
VarSymbol label = (VarSymbol)TreeInfo.symbol(c.pat);
JCLiteral pat = map.forConstant(label);
cases.append(make.Case(pat, c.stats));
} else {
cases.append(c);
}
}
JCSwitch enumSwitch = make.Switch(selector, cases.toList());
patchTargets(enumSwitch, tree, enumSwitch);
return enumSwitch;
}
|
public void visitForLoop(JCForLoop tree) {
tree.init = translate(tree.init);
if (tree.cond != null)
tree.cond = translate(tree.cond, syms.booleanType);
tree.step = translate(tree.step);
tree.body = translate(tree.body);
result = tree;
}
|
public void visitForeachLoop(JCEnhancedForLoop tree) {
if (types.elemtype(tree.expr.type) == null)
visitIterableForeachLoop(tree);
else
visitArrayForeachLoop(tree);
}
Translate away the foreach loop. |
public void visitIdent(JCIdent tree) {
result = access(tree.sym, tree, enclOp, false);
}
|
public void visitIf(JCIf tree) {
JCTree cond = tree.cond = translate(tree.cond, syms.booleanType);
if (cond.type.isTrue()) {
result = translate(tree.thenpart);
} else if (cond.type.isFalse()) {
if (tree.elsepart != null) {
result = translate(tree.elsepart);
} else {
result = make.Skip();
}
} else {
// Condition is not a compile-time constant.
tree.thenpart = translate(tree.thenpart);
tree.elsepart = translate(tree.elsepart);
result = tree;
}
}
Visitor method for if statements. |
public void visitIndexed(JCArrayAccess tree) {
tree.indexed = translate(tree.indexed);
tree.index = translate(tree.index, syms.intType);
result = tree;
}
|
public void visitLetExpr(LetExpr tree) {
tree.defs = translateVarDefs(tree.defs);
tree.expr = translate(tree.expr, tree.type);
result = tree;
}
|
public void visitMethodDef(JCMethodDecl tree) {
if (tree.name == names.init && (currentClass.flags_field&ENUM) != 0) {
// Add "String $enum$name, int $enum$ordinal" to the beginning of the
// argument list for each constructor of an enum.
JCVariableDecl nameParam = make_at(tree.pos()).
Param(names.fromString(target.syntheticNameChar() +
"enum" + target.syntheticNameChar() + "name"),
syms.stringType, tree.sym);
nameParam.mods.flags |= SYNTHETIC; nameParam.sym.flags_field |= SYNTHETIC;
JCVariableDecl ordParam = make.
Param(names.fromString(target.syntheticNameChar() +
"enum" + target.syntheticNameChar() +
"ordinal"),
syms.intType, tree.sym);
ordParam.mods.flags |= SYNTHETIC; ordParam.sym.flags_field |= SYNTHETIC;
tree.params = tree.params.prepend(ordParam).prepend(nameParam);
MethodSymbol m = tree.sym;
Type olderasure = m.erasure(types);
m.erasure_field = new MethodType(
olderasure.getParameterTypes().prepend(syms.intType).prepend(syms.stringType),
olderasure.getReturnType(),
olderasure.getThrownTypes(),
syms.methodClass);
if (target.compilerBootstrap(m.owner)) {
// Initialize synthetic name field
Symbol nameVarSym = lookupSynthetic(names.fromString("$name"),
tree.sym.owner.members());
JCIdent nameIdent = make.Ident(nameParam.sym);
JCIdent id1 = make.Ident(nameVarSym);
JCAssign newAssign = make.Assign(id1, nameIdent);
newAssign.type = id1.type;
JCExpressionStatement nameAssign = make.Exec(newAssign);
nameAssign.type = id1.type;
tree.body.stats = tree.body.stats.prepend(nameAssign);
// Initialize synthetic ordinal field
Symbol ordinalVarSym = lookupSynthetic(names.fromString("$ordinal"),
tree.sym.owner.members());
JCIdent ordIdent = make.Ident(ordParam.sym);
id1 = make.Ident(ordinalVarSym);
newAssign = make.Assign(id1, ordIdent);
newAssign.type = id1.type;
JCExpressionStatement ordinalAssign = make.Exec(newAssign);
ordinalAssign.type = id1.type;
tree.body.stats = tree.body.stats.prepend(ordinalAssign);
}
}
JCMethodDecl prevMethodDef = currentMethodDef;
MethodSymbol prevMethodSym = currentMethodSym;
try {
currentMethodDef = tree;
currentMethodSym = tree.sym;
visitMethodDefInternal(tree);
} finally {
currentMethodDef = prevMethodDef;
currentMethodSym = prevMethodSym;
}
}
|
public void visitNewArray(JCNewArray tree) {
tree.elemtype = translate(tree.elemtype);
for (List< JCExpression > t = tree.dims; t.tail != null; t = t.tail)
if (t.head != null) t.head = translate(t.head, syms.intType);
tree.elems = translate(tree.elems, types.elemtype(tree.type));
result = tree;
}
|
public void visitNewClass(JCNewClass tree) {
ClassSymbol c = (ClassSymbol)tree.constructor.owner;
// Box arguments, if necessary
boolean isEnum = (tree.constructor.owner.flags() & ENUM) != 0;
List< Type > argTypes = tree.constructor.type.getParameterTypes();
if (isEnum) argTypes = argTypes.prepend(syms.intType).prepend(syms.stringType);
tree.args = boxArgs(argTypes, tree.args, tree.varargsElement);
tree.varargsElement = null;
// If created class is local, add free variables after
// explicit constructor arguments.
if ((c.owner.kind & (VAR | MTH)) != 0) {
tree.args = tree.args.appendList(loadFreevars(tree.pos(), freevars(c)));
}
// If an access constructor is used, append null as a last argument.
Symbol constructor = accessConstructor(tree.pos(), tree.constructor);
if (constructor != tree.constructor) {
tree.args = tree.args.append(makeNull());
tree.constructor = constructor;
}
// If created class has an outer instance, and new is qualified, pass
// qualifier as first argument. If new is not qualified, pass the
// correct outer instance as first argument.
if (c.hasOuterInstance()) {
JCExpression thisArg;
if (tree.encl != null) {
thisArg = attr.makeNullCheck(translate(tree.encl));
thisArg.type = tree.encl.type;
} else if ((c.owner.kind & (MTH | VAR)) != 0) {
// local class
thisArg = makeThis(tree.pos(), c.type.getEnclosingType().tsym);
} else {
// nested class
thisArg = makeOwnerThis(tree.pos(), c, false);
}
tree.args = tree.args.prepend(thisArg);
}
tree.encl = null;
// If we have an anonymous class, create its flat version, rather
// than the class or interface following new.
if (tree.def != null) {
translate(tree.def);
tree.clazz = access(make_at(tree.clazz.pos()).Ident(tree.def.sym));
tree.def = null;
} else {
tree.clazz = access(c, tree.clazz, enclOp, false);
}
result = tree;
}
|
public void visitParens(JCParens tree) {
JCTree expr = translate(tree.expr);
result = ((expr == tree.expr) ? tree : expr);
}
Visitor method for parenthesized expressions.
If the subexpression has changed, omit the parens. |
public void visitReturn(JCReturn tree) {
if (tree.expr != null)
tree.expr = translate(tree.expr,
types.erasure(currentMethodDef
.restype.type));
result = tree;
}
|
public void visitSelect(JCFieldAccess tree) {
// need to special case-access of the form C.super.x
// these will always need an access method.
boolean qualifiedSuperAccess =
tree.selected.getTag() == JCTree.SELECT &&
TreeInfo.name(tree.selected) == names._super;
tree.selected = translate(tree.selected);
if (tree.name == names._class)
result = classOf(tree.selected);
else if (tree.name == names._this || tree.name == names._super)
result = makeThis(tree.pos(), tree.selected.type.tsym);
else
result = access(tree.sym, tree, enclOp, qualifiedSuperAccess);
}
|
public JCTree visitStringSwitch(JCSwitch tree) {
List< JCCase > caseList = tree.getCases();
int alternatives = caseList.size();
if (alternatives == 0) { // Strange but legal possibility
return make.at(tree.pos()).Exec(attr.makeNullCheck(tree.getExpression()));
} else {
/*
* The general approach used is to translate a single
* string switch statement into a series of two chained
* switch statements: the first a synthesized statement
* switching on the argument string's hash value and
* computing a string's position in the list of original
* case labels, if any, followed by a second switch on the
* computed integer value. The second switch has the same
* code structure as the original string switch statement
* except that the string case labels are replaced with
* positional integer constants starting at 0.
*
* The first switch statement can be thought of as an
* inlined map from strings to their position in the case
* label list. An alternate implementation would use an
* actual Map for this purpose, as done for enum switches.
*
* With some additional effort, it would be possible to
* use a single switch statement on the hash code of the
* argument, but care would need to be taken to preserve
* the proper control flow in the presence of hash
* collisions and other complications, such as
* fallthroughs. Switch statements with one or two
* alternatives could also be specially translated into
* if-then statements to omit the computation of the hash
* code.
*
* The generated code assumes that the hashing algorithm
* of String is the same in the compilation environment as
* in the environment the code will run in. The string
* hashing algorithm in the SE JDK has been unchanged
* since at least JDK 1.2. Since the algorithm has been
* specified since that release as well, it is very
* unlikely to be changed in the future.
*
* Different hashing algorithms, such as the length of the
* strings or a perfect hashing algorithm over the
* particular set of case labels, could potentially be
* used instead of String.hashCode.
*/
ListBuffer< JCStatement > stmtList = new ListBuffer< JCStatement >();
// Map from String case labels to their original position in
// the list of case labels.
Map< String, Integer > caseLabelToPosition =
new LinkedHashMap< String, Integer >(alternatives + 1, 1.0f);
// Map of hash codes to the string case labels having that hashCode.
Map< Integer, Set< String > > hashToString =
new LinkedHashMap< Integer, Set< String > >(alternatives + 1, 1.0f);
int casePosition = 0;
for(JCCase oneCase : caseList) {
JCExpression expression = oneCase.getExpression();
if (expression != null) { // expression for a "default" case is null
String labelExpr = (String) expression.type.constValue();
Integer mapping = caseLabelToPosition.put(labelExpr, casePosition);
Assert.checkNull(mapping);
int hashCode = labelExpr.hashCode();
Set< String > stringSet = hashToString.get(hashCode);
if (stringSet == null) {
stringSet = new LinkedHashSet< String >(1, 1.0f);
stringSet.add(labelExpr);
hashToString.put(hashCode, stringSet);
} else {
boolean added = stringSet.add(labelExpr);
Assert.check(added);
}
}
casePosition++;
}
// Synthesize a switch statement that has the effect of
// mapping from a string to the integer position of that
// string in the list of case labels. This is done by
// switching on the hashCode of the string followed by an
// if-then-else chain comparing the input for equality
// with all the case labels having that hash value.
/*
* s$ = top of stack;
* tmp$ = -1;
* switch($s.hashCode()) {
* case caseLabel.hashCode:
* if (s$.equals("caseLabel_1")
* tmp$ = caseLabelToPosition("caseLabel_1");
* else if (s$.equals("caseLabel_2"))
* tmp$ = caseLabelToPosition("caseLabel_2");
* ...
* break;
* ...
* }
*/
VarSymbol dollar_s = new VarSymbol(FINAL|SYNTHETIC,
names.fromString("s" + tree.pos + target.syntheticNameChar()),
syms.stringType,
currentMethodSym);
stmtList.append(make.at(tree.pos()).VarDef(dollar_s, tree.getExpression()).setType(dollar_s.type));
VarSymbol dollar_tmp = new VarSymbol(SYNTHETIC,
names.fromString("tmp" + tree.pos + target.syntheticNameChar()),
syms.intType,
currentMethodSym);
JCVariableDecl dollar_tmp_def =
(JCVariableDecl)make.VarDef(dollar_tmp, make.Literal(INT, -1)).setType(dollar_tmp.type);
dollar_tmp_def.init.type = dollar_tmp.type = syms.intType;
stmtList.append(dollar_tmp_def);
ListBuffer< JCCase > caseBuffer = ListBuffer.lb();
// hashCode will trigger nullcheck on original switch expression
JCMethodInvocation hashCodeCall = makeCall(make.Ident(dollar_s),
names.hashCode,
List.< JCExpression >nil()).setType(syms.intType);
JCSwitch switch1 = make.Switch(hashCodeCall,
caseBuffer.toList());
for(Map.Entry< Integer, Set< String > > entry : hashToString.entrySet()) {
int hashCode = entry.getKey();
Set< String > stringsWithHashCode = entry.getValue();
Assert.check(stringsWithHashCode.size() >= 1);
JCStatement elsepart = null;
for(String caseLabel : stringsWithHashCode ) {
JCMethodInvocation stringEqualsCall = makeCall(make.Ident(dollar_s),
names.equals,
List.< JCExpression >of(make.Literal(caseLabel)));
elsepart = make.If(stringEqualsCall,
make.Exec(make.Assign(make.Ident(dollar_tmp),
make.Literal(caseLabelToPosition.get(caseLabel))).
setType(dollar_tmp.type)),
elsepart);
}
ListBuffer< JCStatement > lb = ListBuffer.lb();
JCBreak breakStmt = make.Break(null);
breakStmt.target = switch1;
lb.append(elsepart).append(breakStmt);
caseBuffer.append(make.Case(make.Literal(hashCode), lb.toList()));
}
switch1.cases = caseBuffer.toList();
stmtList.append(switch1);
// Make isomorphic switch tree replacing string labels
// with corresponding integer ones from the label to
// position map.
ListBuffer< JCCase > lb = ListBuffer.lb();
JCSwitch switch2 = make.Switch(make.Ident(dollar_tmp), lb.toList());
for(JCCase oneCase : caseList ) {
// Rewire up old unlabeled break statements to the
// replacement switch being created.
patchTargets(oneCase, tree, switch2);
boolean isDefault = (oneCase.getExpression() == null);
JCExpression caseExpr;
if (isDefault)
caseExpr = null;
else {
caseExpr = make.Literal(caseLabelToPosition.get((String)oneCase.
getExpression().
type.constValue()));
}
lb.append(make.Case(caseExpr,
oneCase.getStatements()));
}
switch2.cases = lb.toList();
stmtList.append(switch2);
return make.Block(0L, stmtList.toList());
}
}
|
public void visitSwitch(JCSwitch tree) {
Type selsuper = types.supertype(tree.selector.type);
boolean enumSwitch = selsuper != null &&
(tree.selector.type.tsym.flags() & ENUM) != 0;
boolean stringSwitch = selsuper != null &&
types.isSameType(tree.selector.type, syms.stringType);
Type target = enumSwitch ? tree.selector.type :
(stringSwitch? syms.stringType : syms.intType);
tree.selector = translate(tree.selector, target);
tree.cases = translateCases(tree.cases);
if (enumSwitch) {
result = visitEnumSwitch(tree);
} else if (stringSwitch) {
result = visitStringSwitch(tree);
} else {
result = tree;
}
}
|
public void visitTopLevel(JCCompilationUnit tree) {
if (needPackageInfoClass(tree)) {
Name name = names.package_info;
long flags = Flags.ABSTRACT | Flags.INTERFACE;
if (target.isPackageInfoSynthetic())
// package-info is marked SYNTHETIC in JDK 1.6 and later releases
flags = flags | Flags.SYNTHETIC;
JCClassDecl packageAnnotationsClass
= make.ClassDef(make.Modifiers(flags,
tree.packageAnnotations),
name, List.< JCTypeParameter >nil(),
null, List.< JCExpression >nil(), List.< JCTree >nil());
ClassSymbol c = tree.packge.package_info;
c.flags_field |= flags;
c.attributes_field = tree.packge.attributes_field;
ClassType ctype = (ClassType) c.type;
ctype.supertype_field = syms.objectType;
ctype.interfaces_field = List.nil();
packageAnnotationsClass.sym = c;
translated.append(packageAnnotationsClass);
}
}
|
public void visitTry(JCTry tree) {
if (tree.resources.isEmpty()) {
super.visitTry(tree);
} else {
result = makeTwrTry(tree);
}
}
|
public void visitTypeCast(JCTypeCast tree) {
tree.clazz = translate(tree.clazz);
if (tree.type.isPrimitive() != tree.expr.type.isPrimitive())
tree.expr = translate(tree.expr, tree.type);
else
tree.expr = translate(tree.expr);
result = tree;
}
|
public void visitUnary(JCUnary tree) {
boolean isUpdateOperator =
JCTree.PREINC < = tree.getTag() && tree.getTag() < = JCTree.POSTDEC;
if (isUpdateOperator && !tree.arg.type.isPrimitive()) {
switch(tree.getTag()) {
case JCTree.PREINC: // ++ e
// translate to e += 1
case JCTree.PREDEC: // -- e
// translate to e -= 1
{
int opcode = (tree.getTag() == JCTree.PREINC)
? JCTree.PLUS_ASG : JCTree.MINUS_ASG;
JCAssignOp newTree = makeAssignop(opcode,
tree.arg,
make.Literal(1));
result = translate(newTree, tree.type);
return;
}
case JCTree.POSTINC: // e ++
case JCTree.POSTDEC: // e --
{
result = translate(lowerBoxedPostop(tree), tree.type);
return;
}
}
throw new AssertionError(tree);
}
tree.arg = boxIfNeeded(translate(tree.arg, tree), tree.type);
if (tree.getTag() == JCTree.NOT && tree.arg.type.constValue() != null) {
tree.type = cfolder.fold1(bool_not, tree.arg.type);
}
// If translated left hand side is an Apply, we are
// seeing an access method invocation. In this case, return
// that access method invocation as result.
if (isUpdateOperator && tree.arg.getTag() == JCTree.APPLY) {
result = tree.arg;
} else {
result = tree;
}
}
|
public void visitVarDef(JCVariableDecl tree) {
MethodSymbol oldMethodSym = currentMethodSym;
tree.mods = translate(tree.mods);
tree.vartype = translate(tree.vartype);
if (currentMethodSym == null) {
// A class or instance field initializer.
currentMethodSym =
new MethodSymbol((tree.mods.flags&STATIC) | BLOCK,
names.empty, null,
currentClass);
}
if (tree.init != null) tree.init = translate(tree.init, tree.type);
result = tree;
currentMethodSym = oldMethodSym;
}
|
public void visitWhileLoop(JCWhileLoop tree) {
tree.cond = translate(tree.cond, syms.booleanType);
tree.body = translate(tree.body);
result = tree;
}
|