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