src/share/classes/com/sun/tools/javac/jvm/Gen.java

Tue, 28 Dec 2010 15:54:52 -0800

author
ohair
date
Tue, 28 Dec 2010 15:54:52 -0800
changeset 798
4868a36f6fd8
parent 782
bcf44475aeee
child 815
d17f37522154
permissions
-rw-r--r--

6962318: Update copyright year
Reviewed-by: xdono

     1 /*
     2  * Copyright (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved.
     3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
     4  *
     5  * This code is free software; you can redistribute it and/or modify it
     6  * under the terms of the GNU General Public License version 2 only, as
     7  * published by the Free Software Foundation.  Oracle designates this
     8  * particular file as subject to the "Classpath" exception as provided
     9  * by Oracle in the LICENSE file that accompanied this code.
    10  *
    11  * This code is distributed in the hope that it will be useful, but WITHOUT
    12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
    13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
    14  * version 2 for more details (a copy is included in the LICENSE file that
    15  * accompanied this code).
    16  *
    17  * You should have received a copy of the GNU General Public License version
    18  * 2 along with this work; if not, write to the Free Software Foundation,
    19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
    20  *
    21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
    22  * or visit www.oracle.com if you need additional information or have any
    23  * questions.
    24  */
    26 package com.sun.tools.javac.jvm;
    27 import java.util.*;
    29 import javax.lang.model.element.ElementKind;
    31 import com.sun.tools.javac.util.*;
    32 import com.sun.tools.javac.util.JCDiagnostic.DiagnosticPosition;
    33 import com.sun.tools.javac.util.List;
    34 import com.sun.tools.javac.code.*;
    35 import com.sun.tools.javac.comp.*;
    36 import com.sun.tools.javac.tree.*;
    38 import com.sun.tools.javac.code.Symbol.*;
    39 import com.sun.tools.javac.code.Type.*;
    40 import com.sun.tools.javac.jvm.Code.*;
    41 import com.sun.tools.javac.jvm.Items.*;
    42 import com.sun.tools.javac.tree.JCTree.*;
    44 import static com.sun.tools.javac.code.Flags.*;
    45 import static com.sun.tools.javac.code.Kinds.*;
    46 import static com.sun.tools.javac.code.TypeTags.*;
    47 import static com.sun.tools.javac.jvm.ByteCodes.*;
    48 import static com.sun.tools.javac.jvm.CRTFlags.*;
    49 import static com.sun.tools.javac.main.OptionName.*;
    51 /** This pass maps flat Java (i.e. without inner classes) to bytecodes.
    52  *
    53  *  <p><b>This is NOT part of any supported API.
    54  *  If you write code that depends on this, you do so at your own risk.
    55  *  This code and its internal interfaces are subject to change or
    56  *  deletion without notice.</b>
    57  */
    58 public class Gen extends JCTree.Visitor {
    59     protected static final Context.Key<Gen> genKey =
    60         new Context.Key<Gen>();
    62     private final Log log;
    63     private final Symtab syms;
    64     private final Check chk;
    65     private final Resolve rs;
    66     private final TreeMaker make;
    67     private final Names names;
    68     private final Target target;
    69     private final Type stringBufferType;
    70     private final Map<Type,Symbol> stringBufferAppend;
    71     private Name accessDollar;
    72     private final Types types;
    74     /** Switch: GJ mode?
    75      */
    76     private final boolean allowGenerics;
    78     /** Set when Miranda method stubs are to be generated. */
    79     private final boolean generateIproxies;
    81     /** Format of stackmap tables to be generated. */
    82     private final Code.StackMapFormat stackMap;
    84     /** A type that serves as the expected type for all method expressions.
    85      */
    86     private final Type methodType;
    88     public static Gen instance(Context context) {
    89         Gen instance = context.get(genKey);
    90         if (instance == null)
    91             instance = new Gen(context);
    92         return instance;
    93     }
    95     protected Gen(Context context) {
    96         context.put(genKey, this);
    98         names = Names.instance(context);
    99         log = Log.instance(context);
   100         syms = Symtab.instance(context);
   101         chk = Check.instance(context);
   102         rs = Resolve.instance(context);
   103         make = TreeMaker.instance(context);
   104         target = Target.instance(context);
   105         types = Types.instance(context);
   106         methodType = new MethodType(null, null, null, syms.methodClass);
   107         allowGenerics = Source.instance(context).allowGenerics();
   108         stringBufferType = target.useStringBuilder()
   109             ? syms.stringBuilderType
   110             : syms.stringBufferType;
   111         stringBufferAppend = new HashMap<Type,Symbol>();
   112         accessDollar = names.
   113             fromString("access" + target.syntheticNameChar());
   115         Options options = Options.instance(context);
   116         lineDebugInfo =
   117             options.isUnset(G_CUSTOM) ||
   118             options.isSet(G_CUSTOM, "lines");
   119         varDebugInfo =
   120             options.isUnset(G_CUSTOM)
   121             ? options.isSet(G)
   122             : options.isSet(G_CUSTOM, "vars");
   123         genCrt = options.isSet(XJCOV);
   124         debugCode = options.isSet("debugcode");
   125         allowInvokedynamic = target.hasInvokedynamic() || options.isSet("invokedynamic");
   127         generateIproxies =
   128             target.requiresIproxy() ||
   129             options.isSet("miranda");
   131         if (target.generateStackMapTable()) {
   132             // ignore cldc because we cannot have both stackmap formats
   133             this.stackMap = StackMapFormat.JSR202;
   134         } else {
   135             if (target.generateCLDCStackmap()) {
   136                 this.stackMap = StackMapFormat.CLDC;
   137             } else {
   138                 this.stackMap = StackMapFormat.NONE;
   139             }
   140         }
   142         // by default, avoid jsr's for simple finalizers
   143         int setjsrlimit = 50;
   144         String jsrlimitString = options.get("jsrlimit");
   145         if (jsrlimitString != null) {
   146             try {
   147                 setjsrlimit = Integer.parseInt(jsrlimitString);
   148             } catch (NumberFormatException ex) {
   149                 // ignore ill-formed numbers for jsrlimit
   150             }
   151         }
   152         this.jsrlimit = setjsrlimit;
   153         this.useJsrLocally = false; // reset in visitTry
   154     }
   156     /** Switches
   157      */
   158     private final boolean lineDebugInfo;
   159     private final boolean varDebugInfo;
   160     private final boolean genCrt;
   161     private final boolean debugCode;
   162     private final boolean allowInvokedynamic;
   164     /** Default limit of (approximate) size of finalizer to inline.
   165      *  Zero means always use jsr.  100 or greater means never use
   166      *  jsr.
   167      */
   168     private final int jsrlimit;
   170     /** True if jsr is used.
   171      */
   172     private boolean useJsrLocally;
   174     /* Constant pool, reset by genClass.
   175      */
   176     private Pool pool = new Pool();
   178     /** Code buffer, set by genMethod.
   179      */
   180     private Code code;
   182     /** Items structure, set by genMethod.
   183      */
   184     private Items items;
   186     /** Environment for symbol lookup, set by genClass
   187      */
   188     private Env<AttrContext> attrEnv;
   190     /** The top level tree.
   191      */
   192     private JCCompilationUnit toplevel;
   194     /** The number of code-gen errors in this class.
   195      */
   196     private int nerrs = 0;
   198     /** A hash table mapping syntax trees to their ending source positions.
   199      */
   200     private Map<JCTree, Integer> endPositions;
   202     /** Generate code to load an integer constant.
   203      *  @param n     The integer to be loaded.
   204      */
   205     void loadIntConst(int n) {
   206         items.makeImmediateItem(syms.intType, n).load();
   207     }
   209     /** The opcode that loads a zero constant of a given type code.
   210      *  @param tc   The given type code (@see ByteCode).
   211      */
   212     public static int zero(int tc) {
   213         switch(tc) {
   214         case INTcode: case BYTEcode: case SHORTcode: case CHARcode:
   215             return iconst_0;
   216         case LONGcode:
   217             return lconst_0;
   218         case FLOATcode:
   219             return fconst_0;
   220         case DOUBLEcode:
   221             return dconst_0;
   222         default:
   223             throw new AssertionError("zero");
   224         }
   225     }
   227     /** The opcode that loads a one constant of a given type code.
   228      *  @param tc   The given type code (@see ByteCode).
   229      */
   230     public static int one(int tc) {
   231         return zero(tc) + 1;
   232     }
   234     /** Generate code to load -1 of the given type code (either int or long).
   235      *  @param tc   The given type code (@see ByteCode).
   236      */
   237     void emitMinusOne(int tc) {
   238         if (tc == LONGcode) {
   239             items.makeImmediateItem(syms.longType, new Long(-1)).load();
   240         } else {
   241             code.emitop0(iconst_m1);
   242         }
   243     }
   245     /** Construct a symbol to reflect the qualifying type that should
   246      *  appear in the byte code as per JLS 13.1.
   247      *
   248      *  For target >= 1.2: Clone a method with the qualifier as owner (except
   249      *  for those cases where we need to work around VM bugs).
   250      *
   251      *  For target <= 1.1: If qualified variable or method is defined in a
   252      *  non-accessible class, clone it with the qualifier class as owner.
   253      *
   254      *  @param sym    The accessed symbol
   255      *  @param site   The qualifier's type.
   256      */
   257     Symbol binaryQualifier(Symbol sym, Type site) {
   259         if (site.tag == ARRAY) {
   260             if (sym == syms.lengthVar ||
   261                 sym.owner != syms.arrayClass)
   262                 return sym;
   263             // array clone can be qualified by the array type in later targets
   264             Symbol qualifier = target.arrayBinaryCompatibility()
   265                 ? new ClassSymbol(Flags.PUBLIC, site.tsym.name,
   266                                   site, syms.noSymbol)
   267                 : syms.objectType.tsym;
   268             return sym.clone(qualifier);
   269         }
   271         if (sym.owner == site.tsym ||
   272             (sym.flags() & (STATIC | SYNTHETIC)) == (STATIC | SYNTHETIC)) {
   273             return sym;
   274         }
   275         if (!target.obeyBinaryCompatibility())
   276             return rs.isAccessible(attrEnv, (TypeSymbol)sym.owner)
   277                 ? sym
   278                 : sym.clone(site.tsym);
   280         if (!target.interfaceFieldsBinaryCompatibility()) {
   281             if ((sym.owner.flags() & INTERFACE) != 0 && sym.kind == VAR)
   282                 return sym;
   283         }
   285         // leave alone methods inherited from Object
   286         // JLS2 13.1.
   287         if (sym.owner == syms.objectType.tsym)
   288             return sym;
   290         if (!target.interfaceObjectOverridesBinaryCompatibility()) {
   291             if ((sym.owner.flags() & INTERFACE) != 0 &&
   292                 syms.objectType.tsym.members().lookup(sym.name).scope != null)
   293                 return sym;
   294         }
   296         return sym.clone(site.tsym);
   297     }
   299     /** Insert a reference to given type in the constant pool,
   300      *  checking for an array with too many dimensions;
   301      *  return the reference's index.
   302      *  @param type   The type for which a reference is inserted.
   303      */
   304     int makeRef(DiagnosticPosition pos, Type type) {
   305         checkDimension(pos, type);
   306         return pool.put(type.tag == CLASS ? (Object)type.tsym : (Object)type);
   307     }
   309     /** Check if the given type is an array with too many dimensions.
   310      */
   311     private void checkDimension(DiagnosticPosition pos, Type t) {
   312         switch (t.tag) {
   313         case METHOD:
   314             checkDimension(pos, t.getReturnType());
   315             for (List<Type> args = t.getParameterTypes(); args.nonEmpty(); args = args.tail)
   316                 checkDimension(pos, args.head);
   317             break;
   318         case ARRAY:
   319             if (types.dimensions(t) > ClassFile.MAX_DIMENSIONS) {
   320                 log.error(pos, "limit.dimensions");
   321                 nerrs++;
   322             }
   323             break;
   324         default:
   325             break;
   326         }
   327     }
   329     /** Create a tempory variable.
   330      *  @param type   The variable's type.
   331      */
   332     LocalItem makeTemp(Type type) {
   333         VarSymbol v = new VarSymbol(Flags.SYNTHETIC,
   334                                     names.empty,
   335                                     type,
   336                                     env.enclMethod.sym);
   337         code.newLocal(v);
   338         return items.makeLocalItem(v);
   339     }
   341     /** Generate code to call a non-private method or constructor.
   342      *  @param pos         Position to be used for error reporting.
   343      *  @param site        The type of which the method is a member.
   344      *  @param name        The method's name.
   345      *  @param argtypes    The method's argument types.
   346      *  @param isStatic    A flag that indicates whether we call a
   347      *                     static or instance method.
   348      */
   349     void callMethod(DiagnosticPosition pos,
   350                     Type site, Name name, List<Type> argtypes,
   351                     boolean isStatic) {
   352         Symbol msym = rs.
   353             resolveInternalMethod(pos, attrEnv, site, name, argtypes, null);
   354         if (isStatic) items.makeStaticItem(msym).invoke();
   355         else items.makeMemberItem(msym, name == names.init).invoke();
   356     }
   358     /** Is the given method definition an access method
   359      *  resulting from a qualified super? This is signified by an odd
   360      *  access code.
   361      */
   362     private boolean isAccessSuper(JCMethodDecl enclMethod) {
   363         return
   364             (enclMethod.mods.flags & SYNTHETIC) != 0 &&
   365             isOddAccessName(enclMethod.name);
   366     }
   368     /** Does given name start with "access$" and end in an odd digit?
   369      */
   370     private boolean isOddAccessName(Name name) {
   371         return
   372             name.startsWith(accessDollar) &&
   373             (name.getByteAt(name.getByteLength() - 1) & 1) == 1;
   374     }
   376 /* ************************************************************************
   377  * Non-local exits
   378  *************************************************************************/
   380     /** Generate code to invoke the finalizer associated with given
   381      *  environment.
   382      *  Any calls to finalizers are appended to the environments `cont' chain.
   383      *  Mark beginning of gap in catch all range for finalizer.
   384      */
   385     void genFinalizer(Env<GenContext> env) {
   386         if (code.isAlive() && env.info.finalize != null)
   387             env.info.finalize.gen();
   388     }
   390     /** Generate code to call all finalizers of structures aborted by
   391      *  a non-local
   392      *  exit.  Return target environment of the non-local exit.
   393      *  @param target      The tree representing the structure that's aborted
   394      *  @param env         The environment current at the non-local exit.
   395      */
   396     Env<GenContext> unwind(JCTree target, Env<GenContext> env) {
   397         Env<GenContext> env1 = env;
   398         while (true) {
   399             genFinalizer(env1);
   400             if (env1.tree == target) break;
   401             env1 = env1.next;
   402         }
   403         return env1;
   404     }
   406     /** Mark end of gap in catch-all range for finalizer.
   407      *  @param env   the environment which might contain the finalizer
   408      *               (if it does, env.info.gaps != null).
   409      */
   410     void endFinalizerGap(Env<GenContext> env) {
   411         if (env.info.gaps != null && env.info.gaps.length() % 2 == 1)
   412             env.info.gaps.append(code.curPc());
   413     }
   415     /** Mark end of all gaps in catch-all ranges for finalizers of environments
   416      *  lying between, and including to two environments.
   417      *  @param from    the most deeply nested environment to mark
   418      *  @param to      the least deeply nested environment to mark
   419      */
   420     void endFinalizerGaps(Env<GenContext> from, Env<GenContext> to) {
   421         Env<GenContext> last = null;
   422         while (last != to) {
   423             endFinalizerGap(from);
   424             last = from;
   425             from = from.next;
   426         }
   427     }
   429     /** Do any of the structures aborted by a non-local exit have
   430      *  finalizers that require an empty stack?
   431      *  @param target      The tree representing the structure that's aborted
   432      *  @param env         The environment current at the non-local exit.
   433      */
   434     boolean hasFinally(JCTree target, Env<GenContext> env) {
   435         while (env.tree != target) {
   436             if (env.tree.getTag() == JCTree.TRY && env.info.finalize.hasFinalizer())
   437                 return true;
   438             env = env.next;
   439         }
   440         return false;
   441     }
   443 /* ************************************************************************
   444  * Normalizing class-members.
   445  *************************************************************************/
   447     /** Distribute member initializer code into constructors and <clinit>
   448      *  method.
   449      *  @param defs         The list of class member declarations.
   450      *  @param c            The enclosing class.
   451      */
   452     List<JCTree> normalizeDefs(List<JCTree> defs, ClassSymbol c) {
   453         ListBuffer<JCStatement> initCode = new ListBuffer<JCStatement>();
   454         ListBuffer<JCStatement> clinitCode = new ListBuffer<JCStatement>();
   455         ListBuffer<JCTree> methodDefs = new ListBuffer<JCTree>();
   456         // Sort definitions into three listbuffers:
   457         //  - initCode for instance initializers
   458         //  - clinitCode for class initializers
   459         //  - methodDefs for method definitions
   460         for (List<JCTree> l = defs; l.nonEmpty(); l = l.tail) {
   461             JCTree def = l.head;
   462             switch (def.getTag()) {
   463             case JCTree.BLOCK:
   464                 JCBlock block = (JCBlock)def;
   465                 if ((block.flags & STATIC) != 0)
   466                     clinitCode.append(block);
   467                 else
   468                     initCode.append(block);
   469                 break;
   470             case JCTree.METHODDEF:
   471                 methodDefs.append(def);
   472                 break;
   473             case JCTree.VARDEF:
   474                 JCVariableDecl vdef = (JCVariableDecl) def;
   475                 VarSymbol sym = vdef.sym;
   476                 checkDimension(vdef.pos(), sym.type);
   477                 if (vdef.init != null) {
   478                     if ((sym.flags() & STATIC) == 0) {
   479                         // Always initialize instance variables.
   480                         JCStatement init = make.at(vdef.pos()).
   481                             Assignment(sym, vdef.init);
   482                         initCode.append(init);
   483                         if (endPositions != null) {
   484                             Integer endPos = endPositions.remove(vdef);
   485                             if (endPos != null) endPositions.put(init, endPos);
   486                         }
   487                     } else if (sym.getConstValue() == null) {
   488                         // Initialize class (static) variables only if
   489                         // they are not compile-time constants.
   490                         JCStatement init = make.at(vdef.pos).
   491                             Assignment(sym, vdef.init);
   492                         clinitCode.append(init);
   493                         if (endPositions != null) {
   494                             Integer endPos = endPositions.remove(vdef);
   495                             if (endPos != null) endPositions.put(init, endPos);
   496                         }
   497                     } else {
   498                         checkStringConstant(vdef.init.pos(), sym.getConstValue());
   499                     }
   500                 }
   501                 break;
   502             default:
   503                 assert false;
   504             }
   505         }
   506         // Insert any instance initializers into all constructors.
   507         if (initCode.length() != 0) {
   508             List<JCStatement> inits = initCode.toList();
   509             for (JCTree t : methodDefs) {
   510                 normalizeMethod((JCMethodDecl)t, inits);
   511             }
   512         }
   513         // If there are class initializers, create a <clinit> method
   514         // that contains them as its body.
   515         if (clinitCode.length() != 0) {
   516             MethodSymbol clinit = new MethodSymbol(
   517                 STATIC, names.clinit,
   518                 new MethodType(
   519                     List.<Type>nil(), syms.voidType,
   520                     List.<Type>nil(), syms.methodClass),
   521                 c);
   522             c.members().enter(clinit);
   523             List<JCStatement> clinitStats = clinitCode.toList();
   524             JCBlock block = make.at(clinitStats.head.pos()).Block(0, clinitStats);
   525             block.endpos = TreeInfo.endPos(clinitStats.last());
   526             methodDefs.append(make.MethodDef(clinit, block));
   527         }
   528         // Return all method definitions.
   529         return methodDefs.toList();
   530     }
   532     /** Check a constant value and report if it is a string that is
   533      *  too large.
   534      */
   535     private void checkStringConstant(DiagnosticPosition pos, Object constValue) {
   536         if (nerrs != 0 || // only complain about a long string once
   537             constValue == null ||
   538             !(constValue instanceof String) ||
   539             ((String)constValue).length() < Pool.MAX_STRING_LENGTH)
   540             return;
   541         log.error(pos, "limit.string");
   542         nerrs++;
   543     }
   545     /** Insert instance initializer code into initial constructor.
   546      *  @param md        The tree potentially representing a
   547      *                   constructor's definition.
   548      *  @param initCode  The list of instance initializer statements.
   549      */
   550     void normalizeMethod(JCMethodDecl md, List<JCStatement> initCode) {
   551         if (md.name == names.init && TreeInfo.isInitialConstructor(md)) {
   552             // We are seeing a constructor that does not call another
   553             // constructor of the same class.
   554             List<JCStatement> stats = md.body.stats;
   555             ListBuffer<JCStatement> newstats = new ListBuffer<JCStatement>();
   557             if (stats.nonEmpty()) {
   558                 // Copy initializers of synthetic variables generated in
   559                 // the translation of inner classes.
   560                 while (TreeInfo.isSyntheticInit(stats.head)) {
   561                     newstats.append(stats.head);
   562                     stats = stats.tail;
   563                 }
   564                 // Copy superclass constructor call
   565                 newstats.append(stats.head);
   566                 stats = stats.tail;
   567                 // Copy remaining synthetic initializers.
   568                 while (stats.nonEmpty() &&
   569                        TreeInfo.isSyntheticInit(stats.head)) {
   570                     newstats.append(stats.head);
   571                     stats = stats.tail;
   572                 }
   573                 // Now insert the initializer code.
   574                 newstats.appendList(initCode);
   575                 // And copy all remaining statements.
   576                 while (stats.nonEmpty()) {
   577                     newstats.append(stats.head);
   578                     stats = stats.tail;
   579                 }
   580             }
   581             md.body.stats = newstats.toList();
   582             if (md.body.endpos == Position.NOPOS)
   583                 md.body.endpos = TreeInfo.endPos(md.body.stats.last());
   584         }
   585     }
   587 /* ********************************************************************
   588  * Adding miranda methods
   589  *********************************************************************/
   591     /** Add abstract methods for all methods defined in one of
   592      *  the interfaces of a given class,
   593      *  provided they are not already implemented in the class.
   594      *
   595      *  @param c      The class whose interfaces are searched for methods
   596      *                for which Miranda methods should be added.
   597      */
   598     void implementInterfaceMethods(ClassSymbol c) {
   599         implementInterfaceMethods(c, c);
   600     }
   602     /** Add abstract methods for all methods defined in one of
   603      *  the interfaces of a given class,
   604      *  provided they are not already implemented in the class.
   605      *
   606      *  @param c      The class whose interfaces are searched for methods
   607      *                for which Miranda methods should be added.
   608      *  @param site   The class in which a definition may be needed.
   609      */
   610     void implementInterfaceMethods(ClassSymbol c, ClassSymbol site) {
   611         for (List<Type> l = types.interfaces(c.type); l.nonEmpty(); l = l.tail) {
   612             ClassSymbol i = (ClassSymbol)l.head.tsym;
   613             for (Scope.Entry e = i.members().elems;
   614                  e != null;
   615                  e = e.sibling)
   616             {
   617                 if (e.sym.kind == MTH && (e.sym.flags() & STATIC) == 0)
   618                 {
   619                     MethodSymbol absMeth = (MethodSymbol)e.sym;
   620                     MethodSymbol implMeth = absMeth.binaryImplementation(site, types);
   621                     if (implMeth == null)
   622                         addAbstractMethod(site, absMeth);
   623                     else if ((implMeth.flags() & IPROXY) != 0)
   624                         adjustAbstractMethod(site, implMeth, absMeth);
   625                 }
   626             }
   627             implementInterfaceMethods(i, site);
   628         }
   629     }
   631     /** Add an abstract methods to a class
   632      *  which implicitly implements a method defined in some interface
   633      *  implemented by the class. These methods are called "Miranda methods".
   634      *  Enter the newly created method into its enclosing class scope.
   635      *  Note that it is not entered into the class tree, as the emitter
   636      *  doesn't need to see it there to emit an abstract method.
   637      *
   638      *  @param c      The class to which the Miranda method is added.
   639      *  @param m      The interface method symbol for which a Miranda method
   640      *                is added.
   641      */
   642     private void addAbstractMethod(ClassSymbol c,
   643                                    MethodSymbol m) {
   644         MethodSymbol absMeth = new MethodSymbol(
   645             m.flags() | IPROXY | SYNTHETIC, m.name,
   646             m.type, // was c.type.memberType(m), but now only !generics supported
   647             c);
   648         c.members().enter(absMeth); // add to symbol table
   649     }
   651     private void adjustAbstractMethod(ClassSymbol c,
   652                                       MethodSymbol pm,
   653                                       MethodSymbol im) {
   654         MethodType pmt = (MethodType)pm.type;
   655         Type imt = types.memberType(c.type, im);
   656         pmt.thrown = chk.intersect(pmt.getThrownTypes(), imt.getThrownTypes());
   657     }
   659 /* ************************************************************************
   660  * Traversal methods
   661  *************************************************************************/
   663     /** Visitor argument: The current environment.
   664      */
   665     Env<GenContext> env;
   667     /** Visitor argument: The expected type (prototype).
   668      */
   669     Type pt;
   671     /** Visitor result: The item representing the computed value.
   672      */
   673     Item result;
   675     /** Visitor method: generate code for a definition, catching and reporting
   676      *  any completion failures.
   677      *  @param tree    The definition to be visited.
   678      *  @param env     The environment current at the definition.
   679      */
   680     public void genDef(JCTree tree, Env<GenContext> env) {
   681         Env<GenContext> prevEnv = this.env;
   682         try {
   683             this.env = env;
   684             tree.accept(this);
   685         } catch (CompletionFailure ex) {
   686             chk.completionError(tree.pos(), ex);
   687         } finally {
   688             this.env = prevEnv;
   689         }
   690     }
   692     /** Derived visitor method: check whether CharacterRangeTable
   693      *  should be emitted, if so, put a new entry into CRTable
   694      *  and call method to generate bytecode.
   695      *  If not, just call method to generate bytecode.
   696      *  @see    #genStat(Tree, Env)
   697      *
   698      *  @param  tree     The tree to be visited.
   699      *  @param  env      The environment to use.
   700      *  @param  crtFlags The CharacterRangeTable flags
   701      *                   indicating type of the entry.
   702      */
   703     public void genStat(JCTree tree, Env<GenContext> env, int crtFlags) {
   704         if (!genCrt) {
   705             genStat(tree, env);
   706             return;
   707         }
   708         int startpc = code.curPc();
   709         genStat(tree, env);
   710         if (tree.getTag() == JCTree.BLOCK) crtFlags |= CRT_BLOCK;
   711         code.crt.put(tree, crtFlags, startpc, code.curPc());
   712     }
   714     /** Derived visitor method: generate code for a statement.
   715      */
   716     public void genStat(JCTree tree, Env<GenContext> env) {
   717         if (code.isAlive()) {
   718             code.statBegin(tree.pos);
   719             genDef(tree, env);
   720         } else if (env.info.isSwitch && tree.getTag() == JCTree.VARDEF) {
   721             // variables whose declarations are in a switch
   722             // can be used even if the decl is unreachable.
   723             code.newLocal(((JCVariableDecl) tree).sym);
   724         }
   725     }
   727     /** Derived visitor method: check whether CharacterRangeTable
   728      *  should be emitted, if so, put a new entry into CRTable
   729      *  and call method to generate bytecode.
   730      *  If not, just call method to generate bytecode.
   731      *  @see    #genStats(List, Env)
   732      *
   733      *  @param  trees    The list of trees to be visited.
   734      *  @param  env      The environment to use.
   735      *  @param  crtFlags The CharacterRangeTable flags
   736      *                   indicating type of the entry.
   737      */
   738     public void genStats(List<JCStatement> trees, Env<GenContext> env, int crtFlags) {
   739         if (!genCrt) {
   740             genStats(trees, env);
   741             return;
   742         }
   743         if (trees.length() == 1) {        // mark one statement with the flags
   744             genStat(trees.head, env, crtFlags | CRT_STATEMENT);
   745         } else {
   746             int startpc = code.curPc();
   747             genStats(trees, env);
   748             code.crt.put(trees, crtFlags, startpc, code.curPc());
   749         }
   750     }
   752     /** Derived visitor method: generate code for a list of statements.
   753      */
   754     public void genStats(List<? extends JCTree> trees, Env<GenContext> env) {
   755         for (List<? extends JCTree> l = trees; l.nonEmpty(); l = l.tail)
   756             genStat(l.head, env, CRT_STATEMENT);
   757     }
   759     /** Derived visitor method: check whether CharacterRangeTable
   760      *  should be emitted, if so, put a new entry into CRTable
   761      *  and call method to generate bytecode.
   762      *  If not, just call method to generate bytecode.
   763      *  @see    #genCond(Tree,boolean)
   764      *
   765      *  @param  tree     The tree to be visited.
   766      *  @param  crtFlags The CharacterRangeTable flags
   767      *                   indicating type of the entry.
   768      */
   769     public CondItem genCond(JCTree tree, int crtFlags) {
   770         if (!genCrt) return genCond(tree, false);
   771         int startpc = code.curPc();
   772         CondItem item = genCond(tree, (crtFlags & CRT_FLOW_CONTROLLER) != 0);
   773         code.crt.put(tree, crtFlags, startpc, code.curPc());
   774         return item;
   775     }
   777     /** Derived visitor method: generate code for a boolean
   778      *  expression in a control-flow context.
   779      *  @param _tree         The expression to be visited.
   780      *  @param markBranches The flag to indicate that the condition is
   781      *                      a flow controller so produced conditions
   782      *                      should contain a proper tree to generate
   783      *                      CharacterRangeTable branches for them.
   784      */
   785     public CondItem genCond(JCTree _tree, boolean markBranches) {
   786         JCTree inner_tree = TreeInfo.skipParens(_tree);
   787         if (inner_tree.getTag() == JCTree.CONDEXPR) {
   788             JCConditional tree = (JCConditional)inner_tree;
   789             CondItem cond = genCond(tree.cond, CRT_FLOW_CONTROLLER);
   790             if (cond.isTrue()) {
   791                 code.resolve(cond.trueJumps);
   792                 CondItem result = genCond(tree.truepart, CRT_FLOW_TARGET);
   793                 if (markBranches) result.tree = tree.truepart;
   794                 return result;
   795             }
   796             if (cond.isFalse()) {
   797                 code.resolve(cond.falseJumps);
   798                 CondItem result = genCond(tree.falsepart, CRT_FLOW_TARGET);
   799                 if (markBranches) result.tree = tree.falsepart;
   800                 return result;
   801             }
   802             Chain secondJumps = cond.jumpFalse();
   803             code.resolve(cond.trueJumps);
   804             CondItem first = genCond(tree.truepart, CRT_FLOW_TARGET);
   805             if (markBranches) first.tree = tree.truepart;
   806             Chain falseJumps = first.jumpFalse();
   807             code.resolve(first.trueJumps);
   808             Chain trueJumps = code.branch(goto_);
   809             code.resolve(secondJumps);
   810             CondItem second = genCond(tree.falsepart, CRT_FLOW_TARGET);
   811             CondItem result = items.makeCondItem(second.opcode,
   812                                       Code.mergeChains(trueJumps, second.trueJumps),
   813                                       Code.mergeChains(falseJumps, second.falseJumps));
   814             if (markBranches) result.tree = tree.falsepart;
   815             return result;
   816         } else {
   817             CondItem result = genExpr(_tree, syms.booleanType).mkCond();
   818             if (markBranches) result.tree = _tree;
   819             return result;
   820         }
   821     }
   823     /** Visitor method: generate code for an expression, catching and reporting
   824      *  any completion failures.
   825      *  @param tree    The expression to be visited.
   826      *  @param pt      The expression's expected type (proto-type).
   827      */
   828     public Item genExpr(JCTree tree, Type pt) {
   829         Type prevPt = this.pt;
   830         try {
   831             if (tree.type.constValue() != null) {
   832                 // Short circuit any expressions which are constants
   833                 checkStringConstant(tree.pos(), tree.type.constValue());
   834                 result = items.makeImmediateItem(tree.type, tree.type.constValue());
   835             } else {
   836                 this.pt = pt;
   837                 tree.accept(this);
   838             }
   839             return result.coerce(pt);
   840         } catch (CompletionFailure ex) {
   841             chk.completionError(tree.pos(), ex);
   842             code.state.stacksize = 1;
   843             return items.makeStackItem(pt);
   844         } finally {
   845             this.pt = prevPt;
   846         }
   847     }
   849     /** Derived visitor method: generate code for a list of method arguments.
   850      *  @param trees    The argument expressions to be visited.
   851      *  @param pts      The expression's expected types (i.e. the formal parameter
   852      *                  types of the invoked method).
   853      */
   854     public void genArgs(List<JCExpression> trees, List<Type> pts) {
   855         for (List<JCExpression> l = trees; l.nonEmpty(); l = l.tail) {
   856             genExpr(l.head, pts.head).load();
   857             pts = pts.tail;
   858         }
   859         // require lists be of same length
   860         assert pts.isEmpty();
   861     }
   863 /* ************************************************************************
   864  * Visitor methods for statements and definitions
   865  *************************************************************************/
   867     /** Thrown when the byte code size exceeds limit.
   868      */
   869     public static class CodeSizeOverflow extends RuntimeException {
   870         private static final long serialVersionUID = 0;
   871         public CodeSizeOverflow() {}
   872     }
   874     public void visitMethodDef(JCMethodDecl tree) {
   875         // Create a new local environment that points pack at method
   876         // definition.
   877         Env<GenContext> localEnv = env.dup(tree);
   878         localEnv.enclMethod = tree;
   880         // The expected type of every return statement in this method
   881         // is the method's return type.
   882         this.pt = tree.sym.erasure(types).getReturnType();
   884         checkDimension(tree.pos(), tree.sym.erasure(types));
   885         genMethod(tree, localEnv, false);
   886     }
   887 //where
   888         /** Generate code for a method.
   889          *  @param tree     The tree representing the method definition.
   890          *  @param env      The environment current for the method body.
   891          *  @param fatcode  A flag that indicates whether all jumps are
   892          *                  within 32K.  We first invoke this method under
   893          *                  the assumption that fatcode == false, i.e. all
   894          *                  jumps are within 32K.  If this fails, fatcode
   895          *                  is set to true and we try again.
   896          */
   897         void genMethod(JCMethodDecl tree, Env<GenContext> env, boolean fatcode) {
   898             MethodSymbol meth = tree.sym;
   899 //      System.err.println("Generating " + meth + " in " + meth.owner); //DEBUG
   900             if (Code.width(types.erasure(env.enclMethod.sym.type).getParameterTypes())  +
   901                 (((tree.mods.flags & STATIC) == 0 || meth.isConstructor()) ? 1 : 0) >
   902                 ClassFile.MAX_PARAMETERS) {
   903                 log.error(tree.pos(), "limit.parameters");
   904                 nerrs++;
   905             }
   907             else if (tree.body != null) {
   908                 // Create a new code structure and initialize it.
   909                 int startpcCrt = initCode(tree, env, fatcode);
   911                 try {
   912                     genStat(tree.body, env);
   913                 } catch (CodeSizeOverflow e) {
   914                     // Failed due to code limit, try again with jsr/ret
   915                     startpcCrt = initCode(tree, env, fatcode);
   916                     genStat(tree.body, env);
   917                 }
   919                 if (code.state.stacksize != 0) {
   920                     log.error(tree.body.pos(), "stack.sim.error", tree);
   921                     throw new AssertionError();
   922                 }
   924                 // If last statement could complete normally, insert a
   925                 // return at the end.
   926                 if (code.isAlive()) {
   927                     code.statBegin(TreeInfo.endPos(tree.body));
   928                     if (env.enclMethod == null ||
   929                         env.enclMethod.sym.type.getReturnType().tag == VOID) {
   930                         code.emitop0(return_);
   931                     } else {
   932                         // sometime dead code seems alive (4415991);
   933                         // generate a small loop instead
   934                         int startpc = code.entryPoint();
   935                         CondItem c = items.makeCondItem(goto_);
   936                         code.resolve(c.jumpTrue(), startpc);
   937                     }
   938                 }
   939                 if (genCrt)
   940                     code.crt.put(tree.body,
   941                                  CRT_BLOCK,
   942                                  startpcCrt,
   943                                  code.curPc());
   945                 code.endScopes(0);
   947                 // If we exceeded limits, panic
   948                 if (code.checkLimits(tree.pos(), log)) {
   949                     nerrs++;
   950                     return;
   951                 }
   953                 // If we generated short code but got a long jump, do it again
   954                 // with fatCode = true.
   955                 if (!fatcode && code.fatcode) genMethod(tree, env, true);
   957                 // Clean up
   958                 if(stackMap == StackMapFormat.JSR202) {
   959                     code.lastFrame = null;
   960                     code.frameBeforeLast = null;
   961                 }
   962             }
   963         }
   965         private int initCode(JCMethodDecl tree, Env<GenContext> env, boolean fatcode) {
   966             MethodSymbol meth = tree.sym;
   968             // Create a new code structure.
   969             meth.code = code = new Code(meth,
   970                                         fatcode,
   971                                         lineDebugInfo ? toplevel.lineMap : null,
   972                                         varDebugInfo,
   973                                         stackMap,
   974                                         debugCode,
   975                                         genCrt ? new CRTable(tree, env.toplevel.endPositions)
   976                                                : null,
   977                                         syms,
   978                                         types,
   979                                         pool);
   980             items = new Items(pool, code, syms, types);
   981             if (code.debugCode)
   982                 System.err.println(meth + " for body " + tree);
   984             // If method is not static, create a new local variable address
   985             // for `this'.
   986             if ((tree.mods.flags & STATIC) == 0) {
   987                 Type selfType = meth.owner.type;
   988                 if (meth.isConstructor() && selfType != syms.objectType)
   989                     selfType = UninitializedType.uninitializedThis(selfType);
   990                 code.setDefined(
   991                         code.newLocal(
   992                             new VarSymbol(FINAL, names._this, selfType, meth.owner)));
   993             }
   995             // Mark all parameters as defined from the beginning of
   996             // the method.
   997             for (List<JCVariableDecl> l = tree.params; l.nonEmpty(); l = l.tail) {
   998                 checkDimension(l.head.pos(), l.head.sym.type);
   999                 code.setDefined(code.newLocal(l.head.sym));
  1002             // Get ready to generate code for method body.
  1003             int startpcCrt = genCrt ? code.curPc() : 0;
  1004             code.entryPoint();
  1006             // Suppress initial stackmap
  1007             code.pendingStackMap = false;
  1009             return startpcCrt;
  1012     public void visitVarDef(JCVariableDecl tree) {
  1013         VarSymbol v = tree.sym;
  1014         code.newLocal(v);
  1015         if (tree.init != null) {
  1016             checkStringConstant(tree.init.pos(), v.getConstValue());
  1017             if (v.getConstValue() == null || varDebugInfo) {
  1018                 genExpr(tree.init, v.erasure(types)).load();
  1019                 items.makeLocalItem(v).store();
  1022         checkDimension(tree.pos(), v.type);
  1025     public void visitSkip(JCSkip tree) {
  1028     public void visitBlock(JCBlock tree) {
  1029         int limit = code.nextreg;
  1030         Env<GenContext> localEnv = env.dup(tree, new GenContext());
  1031         genStats(tree.stats, localEnv);
  1032         // End the scope of all block-local variables in variable info.
  1033         if (env.tree.getTag() != JCTree.METHODDEF) {
  1034             code.statBegin(tree.endpos);
  1035             code.endScopes(limit);
  1036             code.pendingStatPos = Position.NOPOS;
  1040     public void visitDoLoop(JCDoWhileLoop tree) {
  1041         genLoop(tree, tree.body, tree.cond, List.<JCExpressionStatement>nil(), false);
  1044     public void visitWhileLoop(JCWhileLoop tree) {
  1045         genLoop(tree, tree.body, tree.cond, List.<JCExpressionStatement>nil(), true);
  1048     public void visitForLoop(JCForLoop tree) {
  1049         int limit = code.nextreg;
  1050         genStats(tree.init, env);
  1051         genLoop(tree, tree.body, tree.cond, tree.step, true);
  1052         code.endScopes(limit);
  1054     //where
  1055         /** Generate code for a loop.
  1056          *  @param loop       The tree representing the loop.
  1057          *  @param body       The loop's body.
  1058          *  @param cond       The loop's controling condition.
  1059          *  @param step       "Step" statements to be inserted at end of
  1060          *                    each iteration.
  1061          *  @param testFirst  True if the loop test belongs before the body.
  1062          */
  1063         private void genLoop(JCStatement loop,
  1064                              JCStatement body,
  1065                              JCExpression cond,
  1066                              List<JCExpressionStatement> step,
  1067                              boolean testFirst) {
  1068             Env<GenContext> loopEnv = env.dup(loop, new GenContext());
  1069             int startpc = code.entryPoint();
  1070             if (testFirst) {
  1071                 CondItem c;
  1072                 if (cond != null) {
  1073                     code.statBegin(cond.pos);
  1074                     c = genCond(TreeInfo.skipParens(cond), CRT_FLOW_CONTROLLER);
  1075                 } else {
  1076                     c = items.makeCondItem(goto_);
  1078                 Chain loopDone = c.jumpFalse();
  1079                 code.resolve(c.trueJumps);
  1080                 genStat(body, loopEnv, CRT_STATEMENT | CRT_FLOW_TARGET);
  1081                 code.resolve(loopEnv.info.cont);
  1082                 genStats(step, loopEnv);
  1083                 code.resolve(code.branch(goto_), startpc);
  1084                 code.resolve(loopDone);
  1085             } else {
  1086                 genStat(body, loopEnv, CRT_STATEMENT | CRT_FLOW_TARGET);
  1087                 code.resolve(loopEnv.info.cont);
  1088                 genStats(step, loopEnv);
  1089                 CondItem c;
  1090                 if (cond != null) {
  1091                     code.statBegin(cond.pos);
  1092                     c = genCond(TreeInfo.skipParens(cond), CRT_FLOW_CONTROLLER);
  1093                 } else {
  1094                     c = items.makeCondItem(goto_);
  1096                 code.resolve(c.jumpTrue(), startpc);
  1097                 code.resolve(c.falseJumps);
  1099             code.resolve(loopEnv.info.exit);
  1102     public void visitForeachLoop(JCEnhancedForLoop tree) {
  1103         throw new AssertionError(); // should have been removed by Lower.
  1106     public void visitLabelled(JCLabeledStatement tree) {
  1107         Env<GenContext> localEnv = env.dup(tree, new GenContext());
  1108         genStat(tree.body, localEnv, CRT_STATEMENT);
  1109         code.resolve(localEnv.info.exit);
  1112     public void visitSwitch(JCSwitch tree) {
  1113         int limit = code.nextreg;
  1114         assert tree.selector.type.tag != CLASS;
  1115         int startpcCrt = genCrt ? code.curPc() : 0;
  1116         Item sel = genExpr(tree.selector, syms.intType);
  1117         List<JCCase> cases = tree.cases;
  1118         if (cases.isEmpty()) {
  1119             // We are seeing:  switch <sel> {}
  1120             sel.load().drop();
  1121             if (genCrt)
  1122                 code.crt.put(TreeInfo.skipParens(tree.selector),
  1123                              CRT_FLOW_CONTROLLER, startpcCrt, code.curPc());
  1124         } else {
  1125             // We are seeing a nonempty switch.
  1126             sel.load();
  1127             if (genCrt)
  1128                 code.crt.put(TreeInfo.skipParens(tree.selector),
  1129                              CRT_FLOW_CONTROLLER, startpcCrt, code.curPc());
  1130             Env<GenContext> switchEnv = env.dup(tree, new GenContext());
  1131             switchEnv.info.isSwitch = true;
  1133             // Compute number of labels and minimum and maximum label values.
  1134             // For each case, store its label in an array.
  1135             int lo = Integer.MAX_VALUE;  // minimum label.
  1136             int hi = Integer.MIN_VALUE;  // maximum label.
  1137             int nlabels = 0;               // number of labels.
  1139             int[] labels = new int[cases.length()];  // the label array.
  1140             int defaultIndex = -1;     // the index of the default clause.
  1142             List<JCCase> l = cases;
  1143             for (int i = 0; i < labels.length; i++) {
  1144                 if (l.head.pat != null) {
  1145                     int val = ((Number)l.head.pat.type.constValue()).intValue();
  1146                     labels[i] = val;
  1147                     if (val < lo) lo = val;
  1148                     if (hi < val) hi = val;
  1149                     nlabels++;
  1150                 } else {
  1151                     assert defaultIndex == -1;
  1152                     defaultIndex = i;
  1154                 l = l.tail;
  1157             // Determine whether to issue a tableswitch or a lookupswitch
  1158             // instruction.
  1159             long table_space_cost = 4 + ((long) hi - lo + 1); // words
  1160             long table_time_cost = 3; // comparisons
  1161             long lookup_space_cost = 3 + 2 * (long) nlabels;
  1162             long lookup_time_cost = nlabels;
  1163             int opcode =
  1164                 nlabels > 0 &&
  1165                 table_space_cost + 3 * table_time_cost <=
  1166                 lookup_space_cost + 3 * lookup_time_cost
  1168                 tableswitch : lookupswitch;
  1170             int startpc = code.curPc();    // the position of the selector operation
  1171             code.emitop0(opcode);
  1172             code.align(4);
  1173             int tableBase = code.curPc();  // the start of the jump table
  1174             int[] offsets = null;          // a table of offsets for a lookupswitch
  1175             code.emit4(-1);                // leave space for default offset
  1176             if (opcode == tableswitch) {
  1177                 code.emit4(lo);            // minimum label
  1178                 code.emit4(hi);            // maximum label
  1179                 for (long i = lo; i <= hi; i++) {  // leave space for jump table
  1180                     code.emit4(-1);
  1182             } else {
  1183                 code.emit4(nlabels);    // number of labels
  1184                 for (int i = 0; i < nlabels; i++) {
  1185                     code.emit4(-1); code.emit4(-1); // leave space for lookup table
  1187                 offsets = new int[labels.length];
  1189             Code.State stateSwitch = code.state.dup();
  1190             code.markDead();
  1192             // For each case do:
  1193             l = cases;
  1194             for (int i = 0; i < labels.length; i++) {
  1195                 JCCase c = l.head;
  1196                 l = l.tail;
  1198                 int pc = code.entryPoint(stateSwitch);
  1199                 // Insert offset directly into code or else into the
  1200                 // offsets table.
  1201                 if (i != defaultIndex) {
  1202                     if (opcode == tableswitch) {
  1203                         code.put4(
  1204                             tableBase + 4 * (labels[i] - lo + 3),
  1205                             pc - startpc);
  1206                     } else {
  1207                         offsets[i] = pc - startpc;
  1209                 } else {
  1210                     code.put4(tableBase, pc - startpc);
  1213                 // Generate code for the statements in this case.
  1214                 genStats(c.stats, switchEnv, CRT_FLOW_TARGET);
  1217             // Resolve all breaks.
  1218             code.resolve(switchEnv.info.exit);
  1220             // If we have not set the default offset, we do so now.
  1221             if (code.get4(tableBase) == -1) {
  1222                 code.put4(tableBase, code.entryPoint(stateSwitch) - startpc);
  1225             if (opcode == tableswitch) {
  1226                 // Let any unfilled slots point to the default case.
  1227                 int defaultOffset = code.get4(tableBase);
  1228                 for (long i = lo; i <= hi; i++) {
  1229                     int t = (int)(tableBase + 4 * (i - lo + 3));
  1230                     if (code.get4(t) == -1)
  1231                         code.put4(t, defaultOffset);
  1233             } else {
  1234                 // Sort non-default offsets and copy into lookup table.
  1235                 if (defaultIndex >= 0)
  1236                     for (int i = defaultIndex; i < labels.length - 1; i++) {
  1237                         labels[i] = labels[i+1];
  1238                         offsets[i] = offsets[i+1];
  1240                 if (nlabels > 0)
  1241                     qsort2(labels, offsets, 0, nlabels - 1);
  1242                 for (int i = 0; i < nlabels; i++) {
  1243                     int caseidx = tableBase + 8 * (i + 1);
  1244                     code.put4(caseidx, labels[i]);
  1245                     code.put4(caseidx + 4, offsets[i]);
  1249         code.endScopes(limit);
  1251 //where
  1252         /** Sort (int) arrays of keys and values
  1253          */
  1254        static void qsort2(int[] keys, int[] values, int lo, int hi) {
  1255             int i = lo;
  1256             int j = hi;
  1257             int pivot = keys[(i+j)/2];
  1258             do {
  1259                 while (keys[i] < pivot) i++;
  1260                 while (pivot < keys[j]) j--;
  1261                 if (i <= j) {
  1262                     int temp1 = keys[i];
  1263                     keys[i] = keys[j];
  1264                     keys[j] = temp1;
  1265                     int temp2 = values[i];
  1266                     values[i] = values[j];
  1267                     values[j] = temp2;
  1268                     i++;
  1269                     j--;
  1271             } while (i <= j);
  1272             if (lo < j) qsort2(keys, values, lo, j);
  1273             if (i < hi) qsort2(keys, values, i, hi);
  1276     public void visitSynchronized(JCSynchronized tree) {
  1277         int limit = code.nextreg;
  1278         // Generate code to evaluate lock and save in temporary variable.
  1279         final LocalItem lockVar = makeTemp(syms.objectType);
  1280         genExpr(tree.lock, tree.lock.type).load().duplicate();
  1281         lockVar.store();
  1283         // Generate code to enter monitor.
  1284         code.emitop0(monitorenter);
  1285         code.state.lock(lockVar.reg);
  1287         // Generate code for a try statement with given body, no catch clauses
  1288         // in a new environment with the "exit-monitor" operation as finalizer.
  1289         final Env<GenContext> syncEnv = env.dup(tree, new GenContext());
  1290         syncEnv.info.finalize = new GenFinalizer() {
  1291             void gen() {
  1292                 genLast();
  1293                 assert syncEnv.info.gaps.length() % 2 == 0;
  1294                 syncEnv.info.gaps.append(code.curPc());
  1296             void genLast() {
  1297                 if (code.isAlive()) {
  1298                     lockVar.load();
  1299                     code.emitop0(monitorexit);
  1300                     code.state.unlock(lockVar.reg);
  1303         };
  1304         syncEnv.info.gaps = new ListBuffer<Integer>();
  1305         genTry(tree.body, List.<JCCatch>nil(), syncEnv);
  1306         code.endScopes(limit);
  1309     public void visitTry(final JCTry tree) {
  1310         // Generate code for a try statement with given body and catch clauses,
  1311         // in a new environment which calls the finally block if there is one.
  1312         final Env<GenContext> tryEnv = env.dup(tree, new GenContext());
  1313         final Env<GenContext> oldEnv = env;
  1314         if (!useJsrLocally) {
  1315             useJsrLocally =
  1316                 (stackMap == StackMapFormat.NONE) &&
  1317                 (jsrlimit <= 0 ||
  1318                 jsrlimit < 100 &&
  1319                 estimateCodeComplexity(tree.finalizer)>jsrlimit);
  1321         tryEnv.info.finalize = new GenFinalizer() {
  1322             void gen() {
  1323                 if (useJsrLocally) {
  1324                     if (tree.finalizer != null) {
  1325                         Code.State jsrState = code.state.dup();
  1326                         jsrState.push(Code.jsrReturnValue);
  1327                         tryEnv.info.cont =
  1328                             new Chain(code.emitJump(jsr),
  1329                                       tryEnv.info.cont,
  1330                                       jsrState);
  1332                     assert tryEnv.info.gaps.length() % 2 == 0;
  1333                     tryEnv.info.gaps.append(code.curPc());
  1334                 } else {
  1335                     assert tryEnv.info.gaps.length() % 2 == 0;
  1336                     tryEnv.info.gaps.append(code.curPc());
  1337                     genLast();
  1340             void genLast() {
  1341                 if (tree.finalizer != null)
  1342                     genStat(tree.finalizer, oldEnv, CRT_BLOCK);
  1344             boolean hasFinalizer() {
  1345                 return tree.finalizer != null;
  1347         };
  1348         tryEnv.info.gaps = new ListBuffer<Integer>();
  1349         genTry(tree.body, tree.catchers, tryEnv);
  1351     //where
  1352         /** Generate code for a try or synchronized statement
  1353          *  @param body      The body of the try or synchronized statement.
  1354          *  @param catchers  The lis of catch clauses.
  1355          *  @param env       the environment current for the body.
  1356          */
  1357         void genTry(JCTree body, List<JCCatch> catchers, Env<GenContext> env) {
  1358             int limit = code.nextreg;
  1359             int startpc = code.curPc();
  1360             Code.State stateTry = code.state.dup();
  1361             genStat(body, env, CRT_BLOCK);
  1362             int endpc = code.curPc();
  1363             boolean hasFinalizer =
  1364                 env.info.finalize != null &&
  1365                 env.info.finalize.hasFinalizer();
  1366             List<Integer> gaps = env.info.gaps.toList();
  1367             code.statBegin(TreeInfo.endPos(body));
  1368             genFinalizer(env);
  1369             code.statBegin(TreeInfo.endPos(env.tree));
  1370             Chain exitChain = code.branch(goto_);
  1371             endFinalizerGap(env);
  1372             if (startpc != endpc) for (List<JCCatch> l = catchers; l.nonEmpty(); l = l.tail) {
  1373                 // start off with exception on stack
  1374                 code.entryPoint(stateTry, l.head.param.sym.type);
  1375                 genCatch(l.head, env, startpc, endpc, gaps);
  1376                 genFinalizer(env);
  1377                 if (hasFinalizer || l.tail.nonEmpty()) {
  1378                     code.statBegin(TreeInfo.endPos(env.tree));
  1379                     exitChain = Code.mergeChains(exitChain,
  1380                                                  code.branch(goto_));
  1382                 endFinalizerGap(env);
  1384             if (hasFinalizer) {
  1385                 // Create a new register segement to avoid allocating
  1386                 // the same variables in finalizers and other statements.
  1387                 code.newRegSegment();
  1389                 // Add a catch-all clause.
  1391                 // start off with exception on stack
  1392                 int catchallpc = code.entryPoint(stateTry, syms.throwableType);
  1394                 // Register all exception ranges for catch all clause.
  1395                 // The range of the catch all clause is from the beginning
  1396                 // of the try or synchronized block until the present
  1397                 // code pointer excluding all gaps in the current
  1398                 // environment's GenContext.
  1399                 int startseg = startpc;
  1400                 while (env.info.gaps.nonEmpty()) {
  1401                     int endseg = env.info.gaps.next().intValue();
  1402                     registerCatch(body.pos(), startseg, endseg,
  1403                                   catchallpc, 0);
  1404                     startseg = env.info.gaps.next().intValue();
  1406                 code.statBegin(TreeInfo.finalizerPos(env.tree));
  1407                 code.markStatBegin();
  1409                 Item excVar = makeTemp(syms.throwableType);
  1410                 excVar.store();
  1411                 genFinalizer(env);
  1412                 excVar.load();
  1413                 registerCatch(body.pos(), startseg,
  1414                               env.info.gaps.next().intValue(),
  1415                               catchallpc, 0);
  1416                 code.emitop0(athrow);
  1417                 code.markDead();
  1419                 // If there are jsr's to this finalizer, ...
  1420                 if (env.info.cont != null) {
  1421                     // Resolve all jsr's.
  1422                     code.resolve(env.info.cont);
  1424                     // Mark statement line number
  1425                     code.statBegin(TreeInfo.finalizerPos(env.tree));
  1426                     code.markStatBegin();
  1428                     // Save return address.
  1429                     LocalItem retVar = makeTemp(syms.throwableType);
  1430                     retVar.store();
  1432                     // Generate finalizer code.
  1433                     env.info.finalize.genLast();
  1435                     // Return.
  1436                     code.emitop1w(ret, retVar.reg);
  1437                     code.markDead();
  1441             // Resolve all breaks.
  1442             code.resolve(exitChain);
  1444             code.endScopes(limit);
  1447         /** Generate code for a catch clause.
  1448          *  @param tree     The catch clause.
  1449          *  @param env      The environment current in the enclosing try.
  1450          *  @param startpc  Start pc of try-block.
  1451          *  @param endpc    End pc of try-block.
  1452          */
  1453         void genCatch(JCCatch tree,
  1454                       Env<GenContext> env,
  1455                       int startpc, int endpc,
  1456                       List<Integer> gaps) {
  1457             if (startpc != endpc) {
  1458                 List<JCExpression> subClauses = TreeInfo.isMultiCatch(tree) ?
  1459                         ((JCTypeDisjunction)tree.param.vartype).alternatives :
  1460                         List.of(tree.param.vartype);
  1461                 while (gaps.nonEmpty()) {
  1462                     for (JCExpression subCatch : subClauses) {
  1463                         int catchType = makeRef(tree.pos(), subCatch.type);
  1464                         int end = gaps.head.intValue();
  1465                         registerCatch(tree.pos(),
  1466                                       startpc,  end, code.curPc(),
  1467                                       catchType);
  1469                     gaps = gaps.tail;
  1470                     startpc = gaps.head.intValue();
  1471                     gaps = gaps.tail;
  1473                 if (startpc < endpc) {
  1474                     for (JCExpression subCatch : subClauses) {
  1475                         int catchType = makeRef(tree.pos(), subCatch.type);
  1476                         registerCatch(tree.pos(),
  1477                                       startpc, endpc, code.curPc(),
  1478                                       catchType);
  1481                 VarSymbol exparam = tree.param.sym;
  1482                 code.statBegin(tree.pos);
  1483                 code.markStatBegin();
  1484                 int limit = code.nextreg;
  1485                 int exlocal = code.newLocal(exparam);
  1486                 items.makeLocalItem(exparam).store();
  1487                 code.statBegin(TreeInfo.firstStatPos(tree.body));
  1488                 genStat(tree.body, env, CRT_BLOCK);
  1489                 code.endScopes(limit);
  1490                 code.statBegin(TreeInfo.endPos(tree.body));
  1494         /** Register a catch clause in the "Exceptions" code-attribute.
  1495          */
  1496         void registerCatch(DiagnosticPosition pos,
  1497                            int startpc, int endpc,
  1498                            int handler_pc, int catch_type) {
  1499             if (startpc != endpc) {
  1500                 char startpc1 = (char)startpc;
  1501                 char endpc1 = (char)endpc;
  1502                 char handler_pc1 = (char)handler_pc;
  1503                 if (startpc1 == startpc &&
  1504                     endpc1 == endpc &&
  1505                     handler_pc1 == handler_pc) {
  1506                     code.addCatch(startpc1, endpc1, handler_pc1,
  1507                                   (char)catch_type);
  1508                 } else {
  1509                     if (!useJsrLocally && !target.generateStackMapTable()) {
  1510                         useJsrLocally = true;
  1511                         throw new CodeSizeOverflow();
  1512                     } else {
  1513                         log.error(pos, "limit.code.too.large.for.try.stmt");
  1514                         nerrs++;
  1520     /** Very roughly estimate the number of instructions needed for
  1521      *  the given tree.
  1522      */
  1523     int estimateCodeComplexity(JCTree tree) {
  1524         if (tree == null) return 0;
  1525         class ComplexityScanner extends TreeScanner {
  1526             int complexity = 0;
  1527             public void scan(JCTree tree) {
  1528                 if (complexity > jsrlimit) return;
  1529                 super.scan(tree);
  1531             public void visitClassDef(JCClassDecl tree) {}
  1532             public void visitDoLoop(JCDoWhileLoop tree)
  1533                 { super.visitDoLoop(tree); complexity++; }
  1534             public void visitWhileLoop(JCWhileLoop tree)
  1535                 { super.visitWhileLoop(tree); complexity++; }
  1536             public void visitForLoop(JCForLoop tree)
  1537                 { super.visitForLoop(tree); complexity++; }
  1538             public void visitSwitch(JCSwitch tree)
  1539                 { super.visitSwitch(tree); complexity+=5; }
  1540             public void visitCase(JCCase tree)
  1541                 { super.visitCase(tree); complexity++; }
  1542             public void visitSynchronized(JCSynchronized tree)
  1543                 { super.visitSynchronized(tree); complexity+=6; }
  1544             public void visitTry(JCTry tree)
  1545                 { super.visitTry(tree);
  1546                   if (tree.finalizer != null) complexity+=6; }
  1547             public void visitCatch(JCCatch tree)
  1548                 { super.visitCatch(tree); complexity+=2; }
  1549             public void visitConditional(JCConditional tree)
  1550                 { super.visitConditional(tree); complexity+=2; }
  1551             public void visitIf(JCIf tree)
  1552                 { super.visitIf(tree); complexity+=2; }
  1553             // note: for break, continue, and return we don't take unwind() into account.
  1554             public void visitBreak(JCBreak tree)
  1555                 { super.visitBreak(tree); complexity+=1; }
  1556             public void visitContinue(JCContinue tree)
  1557                 { super.visitContinue(tree); complexity+=1; }
  1558             public void visitReturn(JCReturn tree)
  1559                 { super.visitReturn(tree); complexity+=1; }
  1560             public void visitThrow(JCThrow tree)
  1561                 { super.visitThrow(tree); complexity+=1; }
  1562             public void visitAssert(JCAssert tree)
  1563                 { super.visitAssert(tree); complexity+=5; }
  1564             public void visitApply(JCMethodInvocation tree)
  1565                 { super.visitApply(tree); complexity+=2; }
  1566             public void visitNewClass(JCNewClass tree)
  1567                 { scan(tree.encl); scan(tree.args); complexity+=2; }
  1568             public void visitNewArray(JCNewArray tree)
  1569                 { super.visitNewArray(tree); complexity+=5; }
  1570             public void visitAssign(JCAssign tree)
  1571                 { super.visitAssign(tree); complexity+=1; }
  1572             public void visitAssignop(JCAssignOp tree)
  1573                 { super.visitAssignop(tree); complexity+=2; }
  1574             public void visitUnary(JCUnary tree)
  1575                 { complexity+=1;
  1576                   if (tree.type.constValue() == null) super.visitUnary(tree); }
  1577             public void visitBinary(JCBinary tree)
  1578                 { complexity+=1;
  1579                   if (tree.type.constValue() == null) super.visitBinary(tree); }
  1580             public void visitTypeTest(JCInstanceOf tree)
  1581                 { super.visitTypeTest(tree); complexity+=1; }
  1582             public void visitIndexed(JCArrayAccess tree)
  1583                 { super.visitIndexed(tree); complexity+=1; }
  1584             public void visitSelect(JCFieldAccess tree)
  1585                 { super.visitSelect(tree);
  1586                   if (tree.sym.kind == VAR) complexity+=1; }
  1587             public void visitIdent(JCIdent tree) {
  1588                 if (tree.sym.kind == VAR) {
  1589                     complexity+=1;
  1590                     if (tree.type.constValue() == null &&
  1591                         tree.sym.owner.kind == TYP)
  1592                         complexity+=1;
  1595             public void visitLiteral(JCLiteral tree)
  1596                 { complexity+=1; }
  1597             public void visitTree(JCTree tree) {}
  1598             public void visitWildcard(JCWildcard tree) {
  1599                 throw new AssertionError(this.getClass().getName());
  1602         ComplexityScanner scanner = new ComplexityScanner();
  1603         tree.accept(scanner);
  1604         return scanner.complexity;
  1607     public void visitIf(JCIf tree) {
  1608         int limit = code.nextreg;
  1609         Chain thenExit = null;
  1610         CondItem c = genCond(TreeInfo.skipParens(tree.cond),
  1611                              CRT_FLOW_CONTROLLER);
  1612         Chain elseChain = c.jumpFalse();
  1613         if (!c.isFalse()) {
  1614             code.resolve(c.trueJumps);
  1615             genStat(tree.thenpart, env, CRT_STATEMENT | CRT_FLOW_TARGET);
  1616             thenExit = code.branch(goto_);
  1618         if (elseChain != null) {
  1619             code.resolve(elseChain);
  1620             if (tree.elsepart != null)
  1621                 genStat(tree.elsepart, env,CRT_STATEMENT | CRT_FLOW_TARGET);
  1623         code.resolve(thenExit);
  1624         code.endScopes(limit);
  1627     public void visitExec(JCExpressionStatement tree) {
  1628         // Optimize x++ to ++x and x-- to --x.
  1629         JCExpression e = tree.expr;
  1630         switch (e.getTag()) {
  1631             case JCTree.POSTINC:
  1632                 ((JCUnary) e).setTag(JCTree.PREINC);
  1633                 break;
  1634             case JCTree.POSTDEC:
  1635                 ((JCUnary) e).setTag(JCTree.PREDEC);
  1636                 break;
  1638         genExpr(tree.expr, tree.expr.type).drop();
  1641     public void visitBreak(JCBreak tree) {
  1642         Env<GenContext> targetEnv = unwind(tree.target, env);
  1643         assert code.state.stacksize == 0;
  1644         targetEnv.info.addExit(code.branch(goto_));
  1645         endFinalizerGaps(env, targetEnv);
  1648     public void visitContinue(JCContinue tree) {
  1649         Env<GenContext> targetEnv = unwind(tree.target, env);
  1650         assert code.state.stacksize == 0;
  1651         targetEnv.info.addCont(code.branch(goto_));
  1652         endFinalizerGaps(env, targetEnv);
  1655     public void visitReturn(JCReturn tree) {
  1656         int limit = code.nextreg;
  1657         final Env<GenContext> targetEnv;
  1658         if (tree.expr != null) {
  1659             Item r = genExpr(tree.expr, pt).load();
  1660             if (hasFinally(env.enclMethod, env)) {
  1661                 r = makeTemp(pt);
  1662                 r.store();
  1664             targetEnv = unwind(env.enclMethod, env);
  1665             r.load();
  1666             code.emitop0(ireturn + Code.truncate(Code.typecode(pt)));
  1667         } else {
  1668             targetEnv = unwind(env.enclMethod, env);
  1669             code.emitop0(return_);
  1671         endFinalizerGaps(env, targetEnv);
  1672         code.endScopes(limit);
  1675     public void visitThrow(JCThrow tree) {
  1676         genExpr(tree.expr, tree.expr.type).load();
  1677         code.emitop0(athrow);
  1680 /* ************************************************************************
  1681  * Visitor methods for expressions
  1682  *************************************************************************/
  1684     public void visitApply(JCMethodInvocation tree) {
  1685         setTypeAnnotationPositions(tree.pos);
  1686         // Generate code for method.
  1687         Item m = genExpr(tree.meth, methodType);
  1688         // Generate code for all arguments, where the expected types are
  1689         // the parameters of the method's external type (that is, any implicit
  1690         // outer instance of a super(...) call appears as first parameter).
  1691         genArgs(tree.args,
  1692                 TreeInfo.symbol(tree.meth).externalType(types).getParameterTypes());
  1693         result = m.invoke();
  1696     public void visitConditional(JCConditional tree) {
  1697         Chain thenExit = null;
  1698         CondItem c = genCond(tree.cond, CRT_FLOW_CONTROLLER);
  1699         Chain elseChain = c.jumpFalse();
  1700         if (!c.isFalse()) {
  1701             code.resolve(c.trueJumps);
  1702             int startpc = genCrt ? code.curPc() : 0;
  1703             genExpr(tree.truepart, pt).load();
  1704             code.state.forceStackTop(tree.type);
  1705             if (genCrt) code.crt.put(tree.truepart, CRT_FLOW_TARGET,
  1706                                      startpc, code.curPc());
  1707             thenExit = code.branch(goto_);
  1709         if (elseChain != null) {
  1710             code.resolve(elseChain);
  1711             int startpc = genCrt ? code.curPc() : 0;
  1712             genExpr(tree.falsepart, pt).load();
  1713             code.state.forceStackTop(tree.type);
  1714             if (genCrt) code.crt.put(tree.falsepart, CRT_FLOW_TARGET,
  1715                                      startpc, code.curPc());
  1717         code.resolve(thenExit);
  1718         result = items.makeStackItem(pt);
  1721     private void setTypeAnnotationPositions(int treePos) {
  1722         MethodSymbol meth = code.meth;
  1724         for (Attribute.TypeCompound ta : meth.typeAnnotations) {
  1725             if (ta.position.pos == treePos) {
  1726                 ta.position.offset = code.cp;
  1727                 ta.position.lvarOffset = new int[] { code.cp };
  1728                 ta.position.isValidOffset = true;
  1732         if (code.meth.getKind() != ElementKind.CONSTRUCTOR
  1733                 && code.meth.getKind() != ElementKind.STATIC_INIT)
  1734             return;
  1736         for (Attribute.TypeCompound ta : meth.owner.typeAnnotations) {
  1737             if (ta.position.pos == treePos) {
  1738                 ta.position.offset = code.cp;
  1739                 ta.position.lvarOffset = new int[] { code.cp };
  1740                 ta.position.isValidOffset = true;
  1744         ClassSymbol clazz = meth.enclClass();
  1745         for (Symbol s : new com.sun.tools.javac.model.FilteredMemberList(clazz.members())) {
  1746             if (!s.getKind().isField())
  1747                 continue;
  1748             for (Attribute.TypeCompound ta : s.typeAnnotations) {
  1749                 if (ta.position.pos == treePos) {
  1750                     ta.position.offset = code.cp;
  1751                     ta.position.lvarOffset = new int[] { code.cp };
  1752                     ta.position.isValidOffset = true;
  1758     public void visitNewClass(JCNewClass tree) {
  1759         // Enclosing instances or anonymous classes should have been eliminated
  1760         // by now.
  1761         assert tree.encl == null && tree.def == null;
  1762         setTypeAnnotationPositions(tree.pos);
  1764         code.emitop2(new_, makeRef(tree.pos(), tree.type));
  1765         code.emitop0(dup);
  1767         // Generate code for all arguments, where the expected types are
  1768         // the parameters of the constructor's external type (that is,
  1769         // any implicit outer instance appears as first parameter).
  1770         genArgs(tree.args, tree.constructor.externalType(types).getParameterTypes());
  1772         items.makeMemberItem(tree.constructor, true).invoke();
  1773         result = items.makeStackItem(tree.type);
  1776     public void visitNewArray(JCNewArray tree) {
  1777         setTypeAnnotationPositions(tree.pos);
  1779         if (tree.elems != null) {
  1780             Type elemtype = types.elemtype(tree.type);
  1781             loadIntConst(tree.elems.length());
  1782             Item arr = makeNewArray(tree.pos(), tree.type, 1);
  1783             int i = 0;
  1784             for (List<JCExpression> l = tree.elems; l.nonEmpty(); l = l.tail) {
  1785                 arr.duplicate();
  1786                 loadIntConst(i);
  1787                 i++;
  1788                 genExpr(l.head, elemtype).load();
  1789                 items.makeIndexedItem(elemtype).store();
  1791             result = arr;
  1792         } else {
  1793             for (List<JCExpression> l = tree.dims; l.nonEmpty(); l = l.tail) {
  1794                 genExpr(l.head, syms.intType).load();
  1796             result = makeNewArray(tree.pos(), tree.type, tree.dims.length());
  1799 //where
  1800         /** Generate code to create an array with given element type and number
  1801          *  of dimensions.
  1802          */
  1803         Item makeNewArray(DiagnosticPosition pos, Type type, int ndims) {
  1804             Type elemtype = types.elemtype(type);
  1805             if (types.dimensions(type) > ClassFile.MAX_DIMENSIONS) {
  1806                 log.error(pos, "limit.dimensions");
  1807                 nerrs++;
  1809             int elemcode = Code.arraycode(elemtype);
  1810             if (elemcode == 0 || (elemcode == 1 && ndims == 1)) {
  1811                 code.emitAnewarray(makeRef(pos, elemtype), type);
  1812             } else if (elemcode == 1) {
  1813                 code.emitMultianewarray(ndims, makeRef(pos, type), type);
  1814             } else {
  1815                 code.emitNewarray(elemcode, type);
  1817             return items.makeStackItem(type);
  1820     public void visitParens(JCParens tree) {
  1821         result = genExpr(tree.expr, tree.expr.type);
  1824     public void visitAssign(JCAssign tree) {
  1825         Item l = genExpr(tree.lhs, tree.lhs.type);
  1826         genExpr(tree.rhs, tree.lhs.type).load();
  1827         result = items.makeAssignItem(l);
  1830     public void visitAssignop(JCAssignOp tree) {
  1831         OperatorSymbol operator = (OperatorSymbol) tree.operator;
  1832         Item l;
  1833         if (operator.opcode == string_add) {
  1834             // Generate code to make a string buffer
  1835             makeStringBuffer(tree.pos());
  1837             // Generate code for first string, possibly save one
  1838             // copy under buffer
  1839             l = genExpr(tree.lhs, tree.lhs.type);
  1840             if (l.width() > 0) {
  1841                 code.emitop0(dup_x1 + 3 * (l.width() - 1));
  1844             // Load first string and append to buffer.
  1845             l.load();
  1846             appendString(tree.lhs);
  1848             // Append all other strings to buffer.
  1849             appendStrings(tree.rhs);
  1851             // Convert buffer to string.
  1852             bufferToString(tree.pos());
  1853         } else {
  1854             // Generate code for first expression
  1855             l = genExpr(tree.lhs, tree.lhs.type);
  1857             // If we have an increment of -32768 to +32767 of a local
  1858             // int variable we can use an incr instruction instead of
  1859             // proceeding further.
  1860             if ((tree.getTag() == JCTree.PLUS_ASG || tree.getTag() == JCTree.MINUS_ASG) &&
  1861                 l instanceof LocalItem &&
  1862                 tree.lhs.type.tag <= INT &&
  1863                 tree.rhs.type.tag <= INT &&
  1864                 tree.rhs.type.constValue() != null) {
  1865                 int ival = ((Number) tree.rhs.type.constValue()).intValue();
  1866                 if (tree.getTag() == JCTree.MINUS_ASG) ival = -ival;
  1867                 ((LocalItem)l).incr(ival);
  1868                 result = l;
  1869                 return;
  1871             // Otherwise, duplicate expression, load one copy
  1872             // and complete binary operation.
  1873             l.duplicate();
  1874             l.coerce(operator.type.getParameterTypes().head).load();
  1875             completeBinop(tree.lhs, tree.rhs, operator).coerce(tree.lhs.type);
  1877         result = items.makeAssignItem(l);
  1880     public void visitUnary(JCUnary tree) {
  1881         OperatorSymbol operator = (OperatorSymbol)tree.operator;
  1882         if (tree.getTag() == JCTree.NOT) {
  1883             CondItem od = genCond(tree.arg, false);
  1884             result = od.negate();
  1885         } else {
  1886             Item od = genExpr(tree.arg, operator.type.getParameterTypes().head);
  1887             switch (tree.getTag()) {
  1888             case JCTree.POS:
  1889                 result = od.load();
  1890                 break;
  1891             case JCTree.NEG:
  1892                 result = od.load();
  1893                 code.emitop0(operator.opcode);
  1894                 break;
  1895             case JCTree.COMPL:
  1896                 result = od.load();
  1897                 emitMinusOne(od.typecode);
  1898                 code.emitop0(operator.opcode);
  1899                 break;
  1900             case JCTree.PREINC: case JCTree.PREDEC:
  1901                 od.duplicate();
  1902                 if (od instanceof LocalItem &&
  1903                     (operator.opcode == iadd || operator.opcode == isub)) {
  1904                     ((LocalItem)od).incr(tree.getTag() == JCTree.PREINC ? 1 : -1);
  1905                     result = od;
  1906                 } else {
  1907                     od.load();
  1908                     code.emitop0(one(od.typecode));
  1909                     code.emitop0(operator.opcode);
  1910                     // Perform narrowing primitive conversion if byte,
  1911                     // char, or short.  Fix for 4304655.
  1912                     if (od.typecode != INTcode &&
  1913                         Code.truncate(od.typecode) == INTcode)
  1914                       code.emitop0(int2byte + od.typecode - BYTEcode);
  1915                     result = items.makeAssignItem(od);
  1917                 break;
  1918             case JCTree.POSTINC: case JCTree.POSTDEC:
  1919                 od.duplicate();
  1920                 if (od instanceof LocalItem &&
  1921                     (operator.opcode == iadd || operator.opcode == isub)) {
  1922                     Item res = od.load();
  1923                     ((LocalItem)od).incr(tree.getTag() == JCTree.POSTINC ? 1 : -1);
  1924                     result = res;
  1925                 } else {
  1926                     Item res = od.load();
  1927                     od.stash(od.typecode);
  1928                     code.emitop0(one(od.typecode));
  1929                     code.emitop0(operator.opcode);
  1930                     // Perform narrowing primitive conversion if byte,
  1931                     // char, or short.  Fix for 4304655.
  1932                     if (od.typecode != INTcode &&
  1933                         Code.truncate(od.typecode) == INTcode)
  1934                       code.emitop0(int2byte + od.typecode - BYTEcode);
  1935                     od.store();
  1936                     result = res;
  1938                 break;
  1939             case JCTree.NULLCHK:
  1940                 result = od.load();
  1941                 code.emitop0(dup);
  1942                 genNullCheck(tree.pos());
  1943                 break;
  1944             default:
  1945                 assert false;
  1950     /** Generate a null check from the object value at stack top. */
  1951     private void genNullCheck(DiagnosticPosition pos) {
  1952         callMethod(pos, syms.objectType, names.getClass,
  1953                    List.<Type>nil(), false);
  1954         code.emitop0(pop);
  1957     public void visitBinary(JCBinary tree) {
  1958         OperatorSymbol operator = (OperatorSymbol)tree.operator;
  1959         if (operator.opcode == string_add) {
  1960             // Create a string buffer.
  1961             makeStringBuffer(tree.pos());
  1962             // Append all strings to buffer.
  1963             appendStrings(tree);
  1964             // Convert buffer to string.
  1965             bufferToString(tree.pos());
  1966             result = items.makeStackItem(syms.stringType);
  1967         } else if (tree.getTag() == JCTree.AND) {
  1968             CondItem lcond = genCond(tree.lhs, CRT_FLOW_CONTROLLER);
  1969             if (!lcond.isFalse()) {
  1970                 Chain falseJumps = lcond.jumpFalse();
  1971                 code.resolve(lcond.trueJumps);
  1972                 CondItem rcond = genCond(tree.rhs, CRT_FLOW_TARGET);
  1973                 result = items.
  1974                     makeCondItem(rcond.opcode,
  1975                                  rcond.trueJumps,
  1976                                  Code.mergeChains(falseJumps,
  1977                                                   rcond.falseJumps));
  1978             } else {
  1979                 result = lcond;
  1981         } else if (tree.getTag() == JCTree.OR) {
  1982             CondItem lcond = genCond(tree.lhs, CRT_FLOW_CONTROLLER);
  1983             if (!lcond.isTrue()) {
  1984                 Chain trueJumps = lcond.jumpTrue();
  1985                 code.resolve(lcond.falseJumps);
  1986                 CondItem rcond = genCond(tree.rhs, CRT_FLOW_TARGET);
  1987                 result = items.
  1988                     makeCondItem(rcond.opcode,
  1989                                  Code.mergeChains(trueJumps, rcond.trueJumps),
  1990                                  rcond.falseJumps);
  1991             } else {
  1992                 result = lcond;
  1994         } else {
  1995             Item od = genExpr(tree.lhs, operator.type.getParameterTypes().head);
  1996             od.load();
  1997             result = completeBinop(tree.lhs, tree.rhs, operator);
  2000 //where
  2001         /** Make a new string buffer.
  2002          */
  2003         void makeStringBuffer(DiagnosticPosition pos) {
  2004             code.emitop2(new_, makeRef(pos, stringBufferType));
  2005             code.emitop0(dup);
  2006             callMethod(
  2007                 pos, stringBufferType, names.init, List.<Type>nil(), false);
  2010         /** Append value (on tos) to string buffer (on tos - 1).
  2011          */
  2012         void appendString(JCTree tree) {
  2013             Type t = tree.type.baseType();
  2014             if (t.tag > lastBaseTag && t.tsym != syms.stringType.tsym) {
  2015                 t = syms.objectType;
  2017             items.makeMemberItem(getStringBufferAppend(tree, t), false).invoke();
  2019         Symbol getStringBufferAppend(JCTree tree, Type t) {
  2020             assert t.constValue() == null;
  2021             Symbol method = stringBufferAppend.get(t);
  2022             if (method == null) {
  2023                 method = rs.resolveInternalMethod(tree.pos(),
  2024                                                   attrEnv,
  2025                                                   stringBufferType,
  2026                                                   names.append,
  2027                                                   List.of(t),
  2028                                                   null);
  2029                 stringBufferAppend.put(t, method);
  2031             return method;
  2034         /** Add all strings in tree to string buffer.
  2035          */
  2036         void appendStrings(JCTree tree) {
  2037             tree = TreeInfo.skipParens(tree);
  2038             if (tree.getTag() == JCTree.PLUS && tree.type.constValue() == null) {
  2039                 JCBinary op = (JCBinary) tree;
  2040                 if (op.operator.kind == MTH &&
  2041                     ((OperatorSymbol) op.operator).opcode == string_add) {
  2042                     appendStrings(op.lhs);
  2043                     appendStrings(op.rhs);
  2044                     return;
  2047             genExpr(tree, tree.type).load();
  2048             appendString(tree);
  2051         /** Convert string buffer on tos to string.
  2052          */
  2053         void bufferToString(DiagnosticPosition pos) {
  2054             callMethod(
  2055                 pos,
  2056                 stringBufferType,
  2057                 names.toString,
  2058                 List.<Type>nil(),
  2059                 false);
  2062         /** Complete generating code for operation, with left operand
  2063          *  already on stack.
  2064          *  @param lhs       The tree representing the left operand.
  2065          *  @param rhs       The tree representing the right operand.
  2066          *  @param operator  The operator symbol.
  2067          */
  2068         Item completeBinop(JCTree lhs, JCTree rhs, OperatorSymbol operator) {
  2069             MethodType optype = (MethodType)operator.type;
  2070             int opcode = operator.opcode;
  2071             if (opcode >= if_icmpeq && opcode <= if_icmple &&
  2072                 rhs.type.constValue() instanceof Number &&
  2073                 ((Number) rhs.type.constValue()).intValue() == 0) {
  2074                 opcode = opcode + (ifeq - if_icmpeq);
  2075             } else if (opcode >= if_acmpeq && opcode <= if_acmpne &&
  2076                        TreeInfo.isNull(rhs)) {
  2077                 opcode = opcode + (if_acmp_null - if_acmpeq);
  2078             } else {
  2079                 // The expected type of the right operand is
  2080                 // the second parameter type of the operator, except for
  2081                 // shifts with long shiftcount, where we convert the opcode
  2082                 // to a short shift and the expected type to int.
  2083                 Type rtype = operator.erasure(types).getParameterTypes().tail.head;
  2084                 if (opcode >= ishll && opcode <= lushrl) {
  2085                     opcode = opcode + (ishl - ishll);
  2086                     rtype = syms.intType;
  2088                 // Generate code for right operand and load.
  2089                 genExpr(rhs, rtype).load();
  2090                 // If there are two consecutive opcode instructions,
  2091                 // emit the first now.
  2092                 if (opcode >= (1 << preShift)) {
  2093                     code.emitop0(opcode >> preShift);
  2094                     opcode = opcode & 0xFF;
  2097             if (opcode >= ifeq && opcode <= if_acmpne ||
  2098                 opcode == if_acmp_null || opcode == if_acmp_nonnull) {
  2099                 return items.makeCondItem(opcode);
  2100             } else {
  2101                 code.emitop0(opcode);
  2102                 return items.makeStackItem(optype.restype);
  2106     public void visitTypeCast(JCTypeCast tree) {
  2107         setTypeAnnotationPositions(tree.pos);
  2108         result = genExpr(tree.expr, tree.clazz.type).load();
  2109         // Additional code is only needed if we cast to a reference type
  2110         // which is not statically a supertype of the expression's type.
  2111         // For basic types, the coerce(...) in genExpr(...) will do
  2112         // the conversion.
  2113         if (tree.clazz.type.tag > lastBaseTag &&
  2114             types.asSuper(tree.expr.type, tree.clazz.type.tsym) == null) {
  2115             code.emitop2(checkcast, makeRef(tree.pos(), tree.clazz.type));
  2119     public void visitWildcard(JCWildcard tree) {
  2120         throw new AssertionError(this.getClass().getName());
  2123     public void visitTypeTest(JCInstanceOf tree) {
  2124         setTypeAnnotationPositions(tree.pos);
  2126         genExpr(tree.expr, tree.expr.type).load();
  2127         code.emitop2(instanceof_, makeRef(tree.pos(), tree.clazz.type));
  2128         result = items.makeStackItem(syms.booleanType);
  2131     public void visitIndexed(JCArrayAccess tree) {
  2132         genExpr(tree.indexed, tree.indexed.type).load();
  2133         genExpr(tree.index, syms.intType).load();
  2134         result = items.makeIndexedItem(tree.type);
  2137     public void visitIdent(JCIdent tree) {
  2138         Symbol sym = tree.sym;
  2139         if (tree.name == names._this || tree.name == names._super) {
  2140             Item res = tree.name == names._this
  2141                 ? items.makeThisItem()
  2142                 : items.makeSuperItem();
  2143             if (sym.kind == MTH) {
  2144                 // Generate code to address the constructor.
  2145                 res.load();
  2146                 res = items.makeMemberItem(sym, true);
  2148             result = res;
  2149         } else if (sym.kind == VAR && sym.owner.kind == MTH) {
  2150             result = items.makeLocalItem((VarSymbol)sym);
  2151         } else if ((sym.flags() & STATIC) != 0) {
  2152             if (!isAccessSuper(env.enclMethod))
  2153                 sym = binaryQualifier(sym, env.enclClass.type);
  2154             result = items.makeStaticItem(sym);
  2155         } else {
  2156             items.makeThisItem().load();
  2157             sym = binaryQualifier(sym, env.enclClass.type);
  2158             result = items.makeMemberItem(sym, (sym.flags() & PRIVATE) != 0);
  2162     public void visitSelect(JCFieldAccess tree) {
  2163         Symbol sym = tree.sym;
  2165         if (tree.name == names._class) {
  2166             assert target.hasClassLiterals();
  2167             setTypeAnnotationPositions(tree.pos);
  2168             code.emitop2(ldc2, makeRef(tree.pos(), tree.selected.type));
  2169             result = items.makeStackItem(pt);
  2170             return;
  2171         } else if (tree.name == names.TYPE) {
  2172             // Set the annotation positions for primitive class literals
  2173             // (e.g. int.class) which have been converted to TYPE field
  2174             // access on the corresponding boxed type (e.g. Integer.TYPE).
  2175             setTypeAnnotationPositions(tree.pos);
  2178         Symbol ssym = TreeInfo.symbol(tree.selected);
  2180         // Are we selecting via super?
  2181         boolean selectSuper =
  2182             ssym != null && (ssym.kind == TYP || ssym.name == names._super);
  2184         // Are we accessing a member of the superclass in an access method
  2185         // resulting from a qualified super?
  2186         boolean accessSuper = isAccessSuper(env.enclMethod);
  2188         Item base = (selectSuper)
  2189             ? items.makeSuperItem()
  2190             : genExpr(tree.selected, tree.selected.type);
  2192         if (sym.kind == VAR && ((VarSymbol) sym).getConstValue() != null) {
  2193             // We are seeing a variable that is constant but its selecting
  2194             // expression is not.
  2195             if ((sym.flags() & STATIC) != 0) {
  2196                 if (!selectSuper && (ssym == null || ssym.kind != TYP))
  2197                     base = base.load();
  2198                 base.drop();
  2199             } else {
  2200                 base.load();
  2201                 genNullCheck(tree.selected.pos());
  2203             result = items.
  2204                 makeImmediateItem(sym.type, ((VarSymbol) sym).getConstValue());
  2205         } else if (allowInvokedynamic && sym.kind == MTH && ssym == syms.invokeDynamicType.tsym) {
  2206             base.drop();
  2207             result = items.makeDynamicItem(sym);
  2208         } else {
  2209             if (!accessSuper)
  2210                 sym = binaryQualifier(sym, tree.selected.type);
  2211             if ((sym.flags() & STATIC) != 0) {
  2212                 if (!selectSuper && (ssym == null || ssym.kind != TYP))
  2213                     base = base.load();
  2214                 base.drop();
  2215                 result = items.makeStaticItem(sym);
  2216             } else {
  2217                 base.load();
  2218                 if (sym == syms.lengthVar) {
  2219                     code.emitop0(arraylength);
  2220                     result = items.makeStackItem(syms.intType);
  2221                 } else {
  2222                     result = items.
  2223                         makeMemberItem(sym,
  2224                                        (sym.flags() & PRIVATE) != 0 ||
  2225                                        selectSuper || accessSuper);
  2231     public void visitLiteral(JCLiteral tree) {
  2232         if (tree.type.tag == TypeTags.BOT) {
  2233             code.emitop0(aconst_null);
  2234             if (types.dimensions(pt) > 1) {
  2235                 code.emitop2(checkcast, makeRef(tree.pos(), pt));
  2236                 result = items.makeStackItem(pt);
  2237             } else {
  2238                 result = items.makeStackItem(tree.type);
  2241         else
  2242             result = items.makeImmediateItem(tree.type, tree.value);
  2245     public void visitLetExpr(LetExpr tree) {
  2246         int limit = code.nextreg;
  2247         genStats(tree.defs, env);
  2248         result = genExpr(tree.expr, tree.expr.type).load();
  2249         code.endScopes(limit);
  2252 /* ************************************************************************
  2253  * main method
  2254  *************************************************************************/
  2256     /** Generate code for a class definition.
  2257      *  @param env   The attribution environment that belongs to the
  2258      *               outermost class containing this class definition.
  2259      *               We need this for resolving some additional symbols.
  2260      *  @param cdef  The tree representing the class definition.
  2261      *  @return      True if code is generated with no errors.
  2262      */
  2263     public boolean genClass(Env<AttrContext> env, JCClassDecl cdef) {
  2264         try {
  2265             attrEnv = env;
  2266             ClassSymbol c = cdef.sym;
  2267             this.toplevel = env.toplevel;
  2268             this.endPositions = toplevel.endPositions;
  2269             // If this is a class definition requiring Miranda methods,
  2270             // add them.
  2271             if (generateIproxies &&
  2272                 (c.flags() & (INTERFACE|ABSTRACT)) == ABSTRACT
  2273                 && !allowGenerics // no Miranda methods available with generics
  2275                 implementInterfaceMethods(c);
  2276             cdef.defs = normalizeDefs(cdef.defs, c);
  2277             c.pool = pool;
  2278             pool.reset();
  2279             Env<GenContext> localEnv =
  2280                 new Env<GenContext>(cdef, new GenContext());
  2281             localEnv.toplevel = env.toplevel;
  2282             localEnv.enclClass = cdef;
  2283             for (List<JCTree> l = cdef.defs; l.nonEmpty(); l = l.tail) {
  2284                 genDef(l.head, localEnv);
  2286             if (pool.numEntries() > Pool.MAX_ENTRIES) {
  2287                 log.error(cdef.pos(), "limit.pool");
  2288                 nerrs++;
  2290             if (nerrs != 0) {
  2291                 // if errors, discard code
  2292                 for (List<JCTree> l = cdef.defs; l.nonEmpty(); l = l.tail) {
  2293                     if (l.head.getTag() == JCTree.METHODDEF)
  2294                         ((JCMethodDecl) l.head).sym.code = null;
  2297             cdef.defs = List.nil(); // discard trees
  2298             return nerrs == 0;
  2299         } finally {
  2300             // note: this method does NOT support recursion.
  2301             attrEnv = null;
  2302             this.env = null;
  2303             toplevel = null;
  2304             endPositions = null;
  2305             nerrs = 0;
  2309 /* ************************************************************************
  2310  * Auxiliary classes
  2311  *************************************************************************/
  2313     /** An abstract class for finalizer generation.
  2314      */
  2315     abstract class GenFinalizer {
  2316         /** Generate code to clean up when unwinding. */
  2317         abstract void gen();
  2319         /** Generate code to clean up at last. */
  2320         abstract void genLast();
  2322         /** Does this finalizer have some nontrivial cleanup to perform? */
  2323         boolean hasFinalizer() { return true; }
  2326     /** code generation contexts,
  2327      *  to be used as type parameter for environments.
  2328      */
  2329     static class GenContext {
  2331         /** A chain for all unresolved jumps that exit the current environment.
  2332          */
  2333         Chain exit = null;
  2335         /** A chain for all unresolved jumps that continue in the
  2336          *  current environment.
  2337          */
  2338         Chain cont = null;
  2340         /** A closure that generates the finalizer of the current environment.
  2341          *  Only set for Synchronized and Try contexts.
  2342          */
  2343         GenFinalizer finalize = null;
  2345         /** Is this a switch statement?  If so, allocate registers
  2346          * even when the variable declaration is unreachable.
  2347          */
  2348         boolean isSwitch = false;
  2350         /** A list buffer containing all gaps in the finalizer range,
  2351          *  where a catch all exception should not apply.
  2352          */
  2353         ListBuffer<Integer> gaps = null;
  2355         /** Add given chain to exit chain.
  2356          */
  2357         void addExit(Chain c)  {
  2358             exit = Code.mergeChains(c, exit);
  2361         /** Add given chain to cont chain.
  2362          */
  2363         void addCont(Chain c) {
  2364             cont = Code.mergeChains(c, cont);

mercurial