0001: /*
0002: * Copyright 1999-2007 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.jvm;
0027:
0028: import java.util.*;
0029:
0030: import com.sun.tools.javac.util.*;
0031: import com.sun.tools.javac.util.JCDiagnostic.DiagnosticPosition;
0032: import com.sun.tools.javac.util.List;
0033: import com.sun.tools.javac.code.*;
0034: import com.sun.tools.javac.comp.*;
0035: import com.sun.tools.javac.tree.*;
0036:
0037: import com.sun.tools.javac.code.Symbol.*;
0038: import com.sun.tools.javac.code.Type.*;
0039: import com.sun.tools.javac.jvm.Code.*;
0040: import com.sun.tools.javac.jvm.Items.*;
0041: import com.sun.tools.javac.tree.JCTree.*;
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: import static com.sun.tools.javac.jvm.CRTFlags.*;
0048:
0049: /** This pass maps flat Java (i.e. without inner classes) to bytecodes.
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("@(#)Gen.java 1.154 07/06/14")
0057: public class Gen extends JCTree.Visitor {
0058: protected static final Context.Key<Gen> genKey = new Context.Key<Gen>();
0059:
0060: private final Log log;
0061: private final Symtab syms;
0062: private final Check chk;
0063: private final Resolve rs;
0064: private final TreeMaker make;
0065: private final Name.Table names;
0066: private final Target target;
0067: private final Type stringBufferType;
0068: private final Map<Type, Symbol> stringBufferAppend;
0069: private Name accessDollar;
0070: private final Types types;
0071:
0072: /** Switch: GJ mode?
0073: */
0074: private final boolean allowGenerics;
0075:
0076: /** Set when Miranda method stubs are to be generated. */
0077: private final boolean generateIproxies;
0078:
0079: /** Format of stackmap tables to be generated. */
0080: private final Code.StackMapFormat stackMap;
0081:
0082: /** A type that serves as the expected type for all method expressions.
0083: */
0084: private final Type methodType;
0085:
0086: public static Gen instance(Context context) {
0087: Gen instance = context.get(genKey);
0088: if (instance == null)
0089: instance = new Gen(context);
0090: return instance;
0091: }
0092:
0093: protected Gen(Context context) {
0094: context.put(genKey, this );
0095:
0096: names = Name.Table.instance(context);
0097: log = Log.instance(context);
0098: syms = Symtab.instance(context);
0099: chk = Check.instance(context);
0100: rs = Resolve.instance(context);
0101: make = TreeMaker.instance(context);
0102: target = Target.instance(context);
0103: types = Types.instance(context);
0104: methodType = new MethodType(null, null, null, syms.methodClass);
0105: allowGenerics = Source.instance(context).allowGenerics();
0106: stringBufferType = target.useStringBuilder() ? syms.stringBuilderType
0107: : syms.stringBufferType;
0108: stringBufferAppend = new HashMap<Type, Symbol>();
0109: accessDollar = names.fromString("access"
0110: + target.syntheticNameChar());
0111:
0112: Options options = Options.instance(context);
0113: lineDebugInfo = options.get("-g:") == null
0114: || options.get("-g:lines") != null;
0115: varDebugInfo = options.get("-g:") == null ? options.get("-g") != null
0116: : options.get("-g:vars") != null;
0117: genCrt = options.get("-Xjcov") != null;
0118: debugCode = options.get("debugcode") != null;
0119:
0120: generateIproxies = target.requiresIproxy()
0121: || options.get("miranda") != null;
0122:
0123: if (target.generateStackMapTable()) {
0124: // ignore cldc because we cannot have both stackmap formats
0125: this .stackMap = StackMapFormat.JSR202;
0126: } else {
0127: if (target.generateCLDCStackmap()) {
0128: this .stackMap = StackMapFormat.CLDC;
0129: } else {
0130: this .stackMap = StackMapFormat.NONE;
0131: }
0132: }
0133:
0134: // by default, avoid jsr's for simple finalizers
0135: int setjsrlimit = 50;
0136: String jsrlimitString = options.get("jsrlimit");
0137: if (jsrlimitString != null) {
0138: try {
0139: setjsrlimit = Integer.parseInt(jsrlimitString);
0140: } catch (NumberFormatException ex) {
0141: // ignore ill-formed numbers for jsrlimit
0142: }
0143: }
0144: this .jsrlimit = setjsrlimit;
0145: this .useJsrLocally = false; // reset in visitTry
0146: }
0147:
0148: /** Switches
0149: */
0150: private final boolean lineDebugInfo;
0151: private final boolean varDebugInfo;
0152: private final boolean genCrt;
0153: private final boolean debugCode;
0154:
0155: /** Default limit of (approximate) size of finalizer to inline.
0156: * Zero means always use jsr. 100 or greater means never use
0157: * jsr.
0158: */
0159: private final int jsrlimit;
0160:
0161: /** True if jsr is used.
0162: */
0163: private boolean useJsrLocally;
0164:
0165: /* Constant pool, reset by genClass.
0166: */
0167: private Pool pool = new Pool();
0168:
0169: /** Code buffer, set by genMethod.
0170: */
0171: private Code code;
0172:
0173: /** Items structure, set by genMethod.
0174: */
0175: private Items items;
0176:
0177: /** Environment for symbol lookup, set by genClass
0178: */
0179: private Env<AttrContext> attrEnv;
0180:
0181: /** The top level tree.
0182: */
0183: private JCCompilationUnit toplevel;
0184:
0185: /** The number of code-gen errors in this class.
0186: */
0187: private int nerrs = 0;
0188:
0189: /** A hash table mapping syntax trees to their ending source positions.
0190: */
0191: private Map<JCTree, Integer> endPositions;
0192:
0193: /** Generate code to load an integer constant.
0194: * @param n The integer to be loaded.
0195: */
0196: void loadIntConst(int n) {
0197: items.makeImmediateItem(syms.intType, n).load();
0198: }
0199:
0200: /** The opcode that loads a zero constant of a given type code.
0201: * @param tc The given type code (@see ByteCode).
0202: */
0203: public static int zero(int tc) {
0204: switch (tc) {
0205: case INTcode:
0206: case BYTEcode:
0207: case SHORTcode:
0208: case CHARcode:
0209: return iconst_0;
0210: case LONGcode:
0211: return lconst_0;
0212: case FLOATcode:
0213: return fconst_0;
0214: case DOUBLEcode:
0215: return dconst_0;
0216: default:
0217: throw new AssertionError("zero");
0218: }
0219: }
0220:
0221: /** The opcode that loads a one constant of a given type code.
0222: * @param tc The given type code (@see ByteCode).
0223: */
0224: public static int one(int tc) {
0225: return zero(tc) + 1;
0226: }
0227:
0228: /** Generate code to load -1 of the given type code (either int or long).
0229: * @param tc The given type code (@see ByteCode).
0230: */
0231: void emitMinusOne(int tc) {
0232: if (tc == LONGcode) {
0233: items.makeImmediateItem(syms.longType, new Long(-1)).load();
0234: } else {
0235: code.emitop0(iconst_m1);
0236: }
0237: }
0238:
0239: /** Construct a symbol to reflect the qualifying type that should
0240: * appear in the byte code as per JLS 13.1.
0241: *
0242: * For target >= 1.2: Clone a method with the qualifier as owner (except
0243: * for those cases where we need to work around VM bugs).
0244: *
0245: * For target <= 1.1: If qualified variable or method is defined in a
0246: * non-accessible class, clone it with the qualifier class as owner.
0247: *
0248: * @param sym The accessed symbol
0249: * @param site The qualifier's type.
0250: */
0251: Symbol binaryQualifier(Symbol sym, Type site) {
0252:
0253: if (site.tag == ARRAY) {
0254: if (sym == syms.lengthVar || sym.owner != syms.arrayClass)
0255: return sym;
0256: // array clone can be qualified by the array type in later targets
0257: Symbol qualifier = target.arrayBinaryCompatibility() ? new ClassSymbol(
0258: Flags.PUBLIC, site.tsym.name, site, syms.noSymbol)
0259: : syms.objectType.tsym;
0260: return sym.clone(qualifier);
0261: }
0262:
0263: if (sym.owner == site.tsym
0264: || (sym.flags() & (STATIC | SYNTHETIC)) == (STATIC | SYNTHETIC)) {
0265: return sym;
0266: }
0267: if (!target.obeyBinaryCompatibility())
0268: return rs.isAccessible(attrEnv, (TypeSymbol) sym.owner) ? sym
0269: : sym.clone(site.tsym);
0270:
0271: if (!target.interfaceFieldsBinaryCompatibility()) {
0272: if ((sym.owner.flags() & INTERFACE) != 0 && sym.kind == VAR)
0273: return sym;
0274: }
0275:
0276: // leave alone methods inherited from Object
0277: // JLS2 13.1.
0278: if (sym.owner == syms.objectType.tsym)
0279: return sym;
0280:
0281: if (!target.interfaceObjectOverridesBinaryCompatibility()) {
0282: if ((sym.owner.flags() & INTERFACE) != 0
0283: && syms.objectType.tsym.members().lookup(sym.name).scope != null)
0284: return sym;
0285: }
0286:
0287: return sym.clone(site.tsym);
0288: }
0289:
0290: /** Insert a reference to given type in the constant pool,
0291: * checking for an array with too many dimensions;
0292: * return the reference's index.
0293: * @param type The type for which a reference is inserted.
0294: */
0295: int makeRef(DiagnosticPosition pos, Type type) {
0296: checkDimension(pos, type);
0297: return pool.put(type.tag == CLASS ? (Object) type.tsym
0298: : (Object) type);
0299: }
0300:
0301: /** Check if the given type is an array with too many dimensions.
0302: */
0303: private void checkDimension(DiagnosticPosition pos, Type t) {
0304: switch (t.tag) {
0305: case METHOD:
0306: checkDimension(pos, t.getReturnType());
0307: for (List<Type> args = t.getParameterTypes(); args
0308: .nonEmpty(); args = args.tail)
0309: checkDimension(pos, args.head);
0310: break;
0311: case ARRAY:
0312: if (types.dimensions(t) > ClassFile.MAX_DIMENSIONS) {
0313: log.error(pos, "limit.dimensions");
0314: nerrs++;
0315: }
0316: break;
0317: default:
0318: break;
0319: }
0320: }
0321:
0322: /** Create a tempory variable.
0323: * @param type The variable's type.
0324: */
0325: LocalItem makeTemp(Type type) {
0326: VarSymbol v = new VarSymbol(Flags.SYNTHETIC, names.empty, type,
0327: env.enclMethod.sym);
0328: code.newLocal(v);
0329: return items.makeLocalItem(v);
0330: }
0331:
0332: /** Generate code to call a non-private method or constructor.
0333: * @param pos Position to be used for error reporting.
0334: * @param site The type of which the method is a member.
0335: * @param name The method's name.
0336: * @param argtypes The method's argument types.
0337: * @param isStatic A flag that indicates whether we call a
0338: * static or instance method.
0339: */
0340: void callMethod(DiagnosticPosition pos, Type site, Name name,
0341: List<Type> argtypes, boolean isStatic) {
0342: Symbol msym = rs.resolveInternalMethod(pos, attrEnv, site,
0343: name, argtypes, null);
0344: if (isStatic)
0345: items.makeStaticItem(msym).invoke();
0346: else
0347: items.makeMemberItem(msym, name == names.init).invoke();
0348: }
0349:
0350: /** Is the given method definition an access method
0351: * resulting from a qualified super? This is signified by an odd
0352: * access code.
0353: */
0354: private boolean isAccessSuper(JCMethodDecl enclMethod) {
0355: return (enclMethod.mods.flags & SYNTHETIC) != 0
0356: && isOddAccessName(enclMethod.name);
0357: }
0358:
0359: /** Does given name start with "access$" and end in an odd digit?
0360: */
0361: private boolean isOddAccessName(Name name) {
0362: return name.startsWith(accessDollar)
0363: && (name.byteAt(name.len - 1) & 1) == 1;
0364: }
0365:
0366: /* ************************************************************************
0367: * Non-local exits
0368: *************************************************************************/
0369:
0370: /** Generate code to invoke the finalizer associated with given
0371: * environment.
0372: * Any calls to finalizers are appended to the environments `cont' chain.
0373: * Mark beginning of gap in catch all range for finalizer.
0374: */
0375: void genFinalizer(Env<GenContext> env) {
0376: if (code.isAlive() && env.info.finalize != null)
0377: env.info.finalize.gen();
0378: }
0379:
0380: /** Generate code to call all finalizers of structures aborted by
0381: * a non-local
0382: * exit. Return target environment of the non-local exit.
0383: * @param target The tree representing the structure that's aborted
0384: * @param env The environment current at the non-local exit.
0385: */
0386: Env<GenContext> unwind(JCTree target, Env<GenContext> env) {
0387: Env<GenContext> env1 = env;
0388: while (true) {
0389: genFinalizer(env1);
0390: if (env1.tree == target)
0391: break;
0392: env1 = env1.next;
0393: }
0394: return env1;
0395: }
0396:
0397: /** Mark end of gap in catch-all range for finalizer.
0398: * @param env the environment which might contain the finalizer
0399: * (if it does, env.info.gaps != null).
0400: */
0401: void endFinalizerGap(Env<GenContext> env) {
0402: if (env.info.gaps != null && env.info.gaps.length() % 2 == 1)
0403: env.info.gaps.append(code.curPc());
0404: }
0405:
0406: /** Mark end of all gaps in catch-all ranges for finalizers of environments
0407: * lying between, and including to two environments.
0408: * @param from the most deeply nested environment to mark
0409: * @param to the least deeply nested environment to mark
0410: */
0411: void endFinalizerGaps(Env<GenContext> from, Env<GenContext> to) {
0412: Env<GenContext> last = null;
0413: while (last != to) {
0414: endFinalizerGap(from);
0415: last = from;
0416: from = from.next;
0417: }
0418: }
0419:
0420: /** Do any of the structures aborted by a non-local exit have
0421: * finalizers that require an empty stack?
0422: * @param target The tree representing the structure that's aborted
0423: * @param env The environment current at the non-local exit.
0424: */
0425: boolean hasFinally(JCTree target, Env<GenContext> env) {
0426: while (env.tree != target) {
0427: if (env.tree.getTag() == JCTree.TRY
0428: && env.info.finalize.hasFinalizer())
0429: return true;
0430: env = env.next;
0431: }
0432: return false;
0433: }
0434:
0435: /* ************************************************************************
0436: * Normalizing class-members.
0437: *************************************************************************/
0438:
0439: /** Distribute member initializer code into constructors and <clinit>
0440: * method.
0441: * @param defs The list of class member declarations.
0442: * @param c The enclosing class.
0443: */
0444: List<JCTree> normalizeDefs(List<JCTree> defs, ClassSymbol c) {
0445: ListBuffer<JCStatement> initCode = new ListBuffer<JCStatement>();
0446: ListBuffer<JCStatement> clinitCode = new ListBuffer<JCStatement>();
0447: ListBuffer<JCTree> methodDefs = new ListBuffer<JCTree>();
0448: // Sort definitions into three listbuffers:
0449: // - initCode for instance initializers
0450: // - clinitCode for class initializers
0451: // - methodDefs for method definitions
0452: for (List<JCTree> l = defs; l.nonEmpty(); l = l.tail) {
0453: JCTree def = l.head;
0454: switch (def.getTag()) {
0455: case JCTree.BLOCK:
0456: JCBlock block = (JCBlock) def;
0457: if ((block.flags & STATIC) != 0)
0458: clinitCode.append(block);
0459: else
0460: initCode.append(block);
0461: break;
0462: case JCTree.METHODDEF:
0463: methodDefs.append(def);
0464: break;
0465: case JCTree.VARDEF:
0466: JCVariableDecl vdef = (JCVariableDecl) def;
0467: VarSymbol sym = vdef.sym;
0468: checkDimension(vdef.pos(), sym.type);
0469: if (vdef.init != null) {
0470: if ((sym.flags() & STATIC) == 0) {
0471: // Always initialize instance variables.
0472: JCStatement init = make.at(vdef.pos())
0473: .Assignment(sym, vdef.init);
0474: initCode.append(init);
0475: if (endPositions != null) {
0476: Integer endPos = endPositions.remove(vdef);
0477: if (endPos != null)
0478: endPositions.put(init, endPos);
0479: }
0480: } else if (sym.getConstValue() == null) {
0481: // Initialize class (static) variables only if
0482: // they are not compile-time constants.
0483: JCStatement init = make.at(vdef.pos)
0484: .Assignment(sym, vdef.init);
0485: clinitCode.append(init);
0486: if (endPositions != null) {
0487: Integer endPos = endPositions.remove(vdef);
0488: if (endPos != null)
0489: endPositions.put(init, endPos);
0490: }
0491: } else {
0492: checkStringConstant(vdef.init.pos(), sym
0493: .getConstValue());
0494: }
0495: }
0496: break;
0497: default:
0498: assert false;
0499: }
0500: }
0501: // Insert any instance initializers into all constructors.
0502: if (initCode.length() != 0) {
0503: List<JCStatement> inits = initCode.toList();
0504: for (JCTree t : methodDefs) {
0505: normalizeMethod((JCMethodDecl) t, inits);
0506: }
0507: }
0508: // If there are class initializers, create a <clinit> method
0509: // that contains them as its body.
0510: if (clinitCode.length() != 0) {
0511: MethodSymbol clinit = new MethodSymbol(STATIC,
0512: names.clinit, new MethodType(List.<Type> nil(),
0513: syms.voidType, List.<Type> nil(),
0514: syms.methodClass), c);
0515: c.members().enter(clinit);
0516: List<JCStatement> clinitStats = clinitCode.toList();
0517: JCBlock block = make.at(clinitStats.head.pos()).Block(0,
0518: clinitStats);
0519: block.endpos = TreeInfo.endPos(clinitStats.last());
0520: methodDefs.append(make.MethodDef(clinit, block));
0521: }
0522: // Return all method definitions.
0523: return methodDefs.toList();
0524: }
0525:
0526: /** Check a constant value and report if it is a string that is
0527: * too large.
0528: */
0529: private void checkStringConstant(DiagnosticPosition pos,
0530: Object constValue) {
0531: if (nerrs != 0
0532: || // only complain about a long string once
0533: constValue == null
0534: || !(constValue instanceof String)
0535: || ((String) constValue).length() < Pool.MAX_STRING_LENGTH)
0536: return;
0537: log.error(pos, "limit.string");
0538: nerrs++;
0539: }
0540:
0541: /** Insert instance initializer code into initial constructor.
0542: * @param md The tree potentially representing a
0543: * constructor's definition.
0544: * @param initCode The list of instance initializer statements.
0545: */
0546: void normalizeMethod(JCMethodDecl md, List<JCStatement> initCode) {
0547: if (md.name == names.init && TreeInfo.isInitialConstructor(md)) {
0548: // We are seeing a constructor that does not call another
0549: // constructor of the same class.
0550: List<JCStatement> stats = md.body.stats;
0551: ListBuffer<JCStatement> newstats = new ListBuffer<JCStatement>();
0552:
0553: if (stats.nonEmpty()) {
0554: // Copy initializers of synthetic variables generated in
0555: // the translation of inner classes.
0556: while (TreeInfo.isSyntheticInit(stats.head)) {
0557: newstats.append(stats.head);
0558: stats = stats.tail;
0559: }
0560: // Copy superclass constructor call
0561: newstats.append(stats.head);
0562: stats = stats.tail;
0563: // Copy remaining synthetic initializers.
0564: while (stats.nonEmpty()
0565: && TreeInfo.isSyntheticInit(stats.head)) {
0566: newstats.append(stats.head);
0567: stats = stats.tail;
0568: }
0569: // Now insert the initializer code.
0570: newstats.appendList(initCode);
0571: // And copy all remaining statements.
0572: while (stats.nonEmpty()) {
0573: newstats.append(stats.head);
0574: stats = stats.tail;
0575: }
0576: }
0577: md.body.stats = newstats.toList();
0578: if (md.body.endpos == Position.NOPOS)
0579: md.body.endpos = TreeInfo.endPos(md.body.stats.last());
0580: }
0581: }
0582:
0583: /* ********************************************************************
0584: * Adding miranda methods
0585: *********************************************************************/
0586:
0587: /** Add abstract methods for all methods defined in one of
0588: * the interfaces of a given class,
0589: * provided they are not already implemented in the class.
0590: *
0591: * @param c The class whose interfaces are searched for methods
0592: * for which Miranda methods should be added.
0593: */
0594: void implementInterfaceMethods(ClassSymbol c) {
0595: implementInterfaceMethods(c, c);
0596: }
0597:
0598: /** Add abstract methods for all methods defined in one of
0599: * the interfaces of a given class,
0600: * provided they are not already implemented in the class.
0601: *
0602: * @param c The class whose interfaces are searched for methods
0603: * for which Miranda methods should be added.
0604: * @param site The class in which a definition may be needed.
0605: */
0606: void implementInterfaceMethods(ClassSymbol c, ClassSymbol site) {
0607: for (List<Type> l = types.interfaces(c.type); l.nonEmpty(); l = l.tail) {
0608: ClassSymbol i = (ClassSymbol) l.head.tsym;
0609: for (Scope.Entry e = i.members().elems; e != null; e = e.sibling) {
0610: if (e.sym.kind == MTH && (e.sym.flags() & STATIC) == 0) {
0611: MethodSymbol absMeth = (MethodSymbol) e.sym;
0612: MethodSymbol implMeth = absMeth
0613: .binaryImplementation(site, types);
0614: if (implMeth == null)
0615: addAbstractMethod(site, absMeth);
0616: else if ((implMeth.flags() & IPROXY) != 0)
0617: adjustAbstractMethod(site, implMeth, absMeth);
0618: }
0619: }
0620: implementInterfaceMethods(i, site);
0621: }
0622: }
0623:
0624: /** Add an abstract methods to a class
0625: * which implicitly implements a method defined in some interface
0626: * implemented by the class. These methods are called "Miranda methods".
0627: * Enter the newly created method into its enclosing class scope.
0628: * Note that it is not entered into the class tree, as the emitter
0629: * doesn't need to see it there to emit an abstract method.
0630: *
0631: * @param c The class to which the Miranda method is added.
0632: * @param m The interface method symbol for which a Miranda method
0633: * is added.
0634: */
0635: private void addAbstractMethod(ClassSymbol c, MethodSymbol m) {
0636: MethodSymbol absMeth = new MethodSymbol(m.flags() | IPROXY
0637: | SYNTHETIC, m.name, m.type, // was c.type.memberType(m), but now only !generics supported
0638: c);
0639: c.members().enter(absMeth); // add to symbol table
0640: }
0641:
0642: private void adjustAbstractMethod(ClassSymbol c, MethodSymbol pm,
0643: MethodSymbol im) {
0644: MethodType pmt = (MethodType) pm.type;
0645: Type imt = types.memberType(c.type, im);
0646: pmt.thrown = chk.intersect(pmt.getThrownTypes(), imt
0647: .getThrownTypes());
0648: }
0649:
0650: /* ************************************************************************
0651: * Traversal methods
0652: *************************************************************************/
0653:
0654: /** Visitor argument: The current environment.
0655: */
0656: Env<GenContext> env;
0657:
0658: /** Visitor argument: The expected type (prototype).
0659: */
0660: Type pt;
0661:
0662: /** Visitor result: The item representing the computed value.
0663: */
0664: Item result;
0665:
0666: /** Visitor method: generate code for a definition, catching and reporting
0667: * any completion failures.
0668: * @param tree The definition to be visited.
0669: * @param env The environment current at the definition.
0670: */
0671: public void genDef(JCTree tree, Env<GenContext> env) {
0672: Env<GenContext> prevEnv = this .env;
0673: try {
0674: this .env = env;
0675: tree.accept(this );
0676: } catch (CompletionFailure ex) {
0677: chk.completionError(tree.pos(), ex);
0678: } finally {
0679: this .env = prevEnv;
0680: }
0681: }
0682:
0683: /** Derived visitor method: check whether CharacterRangeTable
0684: * should be emitted, if so, put a new entry into CRTable
0685: * and call method to generate bytecode.
0686: * If not, just call method to generate bytecode.
0687: * @see #genStat(Tree, Env)
0688: *
0689: * @param tree The tree to be visited.
0690: * @param env The environment to use.
0691: * @param crtFlags The CharacterRangeTable flags
0692: * indicating type of the entry.
0693: */
0694: public void genStat(JCTree tree, Env<GenContext> env, int crtFlags) {
0695: if (!genCrt) {
0696: genStat(tree, env);
0697: return;
0698: }
0699: int startpc = code.curPc();
0700: genStat(tree, env);
0701: if (tree.getTag() == JCTree.BLOCK)
0702: crtFlags |= CRT_BLOCK;
0703: code.crt.put(tree, crtFlags, startpc, code.curPc());
0704: }
0705:
0706: /** Derived visitor method: generate code for a statement.
0707: */
0708: public void genStat(JCTree tree, Env<GenContext> env) {
0709: if (code.isAlive()) {
0710: code.statBegin(tree.pos);
0711: genDef(tree, env);
0712: } else if (env.info.isSwitch && tree.getTag() == JCTree.VARDEF) {
0713: // variables whose declarations are in a switch
0714: // can be used even if the decl is unreachable.
0715: code.newLocal(((JCVariableDecl) tree).sym);
0716: }
0717: }
0718:
0719: /** Derived visitor method: check whether CharacterRangeTable
0720: * should be emitted, if so, put a new entry into CRTable
0721: * and call method to generate bytecode.
0722: * If not, just call method to generate bytecode.
0723: * @see #genStats(List, Env)
0724: *
0725: * @param trees The list of trees to be visited.
0726: * @param env The environment to use.
0727: * @param crtFlags The CharacterRangeTable flags
0728: * indicating type of the entry.
0729: */
0730: public void genStats(List<JCStatement> trees, Env<GenContext> env,
0731: int crtFlags) {
0732: if (!genCrt) {
0733: genStats(trees, env);
0734: return;
0735: }
0736: if (trees.length() == 1) { // mark one statement with the flags
0737: genStat(trees.head, env, crtFlags | CRT_STATEMENT);
0738: } else {
0739: int startpc = code.curPc();
0740: genStats(trees, env);
0741: code.crt.put(trees, crtFlags, startpc, code.curPc());
0742: }
0743: }
0744:
0745: /** Derived visitor method: generate code for a list of statements.
0746: */
0747: public void genStats(List<? extends JCTree> trees,
0748: Env<GenContext> env) {
0749: for (List<? extends JCTree> l = trees; l.nonEmpty(); l = l.tail)
0750: genStat(l.head, env, CRT_STATEMENT);
0751: }
0752:
0753: /** Derived visitor method: check whether CharacterRangeTable
0754: * should be emitted, if so, put a new entry into CRTable
0755: * and call method to generate bytecode.
0756: * If not, just call method to generate bytecode.
0757: * @see #genCond(Tree,boolean)
0758: *
0759: * @param tree The tree to be visited.
0760: * @param crtFlags The CharacterRangeTable flags
0761: * indicating type of the entry.
0762: */
0763: public CondItem genCond(JCTree tree, int crtFlags) {
0764: if (!genCrt)
0765: return genCond(tree, false);
0766: int startpc = code.curPc();
0767: CondItem item = genCond(tree,
0768: (crtFlags & CRT_FLOW_CONTROLLER) != 0);
0769: code.crt.put(tree, crtFlags, startpc, code.curPc());
0770: return item;
0771: }
0772:
0773: /** Derived visitor method: generate code for a boolean
0774: * expression in a control-flow context.
0775: * @param _tree The expression to be visited.
0776: * @param markBranches The flag to indicate that the condition is
0777: * a flow controller so produced conditions
0778: * should contain a proper tree to generate
0779: * CharacterRangeTable branches for them.
0780: */
0781: public CondItem genCond(JCTree _tree, boolean markBranches) {
0782: JCTree inner_tree = TreeInfo.skipParens(_tree);
0783: if (inner_tree.getTag() == JCTree.CONDEXPR) {
0784: JCConditional tree = (JCConditional) inner_tree;
0785: CondItem cond = genCond(tree.cond, CRT_FLOW_CONTROLLER);
0786: if (cond.isTrue()) {
0787: code.resolve(cond.trueJumps);
0788: CondItem result = genCond(tree.truepart,
0789: CRT_FLOW_TARGET);
0790: if (markBranches)
0791: result.tree = tree.truepart;
0792: return result;
0793: }
0794: if (cond.isFalse()) {
0795: code.resolve(cond.falseJumps);
0796: CondItem result = genCond(tree.falsepart,
0797: CRT_FLOW_TARGET);
0798: if (markBranches)
0799: result.tree = tree.falsepart;
0800: return result;
0801: }
0802: Chain secondJumps = cond.jumpFalse();
0803: code.resolve(cond.trueJumps);
0804: CondItem first = genCond(tree.truepart, CRT_FLOW_TARGET);
0805: if (markBranches)
0806: first.tree = tree.truepart;
0807: Chain falseJumps = first.jumpFalse();
0808: code.resolve(first.trueJumps);
0809: Chain trueJumps = code.branch(goto_);
0810: code.resolve(secondJumps);
0811: CondItem second = genCond(tree.falsepart, CRT_FLOW_TARGET);
0812: CondItem result = items.makeCondItem(second.opcode, code
0813: .mergeChains(trueJumps, second.trueJumps), code
0814: .mergeChains(falseJumps, second.falseJumps));
0815: if (markBranches)
0816: result.tree = tree.falsepart;
0817: return result;
0818: } else {
0819: CondItem result = genExpr(_tree, syms.booleanType).mkCond();
0820: if (markBranches)
0821: result.tree = _tree;
0822: return result;
0823: }
0824: }
0825:
0826: /** Visitor method: generate code for an expression, catching and reporting
0827: * any completion failures.
0828: * @param tree The expression to be visited.
0829: * @param pt The expression's expected type (proto-type).
0830: */
0831: public Item genExpr(JCTree tree, Type pt) {
0832: Type prevPt = this .pt;
0833: try {
0834: if (tree.type.constValue() != null) {
0835: // Short circuit any expressions which are constants
0836: checkStringConstant(tree.pos(), tree.type.constValue());
0837: result = items.makeImmediateItem(tree.type, tree.type
0838: .constValue());
0839: } else {
0840: this .pt = pt;
0841: tree.accept(this );
0842: }
0843: return result.coerce(pt);
0844: } catch (CompletionFailure ex) {
0845: chk.completionError(tree.pos(), ex);
0846: code.state.stacksize = 1;
0847: return items.makeStackItem(pt);
0848: } finally {
0849: this .pt = prevPt;
0850: }
0851: }
0852:
0853: /** Derived visitor method: generate code for a list of method arguments.
0854: * @param trees The argument expressions to be visited.
0855: * @param pts The expression's expected types (i.e. the formal parameter
0856: * types of the invoked method).
0857: */
0858: public void genArgs(List<JCExpression> trees, List<Type> pts) {
0859: for (List<JCExpression> l = trees; l.nonEmpty(); l = l.tail) {
0860: genExpr(l.head, pts.head).load();
0861: pts = pts.tail;
0862: }
0863: // require lists be of same length
0864: assert pts.isEmpty();
0865: }
0866:
0867: /* ************************************************************************
0868: * Visitor methods for statements and definitions
0869: *************************************************************************/
0870:
0871: /** Thrown when the byte code size exceeds limit.
0872: */
0873: public static class CodeSizeOverflow extends RuntimeException {
0874: private static final long serialVersionUID = 0;
0875:
0876: public CodeSizeOverflow() {
0877: }
0878: }
0879:
0880: public void visitMethodDef(JCMethodDecl tree) {
0881: // Create a new local environment that points pack at method
0882: // definition.
0883: Env<GenContext> localEnv = env.dup(tree);
0884: localEnv.enclMethod = tree;
0885:
0886: // The expected type of every return statement in this method
0887: // is the method's return type.
0888: this .pt = tree.sym.erasure(types).getReturnType();
0889:
0890: checkDimension(tree.pos(), tree.sym.erasure(types));
0891: genMethod(tree, localEnv, false);
0892: }
0893:
0894: //where
0895: /** Generate code for a method.
0896: * @param tree The tree representing the method definition.
0897: * @param env The environment current for the method body.
0898: * @param fatcode A flag that indicates whether all jumps are
0899: * within 32K. We first invoke this method under
0900: * the assumption that fatcode == false, i.e. all
0901: * jumps are within 32K. If this fails, fatcode
0902: * is set to true and we try again.
0903: */
0904: void genMethod(JCMethodDecl tree, Env<GenContext> env,
0905: boolean fatcode) {
0906: MethodSymbol meth = tree.sym;
0907: // System.err.println("Generating " + meth + " in " + meth.owner); //DEBUG
0908: if (Code.width(types.erasure(env.enclMethod.sym.type)
0909: .getParameterTypes())
0910: + (((tree.mods.flags & STATIC) == 0 || meth
0911: .isConstructor()) ? 1 : 0) > ClassFile.MAX_PARAMETERS) {
0912: log.error(tree.pos(), "limit.parameters");
0913: nerrs++;
0914: }
0915:
0916: else if (tree.body != null) {
0917: // Create a new code structure and initialize it.
0918: int startpcCrt = initCode(tree, env, fatcode);
0919:
0920: try {
0921: genStat(tree.body, env);
0922: } catch (CodeSizeOverflow e) {
0923: // Failed due to code limit, try again with jsr/ret
0924: startpcCrt = initCode(tree, env, fatcode);
0925: genStat(tree.body, env);
0926: }
0927:
0928: if (code.state.stacksize != 0) {
0929: log.error(tree.body.pos(), "stack.sim.error", tree);
0930: throw new AssertionError();
0931: }
0932:
0933: // If last statement could complete normally, insert a
0934: // return at the end.
0935: if (code.isAlive()) {
0936: code.statBegin(TreeInfo.endPos(tree.body));
0937: if (env.enclMethod == null
0938: || env.enclMethod.sym.type.getReturnType().tag == VOID) {
0939: code.emitop0(return_);
0940: } else {
0941: // sometime dead code seems alive (4415991);
0942: // generate a small loop instead
0943: int startpc = code.entryPoint();
0944: CondItem c = items.makeCondItem(goto_);
0945: code.resolve(c.jumpTrue(), startpc);
0946: }
0947: }
0948: if (genCrt)
0949: code.crt.put(tree.body, CRT_BLOCK, startpcCrt, code
0950: .curPc());
0951:
0952: // End the scope of all local variables in variable info.
0953: code.endScopes(0);
0954:
0955: // If we exceeded limits, panic
0956: if (code.checkLimits(tree.pos(), log)) {
0957: nerrs++;
0958: return;
0959: }
0960:
0961: // If we generated short code but got a long jump, do it again
0962: // with fatCode = true.
0963: if (!fatcode && code.fatcode)
0964: genMethod(tree, env, true);
0965:
0966: // Clean up
0967: if (stackMap == StackMapFormat.JSR202) {
0968: code.lastFrame = null;
0969: code.frameBeforeLast = null;
0970: }
0971: }
0972: }
0973:
0974: private int initCode(JCMethodDecl tree, Env<GenContext> env,
0975: boolean fatcode) {
0976: MethodSymbol meth = tree.sym;
0977:
0978: // Create a new code structure.
0979: meth.code = code = new Code(meth, fatcode,
0980: lineDebugInfo ? toplevel.lineMap : null, varDebugInfo,
0981: stackMap, debugCode, genCrt ? new CRTable(tree,
0982: env.toplevel.endPositions) : null, syms, types,
0983: pool);
0984: items = new Items(pool, code, syms, types);
0985: if (code.debugCode)
0986: System.err.println(meth + " for body " + tree);
0987:
0988: // If method is not static, create a new local variable address
0989: // for `this'.
0990: if ((tree.mods.flags & STATIC) == 0) {
0991: Type selfType = meth.owner.type;
0992: if (meth.isConstructor() && selfType != syms.objectType)
0993: selfType = UninitializedType
0994: .uninitializedThis(selfType);
0995: code.setDefined(code.newLocal(new VarSymbol(FINAL,
0996: names._this , selfType, meth.owner)));
0997: }
0998:
0999: // Mark all parameters as defined from the beginning of
1000: // the method.
1001: for (List<JCVariableDecl> l = tree.params; l.nonEmpty(); l = l.tail) {
1002: checkDimension(l.head.pos(), l.head.sym.type);
1003: code.setDefined(code.newLocal(l.head.sym));
1004: }
1005:
1006: // Get ready to generate code for method body.
1007: int startpcCrt = genCrt ? code.curPc() : 0;
1008: code.entryPoint();
1009:
1010: // Suppress initial stackmap
1011: code.pendingStackMap = false;
1012:
1013: return startpcCrt;
1014: }
1015:
1016: public void visitVarDef(JCVariableDecl tree) {
1017: VarSymbol v = tree.sym;
1018: code.newLocal(v);
1019: if (tree.init != null) {
1020: checkStringConstant(tree.init.pos(), v.getConstValue());
1021: if (v.getConstValue() == null || varDebugInfo) {
1022: genExpr(tree.init, v.erasure(types)).load();
1023: items.makeLocalItem(v).store();
1024: }
1025: }
1026: checkDimension(tree.pos(), v.type);
1027: }
1028:
1029: public void visitSkip(JCSkip tree) {
1030: }
1031:
1032: public void visitBlock(JCBlock tree) {
1033: int limit = code.nextreg;
1034: Env<GenContext> localEnv = env.dup(tree, new GenContext());
1035: genStats(tree.stats, localEnv);
1036: // End the scope of all block-local variables in variable info.
1037: if (env.tree.getTag() != JCTree.METHODDEF) {
1038: code.statBegin(tree.endpos);
1039: code.endScopes(limit);
1040: code.pendingStatPos = Position.NOPOS;
1041: }
1042: }
1043:
1044: public void visitDoLoop(JCDoWhileLoop tree) {
1045: genLoop(tree, tree.body, tree.cond, List
1046: .<JCExpressionStatement> nil(), false);
1047: }
1048:
1049: public void visitWhileLoop(JCWhileLoop tree) {
1050: genLoop(tree, tree.body, tree.cond, List
1051: .<JCExpressionStatement> nil(), true);
1052: }
1053:
1054: public void visitForLoop(JCForLoop tree) {
1055: int limit = code.nextreg;
1056: genStats(tree.init, env);
1057: genLoop(tree, tree.body, tree.cond, tree.step, true);
1058: code.endScopes(limit);
1059: }
1060:
1061: //where
1062: /** Generate code for a loop.
1063: * @param loop The tree representing the loop.
1064: * @param body The loop's body.
1065: * @param cond The loop's controling condition.
1066: * @param step "Step" statements to be inserted at end of
1067: * each iteration.
1068: * @param testFirst True if the loop test belongs before the body.
1069: */
1070: private void genLoop(JCStatement loop, JCStatement body,
1071: JCExpression cond, List<JCExpressionStatement> step,
1072: boolean testFirst) {
1073: Env<GenContext> loopEnv = env.dup(loop, new GenContext());
1074: int startpc = code.entryPoint();
1075: if (testFirst) {
1076: CondItem c;
1077: if (cond != null) {
1078: code.statBegin(cond.pos);
1079: c = genCond(TreeInfo.skipParens(cond),
1080: CRT_FLOW_CONTROLLER);
1081: } else {
1082: c = items.makeCondItem(goto_);
1083: }
1084: Chain loopDone = c.jumpFalse();
1085: code.resolve(c.trueJumps);
1086: genStat(body, loopEnv, CRT_STATEMENT | CRT_FLOW_TARGET);
1087: code.resolve(loopEnv.info.cont);
1088: genStats(step, loopEnv);
1089: code.resolve(code.branch(goto_), startpc);
1090: code.resolve(loopDone);
1091: } else {
1092: genStat(body, loopEnv, CRT_STATEMENT | CRT_FLOW_TARGET);
1093: code.resolve(loopEnv.info.cont);
1094: genStats(step, loopEnv);
1095: CondItem c;
1096: if (cond != null) {
1097: code.statBegin(cond.pos);
1098: c = genCond(TreeInfo.skipParens(cond),
1099: CRT_FLOW_CONTROLLER);
1100: } else {
1101: c = items.makeCondItem(goto_);
1102: }
1103: code.resolve(c.jumpTrue(), startpc);
1104: code.resolve(c.falseJumps);
1105: }
1106: code.resolve(loopEnv.info.exit);
1107: }
1108:
1109: public void visitForeachLoop(JCEnhancedForLoop tree) {
1110: throw new AssertionError(); // should have been removed by Lower.
1111: }
1112:
1113: public void visitLabelled(JCLabeledStatement tree) {
1114: Env<GenContext> localEnv = env.dup(tree, new GenContext());
1115: genStat(tree.body, localEnv, CRT_STATEMENT);
1116: code.resolve(localEnv.info.exit);
1117: }
1118:
1119: public void visitSwitch(JCSwitch tree) {
1120: int limit = code.nextreg;
1121: assert tree.selector.type.tag != CLASS;
1122: int startpcCrt = genCrt ? code.curPc() : 0;
1123: Item sel = genExpr(tree.selector, syms.intType);
1124: List<JCCase> cases = tree.cases;
1125: if (cases.isEmpty()) {
1126: // We are seeing: switch <sel> {}
1127: sel.load().drop();
1128: if (genCrt)
1129: code.crt.put(TreeInfo.skipParens(tree.selector),
1130: CRT_FLOW_CONTROLLER, startpcCrt, code.curPc());
1131: } else {
1132: // We are seeing a nonempty switch.
1133: sel.load();
1134: if (genCrt)
1135: code.crt.put(TreeInfo.skipParens(tree.selector),
1136: CRT_FLOW_CONTROLLER, startpcCrt, code.curPc());
1137: Env<GenContext> switchEnv = env.dup(tree, new GenContext());
1138: switchEnv.info.isSwitch = true;
1139:
1140: // Compute number of labels and minimum and maximum label values.
1141: // For each case, store its label in an array.
1142: int lo = Integer.MAX_VALUE; // minimum label.
1143: int hi = Integer.MIN_VALUE; // maximum label.
1144: int nlabels = 0; // number of labels.
1145:
1146: int[] labels = new int[cases.length()]; // the label array.
1147: int defaultIndex = -1; // the index of the default clause.
1148:
1149: List<JCCase> l = cases;
1150: for (int i = 0; i < labels.length; i++) {
1151: if (l.head.pat != null) {
1152: int val = ((Number) l.head.pat.type.constValue())
1153: .intValue();
1154: labels[i] = val;
1155: if (val < lo)
1156: lo = val;
1157: if (hi < val)
1158: hi = val;
1159: nlabels++;
1160: } else {
1161: assert defaultIndex == -1;
1162: defaultIndex = i;
1163: }
1164: l = l.tail;
1165: }
1166:
1167: // Determine whether to issue a tableswitch or a lookupswitch
1168: // instruction.
1169: long table_space_cost = 4 + ((long) hi - lo + 1); // words
1170: long table_time_cost = 3; // comparisons
1171: long lookup_space_cost = 3 + 2 * (long) nlabels;
1172: long lookup_time_cost = nlabels;
1173: int opcode = nlabels > 0
1174: && table_space_cost + 3 * table_time_cost <= lookup_space_cost
1175: + 3 * lookup_time_cost ? tableswitch
1176: : lookupswitch;
1177:
1178: int startpc = code.curPc(); // the position of the selector operation
1179: code.emitop0(opcode);
1180: code.align(4);
1181: int tableBase = code.curPc(); // the start of the jump table
1182: int[] offsets = null; // a table of offsets for a lookupswitch
1183: code.emit4(-1); // leave space for default offset
1184: if (opcode == tableswitch) {
1185: code.emit4(lo); // minimum label
1186: code.emit4(hi); // maximum label
1187: for (long i = lo; i <= hi; i++) { // leave space for jump table
1188: code.emit4(-1);
1189: }
1190: } else {
1191: code.emit4(nlabels); // number of labels
1192: for (int i = 0; i < nlabels; i++) {
1193: code.emit4(-1);
1194: code.emit4(-1); // leave space for lookup table
1195: }
1196: offsets = new int[labels.length];
1197: }
1198: Code.State stateSwitch = code.state.dup();
1199: code.markDead();
1200:
1201: // For each case do:
1202: l = cases;
1203: for (int i = 0; i < labels.length; i++) {
1204: JCCase c = l.head;
1205: l = l.tail;
1206:
1207: int pc = code.entryPoint(stateSwitch);
1208: // Insert offset directly into code or else into the
1209: // offsets table.
1210: if (i != defaultIndex) {
1211: if (opcode == tableswitch) {
1212: code.put4(tableBase + 4 * (labels[i] - lo + 3),
1213: pc - startpc);
1214: } else {
1215: offsets[i] = pc - startpc;
1216: }
1217: } else {
1218: code.put4(tableBase, pc - startpc);
1219: }
1220:
1221: // Generate code for the statements in this case.
1222: genStats(c.stats, switchEnv, CRT_FLOW_TARGET);
1223: }
1224:
1225: // Resolve all breaks.
1226: code.resolve(switchEnv.info.exit);
1227:
1228: // If we have not set the default offset, we do so now.
1229: if (code.get4(tableBase) == -1) {
1230: code.put4(tableBase, code.entryPoint(stateSwitch)
1231: - startpc);
1232: }
1233:
1234: if (opcode == tableswitch) {
1235: // Let any unfilled slots point to the default case.
1236: int defaultOffset = code.get4(tableBase);
1237: for (long i = lo; i <= hi; i++) {
1238: int t = (int) (tableBase + 4 * (i - lo + 3));
1239: if (code.get4(t) == -1)
1240: code.put4(t, defaultOffset);
1241: }
1242: } else {
1243: // Sort non-default offsets and copy into lookup table.
1244: if (defaultIndex >= 0)
1245: for (int i = defaultIndex; i < labels.length - 1; i++) {
1246: labels[i] = labels[i + 1];
1247: offsets[i] = offsets[i + 1];
1248: }
1249: if (nlabels > 0)
1250: qsort2(labels, offsets, 0, nlabels - 1);
1251: for (int i = 0; i < nlabels; i++) {
1252: int caseidx = tableBase + 8 * (i + 1);
1253: code.put4(caseidx, labels[i]);
1254: code.put4(caseidx + 4, offsets[i]);
1255: }
1256: }
1257: }
1258: code.endScopes(limit);
1259: }
1260:
1261: //where
1262: /** Sort (int) arrays of keys and values
1263: */
1264: static void qsort2(int[] keys, int[] values, int lo, int hi) {
1265: int i = lo;
1266: int j = hi;
1267: int pivot = keys[(i + j) / 2];
1268: do {
1269: while (keys[i] < pivot)
1270: i++;
1271: while (pivot < keys[j])
1272: j--;
1273: if (i <= j) {
1274: int temp1 = keys[i];
1275: keys[i] = keys[j];
1276: keys[j] = temp1;
1277: int temp2 = values[i];
1278: values[i] = values[j];
1279: values[j] = temp2;
1280: i++;
1281: j--;
1282: }
1283: } while (i <= j);
1284: if (lo < j)
1285: qsort2(keys, values, lo, j);
1286: if (i < hi)
1287: qsort2(keys, values, i, hi);
1288: }
1289:
1290: public void visitSynchronized(JCSynchronized tree) {
1291: int limit = code.nextreg;
1292: // Generate code to evaluate lock and save in temporary variable.
1293: final LocalItem lockVar = makeTemp(syms.objectType);
1294: genExpr(tree.lock, tree.lock.type).load().duplicate();
1295: lockVar.store();
1296:
1297: // Generate code to enter monitor.
1298: code.emitop0(monitorenter);
1299: code.state.lock(lockVar.reg);
1300:
1301: // Generate code for a try statement with given body, no catch clauses
1302: // in a new environment with the "exit-monitor" operation as finalizer.
1303: final Env<GenContext> syncEnv = env.dup(tree, new GenContext());
1304: syncEnv.info.finalize = new GenFinalizer() {
1305: void gen() {
1306: genLast();
1307: assert syncEnv.info.gaps.length() % 2 == 0;
1308: syncEnv.info.gaps.append(code.curPc());
1309: }
1310:
1311: void genLast() {
1312: if (code.isAlive()) {
1313: lockVar.load();
1314: code.emitop0(monitorexit);
1315: code.state.unlock(lockVar.reg);
1316: }
1317: }
1318: };
1319: syncEnv.info.gaps = new ListBuffer<Integer>();
1320: genTry(tree.body, List.<JCCatch> nil(), syncEnv);
1321: code.endScopes(limit);
1322: }
1323:
1324: public void visitTry(final JCTry tree) {
1325: // Generate code for a try statement with given body and catch clauses,
1326: // in a new environment which calls the finally block if there is one.
1327: final Env<GenContext> tryEnv = env.dup(tree, new GenContext());
1328: final Env<GenContext> oldEnv = env;
1329: if (!useJsrLocally) {
1330: useJsrLocally = (stackMap == StackMapFormat.NONE)
1331: && (jsrlimit <= 0 || jsrlimit < 100
1332: && estimateCodeComplexity(tree.finalizer) > jsrlimit);
1333: }
1334: tryEnv.info.finalize = new GenFinalizer() {
1335: void gen() {
1336: if (useJsrLocally) {
1337: if (tree.finalizer != null) {
1338: Code.State jsrState = code.state.dup();
1339: jsrState.push(code.jsrReturnValue);
1340: tryEnv.info.cont = new Chain(
1341: code.emitJump(jsr), tryEnv.info.cont,
1342: jsrState);
1343: }
1344: assert tryEnv.info.gaps.length() % 2 == 0;
1345: tryEnv.info.gaps.append(code.curPc());
1346: } else {
1347: assert tryEnv.info.gaps.length() % 2 == 0;
1348: tryEnv.info.gaps.append(code.curPc());
1349: genLast();
1350: }
1351: }
1352:
1353: void genLast() {
1354: if (tree.finalizer != null)
1355: genStat(tree.finalizer, oldEnv, CRT_BLOCK);
1356: }
1357:
1358: boolean hasFinalizer() {
1359: return tree.finalizer != null;
1360: }
1361: };
1362: tryEnv.info.gaps = new ListBuffer<Integer>();
1363: genTry(tree.body, tree.catchers, tryEnv);
1364: }
1365:
1366: //where
1367: /** Generate code for a try or synchronized statement
1368: * @param body The body of the try or synchronized statement.
1369: * @param catchers The lis of catch clauses.
1370: * @param env the environment current for the body.
1371: */
1372: void genTry(JCTree body, List<JCCatch> catchers, Env<GenContext> env) {
1373: int limit = code.nextreg;
1374: int startpc = code.curPc();
1375: Code.State stateTry = code.state.dup();
1376: genStat(body, env, CRT_BLOCK);
1377: int endpc = code.curPc();
1378: boolean hasFinalizer = env.info.finalize != null
1379: && env.info.finalize.hasFinalizer();
1380: List<Integer> gaps = env.info.gaps.toList();
1381: code.statBegin(TreeInfo.endPos(body));
1382: genFinalizer(env);
1383: code.statBegin(TreeInfo.endPos(env.tree));
1384: Chain exitChain = code.branch(goto_);
1385: endFinalizerGap(env);
1386: if (startpc != endpc)
1387: for (List<JCCatch> l = catchers; l.nonEmpty(); l = l.tail) {
1388: // start off with exception on stack
1389: code.entryPoint(stateTry, l.head.param.sym.type);
1390: genCatch(l.head, env, startpc, endpc, gaps);
1391: genFinalizer(env);
1392: if (hasFinalizer || l.tail.nonEmpty()) {
1393: code.statBegin(TreeInfo.endPos(env.tree));
1394: exitChain = code.mergeChains(exitChain, code
1395: .branch(goto_));
1396: }
1397: endFinalizerGap(env);
1398: }
1399: if (hasFinalizer) {
1400: // Create a new register segement to avoid allocating
1401: // the same variables in finalizers and other statements.
1402: code.newRegSegment();
1403:
1404: // Add a catch-all clause.
1405:
1406: // start off with exception on stack
1407: int catchallpc = code.entryPoint(stateTry,
1408: syms.throwableType);
1409:
1410: // Register all exception ranges for catch all clause.
1411: // The range of the catch all clause is from the beginning
1412: // of the try or synchronized block until the present
1413: // code pointer excluding all gaps in the current
1414: // environment's GenContext.
1415: int startseg = startpc;
1416: while (env.info.gaps.nonEmpty()) {
1417: int endseg = env.info.gaps.next().intValue();
1418: registerCatch(body.pos(), startseg, endseg, catchallpc,
1419: 0);
1420: startseg = env.info.gaps.next().intValue();
1421: }
1422: code.statBegin(TreeInfo.finalizerPos(env.tree));
1423: code.markStatBegin();
1424:
1425: Item excVar = makeTemp(syms.throwableType);
1426: excVar.store();
1427: genFinalizer(env);
1428: excVar.load();
1429: registerCatch(body.pos(), startseg, env.info.gaps.next()
1430: .intValue(), catchallpc, 0);
1431: code.emitop0(athrow);
1432: code.markDead();
1433:
1434: // If there are jsr's to this finalizer, ...
1435: if (env.info.cont != null) {
1436: // Resolve all jsr's.
1437: code.resolve(env.info.cont);
1438:
1439: // Mark statement line number
1440: code.statBegin(TreeInfo.finalizerPos(env.tree));
1441: code.markStatBegin();
1442:
1443: // Save return address.
1444: LocalItem retVar = makeTemp(syms.throwableType);
1445: retVar.store();
1446:
1447: // Generate finalizer code.
1448: env.info.finalize.genLast();
1449:
1450: // Return.
1451: code.emitop1w(ret, retVar.reg);
1452: code.markDead();
1453: }
1454: }
1455:
1456: // Resolve all breaks.
1457: code.resolve(exitChain);
1458:
1459: // End the scopes of all try-local variables in variable info.
1460: code.endScopes(limit);
1461: }
1462:
1463: /** Generate code for a catch clause.
1464: * @param tree The catch clause.
1465: * @param env The environment current in the enclosing try.
1466: * @param startpc Start pc of try-block.
1467: * @param endpc End pc of try-block.
1468: */
1469: void genCatch(JCCatch tree, Env<GenContext> env, int startpc,
1470: int endpc, List<Integer> gaps) {
1471: if (startpc != endpc) {
1472: int catchType = makeRef(tree.pos(), tree.param.type);
1473: while (gaps.nonEmpty()) {
1474: int end = gaps.head.intValue();
1475: registerCatch(tree.pos(), startpc, end, code.curPc(),
1476: catchType);
1477: gaps = gaps.tail;
1478: startpc = gaps.head.intValue();
1479: gaps = gaps.tail;
1480: }
1481: if (startpc < endpc)
1482: registerCatch(tree.pos(), startpc, endpc, code.curPc(),
1483: catchType);
1484: VarSymbol exparam = tree.param.sym;
1485: code.statBegin(tree.pos);
1486: code.markStatBegin();
1487: int limit = code.nextreg;
1488: int exlocal = code.newLocal(exparam);
1489: items.makeLocalItem(exparam).store();
1490: code.statBegin(TreeInfo.firstStatPos(tree.body));
1491: genStat(tree.body, env, CRT_BLOCK);
1492: code.endScopes(limit);
1493: code.statBegin(TreeInfo.endPos(tree.body));
1494: }
1495: }
1496:
1497: /** Register a catch clause in the "Exceptions" code-attribute.
1498: */
1499: void registerCatch(DiagnosticPosition pos, int startpc, int endpc,
1500: int handler_pc, int catch_type) {
1501: if (startpc != endpc) {
1502: char startpc1 = (char) startpc;
1503: char endpc1 = (char) endpc;
1504: char handler_pc1 = (char) handler_pc;
1505: if (startpc1 == startpc && endpc1 == endpc
1506: && handler_pc1 == handler_pc) {
1507: code.addCatch(startpc1, endpc1, handler_pc1,
1508: (char) catch_type);
1509: } else {
1510: if (!useJsrLocally && !target.generateStackMapTable()) {
1511: useJsrLocally = true;
1512: throw new CodeSizeOverflow();
1513: } else {
1514: log.error(pos, "limit.code.too.large.for.try.stmt");
1515: nerrs++;
1516: }
1517: }
1518: }
1519: }
1520:
1521: /** Very roughly estimate the number of instructions needed for
1522: * the given tree.
1523: */
1524: int estimateCodeComplexity(JCTree tree) {
1525: if (tree == null)
1526: return 0;
1527: class ComplexityScanner extends TreeScanner {
1528: int complexity = 0;
1529:
1530: public void scan(JCTree tree) {
1531: if (complexity > jsrlimit)
1532: return;
1533: super .scan(tree);
1534: }
1535:
1536: public void visitClassDef(JCClassDecl tree) {
1537: }
1538:
1539: public void visitDoLoop(JCDoWhileLoop tree) {
1540: super .visitDoLoop(tree);
1541: complexity++;
1542: }
1543:
1544: public void visitWhileLoop(JCWhileLoop tree) {
1545: super .visitWhileLoop(tree);
1546: complexity++;
1547: }
1548:
1549: public void visitForLoop(JCForLoop tree) {
1550: super .visitForLoop(tree);
1551: complexity++;
1552: }
1553:
1554: public void visitSwitch(JCSwitch tree) {
1555: super .visitSwitch(tree);
1556: complexity += 5;
1557: }
1558:
1559: public void visitCase(JCCase tree) {
1560: super .visitCase(tree);
1561: complexity++;
1562: }
1563:
1564: public void visitSynchronized(JCSynchronized tree) {
1565: super .visitSynchronized(tree);
1566: complexity += 6;
1567: }
1568:
1569: public void visitTry(JCTry tree) {
1570: super .visitTry(tree);
1571: if (tree.finalizer != null)
1572: complexity += 6;
1573: }
1574:
1575: public void visitCatch(JCCatch tree) {
1576: super .visitCatch(tree);
1577: complexity += 2;
1578: }
1579:
1580: public void visitConditional(JCConditional tree) {
1581: super .visitConditional(tree);
1582: complexity += 2;
1583: }
1584:
1585: public void visitIf(JCIf tree) {
1586: super .visitIf(tree);
1587: complexity += 2;
1588: }
1589:
1590: // note: for break, continue, and return we don't take unwind() into account.
1591: public void visitBreak(JCBreak tree) {
1592: super .visitBreak(tree);
1593: complexity += 1;
1594: }
1595:
1596: public void visitContinue(JCContinue tree) {
1597: super .visitContinue(tree);
1598: complexity += 1;
1599: }
1600:
1601: public void visitReturn(JCReturn tree) {
1602: super .visitReturn(tree);
1603: complexity += 1;
1604: }
1605:
1606: public void visitThrow(JCThrow tree) {
1607: super .visitThrow(tree);
1608: complexity += 1;
1609: }
1610:
1611: public void visitAssert(JCAssert tree) {
1612: super .visitAssert(tree);
1613: complexity += 5;
1614: }
1615:
1616: public void visitApply(JCMethodInvocation tree) {
1617: super .visitApply(tree);
1618: complexity += 2;
1619: }
1620:
1621: public void visitNewClass(JCNewClass tree) {
1622: scan(tree.encl);
1623: scan(tree.args);
1624: complexity += 2;
1625: }
1626:
1627: public void visitNewArray(JCNewArray tree) {
1628: super .visitNewArray(tree);
1629: complexity += 5;
1630: }
1631:
1632: public void visitAssign(JCAssign tree) {
1633: super .visitAssign(tree);
1634: complexity += 1;
1635: }
1636:
1637: public void visitAssignop(JCAssignOp tree) {
1638: super .visitAssignop(tree);
1639: complexity += 2;
1640: }
1641:
1642: public void visitUnary(JCUnary tree) {
1643: complexity += 1;
1644: if (tree.type.constValue() == null)
1645: super .visitUnary(tree);
1646: }
1647:
1648: public void visitBinary(JCBinary tree) {
1649: complexity += 1;
1650: if (tree.type.constValue() == null)
1651: super .visitBinary(tree);
1652: }
1653:
1654: public void visitTypeTest(JCInstanceOf tree) {
1655: super .visitTypeTest(tree);
1656: complexity += 1;
1657: }
1658:
1659: public void visitIndexed(JCArrayAccess tree) {
1660: super .visitIndexed(tree);
1661: complexity += 1;
1662: }
1663:
1664: public void visitSelect(JCFieldAccess tree) {
1665: super .visitSelect(tree);
1666: if (tree.sym.kind == VAR)
1667: complexity += 1;
1668: }
1669:
1670: public void visitIdent(JCIdent tree) {
1671: if (tree.sym.kind == VAR) {
1672: complexity += 1;
1673: if (tree.type.constValue() == null
1674: && tree.sym.owner.kind == TYP)
1675: complexity += 1;
1676: }
1677: }
1678:
1679: public void visitLiteral(JCLiteral tree) {
1680: complexity += 1;
1681: }
1682:
1683: public void visitTree(JCTree tree) {
1684: }
1685:
1686: public void visitWildcard(JCWildcard tree) {
1687: throw new AssertionError(this .getClass().getName());
1688: }
1689: }
1690: ComplexityScanner scanner = new ComplexityScanner();
1691: tree.accept(scanner);
1692: return scanner.complexity;
1693: }
1694:
1695: public void visitIf(JCIf tree) {
1696: int limit = code.nextreg;
1697: Chain thenExit = null;
1698: CondItem c = genCond(TreeInfo.skipParens(tree.cond),
1699: CRT_FLOW_CONTROLLER);
1700: Chain elseChain = c.jumpFalse();
1701: if (!c.isFalse()) {
1702: code.resolve(c.trueJumps);
1703: genStat(tree.thenpart, env, CRT_STATEMENT | CRT_FLOW_TARGET);
1704: thenExit = code.branch(goto_);
1705: }
1706: if (elseChain != null) {
1707: code.resolve(elseChain);
1708: if (tree.elsepart != null)
1709: genStat(tree.elsepart, env, CRT_STATEMENT
1710: | CRT_FLOW_TARGET);
1711: }
1712: code.resolve(thenExit);
1713: code.endScopes(limit);
1714: }
1715:
1716: public void visitExec(JCExpressionStatement tree) {
1717: // Optimize x++ to ++x and x-- to --x.
1718: JCExpression e = tree.expr;
1719: switch (e.getTag()) {
1720: case JCTree.POSTINC:
1721: ((JCUnary) e).setTag(JCTree.PREINC);
1722: break;
1723: case JCTree.POSTDEC:
1724: ((JCUnary) e).setTag(JCTree.PREDEC);
1725: break;
1726: }
1727: genExpr(tree.expr, tree.expr.type).drop();
1728: }
1729:
1730: public void visitBreak(JCBreak tree) {
1731: Env<GenContext> targetEnv = unwind(tree.target, env);
1732: assert code.state.stacksize == 0;
1733: targetEnv.info.addExit(code.branch(goto_));
1734: endFinalizerGaps(env, targetEnv);
1735: }
1736:
1737: public void visitContinue(JCContinue tree) {
1738: Env<GenContext> targetEnv = unwind(tree.target, env);
1739: assert code.state.stacksize == 0;
1740: targetEnv.info.addCont(code.branch(goto_));
1741: endFinalizerGaps(env, targetEnv);
1742: }
1743:
1744: public void visitReturn(JCReturn tree) {
1745: int limit = code.nextreg;
1746: final Env<GenContext> targetEnv;
1747: if (tree.expr != null) {
1748: Item r = genExpr(tree.expr, pt).load();
1749: if (hasFinally(env.enclMethod, env)) {
1750: r = makeTemp(pt);
1751: r.store();
1752: }
1753: targetEnv = unwind(env.enclMethod, env);
1754: r.load();
1755: code.emitop0(ireturn + Code.truncate(Code.typecode(pt)));
1756: } else {
1757: targetEnv = unwind(env.enclMethod, env);
1758: code.emitop0(return_);
1759: }
1760: endFinalizerGaps(env, targetEnv);
1761: code.endScopes(limit);
1762: }
1763:
1764: public void visitThrow(JCThrow tree) {
1765: genExpr(tree.expr, tree.expr.type).load();
1766: code.emitop0(athrow);
1767: }
1768:
1769: /* ************************************************************************
1770: * Visitor methods for expressions
1771: *************************************************************************/
1772:
1773: public void visitApply(JCMethodInvocation tree) {
1774: // Generate code for method.
1775: Item m = genExpr(tree.meth, methodType);
1776: // Generate code for all arguments, where the expected types are
1777: // the parameters of the method's external type (that is, any implicit
1778: // outer instance of a super(...) call appears as first parameter).
1779: genArgs(tree.args, TreeInfo.symbol(tree.meth).externalType(
1780: types).getParameterTypes());
1781: result = m.invoke();
1782: }
1783:
1784: public void visitConditional(JCConditional tree) {
1785: Chain thenExit = null;
1786: CondItem c = genCond(tree.cond, CRT_FLOW_CONTROLLER);
1787: Chain elseChain = c.jumpFalse();
1788: if (!c.isFalse()) {
1789: code.resolve(c.trueJumps);
1790: int startpc = genCrt ? code.curPc() : 0;
1791: genExpr(tree.truepart, pt).load();
1792: code.state.forceStackTop(tree.type);
1793: if (genCrt)
1794: code.crt.put(tree.truepart, CRT_FLOW_TARGET, startpc,
1795: code.curPc());
1796: thenExit = code.branch(goto_);
1797: }
1798: if (elseChain != null) {
1799: code.resolve(elseChain);
1800: int startpc = genCrt ? code.curPc() : 0;
1801: genExpr(tree.falsepart, pt).load();
1802: code.state.forceStackTop(tree.type);
1803: if (genCrt)
1804: code.crt.put(tree.falsepart, CRT_FLOW_TARGET, startpc,
1805: code.curPc());
1806: }
1807: code.resolve(thenExit);
1808: result = items.makeStackItem(pt);
1809: }
1810:
1811: public void visitNewClass(JCNewClass tree) {
1812: // Enclosing instances or anonymous classes should have been eliminated
1813: // by now.
1814: assert tree.encl == null && tree.def == null;
1815:
1816: code.emitop2(new_, makeRef(tree.pos(), tree.type));
1817: code.emitop0(dup);
1818:
1819: // Generate code for all arguments, where the expected types are
1820: // the parameters of the constructor's external type (that is,
1821: // any implicit outer instance appears as first parameter).
1822: genArgs(tree.args, tree.constructor.externalType(types)
1823: .getParameterTypes());
1824:
1825: items.makeMemberItem(tree.constructor, true).invoke();
1826: result = items.makeStackItem(tree.type);
1827: }
1828:
1829: public void visitNewArray(JCNewArray tree) {
1830: if (tree.elems != null) {
1831: Type elemtype = types.elemtype(tree.type);
1832: loadIntConst(tree.elems.length());
1833: Item arr = makeNewArray(tree.pos(), tree.type, 1);
1834: int i = 0;
1835: for (List<JCExpression> l = tree.elems; l.nonEmpty(); l = l.tail) {
1836: arr.duplicate();
1837: loadIntConst(i);
1838: i++;
1839: genExpr(l.head, elemtype).load();
1840: items.makeIndexedItem(elemtype).store();
1841: }
1842: result = arr;
1843: } else {
1844: for (List<JCExpression> l = tree.dims; l.nonEmpty(); l = l.tail) {
1845: genExpr(l.head, syms.intType).load();
1846: }
1847: result = makeNewArray(tree.pos(), tree.type, tree.dims
1848: .length());
1849: }
1850: }
1851:
1852: //where
1853: /** Generate code to create an array with given element type and number
1854: * of dimensions.
1855: */
1856: Item makeNewArray(DiagnosticPosition pos, Type type, int ndims) {
1857: Type elemtype = types.elemtype(type);
1858: if (types.dimensions(elemtype) + ndims > ClassFile.MAX_DIMENSIONS) {
1859: log.error(pos, "limit.dimensions");
1860: nerrs++;
1861: }
1862: int elemcode = Code.arraycode(elemtype);
1863: if (elemcode == 0 || (elemcode == 1 && ndims == 1)) {
1864: code.emitAnewarray(makeRef(pos, elemtype), type);
1865: } else if (elemcode == 1) {
1866: code.emitMultianewarray(ndims, makeRef(pos, type), type);
1867: } else {
1868: code.emitNewarray(elemcode, type);
1869: }
1870: return items.makeStackItem(type);
1871: }
1872:
1873: public void visitParens(JCParens tree) {
1874: result = genExpr(tree.expr, tree.expr.type);
1875: }
1876:
1877: public void visitAssign(JCAssign tree) {
1878: Item l = genExpr(tree.lhs, tree.lhs.type);
1879: genExpr(tree.rhs, tree.lhs.type).load();
1880: result = items.makeAssignItem(l);
1881: }
1882:
1883: public void visitAssignop(JCAssignOp tree) {
1884: OperatorSymbol operator = (OperatorSymbol) tree.operator;
1885: Item l;
1886: if (operator.opcode == string_add) {
1887: // Generate code to make a string buffer
1888: makeStringBuffer(tree.pos());
1889:
1890: // Generate code for first string, possibly save one
1891: // copy under buffer
1892: l = genExpr(tree.lhs, tree.lhs.type);
1893: if (l.width() > 0) {
1894: code.emitop0(dup_x1 + 3 * (l.width() - 1));
1895: }
1896:
1897: // Load first string and append to buffer.
1898: l.load();
1899: appendString(tree.lhs);
1900:
1901: // Append all other strings to buffer.
1902: appendStrings(tree.rhs);
1903:
1904: // Convert buffer to string.
1905: bufferToString(tree.pos());
1906: } else {
1907: // Generate code for first expression
1908: l = genExpr(tree.lhs, tree.lhs.type);
1909:
1910: // If we have an increment of -32768 to +32767 of a local
1911: // int variable we can use an incr instruction instead of
1912: // proceeding further.
1913: if ((tree.getTag() == JCTree.PLUS_ASG || tree.getTag() == JCTree.MINUS_ASG)
1914: && l instanceof LocalItem
1915: && tree.lhs.type.tag <= INT
1916: && tree.rhs.type.tag <= INT
1917: && tree.rhs.type.constValue() != null) {
1918: int ival = ((Number) tree.rhs.type.constValue())
1919: .intValue();
1920: if (tree.getTag() == JCTree.MINUS_ASG)
1921: ival = -ival;
1922: ((LocalItem) l).incr(ival);
1923: result = l;
1924: return;
1925: }
1926: // Otherwise, duplicate expression, load one copy
1927: // and complete binary operation.
1928: l.duplicate();
1929: l.coerce(operator.type.getParameterTypes().head).load();
1930: completeBinop(tree.lhs, tree.rhs, operator).coerce(
1931: tree.lhs.type);
1932: }
1933: result = items.makeAssignItem(l);
1934: }
1935:
1936: public void visitUnary(JCUnary tree) {
1937: OperatorSymbol operator = (OperatorSymbol) tree.operator;
1938: if (tree.getTag() == JCTree.NOT) {
1939: CondItem od = genCond(tree.arg, false);
1940: result = od.negate();
1941: } else {
1942: Item od = genExpr(tree.arg, operator.type
1943: .getParameterTypes().head);
1944: switch (tree.getTag()) {
1945: case JCTree.POS:
1946: result = od.load();
1947: break;
1948: case JCTree.NEG:
1949: result = od.load();
1950: code.emitop0(operator.opcode);
1951: break;
1952: case JCTree.COMPL:
1953: result = od.load();
1954: emitMinusOne(od.typecode);
1955: code.emitop0(operator.opcode);
1956: break;
1957: case JCTree.PREINC:
1958: case JCTree.PREDEC:
1959: od.duplicate();
1960: if (od instanceof LocalItem
1961: && (operator.opcode == iadd || operator.opcode == isub)) {
1962: ((LocalItem) od)
1963: .incr(tree.getTag() == JCTree.PREINC ? 1
1964: : -1);
1965: result = od;
1966: } else {
1967: od.load();
1968: code.emitop0(one(od.typecode));
1969: code.emitop0(operator.opcode);
1970: // Perform narrowing primitive conversion if byte,
1971: // char, or short. Fix for 4304655.
1972: if (od.typecode != INTcode
1973: && Code.truncate(od.typecode) == INTcode)
1974: code.emitop0(int2byte + od.typecode - BYTEcode);
1975: result = items.makeAssignItem(od);
1976: }
1977: break;
1978: case JCTree.POSTINC:
1979: case JCTree.POSTDEC:
1980: od.duplicate();
1981: if (od instanceof LocalItem
1982: && (operator.opcode == iadd || operator.opcode == isub)) {
1983: Item res = od.load();
1984: ((LocalItem) od)
1985: .incr(tree.getTag() == JCTree.POSTINC ? 1
1986: : -1);
1987: result = res;
1988: } else {
1989: Item res = od.load();
1990: od.stash(od.typecode);
1991: code.emitop0(one(od.typecode));
1992: code.emitop0(operator.opcode);
1993: // Perform narrowing primitive conversion if byte,
1994: // char, or short. Fix for 4304655.
1995: if (od.typecode != INTcode
1996: && Code.truncate(od.typecode) == INTcode)
1997: code.emitop0(int2byte + od.typecode - BYTEcode);
1998: od.store();
1999: result = res;
2000: }
2001: break;
2002: case JCTree.NULLCHK:
2003: result = od.load();
2004: code.emitop0(dup);
2005: genNullCheck(tree.pos());
2006: break;
2007: default:
2008: assert false;
2009: }
2010: }
2011: }
2012:
2013: /** Generate a null check from the object value at stack top. */
2014: private void genNullCheck(DiagnosticPosition pos) {
2015: callMethod(pos, syms.objectType, names.getClass, List
2016: .<Type> nil(), false);
2017: code.emitop0(pop);
2018: }
2019:
2020: public void visitBinary(JCBinary tree) {
2021: OperatorSymbol operator = (OperatorSymbol) tree.operator;
2022: if (operator.opcode == string_add) {
2023: // Create a string buffer.
2024: makeStringBuffer(tree.pos());
2025: // Append all strings to buffer.
2026: appendStrings(tree);
2027: // Convert buffer to string.
2028: bufferToString(tree.pos());
2029: result = items.makeStackItem(syms.stringType);
2030: } else if (tree.getTag() == JCTree.AND) {
2031: CondItem lcond = genCond(tree.lhs, CRT_FLOW_CONTROLLER);
2032: if (!lcond.isFalse()) {
2033: Chain falseJumps = lcond.jumpFalse();
2034: code.resolve(lcond.trueJumps);
2035: CondItem rcond = genCond(tree.rhs, CRT_FLOW_TARGET);
2036: result = items.makeCondItem(rcond.opcode,
2037: rcond.trueJumps, code.mergeChains(falseJumps,
2038: rcond.falseJumps));
2039: } else {
2040: result = lcond;
2041: }
2042: } else if (tree.getTag() == JCTree.OR) {
2043: CondItem lcond = genCond(tree.lhs, CRT_FLOW_CONTROLLER);
2044: if (!lcond.isTrue()) {
2045: Chain trueJumps = lcond.jumpTrue();
2046: code.resolve(lcond.falseJumps);
2047: CondItem rcond = genCond(tree.rhs, CRT_FLOW_TARGET);
2048: result = items.makeCondItem(rcond.opcode, code
2049: .mergeChains(trueJumps, rcond.trueJumps),
2050: rcond.falseJumps);
2051: } else {
2052: result = lcond;
2053: }
2054: } else {
2055: Item od = genExpr(tree.lhs, operator.type
2056: .getParameterTypes().head);
2057: od.load();
2058: result = completeBinop(tree.lhs, tree.rhs, operator);
2059: }
2060: }
2061:
2062: //where
2063: /** Make a new string buffer.
2064: */
2065: void makeStringBuffer(DiagnosticPosition pos) {
2066: code.emitop2(new_, makeRef(pos, stringBufferType));
2067: code.emitop0(dup);
2068: callMethod(pos, stringBufferType, names.init,
2069: List.<Type> nil(), false);
2070: }
2071:
2072: /** Append value (on tos) to string buffer (on tos - 1).
2073: */
2074: void appendString(JCTree tree) {
2075: Type t = tree.type.baseType();
2076: if (t.tag > lastBaseTag && t.tsym != syms.stringType.tsym) {
2077: t = syms.objectType;
2078: }
2079: items.makeMemberItem(getStringBufferAppend(tree, t), false)
2080: .invoke();
2081: }
2082:
2083: Symbol getStringBufferAppend(JCTree tree, Type t) {
2084: assert t.constValue() == null;
2085: Symbol method = stringBufferAppend.get(t);
2086: if (method == null) {
2087: method = rs.resolveInternalMethod(tree.pos(), attrEnv,
2088: stringBufferType, names.append, List.of(t), null);
2089: stringBufferAppend.put(t, method);
2090: }
2091: return method;
2092: }
2093:
2094: /** Add all strings in tree to string buffer.
2095: */
2096: void appendStrings(JCTree tree) {
2097: tree = TreeInfo.skipParens(tree);
2098: if (tree.getTag() == JCTree.PLUS
2099: && tree.type.constValue() == null) {
2100: JCBinary op = (JCBinary) tree;
2101: if (op.operator.kind == MTH
2102: && ((OperatorSymbol) op.operator).opcode == string_add) {
2103: appendStrings(op.lhs);
2104: appendStrings(op.rhs);
2105: return;
2106: }
2107: }
2108: genExpr(tree, tree.type).load();
2109: appendString(tree);
2110: }
2111:
2112: /** Convert string buffer on tos to string.
2113: */
2114: void bufferToString(DiagnosticPosition pos) {
2115: callMethod(pos, stringBufferType, names.toString, List
2116: .<Type> nil(), false);
2117: }
2118:
2119: /** Complete generating code for operation, with left operand
2120: * already on stack.
2121: * @param lhs The tree representing the left operand.
2122: * @param rhs The tree representing the right operand.
2123: * @param operator The operator symbol.
2124: */
2125: Item completeBinop(JCTree lhs, JCTree rhs, OperatorSymbol operator) {
2126: MethodType optype = (MethodType) operator.type;
2127: int opcode = operator.opcode;
2128: if (opcode >= if_icmpeq && opcode <= if_icmple
2129: && rhs.type.constValue() instanceof Number
2130: && ((Number) rhs.type.constValue()).intValue() == 0) {
2131: opcode = opcode + (ifeq - if_icmpeq);
2132: } else if (opcode >= if_acmpeq && opcode <= if_acmpne
2133: && TreeInfo.isNull(rhs)) {
2134: opcode = opcode + (if_acmp_null - if_acmpeq);
2135: } else {
2136: // The expected type of the right operand is
2137: // the second parameter type of the operator, except for
2138: // shifts with long shiftcount, where we convert the opcode
2139: // to a short shift and the expected type to int.
2140: Type rtype = operator.erasure(types).getParameterTypes().tail.head;
2141: if (opcode >= ishll && opcode <= lushrl) {
2142: opcode = opcode + (ishl - ishll);
2143: rtype = syms.intType;
2144: }
2145: // Generate code for right operand and load.
2146: genExpr(rhs, rtype).load();
2147: // If there are two consecutive opcode instructions,
2148: // emit the first now.
2149: if (opcode >= (1 << preShift)) {
2150: code.emitop0(opcode >> preShift);
2151: opcode = opcode & 0xFF;
2152: }
2153: }
2154: if (opcode >= ifeq && opcode <= if_acmpne
2155: || opcode == if_acmp_null || opcode == if_acmp_nonnull) {
2156: return items.makeCondItem(opcode);
2157: } else {
2158: code.emitop0(opcode);
2159: return items.makeStackItem(optype.restype);
2160: }
2161: }
2162:
2163: public void visitTypeCast(JCTypeCast tree) {
2164: result = genExpr(tree.expr, tree.clazz.type).load();
2165: // Additional code is only needed if we cast to a reference type
2166: // which is not statically a supertype of the expression's type.
2167: // For basic types, the coerce(...) in genExpr(...) will do
2168: // the conversion.
2169: if (tree.clazz.type.tag > lastBaseTag
2170: && types.asSuper(tree.expr.type, tree.clazz.type.tsym) == null) {
2171: code.emitop2(checkcast,
2172: makeRef(tree.pos(), tree.clazz.type));
2173: }
2174: }
2175:
2176: public void visitWildcard(JCWildcard tree) {
2177: throw new AssertionError(this .getClass().getName());
2178: }
2179:
2180: public void visitTypeTest(JCInstanceOf tree) {
2181: genExpr(tree.expr, tree.expr.type).load();
2182: code.emitop2(instanceof _, makeRef(tree.pos(), tree.clazz.type));
2183: result = items.makeStackItem(syms.booleanType);
2184: }
2185:
2186: public void visitIndexed(JCArrayAccess tree) {
2187: genExpr(tree.indexed, tree.indexed.type).load();
2188: genExpr(tree.index, syms.intType).load();
2189: result = items.makeIndexedItem(tree.type);
2190: }
2191:
2192: public void visitIdent(JCIdent tree) {
2193: Symbol sym = tree.sym;
2194: if (tree.name == names._this || tree.name == names._super ) {
2195: Item res = tree.name == names._this ? items.makeThisItem()
2196: : items.makeSuperItem();
2197: if (sym.kind == MTH) {
2198: // Generate code to address the constructor.
2199: res.load();
2200: res = items.makeMemberItem(sym, true);
2201: }
2202: result = res;
2203: } else if (sym.kind == VAR && sym.owner.kind == MTH) {
2204: result = items.makeLocalItem((VarSymbol) sym);
2205: } else if ((sym.flags() & STATIC) != 0) {
2206: if (!isAccessSuper(env.enclMethod))
2207: sym = binaryQualifier(sym, env.enclClass.type);
2208: result = items.makeStaticItem(sym);
2209: } else {
2210: items.makeThisItem().load();
2211: sym = binaryQualifier(sym, env.enclClass.type);
2212: result = items.makeMemberItem(sym,
2213: (sym.flags() & PRIVATE) != 0);
2214: }
2215: }
2216:
2217: public void visitSelect(JCFieldAccess tree) {
2218: Symbol sym = tree.sym;
2219:
2220: if (tree.name == names._class) {
2221: assert target.hasClassLiterals();
2222: code.emitop2(ldc2, makeRef(tree.pos(), tree.selected.type));
2223: result = items.makeStackItem(pt);
2224: return;
2225: }
2226:
2227: Symbol ssym = TreeInfo.symbol(tree.selected);
2228:
2229: // Are we selecting via super?
2230: boolean selectSuper = ssym != null
2231: && (ssym.kind == TYP || ssym.name == names._super );
2232:
2233: // Are we accessing a member of the superclass in an access method
2234: // resulting from a qualified super?
2235: boolean accessSuper = isAccessSuper(env.enclMethod);
2236:
2237: Item base = (selectSuper) ? items.makeSuperItem() : genExpr(
2238: tree.selected, tree.selected.type);
2239:
2240: if (sym.kind == VAR
2241: && ((VarSymbol) sym).getConstValue() != null) {
2242: // We are seeing a variable that is constant but its selecting
2243: // expression is not.
2244: if ((sym.flags() & STATIC) != 0) {
2245: if (!selectSuper && (ssym == null || ssym.kind != TYP))
2246: base = base.load();
2247: base.drop();
2248: } else {
2249: base.load();
2250: genNullCheck(tree.selected.pos());
2251: }
2252: result = items.makeImmediateItem(sym.type,
2253: ((VarSymbol) sym).getConstValue());
2254: } else {
2255: if (!accessSuper)
2256: sym = binaryQualifier(sym, tree.selected.type);
2257: if ((sym.flags() & STATIC) != 0) {
2258: if (!selectSuper && (ssym == null || ssym.kind != TYP))
2259: base = base.load();
2260: base.drop();
2261: result = items.makeStaticItem(sym);
2262: } else {
2263: base.load();
2264: if (sym == syms.lengthVar) {
2265: code.emitop0(arraylength);
2266: result = items.makeStackItem(syms.intType);
2267: } else {
2268: result = items.makeMemberItem(sym,
2269: (sym.flags() & PRIVATE) != 0 || selectSuper
2270: || accessSuper);
2271: }
2272: }
2273: }
2274: }
2275:
2276: public void visitLiteral(JCLiteral tree) {
2277: if (tree.type.tag == TypeTags.BOT) {
2278: code.emitop0(aconst_null);
2279: if (types.dimensions(pt) > 1) {
2280: code.emitop2(checkcast, makeRef(tree.pos(), pt));
2281: result = items.makeStackItem(pt);
2282: } else {
2283: result = items.makeStackItem(tree.type);
2284: }
2285: } else
2286: result = items.makeImmediateItem(tree.type, tree.value);
2287: }
2288:
2289: public void visitLetExpr(LetExpr tree) {
2290: int limit = code.nextreg;
2291: genStats(tree.defs, env);
2292: result = genExpr(tree.expr, tree.expr.type).load();
2293: code.endScopes(limit);
2294: }
2295:
2296: /* ************************************************************************
2297: * main method
2298: *************************************************************************/
2299:
2300: /** Generate code for a class definition.
2301: * @param env The attribution environment that belongs to the
2302: * outermost class containing this class definition.
2303: * We need this for resolving some additional symbols.
2304: * @param cdef The tree representing the class definition.
2305: * @return True if code is generated with no errors.
2306: */
2307: public boolean genClass(Env<AttrContext> env, JCClassDecl cdef) {
2308: try {
2309: attrEnv = env;
2310: ClassSymbol c = cdef.sym;
2311: this .toplevel = env.toplevel;
2312: this .endPositions = toplevel.endPositions;
2313: // If this is a class definition requiring Miranda methods,
2314: // add them.
2315: if (generateIproxies
2316: && (c.flags() & (INTERFACE | ABSTRACT)) == ABSTRACT
2317: && !allowGenerics // no Miranda methods available with generics
2318: )
2319: implementInterfaceMethods(c);
2320: cdef.defs = normalizeDefs(cdef.defs, c);
2321: c.pool = pool;
2322: pool.reset();
2323: Env<GenContext> localEnv = new Env<GenContext>(cdef,
2324: new GenContext());
2325: localEnv.toplevel = env.toplevel;
2326: localEnv.enclClass = cdef;
2327: for (List<JCTree> l = cdef.defs; l.nonEmpty(); l = l.tail) {
2328: genDef(l.head, localEnv);
2329: }
2330: if (pool.numEntries() > Pool.MAX_ENTRIES) {
2331: log.error(cdef.pos(), "limit.pool");
2332: nerrs++;
2333: }
2334: if (nerrs != 0) {
2335: // if errors, discard code
2336: for (List<JCTree> l = cdef.defs; l.nonEmpty(); l = l.tail) {
2337: if (l.head.getTag() == JCTree.METHODDEF)
2338: ((JCMethodDecl) l.head).sym.code = null;
2339: }
2340: }
2341: cdef.defs = List.nil(); // discard trees
2342: return nerrs == 0;
2343: } finally {
2344: // note: this method does NOT support recursion.
2345: attrEnv = null;
2346: this .env = null;
2347: toplevel = null;
2348: endPositions = null;
2349: nerrs = 0;
2350: }
2351: }
2352:
2353: /* ************************************************************************
2354: * Auxiliary classes
2355: *************************************************************************/
2356:
2357: /** An abstract class for finalizer generation.
2358: */
2359: abstract class GenFinalizer {
2360: /** Generate code to clean up when unwinding. */
2361: abstract void gen();
2362:
2363: /** Generate code to clean up at last. */
2364: abstract void genLast();
2365:
2366: /** Does this finalizer have some nontrivial cleanup to perform? */
2367: boolean hasFinalizer() {
2368: return true;
2369: }
2370: }
2371:
2372: /** code generation contexts,
2373: * to be used as type parameter for environments.
2374: */
2375: static class GenContext {
2376:
2377: /** A chain for all unresolved jumps that exit the current environment.
2378: */
2379: Chain exit = null;
2380:
2381: /** A chain for all unresolved jumps that continue in the
2382: * current environment.
2383: */
2384: Chain cont = null;
2385:
2386: /** A closure that generates the finalizer of the current environment.
2387: * Only set for Synchronized and Try contexts.
2388: */
2389: GenFinalizer finalize = null;
2390:
2391: /** Is this a switch statement? If so, allocate registers
2392: * even when the variable declaration is unreachable.
2393: */
2394: boolean isSwitch = false;
2395:
2396: /** A list buffer containing all gaps in the finalizer range,
2397: * where a catch all exception should not apply.
2398: */
2399: ListBuffer<Integer> gaps = null;
2400:
2401: /** Add given chain to exit chain.
2402: */
2403: void addExit(Chain c) {
2404: exit = Code.mergeChains(c, exit);
2405: }
2406:
2407: /** Add given chain to cont chain.
2408: */
2409: void addCont(Chain c) {
2410: cont = Code.mergeChains(c, cont);
2411: }
2412: }
2413: }
|