0001: /*
0002: * Copyright 1999-2006 Sun Microsystems, Inc. All Rights Reserved.
0003: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
0004: *
0005: * This code is free software; you can redistribute it and/or modify it
0006: * under the terms of the GNU General Public License version 2 only, as
0007: * published by the Free Software Foundation. Sun designates this
0008: * particular file as subject to the "Classpath" exception as provided
0009: * by Sun in the LICENSE file that accompanied this code.
0010: *
0011: * This code is distributed in the hope that it will be useful, but WITHOUT
0012: * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
0013: * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
0014: * version 2 for more details (a copy is included in the LICENSE file that
0015: * accompanied this code).
0016: *
0017: * You should have received a copy of the GNU General Public License version
0018: * 2 along with this work; if not, write to the Free Software Foundation,
0019: * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
0020: *
0021: * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
0022: * CA 95054 USA or visit www.sun.com if you need additional information or
0023: * have any questions.
0024: */
0025:
0026: package com.sun.tools.javac.comp;
0027:
0028: import java.util.*;
0029:
0030: import com.sun.tools.javac.code.*;
0031: import com.sun.tools.javac.jvm.*;
0032: import com.sun.tools.javac.tree.*;
0033: import com.sun.tools.javac.util.*;
0034: import com.sun.tools.javac.util.JCDiagnostic.DiagnosticPosition;
0035: import com.sun.tools.javac.util.List;
0036:
0037: import com.sun.tools.javac.code.Symbol.*;
0038: import com.sun.tools.javac.tree.JCTree.*;
0039: import com.sun.tools.javac.code.Type.*;
0040:
0041: import com.sun.tools.javac.jvm.Target;
0042:
0043: import static com.sun.tools.javac.code.Flags.*;
0044: import static com.sun.tools.javac.code.Kinds.*;
0045: import static com.sun.tools.javac.code.TypeTags.*;
0046: import static com.sun.tools.javac.jvm.ByteCodes.*;
0047:
0048: /** This pass translates away some syntactic sugar: inner classes,
0049: * class literals, assertions, foreach loops, etc.
0050: *
0051: * <p><b>This is NOT part of any API supported by Sun Microsystems. If
0052: * you write code that depends on this, you do so at your own risk.
0053: * This code and its internal interfaces are subject to change or
0054: * deletion without notice.</b>
0055: */
0056: @Version("@(#)Lower.java 1.173 07/06/14")
0057: public class Lower extends TreeTranslator {
0058: protected static final Context.Key<Lower> lowerKey = new Context.Key<Lower>();
0059:
0060: public static Lower instance(Context context) {
0061: Lower instance = context.get(lowerKey);
0062: if (instance == null)
0063: instance = new Lower(context);
0064: return instance;
0065: }
0066:
0067: private Name.Table names;
0068: private Log log;
0069: private Symtab syms;
0070: private Resolve rs;
0071: private Check chk;
0072: private Attr attr;
0073: private TreeMaker make;
0074: private DiagnosticPosition make_pos;
0075: private ClassWriter writer;
0076: private ClassReader reader;
0077: private ConstFold cfolder;
0078: private Target target;
0079: private Source source;
0080: private boolean allowEnums;
0081: private final Name dollarAssertionsDisabled;
0082: private final Name classDollar;
0083: private Types types;
0084: private boolean debugLower;
0085:
0086: protected Lower(Context context) {
0087: context.put(lowerKey, this );
0088: names = Name.Table.instance(context);
0089: log = Log.instance(context);
0090: syms = Symtab.instance(context);
0091: rs = Resolve.instance(context);
0092: chk = Check.instance(context);
0093: attr = Attr.instance(context);
0094: make = TreeMaker.instance(context);
0095: writer = ClassWriter.instance(context);
0096: reader = ClassReader.instance(context);
0097: cfolder = ConstFold.instance(context);
0098: target = Target.instance(context);
0099: source = Source.instance(context);
0100: allowEnums = source.allowEnums();
0101: dollarAssertionsDisabled = names.fromString(target
0102: .syntheticNameChar()
0103: + "assertionsDisabled");
0104: classDollar = names.fromString("class"
0105: + target.syntheticNameChar());
0106:
0107: types = Types.instance(context);
0108: Options options = Options.instance(context);
0109: debugLower = options.get("debuglower") != null;
0110: }
0111:
0112: /** The currently enclosing class.
0113: */
0114: ClassSymbol currentClass;
0115:
0116: /** A queue of all translated classes.
0117: */
0118: ListBuffer<JCTree> translated;
0119:
0120: /** Environment for symbol lookup, set by translateTopLevelClass.
0121: */
0122: Env<AttrContext> attrEnv;
0123:
0124: /** A hash table mapping syntax trees to their ending source positions.
0125: */
0126: Map<JCTree, Integer> endPositions;
0127:
0128: /**************************************************************************
0129: * Global mappings
0130: *************************************************************************/
0131:
0132: /** A hash table mapping local classes to their definitions.
0133: */
0134: Map<ClassSymbol, JCClassDecl> classdefs;
0135:
0136: /** A hash table mapping virtual accessed symbols in outer subclasses
0137: * to the actually referred symbol in superclasses.
0138: */
0139: Map<Symbol, Symbol> actualSymbols;
0140:
0141: /** The current method definition.
0142: */
0143: JCMethodDecl currentMethodDef;
0144:
0145: /** The current method symbol.
0146: */
0147: MethodSymbol currentMethodSym;
0148:
0149: /** The currently enclosing outermost class definition.
0150: */
0151: JCClassDecl outermostClassDef;
0152:
0153: /** The currently enclosing outermost member definition.
0154: */
0155: JCTree outermostMemberDef;
0156:
0157: /** A navigator class for assembling a mapping from local class symbols
0158: * to class definition trees.
0159: * There is only one case; all other cases simply traverse down the tree.
0160: */
0161: class ClassMap extends TreeScanner {
0162:
0163: /** All encountered class defs are entered into classdefs table.
0164: */
0165: public void visitClassDef(JCClassDecl tree) {
0166: classdefs.put(tree.sym, tree);
0167: super .visitClassDef(tree);
0168: }
0169: }
0170:
0171: ClassMap classMap = new ClassMap();
0172:
0173: /** Map a class symbol to its definition.
0174: * @param c The class symbol of which we want to determine the definition.
0175: */
0176: JCClassDecl classDef(ClassSymbol c) {
0177: // First lookup the class in the classdefs table.
0178: JCClassDecl def = classdefs.get(c);
0179: if (def == null && outermostMemberDef != null) {
0180: // If this fails, traverse outermost member definition, entering all
0181: // local classes into classdefs, and try again.
0182: classMap.scan(outermostMemberDef);
0183: def = classdefs.get(c);
0184: }
0185: if (def == null) {
0186: // If this fails, traverse outermost class definition, entering all
0187: // local classes into classdefs, and try again.
0188: classMap.scan(outermostClassDef);
0189: def = classdefs.get(c);
0190: }
0191: return def;
0192: }
0193:
0194: /** A hash table mapping class symbols to lists of free variables.
0195: * accessed by them. Only free variables of the method immediately containing
0196: * a class are associated with that class.
0197: */
0198: Map<ClassSymbol, List<VarSymbol>> freevarCache;
0199:
0200: /** A navigator class for collecting the free variables accessed
0201: * from a local class.
0202: * There is only one case; all other cases simply traverse down the tree.
0203: */
0204: class FreeVarCollector extends TreeScanner {
0205:
0206: /** The owner of the local class.
0207: */
0208: Symbol owner;
0209:
0210: /** The local class.
0211: */
0212: ClassSymbol clazz;
0213:
0214: /** The list of owner's variables accessed from within the local class,
0215: * without any duplicates.
0216: */
0217: List<VarSymbol> fvs;
0218:
0219: FreeVarCollector(ClassSymbol clazz) {
0220: this .clazz = clazz;
0221: this .owner = clazz.owner;
0222: this .fvs = List.nil();
0223: }
0224:
0225: /** Add free variable to fvs list unless it is already there.
0226: */
0227: private void addFreeVar(VarSymbol v) {
0228: for (List<VarSymbol> l = fvs; l.nonEmpty(); l = l.tail)
0229: if (l.head == v)
0230: return;
0231: fvs = fvs.prepend(v);
0232: }
0233:
0234: /** Add all free variables of class c to fvs list
0235: * unless they are already there.
0236: */
0237: private void addFreeVars(ClassSymbol c) {
0238: List<VarSymbol> fvs = freevarCache.get(c);
0239: if (fvs != null) {
0240: for (List<VarSymbol> l = fvs; l.nonEmpty(); l = l.tail) {
0241: addFreeVar(l.head);
0242: }
0243: }
0244: }
0245:
0246: /** If tree refers to a variable in owner of local class, add it to
0247: * free variables list.
0248: */
0249: public void visitIdent(JCIdent tree) {
0250: result = tree;
0251: visitSymbol(tree.sym);
0252: }
0253:
0254: // where
0255: private void visitSymbol(Symbol _sym) {
0256: Symbol sym = _sym;
0257: if (sym.kind == VAR || sym.kind == MTH) {
0258: while (sym != null && sym.owner != owner)
0259: sym = proxies.lookup(proxyName(sym.name)).sym;
0260: if (sym != null && sym.owner == owner) {
0261: VarSymbol v = (VarSymbol) sym;
0262: if (v.getConstValue() == null) {
0263: addFreeVar(v);
0264: }
0265: } else {
0266: if (outerThisStack.head != null
0267: && outerThisStack.head != _sym)
0268: visitSymbol(outerThisStack.head);
0269: }
0270: }
0271: }
0272:
0273: /** If tree refers to a class instance creation expression
0274: * add all free variables of the freshly created class.
0275: */
0276: public void visitNewClass(JCNewClass tree) {
0277: ClassSymbol c = (ClassSymbol) tree.constructor.owner;
0278: addFreeVars(c);
0279: if (tree.encl == null && c.hasOuterInstance()
0280: && outerThisStack.head != null)
0281: visitSymbol(outerThisStack.head);
0282: super .visitNewClass(tree);
0283: }
0284:
0285: /** If tree refers to a qualified this or super expression
0286: * for anything but the current class, add the outer this
0287: * stack as a free variable.
0288: */
0289: public void visitSelect(JCFieldAccess tree) {
0290: if ((tree.name == names._this || tree.name == names._super )
0291: && tree.selected.type.tsym != clazz
0292: && outerThisStack.head != null)
0293: visitSymbol(outerThisStack.head);
0294: super .visitSelect(tree);
0295: }
0296:
0297: /** If tree refers to a superclass constructor call,
0298: * add all free variables of the superclass.
0299: */
0300: public void visitApply(JCMethodInvocation tree) {
0301: if (TreeInfo.name(tree.meth) == names._super ) {
0302: addFreeVars((ClassSymbol) TreeInfo.symbol(tree.meth).owner);
0303: Symbol constructor = TreeInfo.symbol(tree.meth);
0304: ClassSymbol c = (ClassSymbol) constructor.owner;
0305: if (c.hasOuterInstance()
0306: && tree.meth.getTag() != JCTree.SELECT
0307: && outerThisStack.head != null)
0308: visitSymbol(outerThisStack.head);
0309: }
0310: super .visitApply(tree);
0311: }
0312: }
0313:
0314: /** Return the variables accessed from within a local class, which
0315: * are declared in the local class' owner.
0316: * (in reverse order of first access).
0317: */
0318: List<VarSymbol> freevars(ClassSymbol c) {
0319: if ((c.owner.kind & (VAR | MTH)) != 0) {
0320: List<VarSymbol> fvs = freevarCache.get(c);
0321: if (fvs == null) {
0322: FreeVarCollector collector = new FreeVarCollector(c);
0323: collector.scan(classDef(c));
0324: fvs = collector.fvs;
0325: freevarCache.put(c, fvs);
0326: }
0327: return fvs;
0328: } else {
0329: return List.nil();
0330: }
0331: }
0332:
0333: Map<TypeSymbol, EnumMapping> enumSwitchMap = new LinkedHashMap<TypeSymbol, EnumMapping>();
0334:
0335: EnumMapping mapForEnum(DiagnosticPosition pos, TypeSymbol enumClass) {
0336: EnumMapping map = enumSwitchMap.get(enumClass);
0337: if (map == null)
0338: enumSwitchMap.put(enumClass, map = new EnumMapping(pos,
0339: enumClass));
0340: return map;
0341: }
0342:
0343: /** This map gives a translation table to be used for enum
0344: * switches.
0345: *
0346: * <p>For each enum that appears as the type of a switch
0347: * expression, we maintain an EnumMapping to assist in the
0348: * translation, as exemplified by the following example:
0349: *
0350: * <p>we translate
0351: * <pre>
0352: * switch(colorExpression) {
0353: * case red: stmt1;
0354: * case green: stmt2;
0355: * }
0356: * </pre>
0357: * into
0358: * <pre>
0359: * switch(Outer$0.$EnumMap$Color[colorExpression.ordinal()]) {
0360: * case 1: stmt1;
0361: * case 2: stmt2
0362: * }
0363: * </pre>
0364: * with the auxilliary table intialized as follows:
0365: * <pre>
0366: * class Outer$0 {
0367: * synthetic final int[] $EnumMap$Color = new int[Color.values().length];
0368: * static {
0369: * try { $EnumMap$Color[red.ordinal()] = 1; } catch (NoSuchFieldError ex) {}
0370: * try { $EnumMap$Color[green.ordinal()] = 2; } catch (NoSuchFieldError ex) {}
0371: * }
0372: * }
0373: * </pre>
0374: * class EnumMapping provides mapping data and support methods for this translation.
0375: */
0376: class EnumMapping {
0377: EnumMapping(DiagnosticPosition pos, TypeSymbol forEnum) {
0378: this .forEnum = forEnum;
0379: this .values = new LinkedHashMap<VarSymbol, Integer>();
0380: this .pos = pos;
0381: Name varName = names.fromString(target.syntheticNameChar()
0382: + "SwitchMap"
0383: + target.syntheticNameChar()
0384: + writer.xClassName(forEnum.type).toString()
0385: .replace('/', '.').replace('.',
0386: target.syntheticNameChar()));
0387: ClassSymbol outerCacheClass = outerCacheClass();
0388: this .mapVar = new VarSymbol(STATIC | SYNTHETIC | FINAL,
0389: varName, new ArrayType(syms.intType,
0390: syms.arrayClass), outerCacheClass);
0391: enterSynthetic(pos, mapVar, outerCacheClass.members());
0392: }
0393:
0394: DiagnosticPosition pos = null;
0395:
0396: // the next value to use
0397: int next = 1; // 0 (unused map elements) go to the default label
0398:
0399: // the enum for which this is a map
0400: final TypeSymbol forEnum;
0401:
0402: // the field containing the map
0403: final VarSymbol mapVar;
0404:
0405: // the mapped values
0406: final Map<VarSymbol, Integer> values;
0407:
0408: JCLiteral forConstant(VarSymbol v) {
0409: Integer result = values.get(v);
0410: if (result == null)
0411: values.put(v, result = next++);
0412: return make.Literal(result);
0413: }
0414:
0415: // generate the field initializer for the map
0416: void translate() {
0417: make.at(pos.getStartPosition());
0418: JCClassDecl owner = classDef((ClassSymbol) mapVar.owner);
0419:
0420: // synthetic static final int[] $SwitchMap$Color = new int[Color.values().length];
0421: MethodSymbol valuesMethod = lookupMethod(pos, names.values,
0422: forEnum.type, List.<Type> nil());
0423: JCExpression size = make // Color.values().length
0424: .Select(make.App(make.QualIdent(valuesMethod)),
0425: syms.lengthVar);
0426: JCExpression mapVarInit = make
0427: .NewArray(make.Type(syms.intType), List.of(size),
0428: null)
0429: .setType(
0430: new ArrayType(syms.intType, syms.arrayClass));
0431:
0432: // try { $SwitchMap$Color[red.ordinal()] = 1; } catch (java.lang.NoSuchFieldError ex) {}
0433: ListBuffer<JCStatement> stmts = new ListBuffer<JCStatement>();
0434: Symbol ordinalMethod = lookupMethod(pos, names.ordinal,
0435: forEnum.type, List.<Type> nil());
0436: List<JCCatch> catcher = List.<JCCatch> nil().prepend(
0437: make.Catch(make.VarDef(new VarSymbol(PARAMETER,
0438: names.ex, syms.noSuchFieldErrorType,
0439: syms.noSymbol), null), make.Block(0, List
0440: .<JCStatement> nil())));
0441: for (Map.Entry<VarSymbol, Integer> e : values.entrySet()) {
0442: VarSymbol enumerator = e.getKey();
0443: Integer mappedValue = e.getValue();
0444: JCExpression assign = make.Assign(
0445: make
0446: .Indexed(mapVar, make.App(make.Select(
0447: make.QualIdent(enumerator),
0448: ordinalMethod))),
0449: make.Literal(mappedValue))
0450: .setType(syms.intType);
0451: JCStatement exec = make.Exec(assign);
0452: JCStatement _try = make.Try(make
0453: .Block(0, List.of(exec)), catcher, null);
0454: stmts.append(_try);
0455: }
0456:
0457: owner.defs = owner.defs.prepend(
0458: make.Block(STATIC, stmts.toList())).prepend(
0459: make.VarDef(mapVar, mapVarInit));
0460: }
0461: }
0462:
0463: /**************************************************************************
0464: * Tree building blocks
0465: *************************************************************************/
0466:
0467: /** Equivalent to make.at(pos.getStartPosition()) with side effect of caching
0468: * pos as make_pos, for use in diagnostics.
0469: **/
0470: TreeMaker make_at(DiagnosticPosition pos) {
0471: make_pos = pos;
0472: return make.at(pos);
0473: }
0474:
0475: /** Make an attributed tree representing a literal. This will be an
0476: * Ident node in the case of boolean literals, a Literal node in all
0477: * other cases.
0478: * @param type The literal's type.
0479: * @param value The literal's value.
0480: */
0481: JCExpression makeLit(Type type, Object value) {
0482: return make.Literal(type.tag, value).setType(
0483: type.constType(value));
0484: }
0485:
0486: /** Make an attributed tree representing null.
0487: */
0488: JCExpression makeNull() {
0489: return makeLit(syms.botType, null);
0490: }
0491:
0492: /** Make an attributed class instance creation expression.
0493: * @param ctype The class type.
0494: * @param args The constructor arguments.
0495: */
0496: JCNewClass makeNewClass(Type ctype, List<JCExpression> args) {
0497: JCNewClass tree = make.NewClass(null, null, make
0498: .QualIdent(ctype.tsym), args, null);
0499: tree.constructor = rs.resolveConstructor(make_pos, attrEnv,
0500: ctype, TreeInfo.types(args), null, false, false);
0501: tree.type = ctype;
0502: return tree;
0503: }
0504:
0505: /** Make an attributed unary expression.
0506: * @param optag The operators tree tag.
0507: * @param arg The operator's argument.
0508: */
0509: JCUnary makeUnary(int optag, JCExpression arg) {
0510: JCUnary tree = make.Unary(optag, arg);
0511: tree.operator = rs.resolveUnaryOperator(make_pos, optag,
0512: attrEnv, arg.type);
0513: tree.type = tree.operator.type.getReturnType();
0514: return tree;
0515: }
0516:
0517: /** Make an attributed binary expression.
0518: * @param optag The operators tree tag.
0519: * @param lhs The operator's left argument.
0520: * @param rhs The operator's right argument.
0521: */
0522: JCBinary makeBinary(int optag, JCExpression lhs, JCExpression rhs) {
0523: JCBinary tree = make.Binary(optag, lhs, rhs);
0524: tree.operator = rs.resolveBinaryOperator(make_pos, optag,
0525: attrEnv, lhs.type, rhs.type);
0526: tree.type = tree.operator.type.getReturnType();
0527: return tree;
0528: }
0529:
0530: /** Make an attributed assignop expression.
0531: * @param optag The operators tree tag.
0532: * @param lhs The operator's left argument.
0533: * @param rhs The operator's right argument.
0534: */
0535: JCAssignOp makeAssignop(int optag, JCTree lhs, JCTree rhs) {
0536: JCAssignOp tree = make.Assignop(optag, lhs, rhs);
0537: tree.operator = rs.resolveBinaryOperator(make_pos, tree
0538: .getTag()
0539: - JCTree.ASGOffset, attrEnv, lhs.type, rhs.type);
0540: tree.type = lhs.type;
0541: return tree;
0542: }
0543:
0544: /** Convert tree into string object, unless it has already a
0545: * reference type..
0546: */
0547: JCExpression makeString(JCExpression tree) {
0548: if (tree.type.tag >= CLASS) {
0549: return tree;
0550: } else {
0551: Symbol valueOfSym = lookupMethod(tree.pos(), names.valueOf,
0552: syms.stringType, List.of(tree.type));
0553: return make.App(make.QualIdent(valueOfSym), List.of(tree));
0554: }
0555: }
0556:
0557: /** Create an empty anonymous class definition and enter and complete
0558: * its symbol. Return the class definition's symbol.
0559: * and create
0560: * @param flags The class symbol's flags
0561: * @param owner The class symbol's owner
0562: */
0563: ClassSymbol makeEmptyClass(long flags, ClassSymbol owner) {
0564: // Create class symbol.
0565: ClassSymbol c = reader.defineClass(names.empty, owner);
0566: c.flatname = chk.localClassName(c);
0567: c.sourcefile = owner.sourcefile;
0568: c.completer = null;
0569: c.members_field = new Scope(c);
0570: c.flags_field = flags;
0571: ClassType ctype = (ClassType) c.type;
0572: ctype.super type_field = syms.objectType;
0573: ctype.interfaces_field = List.nil();
0574:
0575: JCClassDecl odef = classDef(owner);
0576:
0577: // Enter class symbol in owner scope and compiled table.
0578: enterSynthetic(odef.pos(), c, owner.members());
0579: chk.compiled.put(c.flatname, c);
0580:
0581: // Create class definition tree.
0582: JCClassDecl cdef = make.ClassDef(make.Modifiers(flags),
0583: names.empty, List.<JCTypeParameter> nil(), null, List
0584: .<JCExpression> nil(), List.<JCTree> nil());
0585: cdef.sym = c;
0586: cdef.type = c.type;
0587:
0588: // Append class definition tree to owner's definitions.
0589: odef.defs = odef.defs.prepend(cdef);
0590:
0591: return c;
0592: }
0593:
0594: /**************************************************************************
0595: * Symbol manipulation utilities
0596: *************************************************************************/
0597:
0598: /** Report a conflict between a user symbol and a synthetic symbol.
0599: */
0600: private void duplicateError(DiagnosticPosition pos, Symbol sym) {
0601: if (!sym.type.isErroneous()) {
0602: log.error(pos, "synthetic.name.conflict", sym, sym
0603: .location());
0604: }
0605: }
0606:
0607: /** Enter a synthetic symbol in a given scope, but complain if there was already one there.
0608: * @param pos Position for error reporting.
0609: * @param sym The symbol.
0610: * @param s The scope.
0611: */
0612: private void enterSynthetic(DiagnosticPosition pos, Symbol sym,
0613: Scope s) {
0614: if (sym.name != names.error && sym.name != names.empty) {
0615: for (Scope.Entry e = s.lookup(sym.name); e.scope == s; e = e
0616: .next()) {
0617: if (sym != e.sym && sym.kind == e.sym.kind) {
0618: // VM allows methods and variables with differing types
0619: if ((sym.kind & (MTH | VAR)) != 0
0620: && !types.erasure(sym.type).equals(
0621: types.erasure(e.sym.type)))
0622: continue;
0623: duplicateError(pos, e.sym);
0624: break;
0625: }
0626: }
0627: }
0628: s.enter(sym);
0629: }
0630:
0631: /** Look up a synthetic name in a given scope.
0632: * @param scope The scope.
0633: * @param name The name.
0634: */
0635: private Symbol lookupSynthetic(Name name, Scope s) {
0636: Symbol sym = s.lookup(name).sym;
0637: return (sym == null || (sym.flags() & SYNTHETIC) == 0) ? null
0638: : sym;
0639: }
0640:
0641: /** Look up a method in a given scope.
0642: */
0643: private MethodSymbol lookupMethod(DiagnosticPosition pos,
0644: Name name, Type qual, List<Type> args) {
0645: return rs.resolveInternalMethod(pos, attrEnv, qual, name, args,
0646: null);
0647: }
0648:
0649: /** Look up a constructor.
0650: */
0651: private MethodSymbol lookupConstructor(DiagnosticPosition pos,
0652: Type qual, List<Type> args) {
0653: return rs.resolveInternalConstructor(pos, attrEnv, qual, args,
0654: null);
0655: }
0656:
0657: /** Look up a field.
0658: */
0659: private VarSymbol lookupField(DiagnosticPosition pos, Type qual,
0660: Name name) {
0661: return rs.resolveInternalField(pos, attrEnv, qual, name);
0662: }
0663:
0664: /**************************************************************************
0665: * Access methods
0666: *************************************************************************/
0667:
0668: /** Access codes for dereferencing, assignment,
0669: * and pre/post increment/decrement.
0670: * Access codes for assignment operations are determined by method accessCode
0671: * below.
0672: *
0673: * All access codes for accesses to the current class are even.
0674: * If a member of the superclass should be accessed instead (because
0675: * access was via a qualified super), add one to the corresponding code
0676: * for the current class, making the number odd.
0677: * This numbering scheme is used by the backend to decide whether
0678: * to issue an invokevirtual or invokespecial call.
0679: *
0680: * @see Gen.visitSelect(Select tree)
0681: */
0682: private static final int DEREFcode = 0, ASSIGNcode = 2,
0683: PREINCcode = 4, PREDECcode = 6, POSTINCcode = 8,
0684: POSTDECcode = 10, FIRSTASGOPcode = 12;
0685:
0686: /** Number of access codes
0687: */
0688: private static final int NCODES = accessCode(ByteCodes.lushrl) + 2;
0689:
0690: /** A mapping from symbols to their access numbers.
0691: */
0692: private Map<Symbol, Integer> accessNums;
0693:
0694: /** A mapping from symbols to an array of access symbols, indexed by
0695: * access code.
0696: */
0697: private Map<Symbol, MethodSymbol[]> accessSyms;
0698:
0699: /** A mapping from (constructor) symbols to access constructor symbols.
0700: */
0701: private Map<Symbol, MethodSymbol> accessConstrs;
0702:
0703: /** A queue for all accessed symbols.
0704: */
0705: private ListBuffer<Symbol> accessed;
0706:
0707: /** Map bytecode of binary operation to access code of corresponding
0708: * assignment operation. This is always an even number.
0709: */
0710: private static int accessCode(int bytecode) {
0711: if (ByteCodes.iadd <= bytecode && bytecode <= ByteCodes.lxor)
0712: return (bytecode - iadd) * 2 + FIRSTASGOPcode;
0713: else if (bytecode == ByteCodes.string_add)
0714: return (ByteCodes.lxor + 1 - iadd) * 2 + FIRSTASGOPcode;
0715: else if (ByteCodes.ishll <= bytecode
0716: && bytecode <= ByteCodes.lushrl)
0717: return (bytecode - ishll + ByteCodes.lxor + 2 - iadd) * 2
0718: + FIRSTASGOPcode;
0719: else
0720: return -1;
0721: }
0722:
0723: /** return access code for identifier,
0724: * @param tree The tree representing the identifier use.
0725: * @param enclOp The closest enclosing operation node of tree,
0726: * null if tree is not a subtree of an operation.
0727: */
0728: private static int accessCode(JCTree tree, JCTree enclOp) {
0729: if (enclOp == null)
0730: return DEREFcode;
0731: else if (enclOp.getTag() == JCTree.ASSIGN
0732: && tree == TreeInfo.skipParens(((JCAssign) enclOp).lhs))
0733: return ASSIGNcode;
0734: else if (JCTree.PREINC <= enclOp.getTag()
0735: && enclOp.getTag() <= JCTree.POSTDEC
0736: && tree == TreeInfo.skipParens(((JCUnary) enclOp).arg))
0737: return (enclOp.getTag() - JCTree.PREINC) * 2 + PREINCcode;
0738: else if (JCTree.BITOR_ASG <= enclOp.getTag()
0739: && enclOp.getTag() <= JCTree.MOD_ASG
0740: && tree == TreeInfo
0741: .skipParens(((JCAssignOp) enclOp).lhs))
0742: return accessCode(((OperatorSymbol) ((JCAssignOp) enclOp).operator).opcode);
0743: else
0744: return DEREFcode;
0745: }
0746:
0747: /** Return binary operator that corresponds to given access code.
0748: */
0749: private OperatorSymbol binaryAccessOperator(int acode) {
0750: for (Scope.Entry e = syms.predefClass.members().elems; e != null; e = e.sibling) {
0751: if (e.sym instanceof OperatorSymbol) {
0752: OperatorSymbol op = (OperatorSymbol) e.sym;
0753: if (accessCode(op.opcode) == acode)
0754: return op;
0755: }
0756: }
0757: return null;
0758: }
0759:
0760: /** Return tree tag for assignment operation corresponding
0761: * to given binary operator.
0762: */
0763: private static int treeTag(OperatorSymbol operator) {
0764: switch (operator.opcode) {
0765: case ByteCodes.ior:
0766: case ByteCodes.lor:
0767: return JCTree.BITOR_ASG;
0768: case ByteCodes.ixor:
0769: case ByteCodes.lxor:
0770: return JCTree.BITXOR_ASG;
0771: case ByteCodes.iand:
0772: case ByteCodes.land:
0773: return JCTree.BITAND_ASG;
0774: case ByteCodes.ishl:
0775: case ByteCodes.lshl:
0776: case ByteCodes.ishll:
0777: case ByteCodes.lshll:
0778: return JCTree.SL_ASG;
0779: case ByteCodes.ishr:
0780: case ByteCodes.lshr:
0781: case ByteCodes.ishrl:
0782: case ByteCodes.lshrl:
0783: return JCTree.SR_ASG;
0784: case ByteCodes.iushr:
0785: case ByteCodes.lushr:
0786: case ByteCodes.iushrl:
0787: case ByteCodes.lushrl:
0788: return JCTree.USR_ASG;
0789: case ByteCodes.iadd:
0790: case ByteCodes.ladd:
0791: case ByteCodes.fadd:
0792: case ByteCodes.dadd:
0793: case ByteCodes.string_add:
0794: return JCTree.PLUS_ASG;
0795: case ByteCodes.isub:
0796: case ByteCodes.lsub:
0797: case ByteCodes.fsub:
0798: case ByteCodes.dsub:
0799: return JCTree.MINUS_ASG;
0800: case ByteCodes.imul:
0801: case ByteCodes.lmul:
0802: case ByteCodes.fmul:
0803: case ByteCodes.dmul:
0804: return JCTree.MUL_ASG;
0805: case ByteCodes.idiv:
0806: case ByteCodes.ldiv:
0807: case ByteCodes.fdiv:
0808: case ByteCodes.ddiv:
0809: return JCTree.DIV_ASG;
0810: case ByteCodes.imod:
0811: case ByteCodes.lmod:
0812: case ByteCodes.fmod:
0813: case ByteCodes.dmod:
0814: return JCTree.MOD_ASG;
0815: default:
0816: throw new AssertionError();
0817: }
0818: }
0819:
0820: /** The name of the access method with number `anum' and access code `acode'.
0821: */
0822: Name accessName(int anum, int acode) {
0823: return names.fromString("access" + target.syntheticNameChar()
0824: + anum + acode / 10 + acode % 10);
0825: }
0826:
0827: /** Return access symbol for a private or protected symbol from an inner class.
0828: * @param sym The accessed private symbol.
0829: * @param tree The accessing tree.
0830: * @param enclOp The closest enclosing operation node of tree,
0831: * null if tree is not a subtree of an operation.
0832: * @param protAccess Is access to a protected symbol in another
0833: * package?
0834: * @param refSuper Is access via a (qualified) C.super?
0835: */
0836: MethodSymbol accessSymbol(Symbol sym, JCTree tree, JCTree enclOp,
0837: boolean protAccess, boolean refSuper) {
0838: ClassSymbol accOwner = refSuper && protAccess
0839: // For access via qualified super (T.super.x), place the
0840: // access symbol on T.
0841: ? (ClassSymbol) ((JCFieldAccess) tree).selected.type.tsym
0842: // Otherwise pretend that the owner of an accessed
0843: // protected symbol is the enclosing class of the current
0844: // class which is a subclass of the symbol's owner.
0845: : accessClass(sym, protAccess, tree);
0846:
0847: Symbol vsym = sym;
0848: if (sym.owner != accOwner) {
0849: vsym = sym.clone(accOwner);
0850: actualSymbols.put(vsym, sym);
0851: }
0852:
0853: Integer anum // The access number of the access method.
0854: = accessNums.get(vsym);
0855: if (anum == null) {
0856: anum = accessed.length();
0857: accessNums.put(vsym, anum);
0858: accessSyms.put(vsym, new MethodSymbol[NCODES]);
0859: accessed.append(vsym);
0860: // System.out.println("accessing " + vsym + " in " + vsym.location());
0861: }
0862:
0863: int acode; // The access code of the access method.
0864: List<Type> argtypes; // The argument types of the access method.
0865: Type restype; // The result type of the access method.
0866: List<Type> thrown; // The thrown execeptions of the access method.
0867: switch (vsym.kind) {
0868: case VAR:
0869: acode = accessCode(tree, enclOp);
0870: if (acode >= FIRSTASGOPcode) {
0871: OperatorSymbol operator = binaryAccessOperator(acode);
0872: if (operator.opcode == string_add)
0873: argtypes = List.of(syms.objectType);
0874: else
0875: argtypes = operator.type.getParameterTypes().tail;
0876: } else if (acode == ASSIGNcode)
0877: argtypes = List.of(vsym.erasure(types));
0878: else
0879: argtypes = List.nil();
0880: restype = vsym.erasure(types);
0881: thrown = List.nil();
0882: break;
0883: case MTH:
0884: acode = DEREFcode;
0885: argtypes = vsym.erasure(types).getParameterTypes();
0886: restype = vsym.erasure(types).getReturnType();
0887: thrown = vsym.type.getThrownTypes();
0888: break;
0889: default:
0890: throw new AssertionError();
0891: }
0892:
0893: // For references via qualified super, increment acode by one,
0894: // making it odd.
0895: if (protAccess && refSuper)
0896: acode++;
0897:
0898: // Instance access methods get instance as first parameter.
0899: // For protected symbols this needs to be the instance as a member
0900: // of the type containing the accessed symbol, not the class
0901: // containing the access method.
0902: if ((vsym.flags() & STATIC) == 0) {
0903: argtypes = argtypes.prepend(vsym.owner.erasure(types));
0904: }
0905: MethodSymbol[] accessors = accessSyms.get(vsym);
0906: MethodSymbol accessor = accessors[acode];
0907: if (accessor == null) {
0908: accessor = new MethodSymbol(STATIC | SYNTHETIC, accessName(
0909: anum.intValue(), acode), new MethodType(argtypes,
0910: restype, thrown, syms.methodClass), accOwner);
0911: enterSynthetic(tree.pos(), accessor, accOwner.members());
0912: accessors[acode] = accessor;
0913: }
0914: return accessor;
0915: }
0916:
0917: /** The qualifier to be used for accessing a symbol in an outer class.
0918: * This is either C.sym or C.this.sym, depending on whether or not
0919: * sym is static.
0920: * @param sym The accessed symbol.
0921: */
0922: JCExpression accessBase(DiagnosticPosition pos, Symbol sym) {
0923: return (sym.flags() & STATIC) != 0 ? access(make.at(
0924: pos.getStartPosition()).QualIdent(sym.owner))
0925: : makeOwnerThis(pos, sym, true);
0926: }
0927:
0928: /** Do we need an access method to reference private symbol?
0929: */
0930: boolean needsPrivateAccess(Symbol sym) {
0931: if ((sym.flags() & PRIVATE) == 0 || sym.owner == currentClass) {
0932: return false;
0933: } else if (sym.name == names.init
0934: && (sym.owner.owner.kind & (VAR | MTH)) != 0) {
0935: // private constructor in local class: relax protection
0936: sym.flags_field &= ~PRIVATE;
0937: return false;
0938: } else {
0939: return true;
0940: }
0941: }
0942:
0943: /** Do we need an access method to reference symbol in other package?
0944: */
0945: boolean needsProtectedAccess(Symbol sym, JCTree tree) {
0946: if ((sym.flags() & PROTECTED) == 0
0947: || sym.owner.owner == currentClass.owner || // fast special case
0948: sym.packge() == currentClass.packge())
0949: return false;
0950: if (!currentClass.isSubClass(sym.owner, types))
0951: return true;
0952: if ((sym.flags() & STATIC) != 0
0953: || tree.getTag() != JCTree.SELECT
0954: || TreeInfo.name(((JCFieldAccess) tree).selected) == names._super )
0955: return false;
0956: return !((JCFieldAccess) tree).selected.type.tsym.isSubClass(
0957: currentClass, types);
0958: }
0959:
0960: /** The class in which an access method for given symbol goes.
0961: * @param sym The access symbol
0962: * @param protAccess Is access to a protected symbol in another
0963: * package?
0964: */
0965: ClassSymbol accessClass(Symbol sym, boolean protAccess, JCTree tree) {
0966: if (protAccess) {
0967: Symbol qualifier = null;
0968: ClassSymbol c = currentClass;
0969: if (tree.getTag() == JCTree.SELECT
0970: && (sym.flags() & STATIC) == 0) {
0971: qualifier = ((JCFieldAccess) tree).selected.type.tsym;
0972: while (!qualifier.isSubClass(c, types)) {
0973: c = c.owner.enclClass();
0974: }
0975: return c;
0976: } else {
0977: while (!c.isSubClass(sym.owner, types)) {
0978: c = c.owner.enclClass();
0979: }
0980: }
0981: return c;
0982: } else {
0983: // the symbol is private
0984: return sym.owner.enclClass();
0985: }
0986: }
0987:
0988: /** Ensure that identifier is accessible, return tree accessing the identifier.
0989: * @param sym The accessed symbol.
0990: * @param tree The tree referring to the symbol.
0991: * @param enclOp The closest enclosing operation node of tree,
0992: * null if tree is not a subtree of an operation.
0993: * @param refSuper Is access via a (qualified) C.super?
0994: */
0995: JCExpression access(Symbol sym, JCExpression tree,
0996: JCExpression enclOp, boolean refSuper) {
0997: // Access a free variable via its proxy, or its proxy's proxy
0998: while (sym.kind == VAR && sym.owner.kind == MTH
0999: && sym.owner.enclClass() != currentClass) {
1000: // A constant is replaced by its constant value.
1001: Object cv = ((VarSymbol) sym).getConstValue();
1002: if (cv != null) {
1003: make.at(tree.pos);
1004: return makeLit(sym.type, cv);
1005: }
1006: // Otherwise replace the variable by its proxy.
1007: sym = proxies.lookup(proxyName(sym.name)).sym;
1008: assert sym != null && (sym.flags_field & FINAL) != 0;
1009: tree = make.at(tree.pos).Ident(sym);
1010: }
1011: JCExpression base = (tree.getTag() == JCTree.SELECT) ? ((JCFieldAccess) tree).selected
1012: : null;
1013: switch (sym.kind) {
1014: case TYP:
1015: if (sym.owner.kind != PCK) {
1016: // Convert type idents to
1017: // <flat name> or <package name> . <flat name>
1018: Name flatname = Convert.shortName(sym.flatName());
1019: while (base != null && TreeInfo.symbol(base) != null
1020: && TreeInfo.symbol(base).kind != PCK) {
1021: base = (base.getTag() == JCTree.SELECT) ? ((JCFieldAccess) base).selected
1022: : null;
1023: }
1024: if (tree.getTag() == JCTree.IDENT) {
1025: ((JCIdent) tree).name = flatname;
1026: } else if (base == null) {
1027: tree = make.at(tree.pos).Ident(sym);
1028: ((JCIdent) tree).name = flatname;
1029: } else {
1030: ((JCFieldAccess) tree).selected = base;
1031: ((JCFieldAccess) tree).name = flatname;
1032: }
1033: }
1034: break;
1035: case MTH:
1036: case VAR:
1037: if (sym.owner.kind == TYP) {
1038:
1039: // Access methods are required for
1040: // - private members,
1041: // - protected members in a superclass of an
1042: // enclosing class contained in another package.
1043: // - all non-private members accessed via a qualified super.
1044: boolean protAccess = refSuper
1045: && !needsPrivateAccess(sym)
1046: || needsProtectedAccess(sym, tree);
1047: boolean accReq = protAccess || needsPrivateAccess(sym);
1048:
1049: // A base has to be supplied for
1050: // - simple identifiers accessing variables in outer classes.
1051: boolean baseReq = base == null
1052: && sym.owner != syms.predefClass
1053: && !sym.isMemberOf(currentClass, types);
1054:
1055: if (accReq || baseReq) {
1056: make.at(tree.pos);
1057:
1058: // Constants are replaced by their constant value.
1059: if (sym.kind == VAR) {
1060: Object cv = ((VarSymbol) sym).getConstValue();
1061: if (cv != null)
1062: return makeLit(sym.type, cv);
1063: }
1064:
1065: // Private variables and methods are replaced by calls
1066: // to their access methods.
1067: if (accReq) {
1068: List<JCExpression> args = List.nil();
1069: if ((sym.flags() & STATIC) == 0) {
1070: // Instance access methods get instance
1071: // as first parameter.
1072: if (base == null)
1073: base = makeOwnerThis(tree.pos(), sym,
1074: true);
1075: args = args.prepend(base);
1076: base = null; // so we don't duplicate code
1077: }
1078: Symbol access = accessSymbol(sym, tree, enclOp,
1079: protAccess, refSuper);
1080: JCExpression receiver = make.Select(
1081: base != null ? base : make
1082: .QualIdent(access.owner),
1083: access);
1084: return make.App(receiver, args);
1085:
1086: // Other accesses to members of outer classes get a
1087: // qualifier.
1088: } else if (baseReq) {
1089: return make.at(tree.pos).Select(
1090: accessBase(tree.pos(), sym), sym)
1091: .setType(tree.type);
1092: }
1093: }
1094: }
1095: }
1096: return tree;
1097: }
1098:
1099: /** Ensure that identifier is accessible, return tree accessing the identifier.
1100: * @param tree The identifier tree.
1101: */
1102: JCExpression access(JCExpression tree) {
1103: Symbol sym = TreeInfo.symbol(tree);
1104: return sym == null ? tree : access(sym, tree, null, false);
1105: }
1106:
1107: /** Return access constructor for a private constructor,
1108: * or the constructor itself, if no access constructor is needed.
1109: * @param pos The position to report diagnostics, if any.
1110: * @param constr The private constructor.
1111: */
1112: Symbol accessConstructor(DiagnosticPosition pos, Symbol constr) {
1113: if (needsPrivateAccess(constr)) {
1114: ClassSymbol accOwner = constr.owner.enclClass();
1115: MethodSymbol aconstr = accessConstrs.get(constr);
1116: if (aconstr == null) {
1117: List<Type> argtypes = constr.type.getParameterTypes();
1118: if ((accOwner.flags_field & ENUM) != 0)
1119: argtypes = argtypes.prepend(syms.intType).prepend(
1120: syms.stringType);
1121: aconstr = new MethodSymbol(SYNTHETIC, names.init,
1122: new MethodType(argtypes
1123: .append(accessConstructorTag().erasure(
1124: types)), constr.type
1125: .getReturnType(), constr.type
1126: .getThrownTypes(), syms.methodClass),
1127: accOwner);
1128: enterSynthetic(pos, aconstr, accOwner.members());
1129: accessConstrs.put(constr, aconstr);
1130: accessed.append(constr);
1131: }
1132: return aconstr;
1133: } else {
1134: return constr;
1135: }
1136: }
1137:
1138: /** Return an anonymous class nested in this toplevel class.
1139: */
1140: ClassSymbol accessConstructorTag() {
1141: ClassSymbol topClass = currentClass.outermostClass();
1142: Name flatname = names.fromString(""
1143: + topClass.getQualifiedName()
1144: + target.syntheticNameChar() + "1");
1145: ClassSymbol ctag = chk.compiled.get(flatname);
1146: if (ctag == null)
1147: ctag = makeEmptyClass(STATIC | SYNTHETIC, topClass);
1148: return ctag;
1149: }
1150:
1151: /** Add all required access methods for a private symbol to enclosing class.
1152: * @param sym The symbol.
1153: */
1154: void makeAccessible(Symbol sym) {
1155: JCClassDecl cdef = classDef(sym.owner.enclClass());
1156: assert cdef != null : "class def not found: " + sym + " in "
1157: + sym.owner;
1158: if (sym.name == names.init) {
1159: cdef.defs = cdef.defs.prepend(accessConstructorDef(
1160: cdef.pos, sym, accessConstrs.get(sym)));
1161: } else {
1162: MethodSymbol[] accessors = accessSyms.get(sym);
1163: for (int i = 0; i < NCODES; i++) {
1164: if (accessors[i] != null)
1165: cdef.defs = cdef.defs.prepend(accessDef(cdef.pos,
1166: sym, accessors[i], i));
1167: }
1168: }
1169: }
1170:
1171: /** Construct definition of an access method.
1172: * @param pos The source code position of the definition.
1173: * @param vsym The private or protected symbol.
1174: * @param accessor The access method for the symbol.
1175: * @param acode The access code.
1176: */
1177: JCTree accessDef(int pos, Symbol vsym, MethodSymbol accessor,
1178: int acode) {
1179: // System.err.println("access " + vsym + " with " + accessor);//DEBUG
1180: currentClass = vsym.owner.enclClass();
1181: make.at(pos);
1182: JCMethodDecl md = make.MethodDef(accessor, null);
1183:
1184: // Find actual symbol
1185: Symbol sym = actualSymbols.get(vsym);
1186: if (sym == null)
1187: sym = vsym;
1188:
1189: JCExpression ref; // The tree referencing the private symbol.
1190: List<JCExpression> args; // Any additional arguments to be passed along.
1191: if ((sym.flags() & STATIC) != 0) {
1192: ref = make.Ident(sym);
1193: args = make.Idents(md.params);
1194: } else {
1195: ref = make.Select(make.Ident(md.params.head), sym);
1196: args = make.Idents(md.params.tail);
1197: }
1198: JCStatement stat; // The statement accessing the private symbol.
1199: if (sym.kind == VAR) {
1200: // Normalize out all odd access codes by taking floor modulo 2:
1201: int acode1 = acode - (acode & 1);
1202:
1203: JCExpression expr; // The access method's return value.
1204: switch (acode1) {
1205: case DEREFcode:
1206: expr = ref;
1207: break;
1208: case ASSIGNcode:
1209: expr = make.Assign(ref, args.head);
1210: break;
1211: case PREINCcode:
1212: case POSTINCcode:
1213: case PREDECcode:
1214: case POSTDECcode:
1215: expr = makeUnary(((acode1 - PREINCcode) >> 1)
1216: + JCTree.PREINC, ref);
1217: break;
1218: default:
1219: expr = make.Assignop(
1220: treeTag(binaryAccessOperator(acode1)), ref,
1221: args.head);
1222: ((JCAssignOp) expr).operator = binaryAccessOperator(acode1);
1223: }
1224: stat = make.Return(expr.setType(sym.type));
1225: } else {
1226: stat = make.Call(make.App(ref, args));
1227: }
1228: md.body = make.Block(0, List.of(stat));
1229:
1230: // Make sure all parameters, result types and thrown exceptions
1231: // are accessible.
1232: for (List<JCVariableDecl> l = md.params; l.nonEmpty(); l = l.tail)
1233: l.head.vartype = access(l.head.vartype);
1234: md.restype = access(md.restype);
1235: for (List<JCExpression> l = md.thrown; l.nonEmpty(); l = l.tail)
1236: l.head = access(l.head);
1237:
1238: return md;
1239: }
1240:
1241: /** Construct definition of an access constructor.
1242: * @param pos The source code position of the definition.
1243: * @param constr The private constructor.
1244: * @param accessor The access method for the constructor.
1245: */
1246: JCTree accessConstructorDef(int pos, Symbol constr,
1247: MethodSymbol accessor) {
1248: make.at(pos);
1249: JCMethodDecl md = make.MethodDef(accessor, accessor
1250: .externalType(types), null);
1251: JCIdent callee = make.Ident(names._this );
1252: callee.sym = constr;
1253: callee.type = constr.type;
1254: md.body = make.Block(0, List.<JCStatement> of(make.Call(make
1255: .App(callee, make.Idents(md.params.reverse().tail
1256: .reverse())))));
1257: return md;
1258: }
1259:
1260: /**************************************************************************
1261: * Free variables proxies and this$n
1262: *************************************************************************/
1263:
1264: /** A scope containing all free variable proxies for currently translated
1265: * class, as well as its this$n symbol (if needed).
1266: * Proxy scopes are nested in the same way classes are.
1267: * Inside a constructor, proxies and any this$n symbol are duplicated
1268: * in an additional innermost scope, where they represent the constructor
1269: * parameters.
1270: */
1271: Scope proxies;
1272:
1273: /** A stack containing the this$n field of the currently translated
1274: * classes (if needed) in innermost first order.
1275: * Inside a constructor, proxies and any this$n symbol are duplicated
1276: * in an additional innermost scope, where they represent the constructor
1277: * parameters.
1278: */
1279: List<VarSymbol> outerThisStack;
1280:
1281: /** The name of a free variable proxy.
1282: */
1283: Name proxyName(Name name) {
1284: return names.fromString("val" + target.syntheticNameChar()
1285: + name);
1286: }
1287:
1288: /** Proxy definitions for all free variables in given list, in reverse order.
1289: * @param pos The source code position of the definition.
1290: * @param freevars The free variables.
1291: * @param owner The class in which the definitions go.
1292: */
1293: List<JCVariableDecl> freevarDefs(int pos, List<VarSymbol> freevars,
1294: Symbol owner) {
1295: long flags = FINAL | SYNTHETIC;
1296: if (owner.kind == TYP && target.usePrivateSyntheticFields())
1297: flags |= PRIVATE;
1298: List<JCVariableDecl> defs = List.nil();
1299: for (List<VarSymbol> l = freevars; l.nonEmpty(); l = l.tail) {
1300: VarSymbol v = l.head;
1301: VarSymbol proxy = new VarSymbol(flags, proxyName(v.name), v
1302: .erasure(types), owner);
1303: proxies.enter(proxy);
1304: JCVariableDecl vd = make.at(pos).VarDef(proxy, null);
1305: vd.vartype = access(vd.vartype);
1306: defs = defs.prepend(vd);
1307: }
1308: return defs;
1309: }
1310:
1311: /** The name of a this$n field
1312: * @param type The class referenced by the this$n field
1313: */
1314: Name outerThisName(Type type, Symbol owner) {
1315: Type t = type.getEnclosingType();
1316: int nestingLevel = 0;
1317: while (t.tag == CLASS) {
1318: t = t.getEnclosingType();
1319: nestingLevel++;
1320: }
1321: Name result = names.fromString("this"
1322: + target.syntheticNameChar() + nestingLevel);
1323: while (owner.kind == TYP
1324: && ((ClassSymbol) owner).members().lookup(result).scope != null)
1325: result = names.fromString(result.toString()
1326: + target.syntheticNameChar());
1327: return result;
1328: }
1329:
1330: /** Definition for this$n field.
1331: * @param pos The source code position of the definition.
1332: * @param owner The class in which the definition goes.
1333: */
1334: JCVariableDecl outerThisDef(int pos, Symbol owner) {
1335: long flags = FINAL | SYNTHETIC;
1336: if (owner.kind == TYP && target.usePrivateSyntheticFields())
1337: flags |= PRIVATE;
1338: Type target = types.erasure(owner.enclClass().type
1339: .getEnclosingType());
1340: VarSymbol outerThis = new VarSymbol(flags, outerThisName(
1341: target, owner), target, owner);
1342: outerThisStack = outerThisStack.prepend(outerThis);
1343: JCVariableDecl vd = make.at(pos).VarDef(outerThis, null);
1344: vd.vartype = access(vd.vartype);
1345: return vd;
1346: }
1347:
1348: /** Return a list of trees that load the free variables in given list,
1349: * in reverse order.
1350: * @param pos The source code position to be used for the trees.
1351: * @param freevars The list of free variables.
1352: */
1353: List<JCExpression> loadFreevars(DiagnosticPosition pos,
1354: List<VarSymbol> freevars) {
1355: List<JCExpression> args = List.nil();
1356: for (List<VarSymbol> l = freevars; l.nonEmpty(); l = l.tail)
1357: args = args.prepend(loadFreevar(pos, l.head));
1358: return args;
1359: }
1360:
1361: //where
1362: JCExpression loadFreevar(DiagnosticPosition pos, VarSymbol v) {
1363: return access(v, make.at(pos).Ident(v), null, false);
1364: }
1365:
1366: /** Construct a tree simulating the expression <C.this>.
1367: * @param pos The source code position to be used for the tree.
1368: * @param c The qualifier class.
1369: */
1370: JCExpression makeThis(DiagnosticPosition pos, TypeSymbol c) {
1371: if (currentClass == c) {
1372: // in this case, `this' works fine
1373: return make.at(pos).This(c.erasure(types));
1374: } else {
1375: // need to go via this$n
1376: return makeOuterThis(pos, c);
1377: }
1378: }
1379:
1380: /** Construct a tree that represents the outer instance
1381: * <C.this>. Never pick the current `this'.
1382: * @param pos The source code position to be used for the tree.
1383: * @param c The qualifier class.
1384: */
1385: JCExpression makeOuterThis(DiagnosticPosition pos, TypeSymbol c) {
1386: List<VarSymbol> ots = outerThisStack;
1387: if (ots.isEmpty()) {
1388: log.error(pos, "no.encl.instance.of.type.in.scope", c);
1389: assert false;
1390: return makeNull();
1391: }
1392: VarSymbol ot = ots.head;
1393: JCExpression tree = access(make.at(pos).Ident(ot));
1394: TypeSymbol otc = ot.type.tsym;
1395: while (otc != c) {
1396: do {
1397: ots = ots.tail;
1398: if (ots.isEmpty()) {
1399: log.error(pos, "no.encl.instance.of.type.in.scope",
1400: c);
1401: assert false; // should have been caught in Attr
1402: return tree;
1403: }
1404: ot = ots.head;
1405: } while (ot.owner != otc);
1406: if (otc.owner.kind != PCK && !otc.hasOuterInstance()) {
1407: chk.earlyRefError(pos, c);
1408: assert false; // should have been caught in Attr
1409: return makeNull();
1410: }
1411: tree = access(make.at(pos).Select(tree, ot));
1412: otc = ot.type.tsym;
1413: }
1414: return tree;
1415: }
1416:
1417: /** Construct a tree that represents the closest outer instance
1418: * <C.this> such that the given symbol is a member of C.
1419: * @param pos The source code position to be used for the tree.
1420: * @param sym The accessed symbol.
1421: * @param preciseMatch should we accept a type that is a subtype of
1422: * sym's owner, even if it doesn't contain sym
1423: * due to hiding, overriding, or non-inheritance
1424: * due to protection?
1425: */
1426: JCExpression makeOwnerThis(DiagnosticPosition pos, Symbol sym,
1427: boolean preciseMatch) {
1428: Symbol c = sym.owner;
1429: if (preciseMatch ? sym.isMemberOf(currentClass, types)
1430: : currentClass.isSubClass(sym.owner, types)) {
1431: // in this case, `this' works fine
1432: return make.at(pos).This(c.erasure(types));
1433: } else {
1434: // need to go via this$n
1435: return makeOwnerThisN(pos, sym, preciseMatch);
1436: }
1437: }
1438:
1439: /**
1440: * Similar to makeOwnerThis but will never pick "this".
1441: */
1442: JCExpression makeOwnerThisN(DiagnosticPosition pos, Symbol sym,
1443: boolean preciseMatch) {
1444: Symbol c = sym.owner;
1445: List<VarSymbol> ots = outerThisStack;
1446: if (ots.isEmpty()) {
1447: log.error(pos, "no.encl.instance.of.type.in.scope", c);
1448: assert false;
1449: return makeNull();
1450: }
1451: VarSymbol ot = ots.head;
1452: JCExpression tree = access(make.at(pos).Ident(ot));
1453: TypeSymbol otc = ot.type.tsym;
1454: while (!(preciseMatch ? sym.isMemberOf(otc, types) : otc
1455: .isSubClass(sym.owner, types))) {
1456: do {
1457: ots = ots.tail;
1458: if (ots.isEmpty()) {
1459: log.error(pos, "no.encl.instance.of.type.in.scope",
1460: c);
1461: assert false;
1462: return tree;
1463: }
1464: ot = ots.head;
1465: } while (ot.owner != otc);
1466: tree = access(make.at(pos).Select(tree, ot));
1467: otc = ot.type.tsym;
1468: }
1469: return tree;
1470: }
1471:
1472: /** Return tree simulating the assignment <this.name = name>, where
1473: * name is the name of a free variable.
1474: */
1475: JCStatement initField(int pos, Name name) {
1476: Scope.Entry e = proxies.lookup(name);
1477: Symbol rhs = e.sym;
1478: assert rhs.owner.kind == MTH;
1479: Symbol lhs = e.next().sym;
1480: assert rhs.owner.owner == lhs.owner;
1481: make.at(pos);
1482: return make.Exec(make.Assign(
1483: make.Select(make.This(lhs.owner.erasure(types)), lhs),
1484: make.Ident(rhs)).setType(lhs.erasure(types)));
1485: }
1486:
1487: /** Return tree simulating the assignment <this.this$n = this$n>.
1488: */
1489: JCStatement initOuterThis(int pos) {
1490: VarSymbol rhs = outerThisStack.head;
1491: assert rhs.owner.kind == MTH;
1492: VarSymbol lhs = outerThisStack.tail.head;
1493: assert rhs.owner.owner == lhs.owner;
1494: make.at(pos);
1495: return make.Exec(make.Assign(
1496: make.Select(make.This(lhs.owner.erasure(types)), lhs),
1497: make.Ident(rhs)).setType(lhs.erasure(types)));
1498: }
1499:
1500: /**************************************************************************
1501: * Code for .class
1502: *************************************************************************/
1503:
1504: /** Return the symbol of a class to contain a cache of
1505: * compiler-generated statics such as class$ and the
1506: * $assertionsDisabled flag. We create an anonymous nested class
1507: * (unless one already exists) and return its symbol. However,
1508: * for backward compatibility in 1.4 and earlier we use the
1509: * top-level class itself.
1510: */
1511: private ClassSymbol outerCacheClass() {
1512: ClassSymbol clazz = outermostClassDef.sym;
1513: if ((clazz.flags() & INTERFACE) == 0
1514: && !target.useInnerCacheClass())
1515: return clazz;
1516: Scope s = clazz.members();
1517: for (Scope.Entry e = s.elems; e != null; e = e.sibling)
1518: if (e.sym.kind == TYP && e.sym.name == names.empty
1519: && (e.sym.flags() & INTERFACE) == 0)
1520: return (ClassSymbol) e.sym;
1521: return makeEmptyClass(STATIC | SYNTHETIC, clazz);
1522: }
1523:
1524: /** Return symbol for "class$" method. If there is no method definition
1525: * for class$, construct one as follows:
1526: *
1527: * class class$(String x0) {
1528: * try {
1529: * return Class.forName(x0);
1530: * } catch (ClassNotFoundException x1) {
1531: * throw new NoClassDefFoundError(x1.getMessage());
1532: * }
1533: * }
1534: */
1535: private MethodSymbol classDollarSym(DiagnosticPosition pos) {
1536: ClassSymbol outerCacheClass = outerCacheClass();
1537: MethodSymbol classDollarSym = (MethodSymbol) lookupSynthetic(
1538: classDollar, outerCacheClass.members());
1539: if (classDollarSym == null) {
1540: classDollarSym = new MethodSymbol(STATIC | SYNTHETIC,
1541: classDollar, new MethodType(List
1542: .of(syms.stringType), types
1543: .erasure(syms.classType),
1544: List.<Type> nil(), syms.methodClass),
1545: outerCacheClass);
1546: enterSynthetic(pos, classDollarSym, outerCacheClass
1547: .members());
1548:
1549: JCMethodDecl md = make.MethodDef(classDollarSym, null);
1550: try {
1551: md.body = classDollarSymBody(pos, md);
1552: } catch (CompletionFailure ex) {
1553: md.body = make.Block(0, List.<JCStatement> nil());
1554: chk.completionError(pos, ex);
1555: }
1556: JCClassDecl outerCacheClassDef = classDef(outerCacheClass);
1557: outerCacheClassDef.defs = outerCacheClassDef.defs
1558: .prepend(md);
1559: }
1560: return classDollarSym;
1561: }
1562:
1563: /** Generate code for class$(String name). */
1564: JCBlock classDollarSymBody(DiagnosticPosition pos, JCMethodDecl md) {
1565: MethodSymbol classDollarSym = md.sym;
1566: ClassSymbol outerCacheClass = (ClassSymbol) classDollarSym.owner;
1567:
1568: JCBlock returnResult;
1569:
1570: // in 1.4.2 and above, we use
1571: // Class.forName(String name, boolean init, ClassLoader loader);
1572: // which requires we cache the current loader in cl$
1573: if (target.classLiteralsNoInit()) {
1574: // clsym = "private static ClassLoader cl$"
1575: VarSymbol clsym = new VarSymbol(STATIC | SYNTHETIC, names
1576: .fromString("cl" + target.syntheticNameChar()),
1577: syms.classLoaderType, outerCacheClass);
1578: enterSynthetic(pos, clsym, outerCacheClass.members());
1579:
1580: // emit "private static ClassLoader cl$;"
1581: JCVariableDecl cldef = make.VarDef(clsym, null);
1582: JCClassDecl outerCacheClassDef = classDef(outerCacheClass);
1583: outerCacheClassDef.defs = outerCacheClassDef.defs
1584: .prepend(cldef);
1585:
1586: // newcache := "new cache$1[0]"
1587: JCNewArray newcache = make.NewArray(make
1588: .Type(outerCacheClass.type), List
1589: .<JCExpression> of(make.Literal(INT, 0).setType(
1590: syms.intType)), null);
1591: newcache.type = new ArrayType(types
1592: .erasure(outerCacheClass.type), syms.arrayClass);
1593:
1594: // forNameSym := java.lang.Class.forName(
1595: // String s,boolean init,ClassLoader loader)
1596: Symbol forNameSym = lookupMethod(make_pos, names.forName,
1597: types.erasure(syms.classType), List.of(
1598: syms.stringType, syms.booleanType,
1599: syms.classLoaderType));
1600: // clvalue := "(cl$ == null) ?
1601: // $newcache.getClass().getComponentType().getClassLoader() : cl$"
1602: JCExpression clvalue = make
1603: .Conditional(
1604: makeBinary(JCTree.EQ, make.Ident(clsym),
1605: makeNull()),
1606: make.Assign(
1607: make.Ident(clsym),
1608: makeCall(makeCall(makeCall(
1609: newcache, names.getClass,
1610: List.<JCExpression> nil()),
1611: names.getComponentType,
1612: List.<JCExpression> nil()),
1613: names.getClassLoader,
1614: List.<JCExpression> nil()))
1615: .setType(syms.classLoaderType),
1616: make.Ident(clsym)).setType(
1617: syms.classLoaderType);
1618:
1619: // returnResult := "{ return Class.forName(param1, false, cl$); }"
1620: List<JCExpression> args = List.of(make
1621: .Ident(md.params.head.sym), makeLit(
1622: syms.booleanType, 0), clvalue);
1623: returnResult = make.Block(0, List.<JCStatement> of(make
1624: .Call(make. // return
1625: App(make.Ident(forNameSym), args))));
1626: } else {
1627: // forNameSym := java.lang.Class.forName(String s)
1628: Symbol forNameSym = lookupMethod(make_pos, names.forName,
1629: types.erasure(syms.classType), List
1630: .of(syms.stringType));
1631: // returnResult := "{ return Class.forName(param1); }"
1632: returnResult = make.Block(0, List.of(make.Call(make. // return
1633: App(make.QualIdent(forNameSym), List
1634: .<JCExpression> of(make
1635: .Ident(md.params.head.sym))))));
1636: }
1637:
1638: // catchParam := ClassNotFoundException e1
1639: VarSymbol catchParam = new VarSymbol(0, make.paramName(1),
1640: syms.classNotFoundExceptionType, classDollarSym);
1641:
1642: JCStatement rethrow;
1643: if (target.hasInitCause()) {
1644: // rethrow = "throw new NoClassDefFoundError().initCause(e);
1645: JCTree throwExpr = makeCall(makeNewClass(
1646: syms.noClassDefFoundErrorType, List
1647: .<JCExpression> nil()), names.initCause,
1648: List.<JCExpression> of(make.Ident(catchParam)));
1649: rethrow = make.Throw(throwExpr);
1650: } else {
1651: // getMessageSym := ClassNotFoundException.getMessage()
1652: Symbol getMessageSym = lookupMethod(make_pos,
1653: names.getMessage, syms.classNotFoundExceptionType,
1654: List.<Type> nil());
1655: // rethrow = "throw new NoClassDefFoundError(e.getMessage());"
1656: rethrow = make.Throw(makeNewClass(
1657: syms.noClassDefFoundErrorType, List
1658: .<JCExpression> of(make.App(make.Select(
1659: make.Ident(catchParam),
1660: getMessageSym), List
1661: .<JCExpression> nil()))));
1662: }
1663:
1664: // rethrowStmt := "( $rethrow )"
1665: JCBlock rethrowStmt = make.Block(0, List.of(rethrow));
1666:
1667: // catchBlock := "catch ($catchParam) $rethrowStmt"
1668: JCCatch catchBlock = make.Catch(make.VarDef(catchParam, null),
1669: rethrowStmt);
1670:
1671: // tryCatch := "try $returnResult $catchBlock"
1672: JCStatement tryCatch = make.Try(returnResult, List
1673: .of(catchBlock), null);
1674:
1675: return make.Block(0, List.of(tryCatch));
1676: }
1677:
1678: // where
1679: /** Create an attributed tree of the form left.name(). */
1680: private JCMethodInvocation makeCall(JCExpression left, Name name,
1681: List<JCExpression> args) {
1682: assert left.type != null;
1683: Symbol funcsym = lookupMethod(make_pos, name, left.type,
1684: TreeInfo.types(args));
1685: return make.App(make.Select(left, funcsym), args);
1686: }
1687:
1688: /** The Name Of The variable to cache T.class values.
1689: * @param sig The signature of type T.
1690: */
1691: private Name cacheName(String sig) {
1692: StringBuffer buf = new StringBuffer();
1693: if (sig.startsWith("[")) {
1694: buf = buf.append("array");
1695: while (sig.startsWith("[")) {
1696: buf = buf.append(target.syntheticNameChar());
1697: sig = sig.substring(1);
1698: }
1699: if (sig.startsWith("L")) {
1700: sig = sig.substring(0, sig.length() - 1);
1701: }
1702: } else {
1703: buf = buf.append("class" + target.syntheticNameChar());
1704: }
1705: buf = buf.append(sig.replace('.', target.syntheticNameChar()));
1706: return names.fromString(buf.toString());
1707: }
1708:
1709: /** The variable symbol that caches T.class values.
1710: * If none exists yet, create a definition.
1711: * @param sig The signature of type T.
1712: * @param pos The position to report diagnostics, if any.
1713: */
1714: private VarSymbol cacheSym(DiagnosticPosition pos, String sig) {
1715: ClassSymbol outerCacheClass = outerCacheClass();
1716: Name cname = cacheName(sig);
1717: VarSymbol cacheSym = (VarSymbol) lookupSynthetic(cname,
1718: outerCacheClass.members());
1719: if (cacheSym == null) {
1720: cacheSym = new VarSymbol(STATIC | SYNTHETIC, cname, types
1721: .erasure(syms.classType), outerCacheClass);
1722: enterSynthetic(pos, cacheSym, outerCacheClass.members());
1723:
1724: JCVariableDecl cacheDef = make.VarDef(cacheSym, null);
1725: JCClassDecl outerCacheClassDef = classDef(outerCacheClass);
1726: outerCacheClassDef.defs = outerCacheClassDef.defs
1727: .prepend(cacheDef);
1728: }
1729: return cacheSym;
1730: }
1731:
1732: /** The tree simulating a T.class expression.
1733: * @param clazz The tree identifying type T.
1734: */
1735: private JCExpression classOf(JCTree clazz) {
1736: return classOfType(clazz.type, clazz.pos());
1737: }
1738:
1739: private JCExpression classOfType(Type type, DiagnosticPosition pos) {
1740: switch (type.tag) {
1741: case BYTE:
1742: case SHORT:
1743: case CHAR:
1744: case INT:
1745: case LONG:
1746: case FLOAT:
1747: case DOUBLE:
1748: case BOOLEAN:
1749: case VOID:
1750: // replace with <BoxedClass>.TYPE
1751: ClassSymbol c = types.boxedClass(type);
1752: Symbol typeSym = rs.access(rs.findIdentInType(attrEnv,
1753: c.type, names.TYPE, VAR), pos, c.type, names.TYPE,
1754: true);
1755: if (typeSym.kind == VAR)
1756: ((VarSymbol) typeSym).getConstValue(); // ensure initializer is evaluated
1757: return make.QualIdent(typeSym);
1758: case CLASS:
1759: case ARRAY:
1760: if (target.hasClassLiterals()) {
1761: VarSymbol sym = new VarSymbol(STATIC | PUBLIC | FINAL,
1762: names._class, syms.classType, type.tsym);
1763: return make_at(pos).Select(make.Type(type), sym);
1764: }
1765: // replace with <cache == null ? cache = class$(tsig) : cache>
1766: // where
1767: // - <tsig> is the type signature of T,
1768: // - <cache> is the cache variable for tsig.
1769: String sig = writer.xClassName(type).toString().replace(
1770: '/', '.');
1771: Symbol cs = cacheSym(pos, sig);
1772: return make_at(pos)
1773: .Conditional(
1774: makeBinary(JCTree.EQ, make.Ident(cs),
1775: makeNull()),
1776: make
1777: .Assign(
1778: make.Ident(cs),
1779: make
1780: .App(
1781: make
1782: .Ident(classDollarSym(pos)),
1783: List
1784: .<JCExpression> of(make
1785: .Literal(
1786: CLASS,
1787: sig)
1788: .setType(
1789: syms.stringType))))
1790: .setType(
1791: types
1792: .erasure(syms.classType)),
1793: make.Ident(cs)).setType(
1794: types.erasure(syms.classType));
1795: default:
1796: throw new AssertionError();
1797: }
1798: }
1799:
1800: /**************************************************************************
1801: * Code for enabling/disabling assertions.
1802: *************************************************************************/
1803:
1804: // This code is not particularly robust if the user has
1805: // previously declared a member named '$assertionsDisabled'.
1806: // The same faulty idiom also appears in the translation of
1807: // class literals above. We should report an error if a
1808: // previous declaration is not synthetic.
1809: private JCExpression assertFlagTest(DiagnosticPosition pos) {
1810: // Outermost class may be either true class or an interface.
1811: ClassSymbol outermostClass = outermostClassDef.sym;
1812:
1813: // note that this is a class, as an interface can't contain a statement.
1814: ClassSymbol container = currentClass;
1815:
1816: VarSymbol assertDisabledSym = (VarSymbol) lookupSynthetic(
1817: dollarAssertionsDisabled, container.members());
1818: if (assertDisabledSym == null) {
1819: assertDisabledSym = new VarSymbol(STATIC | FINAL
1820: | SYNTHETIC, dollarAssertionsDisabled,
1821: syms.booleanType, container);
1822: enterSynthetic(pos, assertDisabledSym, container.members());
1823: Symbol desiredAssertionStatusSym = lookupMethod(pos,
1824: names.desiredAssertionStatus, types
1825: .erasure(syms.classType), List.<Type> nil());
1826: JCClassDecl containerDef = classDef(container);
1827: make_at(containerDef.pos());
1828: JCExpression notStatus = makeUnary(JCTree.NOT, make
1829: .App(make.Select(classOfType(types
1830: .erasure(outermostClass.type), containerDef
1831: .pos()), desiredAssertionStatusSym)));
1832: JCVariableDecl assertDisabledDef = make.VarDef(
1833: assertDisabledSym, notStatus);
1834: containerDef.defs = containerDef.defs
1835: .prepend(assertDisabledDef);
1836: }
1837: make_at(pos);
1838: return makeUnary(JCTree.NOT, make.Ident(assertDisabledSym));
1839: }
1840:
1841: /**************************************************************************
1842: * Building blocks for let expressions
1843: *************************************************************************/
1844:
1845: interface TreeBuilder {
1846: JCTree build(JCTree arg);
1847: }
1848:
1849: /** Construct an expression using the builder, with the given rval
1850: * expression as an argument to the builder. However, the rval
1851: * expression must be computed only once, even if used multiple
1852: * times in the result of the builder. We do that by
1853: * constructing a "let" expression that saves the rvalue into a
1854: * temporary variable and then uses the temporary variable in
1855: * place of the expression built by the builder. The complete
1856: * resulting expression is of the form
1857: * <pre>
1858: * (let <b>TYPE</b> <b>TEMP</b> = <b>RVAL</b>;
1859: * in (<b>BUILDER</b>(<b>TEMP</b>)))
1860: * </pre>
1861: * where <code><b>TEMP</b></code> is a newly declared variable
1862: * in the let expression.
1863: */
1864: JCTree abstractRval(JCTree rval, Type type, TreeBuilder builder) {
1865: rval = TreeInfo.skipParens(rval);
1866: switch (rval.getTag()) {
1867: case JCTree.LITERAL:
1868: return builder.build(rval);
1869: case JCTree.IDENT:
1870: JCIdent id = (JCIdent) rval;
1871: if ((id.sym.flags() & FINAL) != 0
1872: && id.sym.owner.kind == MTH)
1873: return builder.build(rval);
1874: }
1875: VarSymbol var = new VarSymbol(FINAL | SYNTHETIC, Name
1876: .fromString(names, target.syntheticNameChar() + ""
1877: + rval.hashCode()), type, currentMethodSym);
1878: JCVariableDecl def = make.VarDef(var, (JCExpression) rval); // XXX cast
1879: JCTree built = builder.build(make.Ident(var));
1880: JCTree res = make.LetExpr(def, built);
1881: res.type = built.type;
1882: return res;
1883: }
1884:
1885: // same as above, with the type of the temporary variable computed
1886: JCTree abstractRval(JCTree rval, TreeBuilder builder) {
1887: return abstractRval(rval, rval.type, builder);
1888: }
1889:
1890: // same as above, but for an expression that may be used as either
1891: // an rvalue or an lvalue. This requires special handling for
1892: // Select expressions, where we place the left-hand-side of the
1893: // select in a temporary, and for Indexed expressions, where we
1894: // place both the indexed expression and the index value in temps.
1895: JCTree abstractLval(JCTree lval, final TreeBuilder builder) {
1896: lval = TreeInfo.skipParens(lval);
1897: switch (lval.getTag()) {
1898: case JCTree.IDENT:
1899: return builder.build(lval);
1900: case JCTree.SELECT: {
1901: final JCFieldAccess s = (JCFieldAccess) lval;
1902: JCTree selected = TreeInfo.skipParens(s.selected);
1903: Symbol lid = TreeInfo.symbol(s.selected);
1904: if (lid != null && lid.kind == TYP)
1905: return builder.build(lval);
1906: return abstractRval(s.selected, new TreeBuilder() {
1907: public JCTree build(final JCTree selected) {
1908: return builder.build(make.Select(
1909: (JCExpression) selected, s.sym));
1910: }
1911: });
1912: }
1913: case JCTree.INDEXED: {
1914: final JCArrayAccess i = (JCArrayAccess) lval;
1915: return abstractRval(i.indexed, new TreeBuilder() {
1916: public JCTree build(final JCTree indexed) {
1917: return abstractRval(i.index, syms.intType,
1918: new TreeBuilder() {
1919: public JCTree build(final JCTree index) {
1920: JCTree newLval = make.Indexed(
1921: (JCExpression) indexed,
1922: (JCExpression) index);
1923: newLval.setType(i.type);
1924: return builder.build(newLval);
1925: }
1926: });
1927: }
1928: });
1929: }
1930: }
1931: throw new AssertionError(lval);
1932: }
1933:
1934: // evaluate and discard the first expression, then evaluate the second.
1935: JCTree makeComma(final JCTree expr1, final JCTree expr2) {
1936: return abstractRval(expr1, new TreeBuilder() {
1937: public JCTree build(final JCTree discarded) {
1938: return expr2;
1939: }
1940: });
1941: }
1942:
1943: /**************************************************************************
1944: * Translation methods
1945: *************************************************************************/
1946:
1947: /** Visitor argument: enclosing operator node.
1948: */
1949: private JCExpression enclOp;
1950:
1951: /** Visitor method: Translate a single node.
1952: * Attach the source position from the old tree to its replacement tree.
1953: */
1954: public <T extends JCTree> T translate(T tree) {
1955: if (tree == null) {
1956: return null;
1957: } else {
1958: make_at(tree.pos());
1959: T result = super .translate(tree);
1960: if (endPositions != null && result != tree) {
1961: Integer endPos = endPositions.remove(tree);
1962: if (endPos != null)
1963: endPositions.put(result, endPos);
1964: }
1965: return result;
1966: }
1967: }
1968:
1969: /** Visitor method: Translate a single node, boxing or unboxing if needed.
1970: */
1971: public <T extends JCTree> T translate(T tree, Type type) {
1972: return (tree == null) ? null : boxIfNeeded(translate(tree),
1973: type);
1974: }
1975:
1976: /** Visitor method: Translate tree.
1977: */
1978: public <T extends JCTree> T translate(T tree, JCExpression enclOp) {
1979: JCExpression prevEnclOp = this .enclOp;
1980: this .enclOp = enclOp;
1981: T res = translate(tree);
1982: this .enclOp = prevEnclOp;
1983: return res;
1984: }
1985:
1986: /** Visitor method: Translate list of trees.
1987: */
1988: public <T extends JCTree> List<T> translate(List<T> trees,
1989: JCExpression enclOp) {
1990: JCExpression prevEnclOp = this .enclOp;
1991: this .enclOp = enclOp;
1992: List<T> res = translate(trees);
1993: this .enclOp = prevEnclOp;
1994: return res;
1995: }
1996:
1997: /** Visitor method: Translate list of trees.
1998: */
1999: public <T extends JCTree> List<T> translate(List<T> trees, Type type) {
2000: if (trees == null)
2001: return null;
2002: for (List<T> l = trees; l.nonEmpty(); l = l.tail)
2003: l.head = translate(l.head, type);
2004: return trees;
2005: }
2006:
2007: public void visitTopLevel(JCCompilationUnit tree) {
2008: if (tree.packageAnnotations.nonEmpty()) {
2009: Name name = names.package_info;
2010: long flags = Flags.SYNTHETIC | Flags.ABSTRACT
2011: | Flags.INTERFACE;
2012: JCClassDecl packageAnnotationsClass = make.ClassDef(make
2013: .Modifiers(flags, tree.packageAnnotations), name,
2014: List.<JCTypeParameter> nil(), null, List
2015: .<JCExpression> nil(), List.<JCTree> nil());
2016: ClassSymbol c = reader.enterClass(name, tree.packge);
2017: c.flatname = names.fromString(tree.packge + "." + name);
2018: c.sourcefile = tree.sourcefile;
2019: c.completer = null;
2020: c.members_field = new Scope(c);
2021: c.flags_field = flags;
2022: c.attributes_field = tree.packge.attributes_field;
2023: tree.packge.attributes_field = List.nil();
2024: ClassType ctype = (ClassType) c.type;
2025: ctype.super type_field = syms.objectType;
2026: ctype.interfaces_field = List.nil();
2027: packageAnnotationsClass.sym = c;
2028:
2029: translated.append(packageAnnotationsClass);
2030: }
2031: }
2032:
2033: public void visitClassDef(JCClassDecl tree) {
2034: ClassSymbol currentClassPrev = currentClass;
2035: MethodSymbol currentMethodSymPrev = currentMethodSym;
2036: currentClass = tree.sym;
2037: currentMethodSym = null;
2038: classdefs.put(currentClass, tree);
2039:
2040: proxies = proxies.dup(currentClass);
2041: List<VarSymbol> prevOuterThisStack = outerThisStack;
2042:
2043: // If this is an enum definition
2044: if ((tree.mods.flags & ENUM) != 0
2045: && (types.super type(currentClass.type).tsym.flags() & ENUM) == 0)
2046: visitEnumDef(tree);
2047:
2048: // If this is a nested class, define a this$n field for
2049: // it and add to proxies.
2050: JCVariableDecl otdef = null;
2051: if (currentClass.hasOuterInstance())
2052: otdef = outerThisDef(tree.pos, currentClass);
2053:
2054: // If this is a local class, define proxies for all its free variables.
2055: List<JCVariableDecl> fvdefs = freevarDefs(tree.pos,
2056: freevars(currentClass), currentClass);
2057:
2058: // Recursively translate superclass, interfaces.
2059: tree.extending = translate(tree.extending);
2060: tree.implementing = translate(tree.implementing);
2061:
2062: // Recursively translate members, taking into account that new members
2063: // might be created during the translation and prepended to the member
2064: // list `tree.defs'.
2065: List<JCTree> seen = List.nil();
2066: while (tree.defs != seen) {
2067: List<JCTree> unseen = tree.defs;
2068: for (List<JCTree> l = unseen; l.nonEmpty() && l != seen; l = l.tail) {
2069: JCTree outermostMemberDefPrev = outermostMemberDef;
2070: if (outermostMemberDefPrev == null)
2071: outermostMemberDef = l.head;
2072: l.head = translate(l.head);
2073: outermostMemberDef = outermostMemberDefPrev;
2074: }
2075: seen = unseen;
2076: }
2077:
2078: // Convert a protected modifier to public, mask static modifier.
2079: if ((tree.mods.flags & PROTECTED) != 0)
2080: tree.mods.flags |= PUBLIC;
2081: tree.mods.flags &= ClassFlags;
2082:
2083: // Convert name to flat representation, replacing '.' by '$'.
2084: tree.name = Convert.shortName(currentClass.flatName());
2085:
2086: // Add this$n and free variables proxy definitions to class.
2087: for (List<JCVariableDecl> l = fvdefs; l.nonEmpty(); l = l.tail) {
2088: tree.defs = tree.defs.prepend(l.head);
2089: enterSynthetic(tree.pos(), l.head.sym, currentClass
2090: .members());
2091: }
2092: if (currentClass.hasOuterInstance()) {
2093: tree.defs = tree.defs.prepend(otdef);
2094: enterSynthetic(tree.pos(), otdef.sym, currentClass
2095: .members());
2096: }
2097:
2098: proxies = proxies.leave();
2099: outerThisStack = prevOuterThisStack;
2100:
2101: // Append translated tree to `translated' queue.
2102: translated.append(tree);
2103:
2104: currentClass = currentClassPrev;
2105: currentMethodSym = currentMethodSymPrev;
2106:
2107: // Return empty block {} as a placeholder for an inner class.
2108: result = make_at(tree.pos()).Block(0, List.<JCStatement> nil());
2109: }
2110:
2111: /** Translate an enum class. */
2112: private void visitEnumDef(JCClassDecl tree) {
2113: make_at(tree.pos());
2114:
2115: // add the supertype, if needed
2116: if (tree.extending == null)
2117: tree.extending = make.Type(types.super type(tree.type));
2118:
2119: // classOfType adds a cache field to tree.defs unless
2120: // target.hasClassLiterals().
2121: JCExpression e_class = classOfType(tree.sym.type, tree.pos())
2122: .setType(types.erasure(syms.classType));
2123:
2124: // process each enumeration constant, adding implicit constructor parameters
2125: int nextOrdinal = 0;
2126: ListBuffer<JCExpression> values = new ListBuffer<JCExpression>();
2127: ListBuffer<JCTree> enumDefs = new ListBuffer<JCTree>();
2128: ListBuffer<JCTree> otherDefs = new ListBuffer<JCTree>();
2129: for (List<JCTree> defs = tree.defs; defs.nonEmpty(); defs = defs.tail) {
2130: if (defs.head.getTag() == JCTree.VARDEF
2131: && (((JCVariableDecl) defs.head).mods.flags & ENUM) != 0) {
2132: JCVariableDecl var = (JCVariableDecl) defs.head;
2133: visitEnumConstantDef(var, nextOrdinal++);
2134: values.append(make.QualIdent(var.sym));
2135: enumDefs.append(var);
2136: } else {
2137: otherDefs.append(defs.head);
2138: }
2139: }
2140:
2141: // private static final T[] #VALUES = { a, b, c };
2142: Name valuesName = names.fromString(target.syntheticNameChar()
2143: + "VALUES");
2144: while (tree.sym.members().lookup(valuesName).scope != null)
2145: // avoid name clash
2146: valuesName = names.fromString(valuesName + ""
2147: + target.syntheticNameChar());
2148: Type arrayType = new ArrayType(types.erasure(tree.type),
2149: syms.arrayClass);
2150: VarSymbol valuesVar = new VarSymbol(PRIVATE | FINAL | STATIC
2151: | SYNTHETIC, valuesName, arrayType, tree.type.tsym);
2152: JCNewArray newArray = make.NewArray(make.Type(types
2153: .erasure(tree.type)), List.<JCExpression> nil(), values
2154: .toList());
2155: newArray.type = arrayType;
2156: enumDefs.append(make.VarDef(valuesVar, newArray));
2157: tree.sym.members().enter(valuesVar);
2158:
2159: Symbol valuesSym = lookupMethod(tree.pos(), names.values,
2160: tree.type, List.<Type> nil());
2161: JCTypeCast valuesResult = make.TypeCast(valuesSym.type
2162: .getReturnType(), make.App(make.Select(make
2163: .Ident(valuesVar), syms.arrayCloneMethod)));
2164: JCMethodDecl valuesDef = make.MethodDef(
2165: (MethodSymbol) valuesSym, make.Block(0, List
2166: .<JCStatement> nil().prepend(
2167: make.Return(valuesResult))));
2168: enumDefs.append(valuesDef);
2169:
2170: /** The template for the following code is:
2171: *
2172: * public static E valueOf(String name) {
2173: * return (E)Enum.valueOf(E.class, name);
2174: * }
2175: *
2176: * where E is tree.sym
2177: */
2178: MethodSymbol valueOfSym = lookupMethod(tree.pos(),
2179: names.valueOf, tree.sym.type, List.of(syms.stringType));
2180: assert (valueOfSym.flags() & STATIC) != 0;
2181: VarSymbol nameArgSym = valueOfSym.params.head;
2182: JCIdent nameVal = make.Ident(nameArgSym);
2183: JCStatement enum_ValueOf = make.Return(make.TypeCast(
2184: tree.sym.type, makeCall(make.Ident(syms.enumSym),
2185: names.valueOf, List.of(e_class, nameVal))));
2186: JCMethodDecl valueOf = make.MethodDef(valueOfSym, make.Block(0,
2187: List.of(enum_ValueOf)));
2188: nameVal.sym = valueOf.params.head.sym;
2189: if (debugLower)
2190: System.err.println(tree.sym + ".valueOf = " + valueOf);
2191: enumDefs.append(valueOf);
2192:
2193: enumDefs.appendList(otherDefs.toList());
2194: tree.defs = enumDefs.toList();
2195:
2196: // Add the necessary members for the EnumCompatibleMode
2197: if (target.compilerBootstrap(tree.sym)) {
2198: addEnumCompatibleMembers(tree);
2199: }
2200: }
2201:
2202: /** Translate an enumeration constant and its initializer. */
2203: private void visitEnumConstantDef(JCVariableDecl var, int ordinal) {
2204: JCNewClass varDef = (JCNewClass) var.init;
2205: varDef.args = varDef.args.prepend(
2206: makeLit(syms.intType, ordinal)).prepend(
2207: makeLit(syms.stringType, var.name.toString()));
2208: }
2209:
2210: public void visitMethodDef(JCMethodDecl tree) {
2211: if (tree.name == names.init
2212: && (currentClass.flags_field & ENUM) != 0) {
2213: // Add "String $enum$name, int $enum$ordinal" to the beginning of the
2214: // argument list for each constructor of an enum.
2215: JCVariableDecl nameParam = make_at(tree.pos()).Param(
2216: names.fromString(target.syntheticNameChar()
2217: + "enum" + target.syntheticNameChar()
2218: + "name"), syms.stringType, tree.sym);
2219: nameParam.mods.flags |= SYNTHETIC;
2220: nameParam.sym.flags_field |= SYNTHETIC;
2221:
2222: JCVariableDecl ordParam = make.Param(names
2223: .fromString(target.syntheticNameChar() + "enum"
2224: + target.syntheticNameChar() + "ordinal"),
2225: syms.intType, tree.sym);
2226: ordParam.mods.flags |= SYNTHETIC;
2227: ordParam.sym.flags_field |= SYNTHETIC;
2228:
2229: tree.params = tree.params.prepend(ordParam).prepend(
2230: nameParam);
2231:
2232: MethodSymbol m = tree.sym;
2233: Type olderasure = m.erasure(types);
2234: m.erasure_field = new MethodType(olderasure
2235: .getParameterTypes().prepend(syms.intType).prepend(
2236: syms.stringType), olderasure
2237: .getReturnType(), olderasure.getThrownTypes(),
2238: syms.methodClass);
2239:
2240: if (target.compilerBootstrap(m.owner)) {
2241: // Initialize synthetic name field
2242: Symbol nameVarSym = lookupSynthetic(names
2243: .fromString("$name"), tree.sym.owner.members());
2244: JCIdent nameIdent = make.Ident(nameParam.sym);
2245: JCIdent id1 = make.Ident(nameVarSym);
2246: JCAssign newAssign = make.Assign(id1, nameIdent);
2247: newAssign.type = id1.type;
2248: JCExpressionStatement nameAssign = make.Exec(newAssign);
2249: nameAssign.type = id1.type;
2250: tree.body.stats = tree.body.stats.prepend(nameAssign);
2251:
2252: // Initialize synthetic ordinal field
2253: Symbol ordinalVarSym = lookupSynthetic(names
2254: .fromString("$ordinal"), tree.sym.owner
2255: .members());
2256: JCIdent ordIdent = make.Ident(ordParam.sym);
2257: id1 = make.Ident(ordinalVarSym);
2258: newAssign = make.Assign(id1, ordIdent);
2259: newAssign.type = id1.type;
2260: JCExpressionStatement ordinalAssign = make
2261: .Exec(newAssign);
2262: ordinalAssign.type = id1.type;
2263: tree.body.stats = tree.body.stats
2264: .prepend(ordinalAssign);
2265: }
2266: }
2267:
2268: JCMethodDecl prevMethodDef = currentMethodDef;
2269: MethodSymbol prevMethodSym = currentMethodSym;
2270: try {
2271: currentMethodDef = tree;
2272: currentMethodSym = tree.sym;
2273: visitMethodDefInternal(tree);
2274: } finally {
2275: currentMethodDef = prevMethodDef;
2276: currentMethodSym = prevMethodSym;
2277: }
2278: }
2279:
2280: //where
2281: private void visitMethodDefInternal(JCMethodDecl tree) {
2282: if (tree.name == names.init
2283: && (currentClass.isInner() || (currentClass.owner.kind & (VAR | MTH)) != 0)) {
2284: // We are seeing a constructor of an inner class.
2285: MethodSymbol m = tree.sym;
2286:
2287: // Push a new proxy scope for constructor parameters.
2288: // and create definitions for any this$n and proxy parameters.
2289: proxies = proxies.dup(m);
2290: List<VarSymbol> prevOuterThisStack = outerThisStack;
2291: List<VarSymbol> fvs = freevars(currentClass);
2292: JCVariableDecl otdef = null;
2293: if (currentClass.hasOuterInstance())
2294: otdef = outerThisDef(tree.pos, m);
2295: List<JCVariableDecl> fvdefs = freevarDefs(tree.pos, fvs, m);
2296:
2297: // Recursively translate result type, parameters and thrown list.
2298: tree.restype = translate(tree.restype);
2299: tree.params = translateVarDefs(tree.params);
2300: tree.thrown = translate(tree.thrown);
2301:
2302: // when compiling stubs, don't process body
2303: if (tree.body == null) {
2304: result = tree;
2305: return;
2306: }
2307:
2308: // Add this$n (if needed) in front of and free variables behind
2309: // constructor parameter list.
2310: tree.params = tree.params.appendList(fvdefs);
2311: if (currentClass.hasOuterInstance())
2312: tree.params = tree.params.prepend(otdef);
2313:
2314: // If this is an initial constructor, i.e., it does not start with
2315: // this(...), insert initializers for this$n and proxies
2316: // before (pre-1.4, after) the call to superclass constructor.
2317: JCStatement selfCall = translate(tree.body.stats.head);
2318:
2319: List<JCStatement> added = List.nil();
2320: if (fvs.nonEmpty()) {
2321: List<Type> addedargtypes = List.nil();
2322: for (List<VarSymbol> l = fvs; l.nonEmpty(); l = l.tail) {
2323: if (TreeInfo.isInitialConstructor(tree))
2324: added = added.prepend(initField(tree.body.pos,
2325: proxyName(l.head.name)));
2326: addedargtypes = addedargtypes.prepend(l.head
2327: .erasure(types));
2328: }
2329: Type olderasure = m.erasure(types);
2330: m.erasure_field = new MethodType(olderasure
2331: .getParameterTypes().appendList(addedargtypes),
2332: olderasure.getReturnType(), olderasure
2333: .getThrownTypes(), syms.methodClass);
2334: }
2335: if (currentClass.hasOuterInstance()
2336: && TreeInfo.isInitialConstructor(tree)) {
2337: added = added.prepend(initOuterThis(tree.body.pos));
2338: }
2339:
2340: // pop local variables from proxy stack
2341: proxies = proxies.leave();
2342:
2343: // recursively translate following local statements and
2344: // combine with this- or super-call
2345: List<JCStatement> stats = translate(tree.body.stats.tail);
2346: if (target.initializeFieldsBeforeSuper())
2347: tree.body.stats = stats.prepend(selfCall).prependList(
2348: added);
2349: else
2350: tree.body.stats = stats.prependList(added).prepend(
2351: selfCall);
2352:
2353: outerThisStack = prevOuterThisStack;
2354: } else {
2355: super .visitMethodDef(tree);
2356: }
2357: result = tree;
2358: }
2359:
2360: public void visitTypeCast(JCTypeCast tree) {
2361: tree.clazz = translate(tree.clazz);
2362: if (tree.type.isPrimitive() != tree.expr.type.isPrimitive())
2363: tree.expr = translate(tree.expr, tree.type);
2364: else
2365: tree.expr = translate(tree.expr);
2366: result = tree;
2367: }
2368:
2369: public void visitNewClass(JCNewClass tree) {
2370: ClassSymbol c = (ClassSymbol) tree.constructor.owner;
2371:
2372: // Box arguments, if necessary
2373: boolean isEnum = (tree.constructor.owner.flags() & ENUM) != 0;
2374: List<Type> argTypes = tree.constructor.type.getParameterTypes();
2375: if (isEnum)
2376: argTypes = argTypes.prepend(syms.intType).prepend(
2377: syms.stringType);
2378: tree.args = boxArgs(argTypes, tree.args, tree.varargsElement);
2379: tree.varargsElement = null;
2380:
2381: // If created class is local, add free variables after
2382: // explicit constructor arguments.
2383: if ((c.owner.kind & (VAR | MTH)) != 0) {
2384: tree.args = tree.args.appendList(loadFreevars(tree.pos(),
2385: freevars(c)));
2386: }
2387:
2388: // If an access constructor is used, append null as a last argument.
2389: Symbol constructor = accessConstructor(tree.pos(),
2390: tree.constructor);
2391: if (constructor != tree.constructor) {
2392: tree.args = tree.args.append(makeNull());
2393: tree.constructor = constructor;
2394: }
2395:
2396: // If created class has an outer instance, and new is qualified, pass
2397: // qualifier as first argument. If new is not qualified, pass the
2398: // correct outer instance as first argument.
2399: if (c.hasOuterInstance()) {
2400: JCExpression this Arg;
2401: if (tree.encl != null) {
2402: this Arg = attr.makeNullCheck(translate(tree.encl));
2403: this Arg.type = tree.encl.type;
2404: } else if ((c.owner.kind & (MTH | VAR)) != 0) {
2405: // local class
2406: this Arg = makeThis(tree.pos(), c.type
2407: .getEnclosingType().tsym);
2408: } else {
2409: // nested class
2410: this Arg = makeOwnerThis(tree.pos(), c, false);
2411: }
2412: tree.args = tree.args.prepend(this Arg);
2413: }
2414: tree.encl = null;
2415:
2416: // If we have an anonymous class, create its flat version, rather
2417: // than the class or interface following new.
2418: if (tree.def != null) {
2419: translate(tree.def);
2420: tree.clazz = access(make_at(tree.clazz.pos()).Ident(
2421: tree.def.sym));
2422: tree.def = null;
2423: } else {
2424: tree.clazz = access(c, tree.clazz, enclOp, false);
2425: }
2426: result = tree;
2427: }
2428:
2429: // Simplify conditionals with known constant controlling expressions.
2430: // This allows us to avoid generating supporting declarations for
2431: // the dead code, which will not be eliminated during code generation.
2432: // Note that Flow.isFalse and Flow.isTrue only return true
2433: // for constant expressions in the sense of JLS 15.27, which
2434: // are guaranteed to have no side-effects. More agressive
2435: // constant propagation would require that we take care to
2436: // preserve possible side-effects in the condition expression.
2437:
2438: /** Visitor method for conditional expressions.
2439: */
2440: public void visitConditional(JCConditional tree) {
2441: JCTree cond = tree.cond = translate(tree.cond, syms.booleanType);
2442: if (cond.type.isTrue()) {
2443: result = convert(translate(tree.truepart, tree.type),
2444: tree.type);
2445: } else if (cond.type.isFalse()) {
2446: result = convert(translate(tree.falsepart, tree.type),
2447: tree.type);
2448: } else {
2449: // Condition is not a compile-time constant.
2450: tree.truepart = translate(tree.truepart, tree.type);
2451: tree.falsepart = translate(tree.falsepart, tree.type);
2452: result = tree;
2453: }
2454: }
2455:
2456: //where
2457: private JCTree convert(JCTree tree, Type pt) {
2458: if (tree.type == pt)
2459: return tree;
2460: JCTree result = make_at(tree.pos()).TypeCast(make.Type(pt),
2461: (JCExpression) tree);
2462: result.type = (tree.type.constValue() != null) ? cfolder
2463: .coerce(tree.type, pt) : pt;
2464: return result;
2465: }
2466:
2467: /** Visitor method for if statements.
2468: */
2469: public void visitIf(JCIf tree) {
2470: JCTree cond = tree.cond = translate(tree.cond, syms.booleanType);
2471: if (cond.type.isTrue()) {
2472: result = translate(tree.thenpart);
2473: } else if (cond.type.isFalse()) {
2474: if (tree.elsepart != null) {
2475: result = translate(tree.elsepart);
2476: } else {
2477: result = make.Skip();
2478: }
2479: } else {
2480: // Condition is not a compile-time constant.
2481: tree.thenpart = translate(tree.thenpart);
2482: tree.elsepart = translate(tree.elsepart);
2483: result = tree;
2484: }
2485: }
2486:
2487: /** Visitor method for assert statements. Translate them away.
2488: */
2489: public void visitAssert(JCAssert tree) {
2490: DiagnosticPosition detailPos = (tree.detail == null) ? tree
2491: .pos() : tree.detail.pos();
2492: tree.cond = translate(tree.cond, syms.booleanType);
2493: if (!tree.cond.type.isTrue()) {
2494: JCExpression cond = assertFlagTest(tree.pos());
2495: List<JCExpression> exnArgs = (tree.detail == null) ? List
2496: .<JCExpression> nil() : List
2497: .of(translate(tree.detail));
2498: if (!tree.cond.type.isFalse()) {
2499: cond = makeBinary(JCTree.AND, cond, makeUnary(
2500: JCTree.NOT, tree.cond));
2501: }
2502: result = make.If(cond, make_at(detailPos).Throw(
2503: makeNewClass(syms.assertionErrorType, exnArgs)),
2504: null);
2505: } else {
2506: result = make.Skip();
2507: }
2508: }
2509:
2510: public void visitApply(JCMethodInvocation tree) {
2511: Symbol meth = TreeInfo.symbol(tree.meth);
2512: List<Type> argtypes = meth.type.getParameterTypes();
2513: if (allowEnums && meth.name == names.init
2514: && meth.owner == syms.enumSym)
2515: argtypes = argtypes.tail.tail;
2516: tree.args = boxArgs(argtypes, tree.args, tree.varargsElement);
2517: tree.varargsElement = null;
2518: Name methName = TreeInfo.name(tree.meth);
2519: if (meth.name == names.init) {
2520: // We are seeing a this(...) or super(...) constructor call.
2521: // If an access constructor is used, append null as a last argument.
2522: Symbol constructor = accessConstructor(tree.pos(), meth);
2523: if (constructor != meth) {
2524: tree.args = tree.args.append(makeNull());
2525: TreeInfo.setSymbol(tree.meth, constructor);
2526: }
2527:
2528: // If we are calling a constructor of a local class, add
2529: // free variables after explicit constructor arguments.
2530: ClassSymbol c = (ClassSymbol) constructor.owner;
2531: if ((c.owner.kind & (VAR | MTH)) != 0) {
2532: tree.args = tree.args.appendList(loadFreevars(tree
2533: .pos(), freevars(c)));
2534: }
2535:
2536: // If we are calling a constructor of an enum class, pass
2537: // along the name and ordinal arguments
2538: if ((c.flags_field & ENUM) != 0
2539: || c.getQualifiedName() == names.java_lang_Enum) {
2540: List<JCVariableDecl> params = currentMethodDef.params;
2541: if (currentMethodSym.owner.hasOuterInstance())
2542: params = params.tail; // drop this$n
2543: tree.args = tree.args
2544: .prepend(
2545: make_at(tree.pos()).Ident(
2546: params.tail.head.sym)) // ordinal
2547: .prepend(make.Ident(params.head.sym)); // name
2548: }
2549:
2550: // If we are calling a constructor of a class with an outer
2551: // instance, and the call
2552: // is qualified, pass qualifier as first argument in front of
2553: // the explicit constructor arguments. If the call
2554: // is not qualified, pass the correct outer instance as
2555: // first argument.
2556: if (c.hasOuterInstance()) {
2557: JCExpression this Arg;
2558: if (tree.meth.getTag() == JCTree.SELECT) {
2559: this Arg = attr
2560: .makeNullCheck(translate(((JCFieldAccess) tree.meth).selected));
2561: tree.meth = make.Ident(constructor);
2562: ((JCIdent) tree.meth).name = methName;
2563: } else if ((c.owner.kind & (MTH | VAR)) != 0
2564: || methName == names._this ) {
2565: // local class or this() call
2566: this Arg = makeThis(tree.meth.pos(), c.type
2567: .getEnclosingType().tsym);
2568: } else {
2569: // super() call of nested class
2570: this Arg = makeOwnerThis(tree.meth.pos(), c, false);
2571: }
2572: tree.args = tree.args.prepend(this Arg);
2573: }
2574: } else {
2575: // We are seeing a normal method invocation; translate this as usual.
2576: tree.meth = translate(tree.meth);
2577:
2578: // If the translated method itself is an Apply tree, we are
2579: // seeing an access method invocation. In this case, append
2580: // the method arguments to the arguments of the access method.
2581: if (tree.meth.getTag() == JCTree.APPLY) {
2582: JCMethodInvocation app = (JCMethodInvocation) tree.meth;
2583: app.args = tree.args.prependList(app.args);
2584: result = app;
2585: return;
2586: }
2587: }
2588: result = tree;
2589: }
2590:
2591: List<JCExpression> boxArgs(List<Type> parameters,
2592: List<JCExpression> _args, Type varargsElement) {
2593: List<JCExpression> args = _args;
2594: if (parameters.isEmpty())
2595: return args;
2596: boolean anyChanges = false;
2597: ListBuffer<JCExpression> result = new ListBuffer<JCExpression>();
2598: while (parameters.tail.nonEmpty()) {
2599: JCExpression arg = translate(args.head, parameters.head);
2600: anyChanges |= (arg != args.head);
2601: result.append(arg);
2602: args = args.tail;
2603: parameters = parameters.tail;
2604: }
2605: Type parameter = parameters.head;
2606: if (varargsElement != null) {
2607: anyChanges = true;
2608: ListBuffer<JCExpression> elems = new ListBuffer<JCExpression>();
2609: while (args.nonEmpty()) {
2610: JCExpression arg = translate(args.head, varargsElement);
2611: elems.append(arg);
2612: args = args.tail;
2613: }
2614: JCNewArray boxedArgs = make.NewArray(make
2615: .Type(varargsElement), List.<JCExpression> nil(),
2616: elems.toList());
2617: boxedArgs.type = new ArrayType(varargsElement,
2618: syms.arrayClass);
2619: result.append(boxedArgs);
2620: } else {
2621: if (args.length() != 1)
2622: throw new AssertionError(args);
2623: JCExpression arg = translate(args.head, parameter);
2624: anyChanges |= (arg != args.head);
2625: result.append(arg);
2626: if (!anyChanges)
2627: return _args;
2628: }
2629: return result.toList();
2630: }
2631:
2632: /** Expand a boxing or unboxing conversion if needed. */
2633: @SuppressWarnings("unchecked")
2634: // XXX unchecked
2635: <T extends JCTree> T boxIfNeeded(T tree, Type type) {
2636: boolean havePrimitive = tree.type.isPrimitive();
2637: if (havePrimitive == type.isPrimitive())
2638: return tree;
2639: if (havePrimitive) {
2640: Type unboxedTarget = types.unboxedType(type);
2641: if (unboxedTarget.tag != NONE) {
2642: if (!types.isSubtype(tree.type, unboxedTarget))
2643: tree.type = unboxedTarget; // e.g. Character c = 89;
2644: return (T) boxPrimitive((JCExpression) tree, type);
2645: } else {
2646: tree = (T) boxPrimitive((JCExpression) tree);
2647: }
2648: } else {
2649: tree = (T) unbox((JCExpression) tree, type);
2650: }
2651: return tree;
2652: }
2653:
2654: /** Box up a single primitive expression. */
2655: JCExpression boxPrimitive(JCExpression tree) {
2656: return boxPrimitive(tree, types.boxedClass(tree.type).type);
2657: }
2658:
2659: /** Box up a single primitive expression. */
2660: JCExpression boxPrimitive(JCExpression tree, Type box) {
2661: make_at(tree.pos());
2662: if (target.boxWithConstructors()) {
2663: Symbol ctor = lookupConstructor(tree.pos(), box, List
2664: .<Type> nil().prepend(tree.type));
2665: return make.Create(ctor, List.of(tree));
2666: } else {
2667: Symbol valueOfSym = lookupMethod(tree.pos(), names.valueOf,
2668: box, List.<Type> nil().prepend(tree.type));
2669: return make.App(make.QualIdent(valueOfSym), List.of(tree));
2670: }
2671: }
2672:
2673: /** Unbox an object to a primitive value. */
2674: JCExpression unbox(JCExpression tree, Type primitive) {
2675: Type unboxedType = types.unboxedType(tree.type);
2676: // note: the "primitive" parameter is not used. There muse be
2677: // a conversion from unboxedType to primitive.
2678: make_at(tree.pos());
2679: Symbol valueSym = lookupMethod(tree.pos(),
2680: unboxedType.tsym.name.append(names.Value), // x.intValue()
2681: tree.type, List.<Type> nil());
2682: return make.App(make.Select(tree, valueSym));
2683: }
2684:
2685: /** Visitor method for parenthesized expressions.
2686: * If the subexpression has changed, omit the parens.
2687: */
2688: public void visitParens(JCParens tree) {
2689: JCTree expr = translate(tree.expr);
2690: result = ((expr == tree.expr) ? tree : expr);
2691: }
2692:
2693: public void visitIndexed(JCArrayAccess tree) {
2694: tree.indexed = translate(tree.indexed);
2695: tree.index = translate(tree.index, syms.intType);
2696: result = tree;
2697: }
2698:
2699: public void visitAssign(JCAssign tree) {
2700: tree.lhs = translate(tree.lhs, tree);
2701: tree.rhs = translate(tree.rhs, tree.lhs.type);
2702:
2703: // If translated left hand side is an Apply, we are
2704: // seeing an access method invocation. In this case, append
2705: // right hand side as last argument of the access method.
2706: if (tree.lhs.getTag() == JCTree.APPLY) {
2707: JCMethodInvocation app = (JCMethodInvocation) tree.lhs;
2708: app.args = List.of(tree.rhs).prependList(app.args);
2709: result = app;
2710: } else {
2711: result = tree;
2712: }
2713: }
2714:
2715: public void visitAssignop(final JCAssignOp tree) {
2716: if (!tree.lhs.type.isPrimitive()
2717: && tree.operator.type.getReturnType().isPrimitive()) {
2718: // boxing required; need to rewrite as x = (unbox typeof x)(x op y);
2719: // or if x == (typeof x)z then z = (unbox typeof x)((typeof x)z op y)
2720: // (but without recomputing x)
2721: JCTree arg = (tree.lhs.getTag() == JCTree.TYPECAST) ? ((JCTypeCast) tree.lhs).expr
2722: : tree.lhs;
2723: JCTree newTree = abstractLval(arg, new TreeBuilder() {
2724: public JCTree build(final JCTree lhs) {
2725: int newTag = tree.getTag() - JCTree.ASGOffset;
2726: // Erasure (TransTypes) can change the type of
2727: // tree.lhs. However, we can still get the
2728: // unerased type of tree.lhs as it is stored
2729: // in tree.type in Attr.
2730: Symbol newOperator = rs.resolveBinaryOperator(tree
2731: .pos(), newTag, attrEnv, tree.type,
2732: tree.rhs.type);
2733: JCExpression expr = (JCExpression) lhs;
2734: if (expr.type != tree.type)
2735: expr = make.TypeCast(tree.type, expr);
2736: JCBinary opResult = make.Binary(newTag, expr,
2737: tree.rhs);
2738: opResult.operator = newOperator;
2739: opResult.type = newOperator.type.getReturnType();
2740: JCTypeCast newRhs = make.TypeCast(types
2741: .unboxedType(tree.type), opResult);
2742: return make.Assign((JCExpression) lhs, newRhs)
2743: .setType(tree.type);
2744: }
2745: });
2746: result = translate(newTree);
2747: return;
2748: }
2749: tree.lhs = translate(tree.lhs, tree);
2750: tree.rhs = translate(tree.rhs, tree.operator.type
2751: .getParameterTypes().tail.head);
2752:
2753: // If translated left hand side is an Apply, we are
2754: // seeing an access method invocation. In this case, append
2755: // right hand side as last argument of the access method.
2756: if (tree.lhs.getTag() == JCTree.APPLY) {
2757: JCMethodInvocation app = (JCMethodInvocation) tree.lhs;
2758: // if operation is a += on strings,
2759: // make sure to convert argument to string
2760: JCExpression rhs = (((OperatorSymbol) tree.operator).opcode == string_add) ? makeString(tree.rhs)
2761: : tree.rhs;
2762: app.args = List.of(rhs).prependList(app.args);
2763: result = app;
2764: } else {
2765: result = tree;
2766: }
2767: }
2768:
2769: /** Lower a tree of the form e++ or e-- where e is an object type */
2770: JCTree lowerBoxedPostop(final JCUnary tree) {
2771: // translate to tmp1=lval(e); tmp2=tmp1; tmp1 OP 1; tmp2
2772: // or
2773: // translate to tmp1=lval(e); tmp2=tmp1; (typeof tree)tmp1 OP 1; tmp2
2774: // where OP is += or -=
2775: final boolean cast = tree.arg.getTag() == JCTree.TYPECAST;
2776: final JCExpression arg = cast ? ((JCTypeCast) tree.arg).expr
2777: : tree.arg;
2778: return abstractLval(arg, new TreeBuilder() {
2779: public JCTree build(final JCTree tmp1) {
2780: return abstractRval(tmp1, tree.arg.type,
2781: new TreeBuilder() {
2782: public JCTree build(final JCTree tmp2) {
2783: int opcode = (tree.getTag() == JCTree.POSTINC) ? JCTree.PLUS_ASG
2784: : JCTree.MINUS_ASG;
2785: JCTree lhs = cast ? make.TypeCast(
2786: tree.arg.type,
2787: (JCExpression) tmp1) : tmp1;
2788: JCTree update = makeAssignop(opcode,
2789: lhs, make.Literal(1));
2790: return makeComma(update, tmp2);
2791: }
2792: });
2793: }
2794: });
2795: }
2796:
2797: public void visitUnary(JCUnary tree) {
2798: boolean isUpdateOperator = JCTree.PREINC <= tree.getTag()
2799: && tree.getTag() <= JCTree.POSTDEC;
2800: if (isUpdateOperator && !tree.arg.type.isPrimitive()) {
2801: switch (tree.getTag()) {
2802: case JCTree.PREINC: // ++ e
2803: // translate to e += 1
2804: case JCTree.PREDEC: // -- e
2805: // translate to e -= 1
2806: {
2807: int opcode = (tree.getTag() == JCTree.PREINC) ? JCTree.PLUS_ASG
2808: : JCTree.MINUS_ASG;
2809: JCAssignOp newTree = makeAssignop(opcode, tree.arg,
2810: make.Literal(1));
2811: result = translate(newTree, tree.type);
2812: return;
2813: }
2814: case JCTree.POSTINC: // e ++
2815: case JCTree.POSTDEC: // e --
2816: {
2817: result = translate(lowerBoxedPostop(tree), tree.type);
2818: return;
2819: }
2820: }
2821: throw new AssertionError(tree);
2822: }
2823:
2824: tree.arg = boxIfNeeded(translate(tree.arg, tree), tree.type);
2825:
2826: if (tree.getTag() == JCTree.NOT
2827: && tree.arg.type.constValue() != null) {
2828: tree.type = cfolder.fold1(bool_not, tree.arg.type);
2829: }
2830:
2831: // If translated left hand side is an Apply, we are
2832: // seeing an access method invocation. In this case, return
2833: // that access method invokation as result.
2834: if (isUpdateOperator && tree.arg.getTag() == JCTree.APPLY) {
2835: result = tree.arg;
2836: } else {
2837: result = tree;
2838: }
2839: }
2840:
2841: public void visitBinary(JCBinary tree) {
2842: List<Type> formals = tree.operator.type.getParameterTypes();
2843: JCTree lhs = tree.lhs = translate(tree.lhs, formals.head);
2844: switch (tree.getTag()) {
2845: case JCTree.OR:
2846: if (lhs.type.isTrue()) {
2847: result = lhs;
2848: return;
2849: }
2850: if (lhs.type.isFalse()) {
2851: result = translate(tree.rhs, formals.tail.head);
2852: return;
2853: }
2854: break;
2855: case JCTree.AND:
2856: if (lhs.type.isFalse()) {
2857: result = lhs;
2858: return;
2859: }
2860: if (lhs.type.isTrue()) {
2861: result = translate(tree.rhs, formals.tail.head);
2862: return;
2863: }
2864: break;
2865: }
2866: tree.rhs = translate(tree.rhs, formals.tail.head);
2867: result = tree;
2868: }
2869:
2870: public void visitIdent(JCIdent tree) {
2871: result = access(tree.sym, tree, enclOp, false);
2872: }
2873:
2874: /** Translate away the foreach loop. */
2875: public void visitForeachLoop(JCEnhancedForLoop tree) {
2876: if (types.elemtype(tree.expr.type) == null)
2877: visitIterableForeachLoop(tree);
2878: else
2879: visitArrayForeachLoop(tree);
2880: }
2881:
2882: // where
2883: /**
2884: * A statment of the form
2885: *
2886: * <pre>
2887: * for ( T v : arrayexpr ) stmt;
2888: * </pre>
2889: *
2890: * (where arrayexpr is of an array type) gets translated to
2891: *
2892: * <pre>
2893: * for ( { arraytype #arr = arrayexpr;
2894: * int #len = array.length;
2895: * int #i = 0; };
2896: * #i < #len; i$++ ) {
2897: * T v = arr$[#i];
2898: * stmt;
2899: * }
2900: * </pre>
2901: *
2902: * where #arr, #len, and #i are freshly named synthetic local variables.
2903: */
2904: private void visitArrayForeachLoop(JCEnhancedForLoop tree) {
2905: make_at(tree.expr.pos());
2906: VarSymbol arraycache = new VarSymbol(0, names.fromString("arr"
2907: + target.syntheticNameChar()), tree.expr.type,
2908: currentMethodSym);
2909: JCStatement arraycachedef = make.VarDef(arraycache, tree.expr);
2910: VarSymbol lencache = new VarSymbol(0, names.fromString("len"
2911: + target.syntheticNameChar()), syms.intType,
2912: currentMethodSym);
2913: JCStatement lencachedef = make.VarDef(lencache, make.Select(
2914: make.Ident(arraycache), syms.lengthVar));
2915: VarSymbol index = new VarSymbol(0, names.fromString("i"
2916: + target.syntheticNameChar()), syms.intType,
2917: currentMethodSym);
2918:
2919: JCVariableDecl indexdef = make.VarDef(index, make.Literal(INT,
2920: 0));
2921: indexdef.init.type = indexdef.type = syms.intType.constType(0);
2922:
2923: List<JCStatement> loopinit = List.of(arraycachedef,
2924: lencachedef, indexdef);
2925: JCBinary cond = makeBinary(JCTree.LT, make.Ident(index), make
2926: .Ident(lencache));
2927:
2928: JCExpressionStatement step = make.Exec(makeUnary(JCTree.PREINC,
2929: make.Ident(index)));
2930:
2931: Type elemtype = types.elemtype(tree.expr.type);
2932: JCStatement loopvarinit = make.VarDef(tree.var.sym, make
2933: .Indexed(make.Ident(arraycache), make.Ident(index))
2934: .setType(elemtype));
2935: JCBlock body = make.Block(0, List.of(loopvarinit, tree.body));
2936:
2937: result = translate(make.ForLoop(loopinit, cond, List.of(step),
2938: body));
2939: patchTargets(body, tree, result);
2940: }
2941:
2942: /** Patch up break and continue targets. */
2943: private void patchTargets(JCTree body, final JCTree src,
2944: final JCTree dest) {
2945: class Patcher extends TreeScanner {
2946: public void visitBreak(JCBreak tree) {
2947: if (tree.target == src)
2948: tree.target = dest;
2949: }
2950:
2951: public void visitContinue(JCContinue tree) {
2952: if (tree.target == src)
2953: tree.target = dest;
2954: }
2955:
2956: public void visitClassDef(JCClassDecl tree) {
2957: }
2958: }
2959: new Patcher().scan(body);
2960: }
2961:
2962: /**
2963: * A statement of the form
2964: *
2965: * <pre>
2966: * for ( T v : coll ) stmt ;
2967: * </pre>
2968: *
2969: * (where coll implements Iterable<? extends T>) gets translated to
2970: *
2971: * <pre>
2972: * for ( Iterator<? extends T> #i = coll.iterator(); #i.hasNext(); ) {
2973: * T v = (T) #i.next();
2974: * stmt;
2975: * }
2976: * </pre>
2977: *
2978: * where #i is a freshly named synthetic local variable.
2979: */
2980: private void visitIterableForeachLoop(JCEnhancedForLoop tree) {
2981: make_at(tree.expr.pos());
2982: Type iteratorTarget = syms.objectType;
2983: Type iterableType = types.asSuper(types
2984: .upperBound(tree.expr.type), syms.iterableType.tsym);
2985: if (iterableType.getTypeArguments().nonEmpty())
2986: iteratorTarget = types.erasure(iterableType
2987: .getTypeArguments().head);
2988: Type eType = tree.expr.type;
2989: tree.expr.type = types.erasure(eType);
2990: if (eType.tag == TYPEVAR && eType.getUpperBound().isCompound())
2991: tree.expr = make.TypeCast(types.erasure(iterableType),
2992: tree.expr);
2993: Symbol iterator = lookupMethod(tree.expr.pos(), names.iterator,
2994: types.erasure(syms.iterableType), List.<Type> nil());
2995: VarSymbol itvar = new VarSymbol(0, names.fromString("i"
2996: + target.syntheticNameChar()), types
2997: .erasure(iterator.type.getReturnType()),
2998: currentMethodSym);
2999: JCStatement init = make.VarDef(itvar, make.App(make.Select(
3000: tree.expr, iterator)));
3001: Symbol hasNext = lookupMethod(tree.expr.pos(), names.hasNext,
3002: itvar.type, List.<Type> nil());
3003: JCMethodInvocation cond = make.App(make.Select(make
3004: .Ident(itvar), hasNext));
3005: Symbol next = lookupMethod(tree.expr.pos(), names.next,
3006: itvar.type, List.<Type> nil());
3007: JCExpression vardefinit = make.App(make.Select(make
3008: .Ident(itvar), next));
3009: if (iteratorTarget != syms.objectType)
3010: vardefinit = make.TypeCast(iteratorTarget, vardefinit);
3011: JCVariableDecl indexDef = make.VarDef(tree.var.sym, vardefinit);
3012: JCBlock body = make.Block(0, List.of(indexDef, tree.body));
3013: result = translate(make.ForLoop(List.of(init), cond, List
3014: .<JCExpressionStatement> nil(), body));
3015: patchTargets(body, tree, result);
3016: }
3017:
3018: public void visitVarDef(JCVariableDecl tree) {
3019: MethodSymbol oldMethodSym = currentMethodSym;
3020: tree.mods = translate(tree.mods);
3021: tree.vartype = translate(tree.vartype);
3022: if (currentMethodSym == null) {
3023: // A class or instance field initializer.
3024: currentMethodSym = new MethodSymbol(
3025: (tree.mods.flags & STATIC) | BLOCK, names.empty,
3026: null, currentClass);
3027: }
3028: if (tree.init != null)
3029: tree.init = translate(tree.init, tree.type);
3030: result = tree;
3031: currentMethodSym = oldMethodSym;
3032: }
3033:
3034: public void visitBlock(JCBlock tree) {
3035: MethodSymbol oldMethodSym = currentMethodSym;
3036: if (currentMethodSym == null) {
3037: // Block is a static or instance initializer.
3038: currentMethodSym = new MethodSymbol(tree.flags | BLOCK,
3039: names.empty, null, currentClass);
3040: }
3041: super .visitBlock(tree);
3042: currentMethodSym = oldMethodSym;
3043: }
3044:
3045: public void visitDoLoop(JCDoWhileLoop tree) {
3046: tree.body = translate(tree.body);
3047: tree.cond = translate(tree.cond, syms.booleanType);
3048: result = tree;
3049: }
3050:
3051: public void visitWhileLoop(JCWhileLoop tree) {
3052: tree.cond = translate(tree.cond, syms.booleanType);
3053: tree.body = translate(tree.body);
3054: result = tree;
3055: }
3056:
3057: public void visitForLoop(JCForLoop tree) {
3058: tree.init = translate(tree.init);
3059: if (tree.cond != null)
3060: tree.cond = translate(tree.cond, syms.booleanType);
3061: tree.step = translate(tree.step);
3062: tree.body = translate(tree.body);
3063: result = tree;
3064: }
3065:
3066: public void visitReturn(JCReturn tree) {
3067: if (tree.expr != null)
3068: tree.expr = translate(tree.expr, types
3069: .erasure(currentMethodDef.restype.type));
3070: result = tree;
3071: }
3072:
3073: public void visitSwitch(JCSwitch tree) {
3074: Type selsuper = types.super type(tree.selector.type);
3075: boolean enumSwitch = selsuper != null
3076: && (tree.selector.type.tsym.flags() & ENUM) != 0;
3077: Type target = enumSwitch ? tree.selector.type : syms.intType;
3078: tree.selector = translate(tree.selector, target);
3079: tree.cases = translateCases(tree.cases);
3080: if (enumSwitch) {
3081: result = visitEnumSwitch(tree);
3082: patchTargets(result, tree, result);
3083: } else {
3084: result = tree;
3085: }
3086: }
3087:
3088: public JCTree visitEnumSwitch(JCSwitch tree) {
3089: TypeSymbol enumSym = tree.selector.type.tsym;
3090: EnumMapping map = mapForEnum(tree.pos(), enumSym);
3091: make_at(tree.pos());
3092: Symbol ordinalMethod = lookupMethod(tree.pos(), names.ordinal,
3093: tree.selector.type, List.<Type> nil());
3094: JCArrayAccess selector = make.Indexed(map.mapVar, make.App(make
3095: .Select(tree.selector, ordinalMethod)));
3096: ListBuffer<JCCase> cases = new ListBuffer<JCCase>();
3097: for (JCCase c : tree.cases) {
3098: if (c.pat != null) {
3099: VarSymbol label = (VarSymbol) TreeInfo.symbol(c.pat);
3100: JCLiteral pat = map.forConstant(label);
3101: cases.append(make.Case(pat, c.stats));
3102: } else {
3103: cases.append(c);
3104: }
3105: }
3106: return make.Switch(selector, cases.toList());
3107: }
3108:
3109: public void visitNewArray(JCNewArray tree) {
3110: tree.elemtype = translate(tree.elemtype);
3111: for (List<JCExpression> t = tree.dims; t.tail != null; t = t.tail)
3112: if (t.head != null)
3113: t.head = translate(t.head, syms.intType);
3114: tree.elems = translate(tree.elems, types.elemtype(tree.type));
3115: result = tree;
3116: }
3117:
3118: public void visitSelect(JCFieldAccess tree) {
3119: // need to special case-access of the form C.super.x
3120: // these will always need an access method.
3121: boolean qualifiedSuperAccess = tree.selected.getTag() == JCTree.SELECT
3122: && TreeInfo.name(tree.selected) == names._super ;
3123: tree.selected = translate(tree.selected);
3124: if (tree.name == names._class)
3125: result = classOf(tree.selected);
3126: else if (tree.name == names._this || tree.name == names._super )
3127: result = makeThis(tree.pos(), tree.selected.type.tsym);
3128: else
3129: result = access(tree.sym, tree, enclOp,
3130: qualifiedSuperAccess);
3131: }
3132:
3133: public void visitLetExpr(LetExpr tree) {
3134: tree.defs = translateVarDefs(tree.defs);
3135: tree.expr = translate(tree.expr, tree.type);
3136: result = tree;
3137: }
3138:
3139: // There ought to be nothing to rewrite here;
3140: // we don't generate code.
3141: public void visitAnnotation(JCAnnotation tree) {
3142: result = tree;
3143: }
3144:
3145: /**************************************************************************
3146: * main method
3147: *************************************************************************/
3148:
3149: /** Translate a toplevel class and return a list consisting of
3150: * the translated class and translated versions of all inner classes.
3151: * @param env The attribution environment current at the class definition.
3152: * We need this for resolving some additional symbols.
3153: * @param cdef The tree representing the class definition.
3154: */
3155: public List<JCTree> translateTopLevelClass(Env<AttrContext> env,
3156: JCTree cdef, TreeMaker make) {
3157: ListBuffer<JCTree> translated = null;
3158: try {
3159: attrEnv = env;
3160: this .make = make;
3161: endPositions = env.toplevel.endPositions;
3162: currentClass = null;
3163: currentMethodDef = null;
3164: outermostClassDef = (cdef.getTag() == JCTree.CLASSDEF) ? (JCClassDecl) cdef
3165: : null;
3166: outermostMemberDef = null;
3167: this .translated = new ListBuffer<JCTree>();
3168: classdefs = new HashMap<ClassSymbol, JCClassDecl>();
3169: actualSymbols = new HashMap<Symbol, Symbol>();
3170: freevarCache = new HashMap<ClassSymbol, List<VarSymbol>>();
3171: proxies = new Scope(syms.noSymbol);
3172: outerThisStack = List.nil();
3173: accessNums = new HashMap<Symbol, Integer>();
3174: accessSyms = new HashMap<Symbol, MethodSymbol[]>();
3175: accessConstrs = new HashMap<Symbol, MethodSymbol>();
3176: accessed = new ListBuffer<Symbol>();
3177: translate(cdef, (JCExpression) null);
3178: for (List<Symbol> l = accessed.toList(); l.nonEmpty(); l = l.tail)
3179: makeAccessible(l.head);
3180: for (EnumMapping map : enumSwitchMap.values())
3181: map.translate();
3182: translated = this .translated;
3183: } finally {
3184: // note that recursive invocations of this method fail hard
3185: attrEnv = null;
3186: this .make = null;
3187: endPositions = null;
3188: currentClass = null;
3189: currentMethodDef = null;
3190: outermostClassDef = null;
3191: outermostMemberDef = null;
3192: this .translated = null;
3193: classdefs = null;
3194: actualSymbols = null;
3195: freevarCache = null;
3196: proxies = null;
3197: outerThisStack = null;
3198: accessNums = null;
3199: accessSyms = null;
3200: accessConstrs = null;
3201: accessed = null;
3202: enumSwitchMap.clear();
3203: }
3204: return translated.toList();
3205: }
3206:
3207: //////////////////////////////////////////////////////////////
3208: // The following contributed by Borland for bootstrapping purposes
3209: //////////////////////////////////////////////////////////////
3210: private void addEnumCompatibleMembers(JCClassDecl cdef) {
3211: make_at(null);
3212:
3213: // Add the special enum fields
3214: VarSymbol ordinalFieldSym = addEnumOrdinalField(cdef);
3215: VarSymbol nameFieldSym = addEnumNameField(cdef);
3216:
3217: // Add the accessor methods for name and ordinal
3218: MethodSymbol ordinalMethodSym = addEnumFieldOrdinalMethod(cdef,
3219: ordinalFieldSym);
3220: MethodSymbol nameMethodSym = addEnumFieldNameMethod(cdef,
3221: nameFieldSym);
3222:
3223: // Add the toString method
3224: addEnumToString(cdef, nameFieldSym);
3225:
3226: // Add the compareTo method
3227: addEnumCompareTo(cdef, ordinalFieldSym);
3228: }
3229:
3230: private VarSymbol addEnumOrdinalField(JCClassDecl cdef) {
3231: VarSymbol ordinal = new VarSymbol(PRIVATE | FINAL | SYNTHETIC,
3232: names.fromString("$ordinal"), syms.intType, cdef.sym);
3233: cdef.sym.members().enter(ordinal);
3234: cdef.defs = cdef.defs.prepend(make.VarDef(ordinal, null));
3235: return ordinal;
3236: }
3237:
3238: private VarSymbol addEnumNameField(JCClassDecl cdef) {
3239: VarSymbol name = new VarSymbol(PRIVATE | FINAL | SYNTHETIC,
3240: names.fromString("$name"), syms.stringType, cdef.sym);
3241: cdef.sym.members().enter(name);
3242: cdef.defs = cdef.defs.prepend(make.VarDef(name, null));
3243: return name;
3244: }
3245:
3246: private MethodSymbol addEnumFieldOrdinalMethod(JCClassDecl cdef,
3247: VarSymbol ordinalSymbol) {
3248: // Add the accessor methods for ordinal
3249: Symbol ordinalSym = lookupMethod(cdef.pos(), names.ordinal,
3250: cdef.type, List.<Type> nil());
3251:
3252: assert (ordinalSym != null);
3253: assert (ordinalSym instanceof MethodSymbol);
3254:
3255: JCStatement ret = make.Return(make.Ident(ordinalSymbol));
3256: cdef.defs = cdef.defs.append(make
3257: .MethodDef((MethodSymbol) ordinalSym, make.Block(0L,
3258: List.of(ret))));
3259:
3260: return (MethodSymbol) ordinalSym;
3261: }
3262:
3263: private MethodSymbol addEnumFieldNameMethod(JCClassDecl cdef,
3264: VarSymbol nameSymbol) {
3265: // Add the accessor methods for name
3266: Symbol nameSym = lookupMethod(cdef.pos(), names._name,
3267: cdef.type, List.<Type> nil());
3268:
3269: assert (nameSym != null);
3270: assert (nameSym instanceof MethodSymbol);
3271:
3272: JCStatement ret = make.Return(make.Ident(nameSymbol));
3273:
3274: cdef.defs = cdef.defs.append(make.MethodDef(
3275: (MethodSymbol) nameSym, make.Block(0L, List.of(ret))));
3276:
3277: return (MethodSymbol) nameSym;
3278: }
3279:
3280: private MethodSymbol addEnumToString(JCClassDecl cdef,
3281: VarSymbol nameSymbol) {
3282: Symbol toStringSym = lookupMethod(cdef.pos(), names.toString,
3283: cdef.type, List.<Type> nil());
3284:
3285: JCTree toStringDecl = null;
3286: if (toStringSym != null)
3287: toStringDecl = TreeInfo.declarationFor(toStringSym, cdef);
3288:
3289: if (toStringDecl != null)
3290: return (MethodSymbol) toStringSym;
3291:
3292: JCStatement ret = make.Return(make.Ident(nameSymbol));
3293:
3294: JCTree resTypeTree = make.Type(syms.stringType);
3295:
3296: MethodType toStringType = new MethodType(List.<Type> nil(),
3297: syms.stringType, List.<Type> nil(), cdef.sym);
3298: toStringSym = new MethodSymbol(PUBLIC, names.toString,
3299: toStringType, cdef.type.tsym);
3300: toStringDecl = make.MethodDef((MethodSymbol) toStringSym, make
3301: .Block(0L, List.of(ret)));
3302:
3303: cdef.defs = cdef.defs.prepend(toStringDecl);
3304: cdef.sym.members().enter(toStringSym);
3305:
3306: return (MethodSymbol) toStringSym;
3307: }
3308:
3309: private MethodSymbol addEnumCompareTo(JCClassDecl cdef,
3310: VarSymbol ordinalSymbol) {
3311: Symbol compareToSym = lookupMethod(cdef.pos(), names.compareTo,
3312: cdef.type, List.of(cdef.sym.type));
3313:
3314: assert (compareToSym != null);
3315: assert (compareToSym instanceof MethodSymbol);
3316:
3317: JCMethodDecl compareToDecl = (JCMethodDecl) TreeInfo
3318: .declarationFor(compareToSym, cdef);
3319:
3320: ListBuffer<JCStatement> blockStatements = new ListBuffer<JCStatement>();
3321:
3322: JCModifiers mod1 = make.Modifiers(0L);
3323: Name oName = Name.fromString(names, "o");
3324: JCVariableDecl par1 = make
3325: .Param(oName, cdef.type, compareToSym);
3326:
3327: JCIdent paramId1 = make.Ident(names.java_lang_Object);
3328: paramId1.type = cdef.type;
3329: paramId1.sym = par1.sym;
3330:
3331: ((MethodSymbol) compareToSym).params = List.of(par1.sym);
3332:
3333: JCIdent par1UsageId = make.Ident(par1.sym);
3334: JCIdent castTargetIdent = make.Ident(cdef.sym);
3335: JCTypeCast cast = make.TypeCast(castTargetIdent, par1UsageId);
3336: cast.setType(castTargetIdent.type);
3337:
3338: Name otherName = Name.fromString(names, "other");
3339:
3340: VarSymbol otherVarSym = new VarSymbol(mod1.flags, otherName,
3341: cdef.type, compareToSym);
3342: JCVariableDecl otherVar = make.VarDef(otherVarSym, cast);
3343: blockStatements.append(otherVar);
3344:
3345: JCIdent id1 = make.Ident(ordinalSymbol);
3346:
3347: JCIdent fLocUsageId = make.Ident(otherVarSym);
3348: JCExpression sel = make.Select(fLocUsageId, ordinalSymbol);
3349: JCBinary bin = makeBinary(JCTree.MINUS, id1, sel);
3350: JCReturn ret = make.Return(bin);
3351: blockStatements.append(ret);
3352: JCMethodDecl compareToMethod = make.MethodDef(
3353: (MethodSymbol) compareToSym, make.Block(0L,
3354: blockStatements.toList()));
3355: compareToMethod.params = List.of(par1);
3356: cdef.defs = cdef.defs.append(compareToMethod);
3357:
3358: return (MethodSymbol) compareToSym;
3359: }
3360: //////////////////////////////////////////////////////////////
3361: // The above contributed by Borland for bootstrapping purposes
3362: //////////////////////////////////////////////////////////////
3363: }
|