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