1 /*
2  * Copyright (c) 1999, 2019, 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.comp;
27 
28 import java.util.*;
29 import java.util.Map.Entry;
30 import java.util.function.Function;
31 import java.util.stream.Stream;
32 
33 import com.sun.source.tree.CaseTree.CaseKind;
34 import com.sun.tools.javac.code.*;
35 import com.sun.tools.javac.code.Kinds.KindSelector;
36 import com.sun.tools.javac.code.Scope.WriteableScope;
37 import com.sun.tools.javac.jvm.*;
38 import com.sun.tools.javac.main.Option.PkgInfo;
39 import com.sun.tools.javac.resources.CompilerProperties.Fragments;
40 import com.sun.tools.javac.tree.*;
41 import com.sun.tools.javac.util.*;
42 import com.sun.tools.javac.util.JCDiagnostic.DiagnosticPosition;
43 import com.sun.tools.javac.util.List;
44 
45 import com.sun.tools.javac.code.Symbol.*;
46 import com.sun.tools.javac.code.Symbol.OperatorSymbol.AccessCode;
47 import com.sun.tools.javac.resources.CompilerProperties.Errors;
48 import com.sun.tools.javac.tree.JCTree.*;
49 import com.sun.tools.javac.code.Type.*;
50 
51 import com.sun.tools.javac.jvm.Target;
52 import com.sun.tools.javac.tree.EndPosTable;
53 
54 import static com.sun.tools.javac.code.Flags.*;
55 import static com.sun.tools.javac.code.Flags.BLOCK;
56 import static com.sun.tools.javac.code.Scope.LookupKind.NON_RECURSIVE;
57 import static com.sun.tools.javac.code.TypeTag.*;
58 import static com.sun.tools.javac.code.Kinds.Kind.*;
59 import static com.sun.tools.javac.code.Symbol.OperatorSymbol.AccessCode.DEREF;
60 import static com.sun.tools.javac.jvm.ByteCodes.*;
61 import com.sun.tools.javac.tree.JCTree.JCBreak;
62 import com.sun.tools.javac.tree.JCTree.JCCase;
63 import com.sun.tools.javac.tree.JCTree.JCExpression;
64 import com.sun.tools.javac.tree.JCTree.JCExpressionStatement;
65 import static com.sun.tools.javac.tree.JCTree.JCOperatorExpression.OperandPos.LEFT;
66 import com.sun.tools.javac.tree.JCTree.JCSwitchExpression;
67 import static com.sun.tools.javac.tree.JCTree.Tag.*;
68 
69 /** This pass translates away some syntactic sugar: inner classes,
70  *  class literals, assertions, foreach loops, etc.
71  *
72  *  <p><b>This is NOT part of any supported API.
73  *  If you write code that depends on this, you do so at your own risk.
74  *  This code and its internal interfaces are subject to change or
75  *  deletion without notice.</b>
76  */
77 public class Lower extends TreeTranslator {
78     protected static final Context.Key<Lower> lowerKey = new Context.Key<>();
79 
instance(Context context)80     public static Lower instance(Context context) {
81         Lower instance = context.get(lowerKey);
82         if (instance == null)
83             instance = new Lower(context);
84         return instance;
85     }
86 
87     private final Names names;
88     private final Log log;
89     private final Symtab syms;
90     private final Resolve rs;
91     private final Operators operators;
92     private final Check chk;
93     private final Attr attr;
94     private TreeMaker make;
95     private DiagnosticPosition make_pos;
96     private final ConstFold cfolder;
97     private final Target target;
98     private final Source source;
99     private final TypeEnvs typeEnvs;
100     private final Name dollarAssertionsDisabled;
101     private final Name classDollar;
102     private final Name dollarCloseResource;
103     private final Types types;
104     private final boolean debugLower;
105     private final boolean disableProtectedAccessors; // experimental
106     private final PkgInfo pkginfoOpt;
107 
Lower(Context context)108     protected Lower(Context context) {
109         context.put(lowerKey, this);
110         names = Names.instance(context);
111         log = Log.instance(context);
112         syms = Symtab.instance(context);
113         rs = Resolve.instance(context);
114         operators = Operators.instance(context);
115         chk = Check.instance(context);
116         attr = Attr.instance(context);
117         make = TreeMaker.instance(context);
118         cfolder = ConstFold.instance(context);
119         target = Target.instance(context);
120         source = Source.instance(context);
121         typeEnvs = TypeEnvs.instance(context);
122         dollarAssertionsDisabled = names.
123             fromString(target.syntheticNameChar() + "assertionsDisabled");
124         classDollar = names.
125             fromString("class" + target.syntheticNameChar());
126         dollarCloseResource = names.
127             fromString(target.syntheticNameChar() + "closeResource");
128 
129         types = Types.instance(context);
130         Options options = Options.instance(context);
131         debugLower = options.isSet("debuglower");
132         pkginfoOpt = PkgInfo.get(options);
133         disableProtectedAccessors = options.isSet("disableProtectedAccessors");
134     }
135 
136     /** The currently enclosing class.
137      */
138     ClassSymbol currentClass;
139 
140     /** A queue of all translated classes.
141      */
142     ListBuffer<JCTree> translated;
143 
144     /** Environment for symbol lookup, set by translateTopLevelClass.
145      */
146     Env<AttrContext> attrEnv;
147 
148     /** A hash table mapping syntax trees to their ending source positions.
149      */
150     EndPosTable endPosTable;
151 
152 /**************************************************************************
153  * Global mappings
154  *************************************************************************/
155 
156     /** A hash table mapping local classes to their definitions.
157      */
158     Map<ClassSymbol, JCClassDecl> classdefs;
159 
160     /** A hash table mapping local classes to a list of pruned trees.
161      */
162     public Map<ClassSymbol, List<JCTree>> prunedTree = new WeakHashMap<>();
163 
164     /** A hash table mapping virtual accessed symbols in outer subclasses
165      *  to the actually referred symbol in superclasses.
166      */
167     Map<Symbol,Symbol> actualSymbols;
168 
169     /** The current method definition.
170      */
171     JCMethodDecl currentMethodDef;
172 
173     /** The current method symbol.
174      */
175     MethodSymbol currentMethodSym;
176 
177     /** The currently enclosing outermost class definition.
178      */
179     JCClassDecl outermostClassDef;
180 
181     /** The currently enclosing outermost member definition.
182      */
183     JCTree outermostMemberDef;
184 
185     /** A map from local variable symbols to their translation (as per LambdaToMethod).
186      * This is required when a capturing local class is created from a lambda (in which
187      * case the captured symbols should be replaced with the translated lambda symbols).
188      */
189     Map<Symbol, Symbol> lambdaTranslationMap = null;
190 
191     /** A navigator class for assembling a mapping from local class symbols
192      *  to class definition trees.
193      *  There is only one case; all other cases simply traverse down the tree.
194      */
195     class ClassMap extends TreeScanner {
196 
197         /** All encountered class defs are entered into classdefs table.
198          */
visitClassDef(JCClassDecl tree)199         public void visitClassDef(JCClassDecl tree) {
200             classdefs.put(tree.sym, tree);
201             super.visitClassDef(tree);
202         }
203     }
204     ClassMap classMap = new ClassMap();
205 
206     /** Map a class symbol to its definition.
207      *  @param c    The class symbol of which we want to determine the definition.
208      */
classDef(ClassSymbol c)209     JCClassDecl classDef(ClassSymbol c) {
210         // First lookup the class in the classdefs table.
211         JCClassDecl def = classdefs.get(c);
212         if (def == null && outermostMemberDef != null) {
213             // If this fails, traverse outermost member definition, entering all
214             // local classes into classdefs, and try again.
215             classMap.scan(outermostMemberDef);
216             def = classdefs.get(c);
217         }
218         if (def == null) {
219             // If this fails, traverse outermost class definition, entering all
220             // local classes into classdefs, and try again.
221             classMap.scan(outermostClassDef);
222             def = classdefs.get(c);
223         }
224         return def;
225     }
226 
227     /** A hash table mapping class symbols to lists of free variables.
228      *  accessed by them. Only free variables of the method immediately containing
229      *  a class are associated with that class.
230      */
231     Map<ClassSymbol,List<VarSymbol>> freevarCache;
232 
233     /** A navigator class for collecting the free variables accessed
234      *  from a local class. There is only one case; all other cases simply
235      *  traverse down the tree. This class doesn't deal with the specific
236      *  of Lower - it's an abstract visitor that is meant to be reused in
237      *  order to share the local variable capture logic.
238      */
239     abstract class BasicFreeVarCollector extends TreeScanner {
240 
241         /** Add all free variables of class c to fvs list
242          *  unless they are already there.
243          */
addFreeVars(ClassSymbol c)244         abstract void addFreeVars(ClassSymbol c);
245 
246         /** If tree refers to a variable in owner of local class, add it to
247          *  free variables list.
248          */
visitIdent(JCIdent tree)249         public void visitIdent(JCIdent tree) {
250             visitSymbol(tree.sym);
251         }
252         // where
visitSymbol(Symbol _sym)253         abstract void visitSymbol(Symbol _sym);
254 
255         /** If tree refers to a class instance creation expression
256          *  add all free variables of the freshly created class.
257          */
visitNewClass(JCNewClass tree)258         public void visitNewClass(JCNewClass tree) {
259             ClassSymbol c = (ClassSymbol)tree.constructor.owner;
260             addFreeVars(c);
261             super.visitNewClass(tree);
262         }
263 
264         /** If tree refers to a superclass constructor call,
265          *  add all free variables of the superclass.
266          */
visitApply(JCMethodInvocation tree)267         public void visitApply(JCMethodInvocation tree) {
268             if (TreeInfo.name(tree.meth) == names._super) {
269                 addFreeVars((ClassSymbol) TreeInfo.symbol(tree.meth).owner);
270             }
271             super.visitApply(tree);
272         }
273 
274         @Override
visitYield(JCYield tree)275         public void visitYield(JCYield tree) {
276             scan(tree.value);
277         }
278 
279     }
280 
281     /**
282      * Lower-specific subclass of {@code BasicFreeVarCollector}.
283      */
284     class FreeVarCollector extends BasicFreeVarCollector {
285 
286         /** The owner of the local class.
287          */
288         Symbol owner;
289 
290         /** The local class.
291          */
292         ClassSymbol clazz;
293 
294         /** The list of owner's variables accessed from within the local class,
295          *  without any duplicates.
296          */
297         List<VarSymbol> fvs;
298 
FreeVarCollector(ClassSymbol clazz)299         FreeVarCollector(ClassSymbol clazz) {
300             this.clazz = clazz;
301             this.owner = clazz.owner;
302             this.fvs = List.nil();
303         }
304 
305         /** Add free variable to fvs list unless it is already there.
306          */
addFreeVar(VarSymbol v)307         private void addFreeVar(VarSymbol v) {
308             for (List<VarSymbol> l = fvs; l.nonEmpty(); l = l.tail)
309                 if (l.head == v) return;
310             fvs = fvs.prepend(v);
311         }
312 
313         @Override
addFreeVars(ClassSymbol c)314         void addFreeVars(ClassSymbol c) {
315             List<VarSymbol> fvs = freevarCache.get(c);
316             if (fvs != null) {
317                 for (List<VarSymbol> l = fvs; l.nonEmpty(); l = l.tail) {
318                     addFreeVar(l.head);
319                 }
320             }
321         }
322 
323         @Override
visitSymbol(Symbol _sym)324         void visitSymbol(Symbol _sym) {
325             Symbol sym = _sym;
326             if (sym.kind == VAR || sym.kind == MTH) {
327                 if (sym != null && sym.owner != owner)
328                     sym = proxies.get(sym);
329                 if (sym != null && sym.owner == owner) {
330                     VarSymbol v = (VarSymbol)sym;
331                     if (v.getConstValue() == null) {
332                         addFreeVar(v);
333                     }
334                 } else {
335                     if (outerThisStack.head != null &&
336                         outerThisStack.head != _sym)
337                         visitSymbol(outerThisStack.head);
338                 }
339             }
340         }
341 
342         /** If tree refers to a class instance creation expression
343          *  add all free variables of the freshly created class.
344          */
visitNewClass(JCNewClass tree)345         public void visitNewClass(JCNewClass tree) {
346             ClassSymbol c = (ClassSymbol)tree.constructor.owner;
347             if (tree.encl == null &&
348                 c.hasOuterInstance() &&
349                 outerThisStack.head != null)
350                 visitSymbol(outerThisStack.head);
351             super.visitNewClass(tree);
352         }
353 
354         /** If tree refers to a qualified this or super expression
355          *  for anything but the current class, add the outer this
356          *  stack as a free variable.
357          */
visitSelect(JCFieldAccess tree)358         public void visitSelect(JCFieldAccess tree) {
359             if ((tree.name == names._this || tree.name == names._super) &&
360                 tree.selected.type.tsym != clazz &&
361                 outerThisStack.head != null)
362                 visitSymbol(outerThisStack.head);
363             super.visitSelect(tree);
364         }
365 
366         /** If tree refers to a superclass constructor call,
367          *  add all free variables of the superclass.
368          */
visitApply(JCMethodInvocation tree)369         public void visitApply(JCMethodInvocation tree) {
370             if (TreeInfo.name(tree.meth) == names._super) {
371                 Symbol constructor = TreeInfo.symbol(tree.meth);
372                 ClassSymbol c = (ClassSymbol)constructor.owner;
373                 if (c.hasOuterInstance() &&
374                     !tree.meth.hasTag(SELECT) &&
375                     outerThisStack.head != null)
376                     visitSymbol(outerThisStack.head);
377             }
378             super.visitApply(tree);
379         }
380 
381     }
382 
ownerToCopyFreeVarsFrom(ClassSymbol c)383     ClassSymbol ownerToCopyFreeVarsFrom(ClassSymbol c) {
384         if (!c.isLocal()) {
385             return null;
386         }
387         Symbol currentOwner = c.owner;
388         while (currentOwner.owner.kind.matches(KindSelector.TYP) && currentOwner.isLocal()) {
389             currentOwner = currentOwner.owner;
390         }
391         if (currentOwner.owner.kind.matches(KindSelector.VAL_MTH) && c.isSubClass(currentOwner, types)) {
392             return (ClassSymbol)currentOwner;
393         }
394         return null;
395     }
396 
397     /** Return the variables accessed from within a local class, which
398      *  are declared in the local class' owner.
399      *  (in reverse order of first access).
400      */
freevars(ClassSymbol c)401     List<VarSymbol> freevars(ClassSymbol c)  {
402         List<VarSymbol> fvs = freevarCache.get(c);
403         if (fvs != null) {
404             return fvs;
405         }
406         if (c.owner.kind.matches(KindSelector.VAL_MTH)) {
407             FreeVarCollector collector = new FreeVarCollector(c);
408             collector.scan(classDef(c));
409             fvs = collector.fvs;
410             freevarCache.put(c, fvs);
411             return fvs;
412         } else {
413             ClassSymbol owner = ownerToCopyFreeVarsFrom(c);
414             if (owner != null) {
415                 fvs = freevarCache.get(owner);
416                 freevarCache.put(c, fvs);
417                 return fvs;
418             } else {
419                 return List.nil();
420             }
421         }
422     }
423 
424     Map<TypeSymbol,EnumMapping> enumSwitchMap = new LinkedHashMap<>();
425 
mapForEnum(DiagnosticPosition pos, TypeSymbol enumClass)426     EnumMapping mapForEnum(DiagnosticPosition pos, TypeSymbol enumClass) {
427         EnumMapping map = enumSwitchMap.get(enumClass);
428         if (map == null)
429             enumSwitchMap.put(enumClass, map = new EnumMapping(pos, enumClass));
430         return map;
431     }
432 
433     /** This map gives a translation table to be used for enum
434      *  switches.
435      *
436      *  <p>For each enum that appears as the type of a switch
437      *  expression, we maintain an EnumMapping to assist in the
438      *  translation, as exemplified by the following example:
439      *
440      *  <p>we translate
441      *  <pre>
442      *          switch(colorExpression) {
443      *          case red: stmt1;
444      *          case green: stmt2;
445      *          }
446      *  </pre>
447      *  into
448      *  <pre>
449      *          switch(Outer$0.$EnumMap$Color[colorExpression.ordinal()]) {
450      *          case 1: stmt1;
451      *          case 2: stmt2
452      *          }
453      *  </pre>
454      *  with the auxiliary table initialized as follows:
455      *  <pre>
456      *          class Outer$0 {
457      *              synthetic final int[] $EnumMap$Color = new int[Color.values().length];
458      *              static {
459      *                  try { $EnumMap$Color[red.ordinal()] = 1; } catch (NoSuchFieldError ex) {}
460      *                  try { $EnumMap$Color[green.ordinal()] = 2; } catch (NoSuchFieldError ex) {}
461      *              }
462      *          }
463      *  </pre>
464      *  class EnumMapping provides mapping data and support methods for this translation.
465      */
466     class EnumMapping {
EnumMapping(DiagnosticPosition pos, TypeSymbol forEnum)467         EnumMapping(DiagnosticPosition pos, TypeSymbol forEnum) {
468             this.forEnum = forEnum;
469             this.values = new LinkedHashMap<>();
470             this.pos = pos;
471             Name varName = names
472                 .fromString(target.syntheticNameChar() +
473                             "SwitchMap" +
474                             target.syntheticNameChar() +
475                             names.fromUtf(ClassWriter.externalize(forEnum.type.tsym.flatName())).toString()
476                             .replace('/', '.')
477                             .replace('.', target.syntheticNameChar()));
478             ClassSymbol outerCacheClass = outerCacheClass();
479             this.mapVar = new VarSymbol(STATIC | SYNTHETIC | FINAL,
480                                         varName,
481                                         new ArrayType(syms.intType, syms.arrayClass),
482                                         outerCacheClass);
483             enterSynthetic(pos, mapVar, outerCacheClass.members());
484         }
485 
486         DiagnosticPosition pos = null;
487 
488         // the next value to use
489         int next = 1; // 0 (unused map elements) go to the default label
490 
491         // the enum for which this is a map
492         final TypeSymbol forEnum;
493 
494         // the field containing the map
495         final VarSymbol mapVar;
496 
497         // the mapped values
498         final Map<VarSymbol,Integer> values;
499 
forConstant(VarSymbol v)500         JCLiteral forConstant(VarSymbol v) {
501             Integer result = values.get(v);
502             if (result == null)
503                 values.put(v, result = next++);
504             return make.Literal(result);
505         }
506 
507         // generate the field initializer for the map
translate()508         void translate() {
509             make.at(pos.getStartPosition());
510             JCClassDecl owner = classDef((ClassSymbol)mapVar.owner);
511 
512             // synthetic static final int[] $SwitchMap$Color = new int[Color.values().length];
513             MethodSymbol valuesMethod = lookupMethod(pos,
514                                                      names.values,
515                                                      forEnum.type,
516                                                      List.nil());
517             JCExpression size = make // Color.values().length
518                 .Select(make.App(make.QualIdent(valuesMethod)),
519                         syms.lengthVar);
520             JCExpression mapVarInit = make
521                 .NewArray(make.Type(syms.intType), List.of(size), null)
522                 .setType(new ArrayType(syms.intType, syms.arrayClass));
523 
524             // try { $SwitchMap$Color[red.ordinal()] = 1; } catch (java.lang.NoSuchFieldError ex) {}
525             ListBuffer<JCStatement> stmts = new ListBuffer<>();
526             Symbol ordinalMethod = lookupMethod(pos,
527                                                 names.ordinal,
528                                                 forEnum.type,
529                                                 List.nil());
530             List<JCCatch> catcher = List.<JCCatch>nil()
531                 .prepend(make.Catch(make.VarDef(new VarSymbol(PARAMETER, names.ex,
532                                                               syms.noSuchFieldErrorType,
533                                                               syms.noSymbol),
534                                                 null),
535                                     make.Block(0, List.nil())));
536             for (Map.Entry<VarSymbol,Integer> e : values.entrySet()) {
537                 VarSymbol enumerator = e.getKey();
538                 Integer mappedValue = e.getValue();
539                 JCExpression assign = make
540                     .Assign(make.Indexed(mapVar,
541                                          make.App(make.Select(make.QualIdent(enumerator),
542                                                               ordinalMethod))),
543                             make.Literal(mappedValue))
544                     .setType(syms.intType);
545                 JCStatement exec = make.Exec(assign);
546                 JCStatement _try = make.Try(make.Block(0, List.of(exec)), catcher, null);
547                 stmts.append(_try);
548             }
549 
550             owner.defs = owner.defs
551                 .prepend(make.Block(STATIC, stmts.toList()))
552                 .prepend(make.VarDef(mapVar, mapVarInit));
553         }
554     }
555 
556 
557 /**************************************************************************
558  * Tree building blocks
559  *************************************************************************/
560 
561     /** Equivalent to make.at(pos.getStartPosition()) with side effect of caching
562      *  pos as make_pos, for use in diagnostics.
563      **/
make_at(DiagnosticPosition pos)564     TreeMaker make_at(DiagnosticPosition pos) {
565         make_pos = pos;
566         return make.at(pos);
567     }
568 
569     /** Make an attributed tree representing a literal. This will be an
570      *  Ident node in the case of boolean literals, a Literal node in all
571      *  other cases.
572      *  @param type       The literal's type.
573      *  @param value      The literal's value.
574      */
makeLit(Type type, Object value)575     JCExpression makeLit(Type type, Object value) {
576         return make.Literal(type.getTag(), value).setType(type.constType(value));
577     }
578 
579     /** Make an attributed tree representing null.
580      */
makeNull()581     JCExpression makeNull() {
582         return makeLit(syms.botType, null);
583     }
584 
585     /** Make an attributed class instance creation expression.
586      *  @param ctype    The class type.
587      *  @param args     The constructor arguments.
588      */
makeNewClass(Type ctype, List<JCExpression> args)589     JCNewClass makeNewClass(Type ctype, List<JCExpression> args) {
590         JCNewClass tree = make.NewClass(null,
591             null, make.QualIdent(ctype.tsym), args, null);
592         tree.constructor = rs.resolveConstructor(
593             make_pos, attrEnv, ctype, TreeInfo.types(args), List.nil());
594         tree.type = ctype;
595         return tree;
596     }
597 
598     /** Make an attributed unary expression.
599      *  @param optag    The operators tree tag.
600      *  @param arg      The operator's argument.
601      */
makeUnary(JCTree.Tag optag, JCExpression arg)602     JCUnary makeUnary(JCTree.Tag optag, JCExpression arg) {
603         JCUnary tree = make.Unary(optag, arg);
604         tree.operator = operators.resolveUnary(tree, optag, arg.type);
605         tree.type = tree.operator.type.getReturnType();
606         return tree;
607     }
608 
609     /** Make an attributed binary expression.
610      *  @param optag    The operators tree tag.
611      *  @param lhs      The operator's left argument.
612      *  @param rhs      The operator's right argument.
613      */
makeBinary(JCTree.Tag optag, JCExpression lhs, JCExpression rhs)614     JCBinary makeBinary(JCTree.Tag optag, JCExpression lhs, JCExpression rhs) {
615         JCBinary tree = make.Binary(optag, lhs, rhs);
616         tree.operator = operators.resolveBinary(tree, optag, lhs.type, rhs.type);
617         tree.type = tree.operator.type.getReturnType();
618         return tree;
619     }
620 
621     /** Make an attributed assignop expression.
622      *  @param optag    The operators tree tag.
623      *  @param lhs      The operator's left argument.
624      *  @param rhs      The operator's right argument.
625      */
makeAssignop(JCTree.Tag optag, JCTree lhs, JCTree rhs)626     JCAssignOp makeAssignop(JCTree.Tag optag, JCTree lhs, JCTree rhs) {
627         JCAssignOp tree = make.Assignop(optag, lhs, rhs);
628         tree.operator = operators.resolveBinary(tree, tree.getTag().noAssignOp(), lhs.type, rhs.type);
629         tree.type = lhs.type;
630         return tree;
631     }
632 
633     /** Convert tree into string object, unless it has already a
634      *  reference type..
635      */
makeString(JCExpression tree)636     JCExpression makeString(JCExpression tree) {
637         if (!tree.type.isPrimitiveOrVoid()) {
638             return tree;
639         } else {
640             Symbol valueOfSym = lookupMethod(tree.pos(),
641                                              names.valueOf,
642                                              syms.stringType,
643                                              List.of(tree.type));
644             return make.App(make.QualIdent(valueOfSym), List.of(tree));
645         }
646     }
647 
648     /** Create an empty anonymous class definition and enter and complete
649      *  its symbol. Return the class definition's symbol.
650      *  and create
651      *  @param flags    The class symbol's flags
652      *  @param owner    The class symbol's owner
653      */
makeEmptyClass(long flags, ClassSymbol owner)654     JCClassDecl makeEmptyClass(long flags, ClassSymbol owner) {
655         return makeEmptyClass(flags, owner, null, true);
656     }
657 
makeEmptyClass(long flags, ClassSymbol owner, Name flatname, boolean addToDefs)658     JCClassDecl makeEmptyClass(long flags, ClassSymbol owner, Name flatname,
659             boolean addToDefs) {
660         // Create class symbol.
661         ClassSymbol c = syms.defineClass(names.empty, owner);
662         if (flatname != null) {
663             c.flatname = flatname;
664         } else {
665             c.flatname = chk.localClassName(c);
666         }
667         c.sourcefile = owner.sourcefile;
668         c.completer = Completer.NULL_COMPLETER;
669         c.members_field = WriteableScope.create(c);
670         c.flags_field = flags;
671         ClassType ctype = (ClassType) c.type;
672         ctype.supertype_field = syms.objectType;
673         ctype.interfaces_field = List.nil();
674 
675         JCClassDecl odef = classDef(owner);
676 
677         // Enter class symbol in owner scope and compiled table.
678         enterSynthetic(odef.pos(), c, owner.members());
679         chk.putCompiled(c);
680 
681         // Create class definition tree.
682         JCClassDecl cdef = make.ClassDef(
683             make.Modifiers(flags), names.empty,
684             List.nil(),
685             null, List.nil(), List.nil());
686         cdef.sym = c;
687         cdef.type = c.type;
688 
689         // Append class definition tree to owner's definitions.
690         if (addToDefs) odef.defs = odef.defs.prepend(cdef);
691         return cdef;
692     }
693 
694 /**************************************************************************
695  * Symbol manipulation utilities
696  *************************************************************************/
697 
698     /** Enter a synthetic symbol in a given scope, but complain if there was already one there.
699      *  @param pos           Position for error reporting.
700      *  @param sym           The symbol.
701      *  @param s             The scope.
702      */
enterSynthetic(DiagnosticPosition pos, Symbol sym, WriteableScope s)703     private void enterSynthetic(DiagnosticPosition pos, Symbol sym, WriteableScope s) {
704         s.enter(sym);
705     }
706 
707     /** Create a fresh synthetic name within a given scope - the unique name is
708      *  obtained by appending '$' chars at the end of the name until no match
709      *  is found.
710      *
711      * @param name base name
712      * @param s scope in which the name has to be unique
713      * @return fresh synthetic name
714      */
makeSyntheticName(Name name, Scope s)715     private Name makeSyntheticName(Name name, Scope s) {
716         do {
717             name = name.append(
718                     target.syntheticNameChar(),
719                     names.empty);
720         } while (lookupSynthetic(name, s) != null);
721         return name;
722     }
723 
724     /** Check whether synthetic symbols generated during lowering conflict
725      *  with user-defined symbols.
726      *
727      *  @param translatedTrees lowered class trees
728      */
checkConflicts(List<JCTree> translatedTrees)729     void checkConflicts(List<JCTree> translatedTrees) {
730         for (JCTree t : translatedTrees) {
731             t.accept(conflictsChecker);
732         }
733     }
734 
735     JCTree.Visitor conflictsChecker = new TreeScanner() {
736 
737         TypeSymbol currentClass;
738 
739         @Override
740         public void visitMethodDef(JCMethodDecl that) {
741             checkConflicts(that.pos(), that.sym, currentClass);
742             super.visitMethodDef(that);
743         }
744 
745         @Override
746         public void visitVarDef(JCVariableDecl that) {
747             if (that.sym.owner.kind == TYP) {
748                 checkConflicts(that.pos(), that.sym, currentClass);
749             }
750             super.visitVarDef(that);
751         }
752 
753         @Override
754         public void visitClassDef(JCClassDecl that) {
755             TypeSymbol prevCurrentClass = currentClass;
756             currentClass = that.sym;
757             try {
758                 super.visitClassDef(that);
759             }
760             finally {
761                 currentClass = prevCurrentClass;
762             }
763         }
764 
765         void checkConflicts(DiagnosticPosition pos, Symbol sym, TypeSymbol c) {
766             for (Type ct = c.type; ct != Type.noType ; ct = types.supertype(ct)) {
767                 for (Symbol sym2 : ct.tsym.members().getSymbolsByName(sym.name, NON_RECURSIVE)) {
768                     // VM allows methods and variables with differing types
769                     if (sym.kind == sym2.kind &&
770                         types.isSameType(types.erasure(sym.type), types.erasure(sym2.type)) &&
771                         sym != sym2 &&
772                         (sym.flags() & Flags.SYNTHETIC) != (sym2.flags() & Flags.SYNTHETIC) &&
773                         (sym.flags() & BRIDGE) == 0 && (sym2.flags() & BRIDGE) == 0) {
774                         syntheticError(pos, (sym2.flags() & SYNTHETIC) == 0 ? sym2 : sym);
775                         return;
776                     }
777                 }
778             }
779         }
780 
781         /** Report a conflict between a user symbol and a synthetic symbol.
782          */
783         private void syntheticError(DiagnosticPosition pos, Symbol sym) {
784             if (!sym.type.isErroneous()) {
785                 log.error(pos, Errors.CannotGenerateClass(sym.location(), Fragments.SyntheticNameConflict(sym, sym.location())));
786             }
787         }
788     };
789 
790     /** Look up a synthetic name in a given scope.
791      *  @param s            The scope.
792      *  @param name         The name.
793      */
lookupSynthetic(Name name, Scope s)794     private Symbol lookupSynthetic(Name name, Scope s) {
795         Symbol sym = s.findFirst(name);
796         return (sym==null || (sym.flags()&SYNTHETIC)==0) ? null : sym;
797     }
798 
799     /** Look up a method in a given scope.
800      */
lookupMethod(DiagnosticPosition pos, Name name, Type qual, List<Type> args)801     private MethodSymbol lookupMethod(DiagnosticPosition pos, Name name, Type qual, List<Type> args) {
802         return rs.resolveInternalMethod(pos, attrEnv, qual, name, args, List.nil());
803     }
804 
805     /** Anon inner classes are used as access constructor tags.
806      * accessConstructorTag will use an existing anon class if one is available,
807      * and synthethise a class (with makeEmptyClass) if one is not available.
808      * However, there is a small possibility that an existing class will not
809      * be generated as expected if it is inside a conditional with a constant
810      * expression. If that is found to be the case, create an empty class tree here.
811      */
checkAccessConstructorTags()812     private void checkAccessConstructorTags() {
813         for (List<ClassSymbol> l = accessConstrTags; l.nonEmpty(); l = l.tail) {
814             ClassSymbol c = l.head;
815             if (isTranslatedClassAvailable(c))
816                 continue;
817             // Create class definition tree.
818             JCClassDecl cdec = makeEmptyClass(STATIC | SYNTHETIC,
819                     c.outermostClass(), c.flatname, false);
820             swapAccessConstructorTag(c, cdec.sym);
821             translated.append(cdec);
822         }
823     }
824     // where
isTranslatedClassAvailable(ClassSymbol c)825     private boolean isTranslatedClassAvailable(ClassSymbol c) {
826         for (JCTree tree: translated) {
827             if (tree.hasTag(CLASSDEF)
828                     && ((JCClassDecl) tree).sym == c) {
829                 return true;
830             }
831         }
832         return false;
833     }
834 
swapAccessConstructorTag(ClassSymbol oldCTag, ClassSymbol newCTag)835     void swapAccessConstructorTag(ClassSymbol oldCTag, ClassSymbol newCTag) {
836         for (MethodSymbol methodSymbol : accessConstrs.values()) {
837             Assert.check(methodSymbol.type.hasTag(METHOD));
838             MethodType oldMethodType =
839                     (MethodType)methodSymbol.type;
840             if (oldMethodType.argtypes.head.tsym == oldCTag)
841                 methodSymbol.type =
842                     types.createMethodTypeWithParameters(oldMethodType,
843                         oldMethodType.getParameterTypes().tail
844                             .prepend(newCTag.erasure(types)));
845         }
846     }
847 
848 /**************************************************************************
849  * Access methods
850  *************************************************************************/
851 
852     /** A mapping from symbols to their access numbers.
853      */
854     private Map<Symbol,Integer> accessNums;
855 
856     /** A mapping from symbols to an array of access symbols, indexed by
857      *  access code.
858      */
859     private Map<Symbol,MethodSymbol[]> accessSyms;
860 
861     /** A mapping from (constructor) symbols to access constructor symbols.
862      */
863     private Map<Symbol,MethodSymbol> accessConstrs;
864 
865     /** A list of all class symbols used for access constructor tags.
866      */
867     private List<ClassSymbol> accessConstrTags;
868 
869     /** A queue for all accessed symbols.
870      */
871     private ListBuffer<Symbol> accessed;
872 
873     /** return access code for identifier,
874      *  @param tree     The tree representing the identifier use.
875      *  @param enclOp   The closest enclosing operation node of tree,
876      *                  null if tree is not a subtree of an operation.
877      */
accessCode(JCTree tree, JCTree enclOp)878     private static int accessCode(JCTree tree, JCTree enclOp) {
879         if (enclOp == null)
880             return AccessCode.DEREF.code;
881         else if (enclOp.hasTag(ASSIGN) &&
882                  tree == TreeInfo.skipParens(((JCAssign) enclOp).lhs))
883             return AccessCode.ASSIGN.code;
884         else if ((enclOp.getTag().isIncOrDecUnaryOp() || enclOp.getTag().isAssignop()) &&
885                 tree == TreeInfo.skipParens(((JCOperatorExpression) enclOp).getOperand(LEFT)))
886             return (((JCOperatorExpression) enclOp).operator).getAccessCode(enclOp.getTag());
887         else
888             return AccessCode.DEREF.code;
889     }
890 
891     /** Return binary operator that corresponds to given access code.
892      */
binaryAccessOperator(int acode, Tag tag)893     private OperatorSymbol binaryAccessOperator(int acode, Tag tag) {
894         return operators.lookupBinaryOp(op -> op.getAccessCode(tag) == acode);
895     }
896 
897     /** Return tree tag for assignment operation corresponding
898      *  to given binary operator.
899      */
treeTag(OperatorSymbol operator)900     private static JCTree.Tag treeTag(OperatorSymbol operator) {
901         switch (operator.opcode) {
902         case ByteCodes.ior: case ByteCodes.lor:
903             return BITOR_ASG;
904         case ByteCodes.ixor: case ByteCodes.lxor:
905             return BITXOR_ASG;
906         case ByteCodes.iand: case ByteCodes.land:
907             return BITAND_ASG;
908         case ByteCodes.ishl: case ByteCodes.lshl:
909         case ByteCodes.ishll: case ByteCodes.lshll:
910             return SL_ASG;
911         case ByteCodes.ishr: case ByteCodes.lshr:
912         case ByteCodes.ishrl: case ByteCodes.lshrl:
913             return SR_ASG;
914         case ByteCodes.iushr: case ByteCodes.lushr:
915         case ByteCodes.iushrl: case ByteCodes.lushrl:
916             return USR_ASG;
917         case ByteCodes.iadd: case ByteCodes.ladd:
918         case ByteCodes.fadd: case ByteCodes.dadd:
919         case ByteCodes.string_add:
920             return PLUS_ASG;
921         case ByteCodes.isub: case ByteCodes.lsub:
922         case ByteCodes.fsub: case ByteCodes.dsub:
923             return MINUS_ASG;
924         case ByteCodes.imul: case ByteCodes.lmul:
925         case ByteCodes.fmul: case ByteCodes.dmul:
926             return MUL_ASG;
927         case ByteCodes.idiv: case ByteCodes.ldiv:
928         case ByteCodes.fdiv: case ByteCodes.ddiv:
929             return DIV_ASG;
930         case ByteCodes.imod: case ByteCodes.lmod:
931         case ByteCodes.fmod: case ByteCodes.dmod:
932             return MOD_ASG;
933         default:
934             throw new AssertionError();
935         }
936     }
937 
938     /** The name of the access method with number `anum' and access code `acode'.
939      */
accessName(int anum, int acode)940     Name accessName(int anum, int acode) {
941         return names.fromString(
942             "access" + target.syntheticNameChar() + anum + acode / 10 + acode % 10);
943     }
944 
945     /** Return access symbol for a private or protected symbol from an inner class.
946      *  @param sym        The accessed private symbol.
947      *  @param tree       The accessing tree.
948      *  @param enclOp     The closest enclosing operation node of tree,
949      *                    null if tree is not a subtree of an operation.
950      *  @param protAccess Is access to a protected symbol in another
951      *                    package?
952      *  @param refSuper   Is access via a (qualified) C.super?
953      */
accessSymbol(Symbol sym, JCTree tree, JCTree enclOp, boolean protAccess, boolean refSuper)954     MethodSymbol accessSymbol(Symbol sym, JCTree tree, JCTree enclOp,
955                               boolean protAccess, boolean refSuper) {
956         ClassSymbol accOwner = refSuper && protAccess
957             // For access via qualified super (T.super.x), place the
958             // access symbol on T.
959             ? (ClassSymbol)((JCFieldAccess) tree).selected.type.tsym
960             // Otherwise pretend that the owner of an accessed
961             // protected symbol is the enclosing class of the current
962             // class which is a subclass of the symbol's owner.
963             : accessClass(sym, protAccess, tree);
964 
965         Symbol vsym = sym;
966         if (sym.owner != accOwner) {
967             vsym = sym.clone(accOwner);
968             actualSymbols.put(vsym, sym);
969         }
970 
971         Integer anum              // The access number of the access method.
972             = accessNums.get(vsym);
973         if (anum == null) {
974             anum = accessed.length();
975             accessNums.put(vsym, anum);
976             accessSyms.put(vsym, new MethodSymbol[AccessCode.numberOfAccessCodes]);
977             accessed.append(vsym);
978             // System.out.println("accessing " + vsym + " in " + vsym.location());
979         }
980 
981         int acode;                // The access code of the access method.
982         List<Type> argtypes;      // The argument types of the access method.
983         Type restype;             // The result type of the access method.
984         List<Type> thrown;        // The thrown exceptions of the access method.
985         switch (vsym.kind) {
986         case VAR:
987             acode = accessCode(tree, enclOp);
988             if (acode >= AccessCode.FIRSTASGOP.code) {
989                 OperatorSymbol operator = binaryAccessOperator(acode, enclOp.getTag());
990                 if (operator.opcode == string_add)
991                     argtypes = List.of(syms.objectType);
992                 else
993                     argtypes = operator.type.getParameterTypes().tail;
994             } else if (acode == AccessCode.ASSIGN.code)
995                 argtypes = List.of(vsym.erasure(types));
996             else
997                 argtypes = List.nil();
998             restype = vsym.erasure(types);
999             thrown = List.nil();
1000             break;
1001         case MTH:
1002             acode = AccessCode.DEREF.code;
1003             argtypes = vsym.erasure(types).getParameterTypes();
1004             restype = vsym.erasure(types).getReturnType();
1005             thrown = vsym.type.getThrownTypes();
1006             break;
1007         default:
1008             throw new AssertionError();
1009         }
1010 
1011         // For references via qualified super, increment acode by one,
1012         // making it odd.
1013         if (protAccess && refSuper) acode++;
1014 
1015         // Instance access methods get instance as first parameter.
1016         // For protected symbols this needs to be the instance as a member
1017         // of the type containing the accessed symbol, not the class
1018         // containing the access method.
1019         if ((vsym.flags() & STATIC) == 0) {
1020             argtypes = argtypes.prepend(vsym.owner.erasure(types));
1021         }
1022         MethodSymbol[] accessors = accessSyms.get(vsym);
1023         MethodSymbol accessor = accessors[acode];
1024         if (accessor == null) {
1025             accessor = new MethodSymbol(
1026                 STATIC | SYNTHETIC | (accOwner.isInterface() ? PUBLIC : 0),
1027                 accessName(anum.intValue(), acode),
1028                 new MethodType(argtypes, restype, thrown, syms.methodClass),
1029                 accOwner);
1030             enterSynthetic(tree.pos(), accessor, accOwner.members());
1031             accessors[acode] = accessor;
1032         }
1033         return accessor;
1034     }
1035 
1036     /** The qualifier to be used for accessing a symbol in an outer class.
1037      *  This is either C.sym or C.this.sym, depending on whether or not
1038      *  sym is static.
1039      *  @param sym   The accessed symbol.
1040      */
accessBase(DiagnosticPosition pos, Symbol sym)1041     JCExpression accessBase(DiagnosticPosition pos, Symbol sym) {
1042         return (sym.flags() & STATIC) != 0
1043             ? access(make.at(pos.getStartPosition()).QualIdent(sym.owner))
1044             : makeOwnerThis(pos, sym, true);
1045     }
1046 
1047     /** Do we need an access method to reference private symbol?
1048      */
needsPrivateAccess(Symbol sym)1049     boolean needsPrivateAccess(Symbol sym) {
1050         if (target.hasNestmateAccess()) {
1051             return false;
1052         }
1053         if ((sym.flags() & PRIVATE) == 0 || sym.owner == currentClass) {
1054             return false;
1055         } else if (sym.name == names.init && sym.owner.isLocal()) {
1056             // private constructor in local class: relax protection
1057             sym.flags_field &= ~PRIVATE;
1058             return false;
1059         } else {
1060             return true;
1061         }
1062     }
1063 
1064     /** Do we need an access method to reference symbol in other package?
1065      */
needsProtectedAccess(Symbol sym, JCTree tree)1066     boolean needsProtectedAccess(Symbol sym, JCTree tree) {
1067         if (disableProtectedAccessors) return false;
1068         if ((sym.flags() & PROTECTED) == 0 ||
1069             sym.owner.owner == currentClass.owner || // fast special case
1070             sym.packge() == currentClass.packge())
1071             return false;
1072         if (!currentClass.isSubClass(sym.owner, types))
1073             return true;
1074         if ((sym.flags() & STATIC) != 0 ||
1075             !tree.hasTag(SELECT) ||
1076             TreeInfo.name(((JCFieldAccess) tree).selected) == names._super)
1077             return false;
1078         return !((JCFieldAccess) tree).selected.type.tsym.isSubClass(currentClass, types);
1079     }
1080 
1081     /** The class in which an access method for given symbol goes.
1082      *  @param sym        The access symbol
1083      *  @param protAccess Is access to a protected symbol in another
1084      *                    package?
1085      */
accessClass(Symbol sym, boolean protAccess, JCTree tree)1086     ClassSymbol accessClass(Symbol sym, boolean protAccess, JCTree tree) {
1087         if (protAccess) {
1088             Symbol qualifier = null;
1089             ClassSymbol c = currentClass;
1090             if (tree.hasTag(SELECT) && (sym.flags() & STATIC) == 0) {
1091                 qualifier = ((JCFieldAccess) tree).selected.type.tsym;
1092                 while (!qualifier.isSubClass(c, types)) {
1093                     c = c.owner.enclClass();
1094                 }
1095                 return c;
1096             } else {
1097                 while (!c.isSubClass(sym.owner, types)) {
1098                     c = c.owner.enclClass();
1099                 }
1100             }
1101             return c;
1102         } else {
1103             // the symbol is private
1104             return sym.owner.enclClass();
1105         }
1106     }
1107 
addPrunedInfo(JCTree tree)1108     private void addPrunedInfo(JCTree tree) {
1109         List<JCTree> infoList = prunedTree.get(currentClass);
1110         infoList = (infoList == null) ? List.of(tree) : infoList.prepend(tree);
1111         prunedTree.put(currentClass, infoList);
1112     }
1113 
1114     /** Ensure that identifier is accessible, return tree accessing the identifier.
1115      *  @param sym      The accessed symbol.
1116      *  @param tree     The tree referring to the symbol.
1117      *  @param enclOp   The closest enclosing operation node of tree,
1118      *                  null if tree is not a subtree of an operation.
1119      *  @param refSuper Is access via a (qualified) C.super?
1120      */
access(Symbol sym, JCExpression tree, JCExpression enclOp, boolean refSuper)1121     JCExpression access(Symbol sym, JCExpression tree, JCExpression enclOp, boolean refSuper) {
1122         // Access a free variable via its proxy, or its proxy's proxy
1123         while (sym.kind == VAR && sym.owner.kind == MTH &&
1124             sym.owner.enclClass() != currentClass) {
1125             // A constant is replaced by its constant value.
1126             Object cv = ((VarSymbol)sym).getConstValue();
1127             if (cv != null) {
1128                 make.at(tree.pos);
1129                 return makeLit(sym.type, cv);
1130             }
1131             if (lambdaTranslationMap != null && lambdaTranslationMap.get(sym) != null) {
1132                 return make.at(tree.pos).Ident(lambdaTranslationMap.get(sym));
1133             } else {
1134                 // Otherwise replace the variable by its proxy.
1135                 sym = proxies.get(sym);
1136                 Assert.check(sym != null && (sym.flags_field & FINAL) != 0);
1137                 tree = make.at(tree.pos).Ident(sym);
1138             }
1139         }
1140         JCExpression base = (tree.hasTag(SELECT)) ? ((JCFieldAccess) tree).selected : null;
1141         switch (sym.kind) {
1142         case TYP:
1143             if (sym.owner.kind != PCK) {
1144                 // Convert type idents to
1145                 // <flat name> or <package name> . <flat name>
1146                 Name flatname = Convert.shortName(sym.flatName());
1147                 while (base != null &&
1148                        TreeInfo.symbol(base) != null &&
1149                        TreeInfo.symbol(base).kind != PCK) {
1150                     base = (base.hasTag(SELECT))
1151                         ? ((JCFieldAccess) base).selected
1152                         : null;
1153                 }
1154                 if (tree.hasTag(IDENT)) {
1155                     ((JCIdent) tree).name = flatname;
1156                 } else if (base == null) {
1157                     tree = make.at(tree.pos).Ident(sym);
1158                     ((JCIdent) tree).name = flatname;
1159                 } else {
1160                     ((JCFieldAccess) tree).selected = base;
1161                     ((JCFieldAccess) tree).name = flatname;
1162                 }
1163             }
1164             break;
1165         case MTH: case VAR:
1166             if (sym.owner.kind == TYP) {
1167 
1168                 // Access methods are required for
1169                 //  - private members,
1170                 //  - protected members in a superclass of an
1171                 //    enclosing class contained in another package.
1172                 //  - all non-private members accessed via a qualified super.
1173                 boolean protAccess = refSuper && !needsPrivateAccess(sym)
1174                     || needsProtectedAccess(sym, tree);
1175                 boolean accReq = protAccess || needsPrivateAccess(sym);
1176 
1177                 // A base has to be supplied for
1178                 //  - simple identifiers accessing variables in outer classes.
1179                 boolean baseReq =
1180                     base == null &&
1181                     sym.owner != syms.predefClass &&
1182                     !sym.isMemberOf(currentClass, types);
1183 
1184                 if (accReq || baseReq) {
1185                     make.at(tree.pos);
1186 
1187                     // Constants are replaced by their constant value.
1188                     if (sym.kind == VAR) {
1189                         Object cv = ((VarSymbol)sym).getConstValue();
1190                         if (cv != null) {
1191                             addPrunedInfo(tree);
1192                             return makeLit(sym.type, cv);
1193                         }
1194                     }
1195 
1196                     // Private variables and methods are replaced by calls
1197                     // to their access methods.
1198                     if (accReq) {
1199                         List<JCExpression> args = List.nil();
1200                         if ((sym.flags() & STATIC) == 0) {
1201                             // Instance access methods get instance
1202                             // as first parameter.
1203                             if (base == null)
1204                                 base = makeOwnerThis(tree.pos(), sym, true);
1205                             args = args.prepend(base);
1206                             base = null;   // so we don't duplicate code
1207                         }
1208                         Symbol access = accessSymbol(sym, tree,
1209                                                      enclOp, protAccess,
1210                                                      refSuper);
1211                         JCExpression receiver = make.Select(
1212                             base != null ? base : make.QualIdent(access.owner),
1213                             access);
1214                         return make.App(receiver, args);
1215 
1216                     // Other accesses to members of outer classes get a
1217                     // qualifier.
1218                     } else if (baseReq) {
1219                         return make.at(tree.pos).Select(
1220                             accessBase(tree.pos(), sym), sym).setType(tree.type);
1221                     }
1222                 }
1223             } else if (sym.owner.kind == MTH && lambdaTranslationMap != null) {
1224                 //sym is a local variable - check the lambda translation map to
1225                 //see if sym has been translated to something else in the current
1226                 //scope (by LambdaToMethod)
1227                 Symbol translatedSym = lambdaTranslationMap.get(sym);
1228                 if (translatedSym != null) {
1229                     tree = make.at(tree.pos).Ident(translatedSym);
1230                 }
1231             }
1232         }
1233         return tree;
1234     }
1235 
1236     /** Ensure that identifier is accessible, return tree accessing the identifier.
1237      *  @param tree     The identifier tree.
1238      */
access(JCExpression tree)1239     JCExpression access(JCExpression tree) {
1240         Symbol sym = TreeInfo.symbol(tree);
1241         return sym == null ? tree : access(sym, tree, null, false);
1242     }
1243 
1244     /** Return access constructor for a private constructor,
1245      *  or the constructor itself, if no access constructor is needed.
1246      *  @param pos       The position to report diagnostics, if any.
1247      *  @param constr    The private constructor.
1248      */
accessConstructor(DiagnosticPosition pos, Symbol constr)1249     Symbol accessConstructor(DiagnosticPosition pos, Symbol constr) {
1250         if (needsPrivateAccess(constr)) {
1251             ClassSymbol accOwner = constr.owner.enclClass();
1252             MethodSymbol aconstr = accessConstrs.get(constr);
1253             if (aconstr == null) {
1254                 List<Type> argtypes = constr.type.getParameterTypes();
1255                 if ((accOwner.flags_field & ENUM) != 0)
1256                     argtypes = argtypes
1257                         .prepend(syms.intType)
1258                         .prepend(syms.stringType);
1259                 aconstr = new MethodSymbol(
1260                     SYNTHETIC,
1261                     names.init,
1262                     new MethodType(
1263                         argtypes.append(
1264                             accessConstructorTag().erasure(types)),
1265                         constr.type.getReturnType(),
1266                         constr.type.getThrownTypes(),
1267                         syms.methodClass),
1268                     accOwner);
1269                 enterSynthetic(pos, aconstr, accOwner.members());
1270                 accessConstrs.put(constr, aconstr);
1271                 accessed.append(constr);
1272             }
1273             return aconstr;
1274         } else {
1275             return constr;
1276         }
1277     }
1278 
1279     /** Return an anonymous class nested in this toplevel class.
1280      */
accessConstructorTag()1281     ClassSymbol accessConstructorTag() {
1282         ClassSymbol topClass = currentClass.outermostClass();
1283         ModuleSymbol topModle = topClass.packge().modle;
1284         for (int i = 1; ; i++) {
1285             Name flatname = names.fromString("" + topClass.getQualifiedName() +
1286                                             target.syntheticNameChar() +
1287                                             i);
1288             ClassSymbol ctag = chk.getCompiled(topModle, flatname);
1289             if (ctag == null)
1290                 ctag = makeEmptyClass(STATIC | SYNTHETIC, topClass).sym;
1291             else if (!ctag.isAnonymous())
1292                 continue;
1293             // keep a record of all tags, to verify that all are generated as required
1294             accessConstrTags = accessConstrTags.prepend(ctag);
1295             return ctag;
1296         }
1297     }
1298 
1299     /** Add all required access methods for a private symbol to enclosing class.
1300      *  @param sym       The symbol.
1301      */
makeAccessible(Symbol sym)1302     void makeAccessible(Symbol sym) {
1303         JCClassDecl cdef = classDef(sym.owner.enclClass());
1304         if (cdef == null) Assert.error("class def not found: " + sym + " in " + sym.owner);
1305         if (sym.name == names.init) {
1306             cdef.defs = cdef.defs.prepend(
1307                 accessConstructorDef(cdef.pos, sym, accessConstrs.get(sym)));
1308         } else {
1309             MethodSymbol[] accessors = accessSyms.get(sym);
1310             for (int i = 0; i < AccessCode.numberOfAccessCodes; i++) {
1311                 if (accessors[i] != null)
1312                     cdef.defs = cdef.defs.prepend(
1313                         accessDef(cdef.pos, sym, accessors[i], i));
1314             }
1315         }
1316     }
1317 
1318     /** Construct definition of an access method.
1319      *  @param pos        The source code position of the definition.
1320      *  @param vsym       The private or protected symbol.
1321      *  @param accessor   The access method for the symbol.
1322      *  @param acode      The access code.
1323      */
accessDef(int pos, Symbol vsym, MethodSymbol accessor, int acode)1324     JCTree accessDef(int pos, Symbol vsym, MethodSymbol accessor, int acode) {
1325 //      System.err.println("access " + vsym + " with " + accessor);//DEBUG
1326         currentClass = vsym.owner.enclClass();
1327         make.at(pos);
1328         JCMethodDecl md = make.MethodDef(accessor, null);
1329 
1330         // Find actual symbol
1331         Symbol sym = actualSymbols.get(vsym);
1332         if (sym == null) sym = vsym;
1333 
1334         JCExpression ref;           // The tree referencing the private symbol.
1335         List<JCExpression> args;    // Any additional arguments to be passed along.
1336         if ((sym.flags() & STATIC) != 0) {
1337             ref = make.Ident(sym);
1338             args = make.Idents(md.params);
1339         } else {
1340             JCExpression site = make.Ident(md.params.head);
1341             if (acode % 2 != 0) {
1342                 //odd access codes represent qualified super accesses - need to
1343                 //emit reference to the direct superclass, even if the refered
1344                 //member is from an indirect superclass (JLS 13.1)
1345                 site.setType(types.erasure(types.supertype(vsym.owner.enclClass().type)));
1346             }
1347             ref = make.Select(site, sym);
1348             args = make.Idents(md.params.tail);
1349         }
1350         JCStatement stat;          // The statement accessing the private symbol.
1351         if (sym.kind == VAR) {
1352             // Normalize out all odd access codes by taking floor modulo 2:
1353             int acode1 = acode - (acode & 1);
1354 
1355             JCExpression expr;      // The access method's return value.
1356             AccessCode aCode = AccessCode.getFromCode(acode1);
1357             switch (aCode) {
1358             case DEREF:
1359                 expr = ref;
1360                 break;
1361             case ASSIGN:
1362                 expr = make.Assign(ref, args.head);
1363                 break;
1364             case PREINC: case POSTINC: case PREDEC: case POSTDEC:
1365                 expr = makeUnary(aCode.tag, ref);
1366                 break;
1367             default:
1368                 expr = make.Assignop(
1369                     treeTag(binaryAccessOperator(acode1, JCTree.Tag.NO_TAG)), ref, args.head);
1370                 ((JCAssignOp) expr).operator = binaryAccessOperator(acode1, JCTree.Tag.NO_TAG);
1371             }
1372             stat = make.Return(expr.setType(sym.type));
1373         } else {
1374             stat = make.Call(make.App(ref, args));
1375         }
1376         md.body = make.Block(0, List.of(stat));
1377 
1378         // Make sure all parameters, result types and thrown exceptions
1379         // are accessible.
1380         for (List<JCVariableDecl> l = md.params; l.nonEmpty(); l = l.tail)
1381             l.head.vartype = access(l.head.vartype);
1382         md.restype = access(md.restype);
1383         for (List<JCExpression> l = md.thrown; l.nonEmpty(); l = l.tail)
1384             l.head = access(l.head);
1385 
1386         return md;
1387     }
1388 
1389     /** Construct definition of an access constructor.
1390      *  @param pos        The source code position of the definition.
1391      *  @param constr     The private constructor.
1392      *  @param accessor   The access method for the constructor.
1393      */
accessConstructorDef(int pos, Symbol constr, MethodSymbol accessor)1394     JCTree accessConstructorDef(int pos, Symbol constr, MethodSymbol accessor) {
1395         make.at(pos);
1396         JCMethodDecl md = make.MethodDef(accessor,
1397                                       accessor.externalType(types),
1398                                       null);
1399         JCIdent callee = make.Ident(names._this);
1400         callee.sym = constr;
1401         callee.type = constr.type;
1402         md.body =
1403             make.Block(0, List.of(
1404                 make.Call(
1405                     make.App(
1406                         callee,
1407                         make.Idents(md.params.reverse().tail.reverse())))));
1408         return md;
1409     }
1410 
1411 /**************************************************************************
1412  * Free variables proxies and this$n
1413  *************************************************************************/
1414 
1415     /** A map which allows to retrieve the translated proxy variable for any given symbol of an
1416      *  enclosing scope that is accessed (the accessed symbol could be the synthetic 'this$n' symbol).
1417      *  Inside a constructor, the map temporarily overrides entries corresponding to proxies and any
1418      *  'this$n' symbols, where they represent the constructor parameters.
1419      */
1420     Map<Symbol, Symbol> proxies;
1421 
1422     /** A scope containing all unnamed resource variables/saved
1423      *  exception variables for translated TWR blocks
1424      */
1425     WriteableScope twrVars;
1426 
1427     /** A stack containing the this$n field of the currently translated
1428      *  classes (if needed) in innermost first order.
1429      *  Inside a constructor, proxies and any this$n symbol are duplicated
1430      *  in an additional innermost scope, where they represent the constructor
1431      *  parameters.
1432      */
1433     List<VarSymbol> outerThisStack;
1434 
1435     /** The name of a free variable proxy.
1436      */
proxyName(Name name, int index)1437     Name proxyName(Name name, int index) {
1438         Name proxyName = names.fromString("val" + target.syntheticNameChar() + name);
1439         if (index > 0) {
1440             proxyName = proxyName.append(names.fromString("" + target.syntheticNameChar() + index));
1441         }
1442         return proxyName;
1443     }
1444 
1445     /** Proxy definitions for all free variables in given list, in reverse order.
1446      *  @param pos        The source code position of the definition.
1447      *  @param freevars   The free variables.
1448      *  @param owner      The class in which the definitions go.
1449      */
freevarDefs(int pos, List<VarSymbol> freevars, Symbol owner)1450     List<JCVariableDecl> freevarDefs(int pos, List<VarSymbol> freevars, Symbol owner) {
1451         return freevarDefs(pos, freevars, owner, 0);
1452     }
1453 
freevarDefs(int pos, List<VarSymbol> freevars, Symbol owner, long additionalFlags)1454     List<JCVariableDecl> freevarDefs(int pos, List<VarSymbol> freevars, Symbol owner,
1455             long additionalFlags) {
1456         long flags = FINAL | SYNTHETIC | additionalFlags;
1457         List<JCVariableDecl> defs = List.nil();
1458         Set<Name> proxyNames = new HashSet<>();
1459         for (List<VarSymbol> l = freevars; l.nonEmpty(); l = l.tail) {
1460             VarSymbol v = l.head;
1461             int index = 0;
1462             Name proxyName;
1463             do {
1464                 proxyName = proxyName(v.name, index++);
1465             } while (!proxyNames.add(proxyName));
1466             VarSymbol proxy = new VarSymbol(
1467                 flags, proxyName, v.erasure(types), owner);
1468             proxies.put(v, proxy);
1469             JCVariableDecl vd = make.at(pos).VarDef(proxy, null);
1470             vd.vartype = access(vd.vartype);
1471             defs = defs.prepend(vd);
1472         }
1473         return defs;
1474     }
1475 
1476     /** The name of a this$n field
1477      *  @param type   The class referenced by the this$n field
1478      */
outerThisName(Type type, Symbol owner)1479     Name outerThisName(Type type, Symbol owner) {
1480         Type t = type.getEnclosingType();
1481         int nestingLevel = 0;
1482         while (t.hasTag(CLASS)) {
1483             t = t.getEnclosingType();
1484             nestingLevel++;
1485         }
1486         Name result = names.fromString("this" + target.syntheticNameChar() + nestingLevel);
1487         while (owner.kind == TYP && ((ClassSymbol)owner).members().findFirst(result) != null)
1488             result = names.fromString(result.toString() + target.syntheticNameChar());
1489         return result;
1490     }
1491 
makeOuterThisVarSymbol(Symbol owner, long flags)1492     private VarSymbol makeOuterThisVarSymbol(Symbol owner, long flags) {
1493         Type target = types.erasure(owner.enclClass().type.getEnclosingType());
1494         VarSymbol outerThis =
1495             new VarSymbol(flags, outerThisName(target, owner), target, owner);
1496         outerThisStack = outerThisStack.prepend(outerThis);
1497         return outerThis;
1498     }
1499 
makeOuterThisVarDecl(int pos, VarSymbol sym)1500     private JCVariableDecl makeOuterThisVarDecl(int pos, VarSymbol sym) {
1501         JCVariableDecl vd = make.at(pos).VarDef(sym, null);
1502         vd.vartype = access(vd.vartype);
1503         return vd;
1504     }
1505 
1506     /** Definition for this$n field.
1507      *  @param pos        The source code position of the definition.
1508      *  @param owner      The method in which the definition goes.
1509      */
outerThisDef(int pos, MethodSymbol owner)1510     JCVariableDecl outerThisDef(int pos, MethodSymbol owner) {
1511         ClassSymbol c = owner.enclClass();
1512         boolean isMandated =
1513             // Anonymous constructors
1514             (owner.isConstructor() && owner.isAnonymous()) ||
1515             // Constructors of non-private inner member classes
1516             (owner.isConstructor() && c.isInner() &&
1517              !c.isPrivate() && !c.isStatic());
1518         long flags =
1519             FINAL | (isMandated ? MANDATED : SYNTHETIC) | PARAMETER;
1520         VarSymbol outerThis = makeOuterThisVarSymbol(owner, flags);
1521         owner.extraParams = owner.extraParams.prepend(outerThis);
1522         return makeOuterThisVarDecl(pos, outerThis);
1523     }
1524 
1525     /** Definition for this$n field.
1526      *  @param pos        The source code position of the definition.
1527      *  @param owner      The class in which the definition goes.
1528      */
outerThisDef(int pos, ClassSymbol owner)1529     JCVariableDecl outerThisDef(int pos, ClassSymbol owner) {
1530         VarSymbol outerThis = makeOuterThisVarSymbol(owner, FINAL | SYNTHETIC);
1531         return makeOuterThisVarDecl(pos, outerThis);
1532     }
1533 
1534     /** Return a list of trees that load the free variables in given list,
1535      *  in reverse order.
1536      *  @param pos          The source code position to be used for the trees.
1537      *  @param freevars     The list of free variables.
1538      */
loadFreevars(DiagnosticPosition pos, List<VarSymbol> freevars)1539     List<JCExpression> loadFreevars(DiagnosticPosition pos, List<VarSymbol> freevars) {
1540         List<JCExpression> args = List.nil();
1541         for (List<VarSymbol> l = freevars; l.nonEmpty(); l = l.tail)
1542             args = args.prepend(loadFreevar(pos, l.head));
1543         return args;
1544     }
1545 //where
loadFreevar(DiagnosticPosition pos, VarSymbol v)1546         JCExpression loadFreevar(DiagnosticPosition pos, VarSymbol v) {
1547             return access(v, make.at(pos).Ident(v), null, false);
1548         }
1549 
1550     /** Construct a tree simulating the expression {@code C.this}.
1551      *  @param pos           The source code position to be used for the tree.
1552      *  @param c             The qualifier class.
1553      */
makeThis(DiagnosticPosition pos, TypeSymbol c)1554     JCExpression makeThis(DiagnosticPosition pos, TypeSymbol c) {
1555         if (currentClass == c) {
1556             // in this case, `this' works fine
1557             return make.at(pos).This(c.erasure(types));
1558         } else {
1559             // need to go via this$n
1560             return makeOuterThis(pos, c);
1561         }
1562     }
1563 
1564     /**
1565      * Optionally replace a try statement with the desugaring of a
1566      * try-with-resources statement.  The canonical desugaring of
1567      *
1568      * try ResourceSpecification
1569      *   Block
1570      *
1571      * is
1572      *
1573      * {
1574      *   final VariableModifiers_minus_final R #resource = Expression;
1575      *
1576      *   try ResourceSpecificationtail
1577      *     Block
1578      *   } body-only-finally {
1579      *     if (#resource != null) //nullcheck skipped if Expression is provably non-null
1580      *         #resource.close();
1581      *   } catch (Throwable #primaryException) {
1582      *       if (#resource != null) //nullcheck skipped if Expression is provably non-null
1583      *           try {
1584      *               #resource.close();
1585      *           } catch (Throwable #suppressedException) {
1586      *              #primaryException.addSuppressed(#suppressedException);
1587      *           }
1588      *       throw #primaryException;
1589      *   }
1590      * }
1591      *
1592      * @param tree  The try statement to inspect.
1593      * @return A a desugared try-with-resources tree, or the original
1594      * try block if there are no resources to manage.
1595      */
makeTwrTry(JCTry tree)1596     JCTree makeTwrTry(JCTry tree) {
1597         make_at(tree.pos());
1598         twrVars = twrVars.dup();
1599         JCBlock twrBlock = makeTwrBlock(tree.resources, tree.body, 0);
1600         if (tree.catchers.isEmpty() && tree.finalizer == null)
1601             result = translate(twrBlock);
1602         else
1603             result = translate(make.Try(twrBlock, tree.catchers, tree.finalizer));
1604         twrVars = twrVars.leave();
1605         return result;
1606     }
1607 
makeTwrBlock(List<JCTree> resources, JCBlock block, int depth)1608     private JCBlock makeTwrBlock(List<JCTree> resources, JCBlock block, int depth) {
1609         if (resources.isEmpty())
1610             return block;
1611 
1612         // Add resource declaration or expression to block statements
1613         ListBuffer<JCStatement> stats = new ListBuffer<>();
1614         JCTree resource = resources.head;
1615         JCExpression resourceUse;
1616         boolean resourceNonNull;
1617         if (resource instanceof JCVariableDecl) {
1618             JCVariableDecl var = (JCVariableDecl) resource;
1619             resourceUse = make.Ident(var.sym).setType(resource.type);
1620             resourceNonNull = var.init != null && TreeInfo.skipParens(var.init).hasTag(NEWCLASS);
1621             stats.add(var);
1622         } else {
1623             Assert.check(resource instanceof JCExpression);
1624             VarSymbol syntheticTwrVar =
1625             new VarSymbol(SYNTHETIC | FINAL,
1626                           makeSyntheticName(names.fromString("twrVar" +
1627                                            depth), twrVars),
1628                           (resource.type.hasTag(BOT)) ?
1629                           syms.autoCloseableType : resource.type,
1630                           currentMethodSym);
1631             twrVars.enter(syntheticTwrVar);
1632             JCVariableDecl syntheticTwrVarDecl =
1633                 make.VarDef(syntheticTwrVar, (JCExpression)resource);
1634             resourceUse = (JCExpression)make.Ident(syntheticTwrVar);
1635             resourceNonNull = false;
1636             stats.add(syntheticTwrVarDecl);
1637         }
1638 
1639         //create (semi-) finally block that will be copied into the main try body:
1640         int oldPos = make.pos;
1641         make.at(TreeInfo.endPos(block));
1642 
1643         // if (#resource != null) { #resource.close(); }
1644         JCStatement bodyCloseStatement = makeResourceCloseInvocation(resourceUse);
1645 
1646         if (!resourceNonNull) {
1647             bodyCloseStatement = make.If(makeNonNullCheck(resourceUse),
1648                                          bodyCloseStatement,
1649                                          null);
1650         }
1651 
1652         JCBlock finallyClause = make.Block(BODY_ONLY_FINALIZE, List.of(bodyCloseStatement));
1653         make.at(oldPos);
1654 
1655         // Create catch clause that saves exception, closes the resource and then rethrows the exception:
1656         VarSymbol primaryException =
1657             new VarSymbol(FINAL|SYNTHETIC,
1658                           names.fromString("t" +
1659                                            target.syntheticNameChar()),
1660                           syms.throwableType,
1661                           currentMethodSym);
1662         JCVariableDecl primaryExceptionDecl = make.VarDef(primaryException, null);
1663 
1664         // close resource:
1665         // try {
1666         //     #resource.close();
1667         // } catch (Throwable #suppressedException) {
1668         //     #primaryException.addSuppressed(#suppressedException);
1669         // }
1670         VarSymbol suppressedException =
1671             new VarSymbol(SYNTHETIC, make.paramName(2),
1672                           syms.throwableType,
1673                           currentMethodSym);
1674         JCStatement addSuppressedStatement =
1675             make.Exec(makeCall(make.Ident(primaryException),
1676                                names.addSuppressed,
1677                                List.of(make.Ident(suppressedException))));
1678         JCBlock closeResourceTryBlock =
1679             make.Block(0L, List.of(makeResourceCloseInvocation(resourceUse)));
1680         JCVariableDecl catchSuppressedDecl = make.VarDef(suppressedException, null);
1681         JCBlock catchSuppressedBlock = make.Block(0L, List.of(addSuppressedStatement));
1682         List<JCCatch> catchSuppressedClauses =
1683                 List.of(make.Catch(catchSuppressedDecl, catchSuppressedBlock));
1684         JCTry closeResourceTry = make.Try(closeResourceTryBlock, catchSuppressedClauses, null);
1685         closeResourceTry.finallyCanCompleteNormally = true;
1686 
1687         JCStatement exceptionalCloseStatement = closeResourceTry;
1688 
1689         if (!resourceNonNull) {
1690             // if (#resource != null) {  }
1691             exceptionalCloseStatement = make.If(makeNonNullCheck(resourceUse),
1692                                                 exceptionalCloseStatement,
1693                                                 null);
1694         }
1695 
1696         JCStatement exceptionalRethrow = make.Throw(make.Ident(primaryException));
1697         JCBlock exceptionalCloseBlock = make.Block(0L, List.of(exceptionalCloseStatement, exceptionalRethrow));
1698         JCCatch exceptionalCatchClause = make.Catch(primaryExceptionDecl, exceptionalCloseBlock);
1699 
1700         //create the main try statement with the close:
1701         JCTry outerTry = make.Try(makeTwrBlock(resources.tail, block, depth + 1),
1702                                   List.of(exceptionalCatchClause),
1703                                   finallyClause);
1704 
1705         outerTry.finallyCanCompleteNormally = true;
1706         stats.add(outerTry);
1707 
1708         JCBlock newBlock = make.Block(0L, stats.toList());
1709         return newBlock;
1710     }
1711 
makeResourceCloseInvocation(JCExpression resource)1712     private JCStatement makeResourceCloseInvocation(JCExpression resource) {
1713         // convert to AutoCloseable if needed
1714         if (types.asSuper(resource.type, syms.autoCloseableType.tsym) == null) {
1715             resource = convert(resource, syms.autoCloseableType);
1716         }
1717 
1718         // create resource.close() method invocation
1719         JCExpression resourceClose = makeCall(resource,
1720                                               names.close,
1721                                               List.nil());
1722         return make.Exec(resourceClose);
1723     }
1724 
makeNonNullCheck(JCExpression expression)1725     private JCExpression makeNonNullCheck(JCExpression expression) {
1726         return makeBinary(NE, expression, makeNull());
1727     }
1728 
1729     /** Construct a tree that represents the outer instance
1730      *  {@code C.this}. Never pick the current `this'.
1731      *  @param pos           The source code position to be used for the tree.
1732      *  @param c             The qualifier class.
1733      */
makeOuterThis(DiagnosticPosition pos, TypeSymbol c)1734     JCExpression makeOuterThis(DiagnosticPosition pos, TypeSymbol c) {
1735         List<VarSymbol> ots = outerThisStack;
1736         if (ots.isEmpty()) {
1737             log.error(pos, Errors.NoEnclInstanceOfTypeInScope(c));
1738             Assert.error();
1739             return makeNull();
1740         }
1741         VarSymbol ot = ots.head;
1742         JCExpression tree = access(make.at(pos).Ident(ot));
1743         TypeSymbol otc = ot.type.tsym;
1744         while (otc != c) {
1745             do {
1746                 ots = ots.tail;
1747                 if (ots.isEmpty()) {
1748                     log.error(pos, Errors.NoEnclInstanceOfTypeInScope(c));
1749                     Assert.error(); // should have been caught in Attr
1750                     return tree;
1751                 }
1752                 ot = ots.head;
1753             } while (ot.owner != otc);
1754             if (otc.owner.kind != PCK && !otc.hasOuterInstance()) {
1755                 chk.earlyRefError(pos, c);
1756                 Assert.error(); // should have been caught in Attr
1757                 return makeNull();
1758             }
1759             tree = access(make.at(pos).Select(tree, ot));
1760             otc = ot.type.tsym;
1761         }
1762         return tree;
1763     }
1764 
1765     /** Construct a tree that represents the closest outer instance
1766      *  {@code C.this} such that the given symbol is a member of C.
1767      *  @param pos           The source code position to be used for the tree.
1768      *  @param sym           The accessed symbol.
1769      *  @param preciseMatch  should we accept a type that is a subtype of
1770      *                       sym's owner, even if it doesn't contain sym
1771      *                       due to hiding, overriding, or non-inheritance
1772      *                       due to protection?
1773      */
makeOwnerThis(DiagnosticPosition pos, Symbol sym, boolean preciseMatch)1774     JCExpression makeOwnerThis(DiagnosticPosition pos, Symbol sym, boolean preciseMatch) {
1775         Symbol c = sym.owner;
1776         if (preciseMatch ? sym.isMemberOf(currentClass, types)
1777                          : currentClass.isSubClass(sym.owner, types)) {
1778             // in this case, `this' works fine
1779             return make.at(pos).This(c.erasure(types));
1780         } else {
1781             // need to go via this$n
1782             return makeOwnerThisN(pos, sym, preciseMatch);
1783         }
1784     }
1785 
1786     /**
1787      * Similar to makeOwnerThis but will never pick "this".
1788      */
makeOwnerThisN(DiagnosticPosition pos, Symbol sym, boolean preciseMatch)1789     JCExpression makeOwnerThisN(DiagnosticPosition pos, Symbol sym, boolean preciseMatch) {
1790         Symbol c = sym.owner;
1791         List<VarSymbol> ots = outerThisStack;
1792         if (ots.isEmpty()) {
1793             log.error(pos, Errors.NoEnclInstanceOfTypeInScope(c));
1794             Assert.error();
1795             return makeNull();
1796         }
1797         VarSymbol ot = ots.head;
1798         JCExpression tree = access(make.at(pos).Ident(ot));
1799         TypeSymbol otc = ot.type.tsym;
1800         while (!(preciseMatch ? sym.isMemberOf(otc, types) : otc.isSubClass(sym.owner, types))) {
1801             do {
1802                 ots = ots.tail;
1803                 if (ots.isEmpty()) {
1804                     log.error(pos, Errors.NoEnclInstanceOfTypeInScope(c));
1805                     Assert.error();
1806                     return tree;
1807                 }
1808                 ot = ots.head;
1809             } while (ot.owner != otc);
1810             tree = access(make.at(pos).Select(tree, ot));
1811             otc = ot.type.tsym;
1812         }
1813         return tree;
1814     }
1815 
1816     /** Return tree simulating the assignment {@code this.name = name}, where
1817      *  name is the name of a free variable.
1818      */
initField(int pos, Symbol rhs, Symbol lhs)1819     JCStatement initField(int pos, Symbol rhs, Symbol lhs) {
1820         Assert.check(rhs.owner.kind == MTH);
1821         Assert.check(rhs.owner.owner == lhs.owner);
1822         make.at(pos);
1823         return
1824             make.Exec(
1825                 make.Assign(
1826                     make.Select(make.This(lhs.owner.erasure(types)), lhs),
1827                     make.Ident(rhs)).setType(lhs.erasure(types)));
1828     }
1829 
1830     /** Return tree simulating the assignment {@code this.this$n = this$n}.
1831      */
initOuterThis(int pos)1832     JCStatement initOuterThis(int pos) {
1833         VarSymbol rhs = outerThisStack.head;
1834         Assert.check(rhs.owner.kind == MTH);
1835         VarSymbol lhs = outerThisStack.tail.head;
1836         Assert.check(rhs.owner.owner == lhs.owner);
1837         make.at(pos);
1838         return
1839             make.Exec(
1840                 make.Assign(
1841                     make.Select(make.This(lhs.owner.erasure(types)), lhs),
1842                     make.Ident(rhs)).setType(lhs.erasure(types)));
1843     }
1844 
1845 /**************************************************************************
1846  * Code for .class
1847  *************************************************************************/
1848 
1849     /** Return the symbol of a class to contain a cache of
1850      *  compiler-generated statics such as class$ and the
1851      *  $assertionsDisabled flag.  We create an anonymous nested class
1852      *  (unless one already exists) and return its symbol.  However,
1853      *  for backward compatibility in 1.4 and earlier we use the
1854      *  top-level class itself.
1855      */
outerCacheClass()1856     private ClassSymbol outerCacheClass() {
1857         ClassSymbol clazz = outermostClassDef.sym;
1858         Scope s = clazz.members();
1859         for (Symbol sym : s.getSymbols(NON_RECURSIVE))
1860             if (sym.kind == TYP &&
1861                 sym.name == names.empty &&
1862                 (sym.flags() & INTERFACE) == 0) return (ClassSymbol) sym;
1863         return makeEmptyClass(STATIC | SYNTHETIC, clazz).sym;
1864     }
1865 
1866     /** Create an attributed tree of the form left.name(). */
makeCall(JCExpression left, Name name, List<JCExpression> args)1867     private JCMethodInvocation makeCall(JCExpression left, Name name, List<JCExpression> args) {
1868         Assert.checkNonNull(left.type);
1869         Symbol funcsym = lookupMethod(make_pos, name, left.type,
1870                                       TreeInfo.types(args));
1871         return make.App(make.Select(left, funcsym), args);
1872     }
1873 
1874     /** The tree simulating a T.class expression.
1875      *  @param clazz      The tree identifying type T.
1876      */
classOf(JCTree clazz)1877     private JCExpression classOf(JCTree clazz) {
1878         return classOfType(clazz.type, clazz.pos());
1879     }
1880 
classOfType(Type type, DiagnosticPosition pos)1881     private JCExpression classOfType(Type type, DiagnosticPosition pos) {
1882         switch (type.getTag()) {
1883         case BYTE: case SHORT: case CHAR: case INT: case LONG: case FLOAT:
1884         case DOUBLE: case BOOLEAN: case VOID:
1885             // replace with <BoxedClass>.TYPE
1886             ClassSymbol c = types.boxedClass(type);
1887             Symbol typeSym =
1888                 rs.accessBase(
1889                     rs.findIdentInType(pos, attrEnv, c.type, names.TYPE, KindSelector.VAR),
1890                     pos, c.type, names.TYPE, true);
1891             if (typeSym.kind == VAR)
1892                 ((VarSymbol)typeSym).getConstValue(); // ensure initializer is evaluated
1893             return make.QualIdent(typeSym);
1894         case CLASS: case ARRAY:
1895                 VarSymbol sym = new VarSymbol(
1896                         STATIC | PUBLIC | FINAL, names._class,
1897                         syms.classType, type.tsym);
1898                 return make_at(pos).Select(make.Type(type), sym);
1899         default:
1900             throw new AssertionError();
1901         }
1902     }
1903 
1904 /**************************************************************************
1905  * Code for enabling/disabling assertions.
1906  *************************************************************************/
1907 
1908     private ClassSymbol assertionsDisabledClassCache;
1909 
1910     /**Used to create an auxiliary class to hold $assertionsDisabled for interfaces.
1911      */
assertionsDisabledClass()1912     private ClassSymbol assertionsDisabledClass() {
1913         if (assertionsDisabledClassCache != null) return assertionsDisabledClassCache;
1914 
1915         assertionsDisabledClassCache = makeEmptyClass(STATIC | SYNTHETIC, outermostClassDef.sym).sym;
1916 
1917         return assertionsDisabledClassCache;
1918     }
1919 
1920     // This code is not particularly robust if the user has
1921     // previously declared a member named '$assertionsDisabled'.
1922     // The same faulty idiom also appears in the translation of
1923     // class literals above.  We should report an error if a
1924     // previous declaration is not synthetic.
1925 
assertFlagTest(DiagnosticPosition pos)1926     private JCExpression assertFlagTest(DiagnosticPosition pos) {
1927         // Outermost class may be either true class or an interface.
1928         ClassSymbol outermostClass = outermostClassDef.sym;
1929 
1930         //only classes can hold a non-public field, look for a usable one:
1931         ClassSymbol container = !currentClass.isInterface() ? currentClass :
1932                 assertionsDisabledClass();
1933 
1934         VarSymbol assertDisabledSym =
1935             (VarSymbol)lookupSynthetic(dollarAssertionsDisabled,
1936                                        container.members());
1937         if (assertDisabledSym == null) {
1938             assertDisabledSym =
1939                 new VarSymbol(STATIC | FINAL | SYNTHETIC,
1940                               dollarAssertionsDisabled,
1941                               syms.booleanType,
1942                               container);
1943             enterSynthetic(pos, assertDisabledSym, container.members());
1944             Symbol desiredAssertionStatusSym = lookupMethod(pos,
1945                                                             names.desiredAssertionStatus,
1946                                                             types.erasure(syms.classType),
1947                                                             List.nil());
1948             JCClassDecl containerDef = classDef(container);
1949             make_at(containerDef.pos());
1950             JCExpression notStatus = makeUnary(NOT, make.App(make.Select(
1951                     classOfType(types.erasure(outermostClass.type),
1952                                 containerDef.pos()),
1953                     desiredAssertionStatusSym)));
1954             JCVariableDecl assertDisabledDef = make.VarDef(assertDisabledSym,
1955                                                    notStatus);
1956             containerDef.defs = containerDef.defs.prepend(assertDisabledDef);
1957 
1958             if (currentClass.isInterface()) {
1959                 //need to load the assertions enabled/disabled state while
1960                 //initializing the interface:
1961                 JCClassDecl currentClassDef = classDef(currentClass);
1962                 make_at(currentClassDef.pos());
1963                 JCStatement dummy = make.If(make.QualIdent(assertDisabledSym), make.Skip(), null);
1964                 JCBlock clinit = make.Block(STATIC, List.of(dummy));
1965                 currentClassDef.defs = currentClassDef.defs.prepend(clinit);
1966             }
1967         }
1968         make_at(pos);
1969         return makeUnary(NOT, make.Ident(assertDisabledSym));
1970     }
1971 
1972 
1973 /**************************************************************************
1974  * Building blocks for let expressions
1975  *************************************************************************/
1976 
1977     interface TreeBuilder {
build(JCExpression arg)1978         JCExpression build(JCExpression arg);
1979     }
1980 
1981     /** Construct an expression using the builder, with the given rval
1982      *  expression as an argument to the builder.  However, the rval
1983      *  expression must be computed only once, even if used multiple
1984      *  times in the result of the builder.  We do that by
1985      *  constructing a "let" expression that saves the rvalue into a
1986      *  temporary variable and then uses the temporary variable in
1987      *  place of the expression built by the builder.  The complete
1988      *  resulting expression is of the form
1989      *  <pre>
1990      *    (let <b>TYPE</b> <b>TEMP</b> = <b>RVAL</b>;
1991      *     in (<b>BUILDER</b>(<b>TEMP</b>)))
1992      *  </pre>
1993      *  where <code><b>TEMP</b></code> is a newly declared variable
1994      *  in the let expression.
1995      */
abstractRval(JCExpression rval, Type type, TreeBuilder builder)1996     JCExpression abstractRval(JCExpression rval, Type type, TreeBuilder builder) {
1997         rval = TreeInfo.skipParens(rval);
1998         switch (rval.getTag()) {
1999         case LITERAL:
2000             return builder.build(rval);
2001         case IDENT:
2002             JCIdent id = (JCIdent) rval;
2003             if ((id.sym.flags() & FINAL) != 0 && id.sym.owner.kind == MTH)
2004                 return builder.build(rval);
2005         }
2006         Name name = TreeInfo.name(rval);
2007         if (name == names._super || name == names._this)
2008             return builder.build(rval);
2009         VarSymbol var =
2010             new VarSymbol(FINAL|SYNTHETIC,
2011                           names.fromString(
2012                                           target.syntheticNameChar()
2013                                           + "" + rval.hashCode()),
2014                                       type,
2015                                       currentMethodSym);
2016         rval = convert(rval,type);
2017         JCVariableDecl def = make.VarDef(var, rval); // XXX cast
2018         JCExpression built = builder.build(make.Ident(var));
2019         JCExpression res = make.LetExpr(def, built);
2020         res.type = built.type;
2021         return res;
2022     }
2023 
2024     // same as above, with the type of the temporary variable computed
abstractRval(JCExpression rval, TreeBuilder builder)2025     JCExpression abstractRval(JCExpression rval, TreeBuilder builder) {
2026         return abstractRval(rval, rval.type, builder);
2027     }
2028 
2029     // same as above, but for an expression that may be used as either
2030     // an rvalue or an lvalue.  This requires special handling for
2031     // Select expressions, where we place the left-hand-side of the
2032     // select in a temporary, and for Indexed expressions, where we
2033     // place both the indexed expression and the index value in temps.
abstractLval(JCExpression lval, final TreeBuilder builder)2034     JCExpression abstractLval(JCExpression lval, final TreeBuilder builder) {
2035         lval = TreeInfo.skipParens(lval);
2036         switch (lval.getTag()) {
2037         case IDENT:
2038             return builder.build(lval);
2039         case SELECT: {
2040             final JCFieldAccess s = (JCFieldAccess)lval;
2041             Symbol lid = TreeInfo.symbol(s.selected);
2042             if (lid != null && lid.kind == TYP) return builder.build(lval);
2043             return abstractRval(s.selected, selected -> builder.build(make.Select(selected, s.sym)));
2044         }
2045         case INDEXED: {
2046             final JCArrayAccess i = (JCArrayAccess)lval;
2047             return abstractRval(i.indexed, indexed -> abstractRval(i.index, syms.intType, index -> {
2048                 JCExpression newLval = make.Indexed(indexed, index);
2049                 newLval.setType(i.type);
2050                 return builder.build(newLval);
2051             }));
2052         }
2053         case TYPECAST: {
2054             return abstractLval(((JCTypeCast)lval).expr, builder);
2055         }
2056         }
2057         throw new AssertionError(lval);
2058     }
2059 
2060     // evaluate and discard the first expression, then evaluate the second.
makeComma(final JCExpression expr1, final JCExpression expr2)2061     JCExpression makeComma(final JCExpression expr1, final JCExpression expr2) {
2062         JCExpression res = make.LetExpr(List.of(make.Exec(expr1)), expr2);
2063         res.type = expr2.type;
2064         return res;
2065     }
2066 
2067 /**************************************************************************
2068  * Translation methods
2069  *************************************************************************/
2070 
2071     /** Visitor argument: enclosing operator node.
2072      */
2073     private JCExpression enclOp;
2074 
2075     /** Visitor method: Translate a single node.
2076      *  Attach the source position from the old tree to its replacement tree.
2077      */
2078     @Override
translate(T tree)2079     public <T extends JCTree> T translate(T tree) {
2080         if (tree == null) {
2081             return null;
2082         } else {
2083             make_at(tree.pos());
2084             T result = super.translate(tree);
2085             if (endPosTable != null && result != tree) {
2086                 endPosTable.replaceTree(tree, result);
2087             }
2088             return result;
2089         }
2090     }
2091 
2092     /** Visitor method: Translate a single node, boxing or unboxing if needed.
2093      */
translate(T tree, Type type)2094     public <T extends JCExpression> T translate(T tree, Type type) {
2095         return (tree == null) ? null : boxIfNeeded(translate(tree), type);
2096     }
2097 
2098     /** Visitor method: Translate tree.
2099      */
translate(T tree, JCExpression enclOp)2100     public <T extends JCTree> T translate(T tree, JCExpression enclOp) {
2101         JCExpression prevEnclOp = this.enclOp;
2102         this.enclOp = enclOp;
2103         T res = translate(tree);
2104         this.enclOp = prevEnclOp;
2105         return res;
2106     }
2107 
2108     /** Visitor method: Translate list of trees.
2109      */
translate(List<T> trees, Type type)2110     public <T extends JCExpression> List<T> translate(List<T> trees, Type type) {
2111         if (trees == null) return null;
2112         for (List<T> l = trees; l.nonEmpty(); l = l.tail)
2113             l.head = translate(l.head, type);
2114         return trees;
2115     }
2116 
visitPackageDef(JCPackageDecl tree)2117     public void visitPackageDef(JCPackageDecl tree) {
2118         if (!needPackageInfoClass(tree))
2119                         return;
2120 
2121         long flags = Flags.ABSTRACT | Flags.INTERFACE;
2122         // package-info is marked SYNTHETIC in JDK 1.6 and later releases
2123         flags = flags | Flags.SYNTHETIC;
2124         ClassSymbol c = tree.packge.package_info;
2125         c.setAttributes(tree.packge);
2126         c.flags_field |= flags;
2127         ClassType ctype = (ClassType) c.type;
2128         ctype.supertype_field = syms.objectType;
2129         ctype.interfaces_field = List.nil();
2130         createInfoClass(tree.annotations, c);
2131     }
2132     // where
needPackageInfoClass(JCPackageDecl pd)2133     private boolean needPackageInfoClass(JCPackageDecl pd) {
2134         switch (pkginfoOpt) {
2135             case ALWAYS:
2136                 return true;
2137             case LEGACY:
2138                 return pd.getAnnotations().nonEmpty();
2139             case NONEMPTY:
2140                 for (Attribute.Compound a :
2141                          pd.packge.getDeclarationAttributes()) {
2142                     Attribute.RetentionPolicy p = types.getRetention(a);
2143                     if (p != Attribute.RetentionPolicy.SOURCE)
2144                         return true;
2145                 }
2146                 return false;
2147         }
2148         throw new AssertionError();
2149     }
2150 
visitModuleDef(JCModuleDecl tree)2151     public void visitModuleDef(JCModuleDecl tree) {
2152         ModuleSymbol msym = tree.sym;
2153         ClassSymbol c = msym.module_info;
2154         c.setAttributes(msym);
2155         c.flags_field |= Flags.MODULE;
2156         createInfoClass(List.nil(), tree.sym.module_info);
2157     }
2158 
createInfoClass(List<JCAnnotation> annots, ClassSymbol c)2159     private void createInfoClass(List<JCAnnotation> annots, ClassSymbol c) {
2160         long flags = Flags.ABSTRACT | Flags.INTERFACE;
2161         JCClassDecl infoClass =
2162                 make.ClassDef(make.Modifiers(flags, annots),
2163                     c.name, List.nil(),
2164                     null, List.nil(), List.nil());
2165         infoClass.sym = c;
2166         translated.append(infoClass);
2167     }
2168 
visitClassDef(JCClassDecl tree)2169     public void visitClassDef(JCClassDecl tree) {
2170         Env<AttrContext> prevEnv = attrEnv;
2171         ClassSymbol currentClassPrev = currentClass;
2172         MethodSymbol currentMethodSymPrev = currentMethodSym;
2173 
2174         currentClass = tree.sym;
2175         currentMethodSym = null;
2176         attrEnv = typeEnvs.remove(currentClass);
2177         if (attrEnv == null)
2178             attrEnv = prevEnv;
2179 
2180         classdefs.put(currentClass, tree);
2181 
2182         Map<Symbol, Symbol> prevProxies = proxies;
2183         proxies = new HashMap<>(proxies);
2184         List<VarSymbol> prevOuterThisStack = outerThisStack;
2185 
2186         // If this is an enum definition
2187         if ((tree.mods.flags & ENUM) != 0 &&
2188             (types.supertype(currentClass.type).tsym.flags() & ENUM) == 0)
2189             visitEnumDef(tree);
2190 
2191         // If this is a nested class, define a this$n field for
2192         // it and add to proxies.
2193         JCVariableDecl otdef = null;
2194         if (currentClass.hasOuterInstance())
2195             otdef = outerThisDef(tree.pos, currentClass);
2196 
2197         // If this is a local class, define proxies for all its free variables.
2198         List<JCVariableDecl> fvdefs = freevarDefs(
2199             tree.pos, freevars(currentClass), currentClass);
2200 
2201         // Recursively translate superclass, interfaces.
2202         tree.extending = translate(tree.extending);
2203         tree.implementing = translate(tree.implementing);
2204 
2205         if (currentClass.isLocal()) {
2206             ClassSymbol encl = currentClass.owner.enclClass();
2207             if (encl.trans_local == null) {
2208                 encl.trans_local = List.nil();
2209             }
2210             encl.trans_local = encl.trans_local.prepend(currentClass);
2211         }
2212 
2213         // Recursively translate members, taking into account that new members
2214         // might be created during the translation and prepended to the member
2215         // list `tree.defs'.
2216         List<JCTree> seen = List.nil();
2217         while (tree.defs != seen) {
2218             List<JCTree> unseen = tree.defs;
2219             for (List<JCTree> l = unseen; l.nonEmpty() && l != seen; l = l.tail) {
2220                 JCTree outermostMemberDefPrev = outermostMemberDef;
2221                 if (outermostMemberDefPrev == null) outermostMemberDef = l.head;
2222                 l.head = translate(l.head);
2223                 outermostMemberDef = outermostMemberDefPrev;
2224             }
2225             seen = unseen;
2226         }
2227 
2228         // Convert a protected modifier to public, mask static modifier.
2229         if ((tree.mods.flags & PROTECTED) != 0) tree.mods.flags |= PUBLIC;
2230         tree.mods.flags &= ClassFlags;
2231 
2232         // Convert name to flat representation, replacing '.' by '$'.
2233         tree.name = Convert.shortName(currentClass.flatName());
2234 
2235         // Add this$n and free variables proxy definitions to class.
2236 
2237         for (List<JCVariableDecl> l = fvdefs; l.nonEmpty(); l = l.tail) {
2238             tree.defs = tree.defs.prepend(l.head);
2239             enterSynthetic(tree.pos(), l.head.sym, currentClass.members());
2240         }
2241         if (currentClass.hasOuterInstance()) {
2242             tree.defs = tree.defs.prepend(otdef);
2243             enterSynthetic(tree.pos(), otdef.sym, currentClass.members());
2244         }
2245 
2246         proxies = prevProxies;
2247         outerThisStack = prevOuterThisStack;
2248 
2249         // Append translated tree to `translated' queue.
2250         translated.append(tree);
2251 
2252         attrEnv = prevEnv;
2253         currentClass = currentClassPrev;
2254         currentMethodSym = currentMethodSymPrev;
2255 
2256         // Return empty block {} as a placeholder for an inner class.
2257         result = make_at(tree.pos()).Block(SYNTHETIC, List.nil());
2258     }
2259 
2260     /** Translate an enum class. */
visitEnumDef(JCClassDecl tree)2261     private void visitEnumDef(JCClassDecl tree) {
2262         make_at(tree.pos());
2263 
2264         // add the supertype, if needed
2265         if (tree.extending == null)
2266             tree.extending = make.Type(types.supertype(tree.type));
2267 
2268         // classOfType adds a cache field to tree.defs
2269         JCExpression e_class = classOfType(tree.sym.type, tree.pos()).
2270             setType(types.erasure(syms.classType));
2271 
2272         // process each enumeration constant, adding implicit constructor parameters
2273         int nextOrdinal = 0;
2274         ListBuffer<JCExpression> values = new ListBuffer<>();
2275         ListBuffer<JCTree> enumDefs = new ListBuffer<>();
2276         ListBuffer<JCTree> otherDefs = new ListBuffer<>();
2277         for (List<JCTree> defs = tree.defs;
2278              defs.nonEmpty();
2279              defs=defs.tail) {
2280             if (defs.head.hasTag(VARDEF) && (((JCVariableDecl) defs.head).mods.flags & ENUM) != 0) {
2281                 JCVariableDecl var = (JCVariableDecl)defs.head;
2282                 visitEnumConstantDef(var, nextOrdinal++);
2283                 values.append(make.QualIdent(var.sym));
2284                 enumDefs.append(var);
2285             } else {
2286                 otherDefs.append(defs.head);
2287             }
2288         }
2289 
2290         // private static final T[] #VALUES = { a, b, c };
2291         Name valuesName = names.fromString(target.syntheticNameChar() + "VALUES");
2292         while (tree.sym.members().findFirst(valuesName) != null) // avoid name clash
2293             valuesName = names.fromString(valuesName + "" + target.syntheticNameChar());
2294         Type arrayType = new ArrayType(types.erasure(tree.type), syms.arrayClass);
2295         VarSymbol valuesVar = new VarSymbol(PRIVATE|FINAL|STATIC|SYNTHETIC,
2296                                             valuesName,
2297                                             arrayType,
2298                                             tree.type.tsym);
2299         JCNewArray newArray = make.NewArray(make.Type(types.erasure(tree.type)),
2300                                           List.nil(),
2301                                           values.toList());
2302         newArray.type = arrayType;
2303         enumDefs.append(make.VarDef(valuesVar, newArray));
2304         tree.sym.members().enter(valuesVar);
2305 
2306         Symbol valuesSym = lookupMethod(tree.pos(), names.values,
2307                                         tree.type, List.nil());
2308         List<JCStatement> valuesBody;
2309         if (useClone()) {
2310             // return (T[]) $VALUES.clone();
2311             JCTypeCast valuesResult =
2312                 make.TypeCast(valuesSym.type.getReturnType(),
2313                               make.App(make.Select(make.Ident(valuesVar),
2314                                                    syms.arrayCloneMethod)));
2315             valuesBody = List.of(make.Return(valuesResult));
2316         } else {
2317             // template: T[] $result = new T[$values.length];
2318             Name resultName = names.fromString(target.syntheticNameChar() + "result");
2319             while (tree.sym.members().findFirst(resultName) != null) // avoid name clash
2320                 resultName = names.fromString(resultName + "" + target.syntheticNameChar());
2321             VarSymbol resultVar = new VarSymbol(FINAL|SYNTHETIC,
2322                                                 resultName,
2323                                                 arrayType,
2324                                                 valuesSym);
2325             JCNewArray resultArray = make.NewArray(make.Type(types.erasure(tree.type)),
2326                                   List.of(make.Select(make.Ident(valuesVar), syms.lengthVar)),
2327                                   null);
2328             resultArray.type = arrayType;
2329             JCVariableDecl decl = make.VarDef(resultVar, resultArray);
2330 
2331             // template: System.arraycopy($VALUES, 0, $result, 0, $VALUES.length);
2332             if (systemArraycopyMethod == null) {
2333                 systemArraycopyMethod =
2334                     new MethodSymbol(PUBLIC | STATIC,
2335                                      names.fromString("arraycopy"),
2336                                      new MethodType(List.of(syms.objectType,
2337                                                             syms.intType,
2338                                                             syms.objectType,
2339                                                             syms.intType,
2340                                                             syms.intType),
2341                                                     syms.voidType,
2342                                                     List.nil(),
2343                                                     syms.methodClass),
2344                                      syms.systemType.tsym);
2345             }
2346             JCStatement copy =
2347                 make.Exec(make.App(make.Select(make.Ident(syms.systemType.tsym),
2348                                                systemArraycopyMethod),
2349                           List.of(make.Ident(valuesVar), make.Literal(0),
2350                                   make.Ident(resultVar), make.Literal(0),
2351                                   make.Select(make.Ident(valuesVar), syms.lengthVar))));
2352 
2353             // template: return $result;
2354             JCStatement ret = make.Return(make.Ident(resultVar));
2355             valuesBody = List.of(decl, copy, ret);
2356         }
2357 
2358         JCMethodDecl valuesDef =
2359              make.MethodDef((MethodSymbol)valuesSym, make.Block(0, valuesBody));
2360 
2361         enumDefs.append(valuesDef);
2362 
2363         if (debugLower)
2364             System.err.println(tree.sym + ".valuesDef = " + valuesDef);
2365 
2366         /** The template for the following code is:
2367          *
2368          *     public static E valueOf(String name) {
2369          *         return (E)Enum.valueOf(E.class, name);
2370          *     }
2371          *
2372          *  where E is tree.sym
2373          */
2374         MethodSymbol valueOfSym = lookupMethod(tree.pos(),
2375                          names.valueOf,
2376                          tree.sym.type,
2377                          List.of(syms.stringType));
2378         Assert.check((valueOfSym.flags() & STATIC) != 0);
2379         VarSymbol nameArgSym = valueOfSym.params.head;
2380         JCIdent nameVal = make.Ident(nameArgSym);
2381         JCStatement enum_ValueOf =
2382             make.Return(make.TypeCast(tree.sym.type,
2383                                       makeCall(make.Ident(syms.enumSym),
2384                                                names.valueOf,
2385                                                List.of(e_class, nameVal))));
2386         JCMethodDecl valueOf = make.MethodDef(valueOfSym,
2387                                            make.Block(0, List.of(enum_ValueOf)));
2388         nameVal.sym = valueOf.params.head.sym;
2389         if (debugLower)
2390             System.err.println(tree.sym + ".valueOf = " + valueOf);
2391         enumDefs.append(valueOf);
2392 
2393         enumDefs.appendList(otherDefs.toList());
2394         tree.defs = enumDefs.toList();
2395     }
2396         // where
2397         private MethodSymbol systemArraycopyMethod;
useClone()2398         private boolean useClone() {
2399             try {
2400                 return syms.objectType.tsym.members().findFirst(names.clone) != null;
2401             }
2402             catch (CompletionFailure e) {
2403                 return false;
2404             }
2405         }
2406 
2407     /** Translate an enumeration constant and its initializer. */
visitEnumConstantDef(JCVariableDecl var, int ordinal)2408     private void visitEnumConstantDef(JCVariableDecl var, int ordinal) {
2409         JCNewClass varDef = (JCNewClass)var.init;
2410         varDef.args = varDef.args.
2411             prepend(makeLit(syms.intType, ordinal)).
2412             prepend(makeLit(syms.stringType, var.name.toString()));
2413     }
2414 
visitMethodDef(JCMethodDecl tree)2415     public void visitMethodDef(JCMethodDecl tree) {
2416         if (tree.name == names.init && (currentClass.flags_field&ENUM) != 0) {
2417             // Add "String $enum$name, int $enum$ordinal" to the beginning of the
2418             // argument list for each constructor of an enum.
2419             JCVariableDecl nameParam = make_at(tree.pos()).
2420                 Param(names.fromString(target.syntheticNameChar() +
2421                                        "enum" + target.syntheticNameChar() + "name"),
2422                       syms.stringType, tree.sym);
2423             nameParam.mods.flags |= SYNTHETIC; nameParam.sym.flags_field |= SYNTHETIC;
2424             JCVariableDecl ordParam = make.
2425                 Param(names.fromString(target.syntheticNameChar() +
2426                                        "enum" + target.syntheticNameChar() +
2427                                        "ordinal"),
2428                       syms.intType, tree.sym);
2429             ordParam.mods.flags |= SYNTHETIC; ordParam.sym.flags_field |= SYNTHETIC;
2430 
2431             MethodSymbol m = tree.sym;
2432             tree.params = tree.params.prepend(ordParam).prepend(nameParam);
2433 
2434             m.extraParams = m.extraParams.prepend(ordParam.sym);
2435             m.extraParams = m.extraParams.prepend(nameParam.sym);
2436             Type olderasure = m.erasure(types);
2437             m.erasure_field = new MethodType(
2438                 olderasure.getParameterTypes().prepend(syms.intType).prepend(syms.stringType),
2439                 olderasure.getReturnType(),
2440                 olderasure.getThrownTypes(),
2441                 syms.methodClass);
2442         }
2443 
2444         JCMethodDecl prevMethodDef = currentMethodDef;
2445         MethodSymbol prevMethodSym = currentMethodSym;
2446         try {
2447             currentMethodDef = tree;
2448             currentMethodSym = tree.sym;
2449             visitMethodDefInternal(tree);
2450         } finally {
2451             currentMethodDef = prevMethodDef;
2452             currentMethodSym = prevMethodSym;
2453         }
2454     }
2455 
visitMethodDefInternal(JCMethodDecl tree)2456     private void visitMethodDefInternal(JCMethodDecl tree) {
2457         if (tree.name == names.init &&
2458             (currentClass.isInner() || currentClass.isLocal())) {
2459             // We are seeing a constructor of an inner class.
2460             MethodSymbol m = tree.sym;
2461 
2462             // Push a new proxy scope for constructor parameters.
2463             // and create definitions for any this$n and proxy parameters.
2464             Map<Symbol, Symbol> prevProxies = proxies;
2465             proxies = new HashMap<>(proxies);
2466             List<VarSymbol> prevOuterThisStack = outerThisStack;
2467             List<VarSymbol> fvs = freevars(currentClass);
2468             JCVariableDecl otdef = null;
2469             if (currentClass.hasOuterInstance())
2470                 otdef = outerThisDef(tree.pos, m);
2471             List<JCVariableDecl> fvdefs = freevarDefs(tree.pos, fvs, m, PARAMETER);
2472 
2473             // Recursively translate result type, parameters and thrown list.
2474             tree.restype = translate(tree.restype);
2475             tree.params = translateVarDefs(tree.params);
2476             tree.thrown = translate(tree.thrown);
2477 
2478             // when compiling stubs, don't process body
2479             if (tree.body == null) {
2480                 result = tree;
2481                 return;
2482             }
2483 
2484             // Add this$n (if needed) in front of and free variables behind
2485             // constructor parameter list.
2486             tree.params = tree.params.appendList(fvdefs);
2487             if (currentClass.hasOuterInstance()) {
2488                 tree.params = tree.params.prepend(otdef);
2489             }
2490 
2491             // If this is an initial constructor, i.e., it does not start with
2492             // this(...), insert initializers for this$n and proxies
2493             // before (pre-1.4, after) the call to superclass constructor.
2494             JCStatement selfCall = translate(tree.body.stats.head);
2495 
2496             List<JCStatement> added = List.nil();
2497             if (fvs.nonEmpty()) {
2498                 List<Type> addedargtypes = List.nil();
2499                 for (List<VarSymbol> l = fvs; l.nonEmpty(); l = l.tail) {
2500                     m.capturedLocals =
2501                         m.capturedLocals.prepend((VarSymbol)
2502                                                 (proxies.get(l.head)));
2503                     if (TreeInfo.isInitialConstructor(tree)) {
2504                         added = added.prepend(
2505                           initField(tree.body.pos, proxies.get(l.head), prevProxies.get(l.head)));
2506                     }
2507                     addedargtypes = addedargtypes.prepend(l.head.erasure(types));
2508                 }
2509                 Type olderasure = m.erasure(types);
2510                 m.erasure_field = new MethodType(
2511                     olderasure.getParameterTypes().appendList(addedargtypes),
2512                     olderasure.getReturnType(),
2513                     olderasure.getThrownTypes(),
2514                     syms.methodClass);
2515             }
2516             if (currentClass.hasOuterInstance() &&
2517                 TreeInfo.isInitialConstructor(tree))
2518             {
2519                 added = added.prepend(initOuterThis(tree.body.pos));
2520             }
2521 
2522             // pop local variables from proxy stack
2523             proxies = prevProxies;
2524 
2525             // recursively translate following local statements and
2526             // combine with this- or super-call
2527             List<JCStatement> stats = translate(tree.body.stats.tail);
2528             tree.body.stats = stats.prepend(selfCall).prependList(added);
2529             outerThisStack = prevOuterThisStack;
2530         } else {
2531             Map<Symbol, Symbol> prevLambdaTranslationMap =
2532                     lambdaTranslationMap;
2533             try {
2534                 lambdaTranslationMap = (tree.sym.flags() & SYNTHETIC) != 0 &&
2535                         tree.sym.name.startsWith(names.lambda) ?
2536                         makeTranslationMap(tree) : null;
2537                 super.visitMethodDef(tree);
2538             } finally {
2539                 lambdaTranslationMap = prevLambdaTranslationMap;
2540             }
2541         }
2542         result = tree;
2543     }
2544     //where
makeTranslationMap(JCMethodDecl tree)2545         private Map<Symbol, Symbol> makeTranslationMap(JCMethodDecl tree) {
2546             Map<Symbol, Symbol> translationMap = new HashMap<>();
2547             for (JCVariableDecl vd : tree.params) {
2548                 Symbol p = vd.sym;
2549                 if (p != p.baseSymbol()) {
2550                     translationMap.put(p.baseSymbol(), p);
2551                 }
2552             }
2553             return translationMap;
2554         }
2555 
visitTypeCast(JCTypeCast tree)2556     public void visitTypeCast(JCTypeCast tree) {
2557         tree.clazz = translate(tree.clazz);
2558         if (tree.type.isPrimitive() != tree.expr.type.isPrimitive())
2559             tree.expr = translate(tree.expr, tree.type);
2560         else
2561             tree.expr = translate(tree.expr);
2562         result = tree;
2563     }
2564 
visitNewClass(JCNewClass tree)2565     public void visitNewClass(JCNewClass tree) {
2566         ClassSymbol c = (ClassSymbol)tree.constructor.owner;
2567 
2568         // Box arguments, if necessary
2569         boolean isEnum = (tree.constructor.owner.flags() & ENUM) != 0;
2570         List<Type> argTypes = tree.constructor.type.getParameterTypes();
2571         if (isEnum) argTypes = argTypes.prepend(syms.intType).prepend(syms.stringType);
2572         tree.args = boxArgs(argTypes, tree.args, tree.varargsElement);
2573         tree.varargsElement = null;
2574 
2575         // If created class is local, add free variables after
2576         // explicit constructor arguments.
2577         if (c.isLocal()) {
2578             tree.args = tree.args.appendList(loadFreevars(tree.pos(), freevars(c)));
2579         }
2580 
2581         // If an access constructor is used, append null as a last argument.
2582         Symbol constructor = accessConstructor(tree.pos(), tree.constructor);
2583         if (constructor != tree.constructor) {
2584             tree.args = tree.args.append(makeNull());
2585             tree.constructor = constructor;
2586         }
2587 
2588         // If created class has an outer instance, and new is qualified, pass
2589         // qualifier as first argument. If new is not qualified, pass the
2590         // correct outer instance as first argument.
2591         if (c.hasOuterInstance()) {
2592             JCExpression thisArg;
2593             if (tree.encl != null) {
2594                 thisArg = attr.makeNullCheck(translate(tree.encl));
2595                 thisArg.type = tree.encl.type;
2596             } else if (c.isLocal()) {
2597                 // local class
2598                 thisArg = makeThis(tree.pos(), c.type.getEnclosingType().tsym);
2599             } else {
2600                 // nested class
2601                 thisArg = makeOwnerThis(tree.pos(), c, false);
2602             }
2603             tree.args = tree.args.prepend(thisArg);
2604         }
2605         tree.encl = null;
2606 
2607         // If we have an anonymous class, create its flat version, rather
2608         // than the class or interface following new.
2609         if (tree.def != null) {
2610             translate(tree.def);
2611             tree.clazz = access(make_at(tree.clazz.pos()).Ident(tree.def.sym));
2612             tree.def = null;
2613         } else {
2614             tree.clazz = access(c, tree.clazz, enclOp, false);
2615         }
2616         result = tree;
2617     }
2618 
2619     // Simplify conditionals with known constant controlling expressions.
2620     // This allows us to avoid generating supporting declarations for
2621     // the dead code, which will not be eliminated during code generation.
2622     // Note that Flow.isFalse and Flow.isTrue only return true
2623     // for constant expressions in the sense of JLS 15.27, which
2624     // are guaranteed to have no side-effects.  More aggressive
2625     // constant propagation would require that we take care to
2626     // preserve possible side-effects in the condition expression.
2627 
2628     // One common case is equality expressions involving a constant and null.
2629     // Since null is not a constant expression (because null cannot be
2630     // represented in the constant pool), equality checks involving null are
2631     // not captured by Flow.isTrue/isFalse.
2632     // Equality checks involving a constant and null, e.g.
2633     //     "" == null
2634     // are safe to simplify as no side-effects can occur.
2635 
isTrue(JCTree exp)2636     private boolean isTrue(JCTree exp) {
2637         if (exp.type.isTrue())
2638             return true;
2639         Boolean b = expValue(exp);
2640         return b == null ? false : b;
2641     }
isFalse(JCTree exp)2642     private boolean isFalse(JCTree exp) {
2643         if (exp.type.isFalse())
2644             return true;
2645         Boolean b = expValue(exp);
2646         return b == null ? false : !b;
2647     }
2648     /* look for (in)equality relations involving null.
2649      * return true - if expression is always true
2650      *       false - if expression is always false
2651      *        null - if expression cannot be eliminated
2652      */
expValue(JCTree exp)2653     private Boolean expValue(JCTree exp) {
2654         while (exp.hasTag(PARENS))
2655             exp = ((JCParens)exp).expr;
2656 
2657         boolean eq;
2658         switch (exp.getTag()) {
2659         case EQ: eq = true;  break;
2660         case NE: eq = false; break;
2661         default:
2662             return null;
2663         }
2664 
2665         // we have a JCBinary(EQ|NE)
2666         // check if we have two literals (constants or null)
2667         JCBinary b = (JCBinary)exp;
2668         if (b.lhs.type.hasTag(BOT)) return expValueIsNull(eq, b.rhs);
2669         if (b.rhs.type.hasTag(BOT)) return expValueIsNull(eq, b.lhs);
2670         return null;
2671     }
expValueIsNull(boolean eq, JCTree t)2672     private Boolean expValueIsNull(boolean eq, JCTree t) {
2673         if (t.type.hasTag(BOT)) return Boolean.valueOf(eq);
2674         if (t.hasTag(LITERAL))  return Boolean.valueOf(!eq);
2675         return null;
2676     }
2677 
2678     /** Visitor method for conditional expressions.
2679      */
2680     @Override
visitConditional(JCConditional tree)2681     public void visitConditional(JCConditional tree) {
2682         JCTree cond = tree.cond = translate(tree.cond, syms.booleanType);
2683         if (isTrue(cond)) {
2684             result = convert(translate(tree.truepart, tree.type), tree.type);
2685             addPrunedInfo(cond);
2686         } else if (isFalse(cond)) {
2687             result = convert(translate(tree.falsepart, tree.type), tree.type);
2688             addPrunedInfo(cond);
2689         } else {
2690             // Condition is not a compile-time constant.
2691             tree.truepart = translate(tree.truepart, tree.type);
2692             tree.falsepart = translate(tree.falsepart, tree.type);
2693             result = tree;
2694         }
2695     }
2696 //where
convert(JCExpression tree, Type pt)2697     private JCExpression convert(JCExpression tree, Type pt) {
2698         if (tree.type == pt || tree.type.hasTag(BOT))
2699             return tree;
2700         JCExpression result = make_at(tree.pos()).TypeCast(make.Type(pt), tree);
2701         result.type = (tree.type.constValue() != null) ? cfolder.coerce(tree.type, pt)
2702                                                        : pt;
2703         return result;
2704     }
2705 
2706     /** Visitor method for if statements.
2707      */
visitIf(JCIf tree)2708     public void visitIf(JCIf tree) {
2709         JCTree cond = tree.cond = translate(tree.cond, syms.booleanType);
2710         if (isTrue(cond)) {
2711             result = translate(tree.thenpart);
2712             addPrunedInfo(cond);
2713         } else if (isFalse(cond)) {
2714             if (tree.elsepart != null) {
2715                 result = translate(tree.elsepart);
2716             } else {
2717                 result = make.Skip();
2718             }
2719             addPrunedInfo(cond);
2720         } else {
2721             // Condition is not a compile-time constant.
2722             tree.thenpart = translate(tree.thenpart);
2723             tree.elsepart = translate(tree.elsepart);
2724             result = tree;
2725         }
2726     }
2727 
2728     /** Visitor method for assert statements. Translate them away.
2729      */
visitAssert(JCAssert tree)2730     public void visitAssert(JCAssert tree) {
2731         tree.cond = translate(tree.cond, syms.booleanType);
2732         if (!tree.cond.type.isTrue()) {
2733             JCExpression cond = assertFlagTest(tree.pos());
2734             List<JCExpression> exnArgs = (tree.detail == null) ?
2735                 List.nil() : List.of(translate(tree.detail));
2736             if (!tree.cond.type.isFalse()) {
2737                 cond = makeBinary
2738                     (AND,
2739                      cond,
2740                      makeUnary(NOT, tree.cond));
2741             }
2742             result =
2743                 make.If(cond,
2744                         make_at(tree).
2745                            Throw(makeNewClass(syms.assertionErrorType, exnArgs)),
2746                         null);
2747         } else {
2748             result = make.Skip();
2749         }
2750     }
2751 
visitApply(JCMethodInvocation tree)2752     public void visitApply(JCMethodInvocation tree) {
2753         Symbol meth = TreeInfo.symbol(tree.meth);
2754         List<Type> argtypes = meth.type.getParameterTypes();
2755         if (meth.name == names.init && meth.owner == syms.enumSym)
2756             argtypes = argtypes.tail.tail;
2757         tree.args = boxArgs(argtypes, tree.args, tree.varargsElement);
2758         tree.varargsElement = null;
2759         Name methName = TreeInfo.name(tree.meth);
2760         if (meth.name==names.init) {
2761             // We are seeing a this(...) or super(...) constructor call.
2762             // If an access constructor is used, append null as a last argument.
2763             Symbol constructor = accessConstructor(tree.pos(), meth);
2764             if (constructor != meth) {
2765                 tree.args = tree.args.append(makeNull());
2766                 TreeInfo.setSymbol(tree.meth, constructor);
2767             }
2768 
2769             // If we are calling a constructor of a local class, add
2770             // free variables after explicit constructor arguments.
2771             ClassSymbol c = (ClassSymbol)constructor.owner;
2772             if (c.isLocal()) {
2773                 tree.args = tree.args.appendList(loadFreevars(tree.pos(), freevars(c)));
2774             }
2775 
2776             // If we are calling a constructor of an enum class, pass
2777             // along the name and ordinal arguments
2778             if ((c.flags_field&ENUM) != 0 || c.getQualifiedName() == names.java_lang_Enum) {
2779                 List<JCVariableDecl> params = currentMethodDef.params;
2780                 if (currentMethodSym.owner.hasOuterInstance())
2781                     params = params.tail; // drop this$n
2782                 tree.args = tree.args
2783                     .prepend(make_at(tree.pos()).Ident(params.tail.head.sym)) // ordinal
2784                     .prepend(make.Ident(params.head.sym)); // name
2785             }
2786 
2787             // If we are calling a constructor of a class with an outer
2788             // instance, and the call
2789             // is qualified, pass qualifier as first argument in front of
2790             // the explicit constructor arguments. If the call
2791             // is not qualified, pass the correct outer instance as
2792             // first argument.
2793             if (c.hasOuterInstance()) {
2794                 JCExpression thisArg;
2795                 if (tree.meth.hasTag(SELECT)) {
2796                     thisArg = attr.
2797                         makeNullCheck(translate(((JCFieldAccess) tree.meth).selected));
2798                     tree.meth = make.Ident(constructor);
2799                     ((JCIdent) tree.meth).name = methName;
2800                 } else if (c.isLocal() || methName == names._this){
2801                     // local class or this() call
2802                     thisArg = makeThis(tree.meth.pos(), c.type.getEnclosingType().tsym);
2803                 } else {
2804                     // super() call of nested class - never pick 'this'
2805                     thisArg = makeOwnerThisN(tree.meth.pos(), c, false);
2806                 }
2807                 tree.args = tree.args.prepend(thisArg);
2808             }
2809         } else {
2810             // We are seeing a normal method invocation; translate this as usual.
2811             tree.meth = translate(tree.meth);
2812 
2813             // If the translated method itself is an Apply tree, we are
2814             // seeing an access method invocation. In this case, append
2815             // the method arguments to the arguments of the access method.
2816             if (tree.meth.hasTag(APPLY)) {
2817                 JCMethodInvocation app = (JCMethodInvocation)tree.meth;
2818                 app.args = tree.args.prependList(app.args);
2819                 result = app;
2820                 return;
2821             }
2822         }
2823         result = tree;
2824     }
2825 
boxArgs(List<Type> parameters, List<JCExpression> _args, Type varargsElement)2826     List<JCExpression> boxArgs(List<Type> parameters, List<JCExpression> _args, Type varargsElement) {
2827         List<JCExpression> args = _args;
2828         if (parameters.isEmpty()) return args;
2829         boolean anyChanges = false;
2830         ListBuffer<JCExpression> result = new ListBuffer<>();
2831         while (parameters.tail.nonEmpty()) {
2832             JCExpression arg = translate(args.head, parameters.head);
2833             anyChanges |= (arg != args.head);
2834             result.append(arg);
2835             args = args.tail;
2836             parameters = parameters.tail;
2837         }
2838         Type parameter = parameters.head;
2839         if (varargsElement != null) {
2840             anyChanges = true;
2841             ListBuffer<JCExpression> elems = new ListBuffer<>();
2842             while (args.nonEmpty()) {
2843                 JCExpression arg = translate(args.head, varargsElement);
2844                 elems.append(arg);
2845                 args = args.tail;
2846             }
2847             JCNewArray boxedArgs = make.NewArray(make.Type(varargsElement),
2848                                                List.nil(),
2849                                                elems.toList());
2850             boxedArgs.type = new ArrayType(varargsElement, syms.arrayClass);
2851             result.append(boxedArgs);
2852         } else {
2853             if (args.length() != 1) throw new AssertionError(args);
2854             JCExpression arg = translate(args.head, parameter);
2855             anyChanges |= (arg != args.head);
2856             result.append(arg);
2857             if (!anyChanges) return _args;
2858         }
2859         return result.toList();
2860     }
2861 
2862     /** Expand a boxing or unboxing conversion if needed. */
2863     @SuppressWarnings("unchecked") // XXX unchecked
boxIfNeeded(T tree, Type type)2864     <T extends JCExpression> T boxIfNeeded(T tree, Type type) {
2865         boolean havePrimitive = tree.type.isPrimitive();
2866         if (havePrimitive == type.isPrimitive())
2867             return tree;
2868         if (havePrimitive) {
2869             Type unboxedTarget = types.unboxedType(type);
2870             if (!unboxedTarget.hasTag(NONE)) {
2871                 if (!types.isSubtype(tree.type, unboxedTarget)) //e.g. Character c = 89;
2872                     tree.type = unboxedTarget.constType(tree.type.constValue());
2873                 return (T)boxPrimitive(tree, types.erasure(type));
2874             } else {
2875                 tree = (T)boxPrimitive(tree);
2876             }
2877         } else {
2878             tree = (T)unbox(tree, type);
2879         }
2880         return tree;
2881     }
2882 
2883     /** Box up a single primitive expression. */
boxPrimitive(JCExpression tree)2884     JCExpression boxPrimitive(JCExpression tree) {
2885         return boxPrimitive(tree, types.boxedClass(tree.type).type);
2886     }
2887 
2888     /** Box up a single primitive expression. */
boxPrimitive(JCExpression tree, Type box)2889     JCExpression boxPrimitive(JCExpression tree, Type box) {
2890         make_at(tree.pos());
2891         Symbol valueOfSym = lookupMethod(tree.pos(),
2892                                          names.valueOf,
2893                                          box,
2894                                          List.<Type>nil()
2895                                          .prepend(tree.type));
2896         return make.App(make.QualIdent(valueOfSym), List.of(tree));
2897     }
2898 
2899     /** Unbox an object to a primitive value. */
unbox(JCExpression tree, Type primitive)2900     JCExpression unbox(JCExpression tree, Type primitive) {
2901         Type unboxedType = types.unboxedType(tree.type);
2902         if (unboxedType.hasTag(NONE)) {
2903             unboxedType = primitive;
2904             if (!unboxedType.isPrimitive())
2905                 throw new AssertionError(unboxedType);
2906             make_at(tree.pos());
2907             tree = make.TypeCast(types.boxedClass(unboxedType).type, tree);
2908         } else {
2909             // There must be a conversion from unboxedType to primitive.
2910             if (!types.isSubtype(unboxedType, primitive))
2911                 throw new AssertionError(tree);
2912         }
2913         make_at(tree.pos());
2914         Symbol valueSym = lookupMethod(tree.pos(),
2915                                        unboxedType.tsym.name.append(names.Value), // x.intValue()
2916                                        tree.type,
2917                                        List.nil());
2918         return make.App(make.Select(tree, valueSym));
2919     }
2920 
2921     /** Visitor method for parenthesized expressions.
2922      *  If the subexpression has changed, omit the parens.
2923      */
visitParens(JCParens tree)2924     public void visitParens(JCParens tree) {
2925         JCTree expr = translate(tree.expr);
2926         result = ((expr == tree.expr) ? tree : expr);
2927     }
2928 
visitIndexed(JCArrayAccess tree)2929     public void visitIndexed(JCArrayAccess tree) {
2930         tree.indexed = translate(tree.indexed);
2931         tree.index = translate(tree.index, syms.intType);
2932         result = tree;
2933     }
2934 
visitAssign(JCAssign tree)2935     public void visitAssign(JCAssign tree) {
2936         tree.lhs = translate(tree.lhs, tree);
2937         tree.rhs = translate(tree.rhs, tree.lhs.type);
2938 
2939         // If translated left hand side is an Apply, we are
2940         // seeing an access method invocation. In this case, append
2941         // right hand side as last argument of the access method.
2942         if (tree.lhs.hasTag(APPLY)) {
2943             JCMethodInvocation app = (JCMethodInvocation)tree.lhs;
2944             app.args = List.of(tree.rhs).prependList(app.args);
2945             result = app;
2946         } else {
2947             result = tree;
2948         }
2949     }
2950 
visitAssignop(final JCAssignOp tree)2951     public void visitAssignop(final JCAssignOp tree) {
2952         final boolean boxingReq = !tree.lhs.type.isPrimitive() &&
2953             tree.operator.type.getReturnType().isPrimitive();
2954 
2955         AssignopDependencyScanner depScanner = new AssignopDependencyScanner(tree);
2956         depScanner.scan(tree.rhs);
2957 
2958         if (boxingReq || depScanner.dependencyFound) {
2959             // boxing required; need to rewrite as x = (unbox typeof x)(x op y);
2960             // or if x == (typeof x)z then z = (unbox typeof x)((typeof x)z op y)
2961             // (but without recomputing x)
2962             JCTree newTree = abstractLval(tree.lhs, lhs -> {
2963                 Tag newTag = tree.getTag().noAssignOp();
2964                 // Erasure (TransTypes) can change the type of
2965                 // tree.lhs.  However, we can still get the
2966                 // unerased type of tree.lhs as it is stored
2967                 // in tree.type in Attr.
2968                 OperatorSymbol newOperator = operators.resolveBinary(tree,
2969                                                               newTag,
2970                                                               tree.type,
2971                                                               tree.rhs.type);
2972                 //Need to use the "lhs" at two places, once on the future left hand side
2973                 //and once in the future binary operator. But further processing may change
2974                 //the components of the tree in place (see visitSelect for e.g. <Class>.super.<ident>),
2975                 //so cloning the tree to avoid interference between the uses:
2976                 JCExpression expr = (JCExpression) lhs.clone();
2977                 if (expr.type != tree.type)
2978                     expr = make.TypeCast(tree.type, expr);
2979                 JCBinary opResult = make.Binary(newTag, expr, tree.rhs);
2980                 opResult.operator = newOperator;
2981                 opResult.type = newOperator.type.getReturnType();
2982                 JCExpression newRhs = boxingReq ?
2983                     make.TypeCast(types.unboxedType(tree.type), opResult) :
2984                     opResult;
2985                 return make.Assign(lhs, newRhs).setType(tree.type);
2986             });
2987             result = translate(newTree);
2988             return;
2989         }
2990         tree.lhs = translate(tree.lhs, tree);
2991         tree.rhs = translate(tree.rhs, tree.operator.type.getParameterTypes().tail.head);
2992 
2993         // If translated left hand side is an Apply, we are
2994         // seeing an access method invocation. In this case, append
2995         // right hand side as last argument of the access method.
2996         if (tree.lhs.hasTag(APPLY)) {
2997             JCMethodInvocation app = (JCMethodInvocation)tree.lhs;
2998             // if operation is a += on strings,
2999             // make sure to convert argument to string
3000             JCExpression rhs = tree.operator.opcode == string_add
3001               ? makeString(tree.rhs)
3002               : tree.rhs;
3003             app.args = List.of(rhs).prependList(app.args);
3004             result = app;
3005         } else {
3006             result = tree;
3007         }
3008     }
3009 
3010     class AssignopDependencyScanner extends TreeScanner {
3011 
3012         Symbol sym;
3013         boolean dependencyFound = false;
3014 
AssignopDependencyScanner(JCAssignOp tree)3015         AssignopDependencyScanner(JCAssignOp tree) {
3016             this.sym = TreeInfo.symbol(tree.lhs);
3017         }
3018 
3019         @Override
scan(JCTree tree)3020         public void scan(JCTree tree) {
3021             if (tree != null && sym != null) {
3022                 tree.accept(this);
3023             }
3024         }
3025 
3026         @Override
visitAssignop(JCAssignOp tree)3027         public void visitAssignop(JCAssignOp tree) {
3028             if (TreeInfo.symbol(tree.lhs) == sym) {
3029                 dependencyFound = true;
3030                 return;
3031             }
3032             super.visitAssignop(tree);
3033         }
3034 
3035         @Override
visitUnary(JCUnary tree)3036         public void visitUnary(JCUnary tree) {
3037             if (TreeInfo.symbol(tree.arg) == sym) {
3038                 dependencyFound = true;
3039                 return;
3040             }
3041             super.visitUnary(tree);
3042         }
3043     }
3044 
3045     /** Lower a tree of the form e++ or e-- where e is an object type */
lowerBoxedPostop(final JCUnary tree)3046     JCExpression lowerBoxedPostop(final JCUnary tree) {
3047         // translate to tmp1=lval(e); tmp2=tmp1; tmp1 OP 1; tmp2
3048         // or
3049         // translate to tmp1=lval(e); tmp2=tmp1; (typeof tree)tmp1 OP 1; tmp2
3050         // where OP is += or -=
3051         final boolean cast = TreeInfo.skipParens(tree.arg).hasTag(TYPECAST);
3052         return abstractLval(tree.arg, tmp1 -> abstractRval(tmp1, tree.arg.type, tmp2 -> {
3053             Tag opcode = (tree.hasTag(POSTINC))
3054                 ? PLUS_ASG : MINUS_ASG;
3055             //"tmp1" and "tmp2" may refer to the same instance
3056             //(for e.g. <Class>.super.<ident>). But further processing may
3057             //change the components of the tree in place (see visitSelect),
3058             //so cloning the tree to avoid interference between the two uses:
3059             JCExpression lhs = (JCExpression)tmp1.clone();
3060             lhs = cast
3061                 ? make.TypeCast(tree.arg.type, lhs)
3062                 : lhs;
3063             JCExpression update = makeAssignop(opcode,
3064                                          lhs,
3065                                          make.Literal(1));
3066             return makeComma(update, tmp2);
3067         }));
3068     }
3069 
3070     public void visitUnary(JCUnary tree) {
3071         boolean isUpdateOperator = tree.getTag().isIncOrDecUnaryOp();
3072         if (isUpdateOperator && !tree.arg.type.isPrimitive()) {
3073             switch(tree.getTag()) {
3074             case PREINC:            // ++ e
3075                     // translate to e += 1
3076             case PREDEC:            // -- e
3077                     // translate to e -= 1
3078                 {
3079                     JCTree.Tag opcode = (tree.hasTag(PREINC))
3080                         ? PLUS_ASG : MINUS_ASG;
3081                     JCAssignOp newTree = makeAssignop(opcode,
3082                                                     tree.arg,
3083                                                     make.Literal(1));
3084                     result = translate(newTree, tree.type);
3085                     return;
3086                 }
3087             case POSTINC:           // e ++
3088             case POSTDEC:           // e --
3089                 {
3090                     result = translate(lowerBoxedPostop(tree), tree.type);
3091                     return;
3092                 }
3093             }
3094             throw new AssertionError(tree);
3095         }
3096 
3097         tree.arg = boxIfNeeded(translate(tree.arg, tree), tree.type);
3098 
3099         if (tree.hasTag(NOT) && tree.arg.type.constValue() != null) {
3100             tree.type = cfolder.fold1(bool_not, tree.arg.type);
3101         }
3102 
3103         // If translated left hand side is an Apply, we are
3104         // seeing an access method invocation. In this case, return
3105         // that access method invocation as result.
3106         if (isUpdateOperator && tree.arg.hasTag(APPLY)) {
3107             result = tree.arg;
3108         } else {
3109             result = tree;
3110         }
3111     }
3112 
3113     public void visitBinary(JCBinary tree) {
3114         List<Type> formals = tree.operator.type.getParameterTypes();
3115         JCTree lhs = tree.lhs = translate(tree.lhs, formals.head);
3116         switch (tree.getTag()) {
3117         case OR:
3118             if (isTrue(lhs)) {
3119                 result = lhs;
3120                 return;
3121             }
3122             if (isFalse(lhs)) {
3123                 result = translate(tree.rhs, formals.tail.head);
3124                 return;
3125             }
3126             break;
3127         case AND:
3128             if (isFalse(lhs)) {
3129                 result = lhs;
3130                 return;
3131             }
3132             if (isTrue(lhs)) {
3133                 result = translate(tree.rhs, formals.tail.head);
3134                 return;
3135             }
3136             break;
3137         }
3138         tree.rhs = translate(tree.rhs, formals.tail.head);
3139         result = tree;
3140     }
3141 
3142     public void visitIdent(JCIdent tree) {
3143         result = access(tree.sym, tree, enclOp, false);
3144     }
3145 
3146     /** Translate away the foreach loop.  */
3147     public void visitForeachLoop(JCEnhancedForLoop tree) {
3148         if (types.elemtype(tree.expr.type) == null)
3149             visitIterableForeachLoop(tree);
3150         else
3151             visitArrayForeachLoop(tree);
3152     }
3153         // where
3154         /**
3155          * A statement of the form
3156          *
3157          * <pre>
3158          *     for ( T v : arrayexpr ) stmt;
3159          * </pre>
3160          *
3161          * (where arrayexpr is of an array type) gets translated to
3162          *
3163          * <pre>{@code
3164          *     for ( { arraytype #arr = arrayexpr;
3165          *             int #len = array.length;
3166          *             int #i = 0; };
3167          *           #i < #len; i$++ ) {
3168          *         T v = arr$[#i];
3169          *         stmt;
3170          *     }
3171          * }</pre>
3172          *
3173          * where #arr, #len, and #i are freshly named synthetic local variables.
3174          */
3175         private void visitArrayForeachLoop(JCEnhancedForLoop tree) {
3176             make_at(tree.expr.pos());
3177             VarSymbol arraycache = new VarSymbol(SYNTHETIC,
3178                                                  names.fromString("arr" + target.syntheticNameChar()),
3179                                                  tree.expr.type,
3180                                                  currentMethodSym);
3181             JCStatement arraycachedef = make.VarDef(arraycache, tree.expr);
3182             VarSymbol lencache = new VarSymbol(SYNTHETIC,
3183                                                names.fromString("len" + target.syntheticNameChar()),
3184                                                syms.intType,
3185                                                currentMethodSym);
3186             JCStatement lencachedef = make.
3187                 VarDef(lencache, make.Select(make.Ident(arraycache), syms.lengthVar));
3188             VarSymbol index = new VarSymbol(SYNTHETIC,
3189                                             names.fromString("i" + target.syntheticNameChar()),
3190                                             syms.intType,
3191                                             currentMethodSym);
3192 
3193             JCVariableDecl indexdef = make.VarDef(index, make.Literal(INT, 0));
3194             indexdef.init.type = indexdef.type = syms.intType.constType(0);
3195 
3196             List<JCStatement> loopinit = List.of(arraycachedef, lencachedef, indexdef);
3197             JCBinary cond = makeBinary(LT, make.Ident(index), make.Ident(lencache));
3198 
3199             JCExpressionStatement step = make.Exec(makeUnary(PREINC, make.Ident(index)));
3200 
3201             Type elemtype = types.elemtype(tree.expr.type);
3202             JCExpression loopvarinit = make.Indexed(make.Ident(arraycache),
3203                                                     make.Ident(index)).setType(elemtype);
3204             JCVariableDecl loopvardef = (JCVariableDecl)make.VarDef(tree.var.mods,
3205                                                   tree.var.name,
3206                                                   tree.var.vartype,
3207                                                   loopvarinit).setType(tree.var.type);
3208             loopvardef.sym = tree.var.sym;
3209             JCBlock body = make.
3210                 Block(0, List.of(loopvardef, tree.body));
3211 
3212             result = translate(make.
3213                                ForLoop(loopinit,
3214                                        cond,
3215                                        List.of(step),
3216                                        body));
3217             patchTargets(body, tree, result);
3218         }
3219         /** Patch up break and continue targets. */
3220         private void patchTargets(JCTree body, final JCTree src, final JCTree dest) {
3221             class Patcher extends TreeScanner {
3222                 public void visitBreak(JCBreak tree) {
3223                     if (tree.target == src)
3224                         tree.target = dest;
3225                 }
3226                 public void visitYield(JCYield tree) {
3227                     if (tree.target == src)
3228                         tree.target = dest;
3229                     scan(tree.value);
3230                 }
3231                 public void visitContinue(JCContinue tree) {
3232                     if (tree.target == src)
3233                         tree.target = dest;
3234                 }
3235                 public void visitClassDef(JCClassDecl tree) {}
3236             }
3237             new Patcher().scan(body);
3238         }
3239         /**
3240          * A statement of the form
3241          *
3242          * <pre>
3243          *     for ( T v : coll ) stmt ;
3244          * </pre>
3245          *
3246          * (where coll implements {@code Iterable<? extends T>}) gets translated to
3247          *
3248          * <pre>{@code
3249          *     for ( Iterator<? extends T> #i = coll.iterator(); #i.hasNext(); ) {
3250          *         T v = (T) #i.next();
3251          *         stmt;
3252          *     }
3253          * }</pre>
3254          *
3255          * where #i is a freshly named synthetic local variable.
3256          */
3257         private void visitIterableForeachLoop(JCEnhancedForLoop tree) {
3258             make_at(tree.expr.pos());
3259             Type iteratorTarget = syms.objectType;
3260             Type iterableType = types.asSuper(types.cvarUpperBound(tree.expr.type),
3261                                               syms.iterableType.tsym);
3262             if (iterableType.getTypeArguments().nonEmpty())
3263                 iteratorTarget = types.erasure(iterableType.getTypeArguments().head);
3264             Type eType = types.skipTypeVars(tree.expr.type, false);
3265             tree.expr.type = types.erasure(eType);
3266             if (eType.isCompound())
3267                 tree.expr = make.TypeCast(types.erasure(iterableType), tree.expr);
3268             Symbol iterator = lookupMethod(tree.expr.pos(),
3269                                            names.iterator,
3270                                            eType,
3271                                            List.nil());
3272             VarSymbol itvar = new VarSymbol(SYNTHETIC, names.fromString("i" + target.syntheticNameChar()),
3273                                             types.erasure(types.asSuper(iterator.type.getReturnType(), syms.iteratorType.tsym)),
3274                                             currentMethodSym);
3275 
3276              JCStatement init = make.
3277                 VarDef(itvar, make.App(make.Select(tree.expr, iterator)
3278                      .setType(types.erasure(iterator.type))));
3279 
3280             Symbol hasNext = lookupMethod(tree.expr.pos(),
3281                                           names.hasNext,
3282                                           itvar.type,
3283                                           List.nil());
3284             JCMethodInvocation cond = make.App(make.Select(make.Ident(itvar), hasNext));
3285             Symbol next = lookupMethod(tree.expr.pos(),
3286                                        names.next,
3287                                        itvar.type,
3288                                        List.nil());
3289             JCExpression vardefinit = make.App(make.Select(make.Ident(itvar), next));
3290             if (tree.var.type.isPrimitive())
3291                 vardefinit = make.TypeCast(types.cvarUpperBound(iteratorTarget), vardefinit);
3292             else
3293                 vardefinit = make.TypeCast(tree.var.type, vardefinit);
3294             JCVariableDecl indexDef = (JCVariableDecl)make.VarDef(tree.var.mods,
3295                                                   tree.var.name,
3296                                                   tree.var.vartype,
3297                                                   vardefinit).setType(tree.var.type);
3298             indexDef.sym = tree.var.sym;
3299             JCBlock body = make.Block(0, List.of(indexDef, tree.body));
3300             body.endpos = TreeInfo.endPos(tree.body);
3301             result = translate(make.
3302                 ForLoop(List.of(init),
3303                         cond,
3304                         List.nil(),
3305                         body));
3306             patchTargets(body, tree, result);
3307         }
3308 
3309     public void visitVarDef(JCVariableDecl tree) {
3310         MethodSymbol oldMethodSym = currentMethodSym;
3311         tree.mods = translate(tree.mods);
3312         tree.vartype = translate(tree.vartype);
3313         if (currentMethodSym == null) {
3314             // A class or instance field initializer.
3315             currentMethodSym =
3316                 new MethodSymbol((tree.mods.flags&STATIC) | BLOCK,
3317                                  names.empty, null,
3318                                  currentClass);
3319         }
3320         if (tree.init != null) tree.init = translate(tree.init, tree.type);
3321         result = tree;
3322         currentMethodSym = oldMethodSym;
3323     }
3324 
3325     public void visitBlock(JCBlock tree) {
3326         MethodSymbol oldMethodSym = currentMethodSym;
3327         if (currentMethodSym == null) {
3328             // Block is a static or instance initializer.
3329             currentMethodSym =
3330                 new MethodSymbol(tree.flags | BLOCK,
3331                                  names.empty, null,
3332                                  currentClass);
3333         }
3334         super.visitBlock(tree);
3335         currentMethodSym = oldMethodSym;
3336     }
3337 
3338     public void visitDoLoop(JCDoWhileLoop tree) {
3339         tree.body = translate(tree.body);
3340         tree.cond = translate(tree.cond, syms.booleanType);
3341         result = tree;
3342     }
3343 
3344     public void visitWhileLoop(JCWhileLoop tree) {
3345         tree.cond = translate(tree.cond, syms.booleanType);
3346         tree.body = translate(tree.body);
3347         result = tree;
3348     }
3349 
3350     public void visitForLoop(JCForLoop tree) {
3351         tree.init = translate(tree.init);
3352         if (tree.cond != null)
3353             tree.cond = translate(tree.cond, syms.booleanType);
3354         tree.step = translate(tree.step);
3355         tree.body = translate(tree.body);
3356         result = tree;
3357     }
3358 
3359     public void visitReturn(JCReturn tree) {
3360         if (tree.expr != null)
3361             tree.expr = translate(tree.expr,
3362                                   types.erasure(currentMethodDef
3363                                                 .restype.type));
3364         result = tree;
3365     }
3366 
3367     public void visitSwitch(JCSwitch tree) {
3368         handleSwitch(tree, tree.selector, tree.cases);
3369     }
3370 
3371     @Override
3372     public void visitSwitchExpression(JCSwitchExpression tree) {
3373         if (tree.cases.stream().noneMatch(c -> c.pats.isEmpty())) {
3374             JCThrow thr = make.Throw(makeNewClass(syms.incompatibleClassChangeErrorType,
3375                                                   List.nil()));
3376             JCCase c = make.Case(JCCase.STATEMENT, List.nil(), List.of(thr), null);
3377             tree.cases = tree.cases.append(c);
3378         }
3379         handleSwitch(tree, tree.selector, tree.cases);
3380     }
3381 
3382     private void handleSwitch(JCTree tree, JCExpression selector, List<JCCase> cases) {
3383         //expand multiple label cases:
3384         ListBuffer<JCCase> convertedCases = new ListBuffer<>();
3385 
3386         for (JCCase c : cases) {
3387             switch (c.pats.size()) {
3388                 case 0: //default
3389                 case 1: //single label
3390                     convertedCases.append(c);
3391                     break;
3392                 default: //multiple labels, expand:
3393                     //case C1, C2, C3: ...
3394                     //=>
3395                     //case C1:
3396                     //case C2:
3397                     //case C3: ...
3398                     List<JCExpression> patterns = c.pats;
3399                     while (patterns.tail.nonEmpty()) {
3400                         convertedCases.append(make_at(c.pos()).Case(JCCase.STATEMENT,
3401                                                            List.of(patterns.head),
3402                                                            List.nil(),
3403                                                            null));
3404                         patterns = patterns.tail;
3405                     }
3406                     c.pats = patterns;
3407                     convertedCases.append(c);
3408                     break;
3409             }
3410         }
3411 
3412         for (JCCase c : convertedCases) {
3413             if (c.caseKind == JCCase.RULE && c.completesNormally) {
3414                 JCBreak b = make_at(c.pos()).Break(null);
3415                 b.target = tree;
3416                 c.stats = c.stats.append(b);
3417             }
3418         }
3419 
3420         cases = convertedCases.toList();
3421 
3422         Type selsuper = types.supertype(selector.type);
3423         boolean enumSwitch = selsuper != null &&
3424             (selector.type.tsym.flags() & ENUM) != 0;
3425         boolean stringSwitch = selsuper != null &&
3426             types.isSameType(selector.type, syms.stringType);
3427         Type target = enumSwitch ? selector.type :
3428             (stringSwitch? syms.stringType : syms.intType);
3429         selector = translate(selector, target);
3430         cases = translateCases(cases);
3431         if (tree.hasTag(SWITCH)) {
3432             ((JCSwitch) tree).selector = selector;
3433             ((JCSwitch) tree).cases = cases;
3434         } else if (tree.hasTag(SWITCH_EXPRESSION)) {
3435             ((JCSwitchExpression) tree).selector = selector;
3436             ((JCSwitchExpression) tree).cases = cases;
3437         } else {
3438             Assert.error();
3439         }
3440         if (enumSwitch) {
3441             result = visitEnumSwitch(tree, selector, cases);
3442         } else if (stringSwitch) {
3443             result = visitStringSwitch(tree, selector, cases);
3444         } else {
3445             result = tree;
3446         }
3447     }
3448 
3449     public JCTree visitEnumSwitch(JCTree tree, JCExpression selector, List<JCCase> cases) {
3450         TypeSymbol enumSym = selector.type.tsym;
3451         EnumMapping map = mapForEnum(tree.pos(), enumSym);
3452         make_at(tree.pos());
3453         Symbol ordinalMethod = lookupMethod(tree.pos(),
3454                                             names.ordinal,
3455                                             selector.type,
3456                                             List.nil());
3457         JCArrayAccess newSelector = make.Indexed(map.mapVar,
3458                                         make.App(make.Select(selector,
3459                                                              ordinalMethod)));
3460         ListBuffer<JCCase> newCases = new ListBuffer<>();
3461         for (JCCase c : cases) {
3462             if (c.pats.nonEmpty()) {
3463                 VarSymbol label = (VarSymbol)TreeInfo.symbol(c.pats.head);
3464                 JCLiteral pat = map.forConstant(label);
3465                 newCases.append(make.Case(JCCase.STATEMENT, List.of(pat), c.stats, null));
3466             } else {
3467                 newCases.append(c);
3468             }
3469         }
3470         JCTree enumSwitch;
3471         if (tree.hasTag(SWITCH)) {
3472             enumSwitch = make.Switch(newSelector, newCases.toList());
3473         } else if (tree.hasTag(SWITCH_EXPRESSION)) {
3474             enumSwitch = make.SwitchExpression(newSelector, newCases.toList());
3475             enumSwitch.setType(tree.type);
3476         } else {
3477             Assert.error();
3478             throw new AssertionError();
3479         }
3480         patchTargets(enumSwitch, tree, enumSwitch);
3481         return enumSwitch;
3482     }
3483 
3484     public JCTree visitStringSwitch(JCTree tree, JCExpression selector, List<JCCase> caseList) {
3485         int alternatives = caseList.size();
3486 
3487         if (alternatives == 0) { // Strange but legal possibility (only legal for switch statement)
3488             return make.at(tree.pos()).Exec(attr.makeNullCheck(selector));
3489         } else {
3490             /*
3491              * The general approach used is to translate a single
3492              * string switch statement into a series of two chained
3493              * switch statements: the first a synthesized statement
3494              * switching on the argument string's hash value and
3495              * computing a string's position in the list of original
3496              * case labels, if any, followed by a second switch on the
3497              * computed integer value.  The second switch has the same
3498              * code structure as the original string switch statement
3499              * except that the string case labels are replaced with
3500              * positional integer constants starting at 0.
3501              *
3502              * The first switch statement can be thought of as an
3503              * inlined map from strings to their position in the case
3504              * label list.  An alternate implementation would use an
3505              * actual Map for this purpose, as done for enum switches.
3506              *
3507              * With some additional effort, it would be possible to
3508              * use a single switch statement on the hash code of the
3509              * argument, but care would need to be taken to preserve
3510              * the proper control flow in the presence of hash
3511              * collisions and other complications, such as
3512              * fallthroughs.  Switch statements with one or two
3513              * alternatives could also be specially translated into
3514              * if-then statements to omit the computation of the hash
3515              * code.
3516              *
3517              * The generated code assumes that the hashing algorithm
3518              * of String is the same in the compilation environment as
3519              * in the environment the code will run in.  The string
3520              * hashing algorithm in the SE JDK has been unchanged
3521              * since at least JDK 1.2.  Since the algorithm has been
3522              * specified since that release as well, it is very
3523              * unlikely to be changed in the future.
3524              *
3525              * Different hashing algorithms, such as the length of the
3526              * strings or a perfect hashing algorithm over the
3527              * particular set of case labels, could potentially be
3528              * used instead of String.hashCode.
3529              */
3530 
3531             ListBuffer<JCStatement> stmtList = new ListBuffer<>();
3532 
3533             // Map from String case labels to their original position in
3534             // the list of case labels.
3535             Map<String, Integer> caseLabelToPosition = new LinkedHashMap<>(alternatives + 1, 1.0f);
3536 
3537             // Map of hash codes to the string case labels having that hashCode.
3538             Map<Integer, Set<String>> hashToString = new LinkedHashMap<>(alternatives + 1, 1.0f);
3539 
3540             int casePosition = 0;
3541 
3542             for(JCCase oneCase : caseList) {
3543                 if (oneCase.pats.nonEmpty()) { // pats is empty for a "default" case
3544                     JCExpression expression = oneCase.pats.head;
3545                     String labelExpr = (String) expression.type.constValue();
3546                     Integer mapping = caseLabelToPosition.put(labelExpr, casePosition);
3547                     Assert.checkNull(mapping);
3548                     int hashCode = labelExpr.hashCode();
3549 
3550                     Set<String> stringSet = hashToString.get(hashCode);
3551                     if (stringSet == null) {
3552                         stringSet = new LinkedHashSet<>(1, 1.0f);
3553                         stringSet.add(labelExpr);
3554                         hashToString.put(hashCode, stringSet);
3555                     } else {
3556                         boolean added = stringSet.add(labelExpr);
3557                         Assert.check(added);
3558                     }
3559                 }
3560                 casePosition++;
3561             }
3562 
3563             // Synthesize a switch statement that has the effect of
3564             // mapping from a string to the integer position of that
3565             // string in the list of case labels.  This is done by
3566             // switching on the hashCode of the string followed by an
3567             // if-then-else chain comparing the input for equality
3568             // with all the case labels having that hash value.
3569 
3570             /*
3571              * s$ = top of stack;
3572              * tmp$ = -1;
3573              * switch($s.hashCode()) {
3574              *     case caseLabel.hashCode:
3575              *         if (s$.equals("caseLabel_1")
3576              *           tmp$ = caseLabelToPosition("caseLabel_1");
3577              *         else if (s$.equals("caseLabel_2"))
3578              *           tmp$ = caseLabelToPosition("caseLabel_2");
3579              *         ...
3580              *         break;
3581              * ...
3582              * }
3583              */
3584 
3585             VarSymbol dollar_s = new VarSymbol(FINAL|SYNTHETIC,
3586                                                names.fromString("s" + tree.pos + target.syntheticNameChar()),
3587                                                syms.stringType,
3588                                                currentMethodSym);
3589             stmtList.append(make.at(tree.pos()).VarDef(dollar_s, selector).setType(dollar_s.type));
3590 
3591             VarSymbol dollar_tmp = new VarSymbol(SYNTHETIC,
3592                                                  names.fromString("tmp" + tree.pos + target.syntheticNameChar()),
3593                                                  syms.intType,
3594                                                  currentMethodSym);
3595             JCVariableDecl dollar_tmp_def =
3596                 (JCVariableDecl)make.VarDef(dollar_tmp, make.Literal(INT, -1)).setType(dollar_tmp.type);
3597             dollar_tmp_def.init.type = dollar_tmp.type = syms.intType;
3598             stmtList.append(dollar_tmp_def);
3599             ListBuffer<JCCase> caseBuffer = new ListBuffer<>();
3600             // hashCode will trigger nullcheck on original switch expression
3601             JCMethodInvocation hashCodeCall = makeCall(make.Ident(dollar_s),
3602                                                        names.hashCode,
3603                                                        List.nil()).setType(syms.intType);
3604             JCSwitch switch1 = make.Switch(hashCodeCall,
3605                                         caseBuffer.toList());
3606             for(Map.Entry<Integer, Set<String>> entry : hashToString.entrySet()) {
3607                 int hashCode = entry.getKey();
3608                 Set<String> stringsWithHashCode = entry.getValue();
3609                 Assert.check(stringsWithHashCode.size() >= 1);
3610 
3611                 JCStatement elsepart = null;
3612                 for(String caseLabel : stringsWithHashCode ) {
3613                     JCMethodInvocation stringEqualsCall = makeCall(make.Ident(dollar_s),
3614                                                                    names.equals,
3615                                                                    List.of(make.Literal(caseLabel)));
3616                     elsepart = make.If(stringEqualsCall,
3617                                        make.Exec(make.Assign(make.Ident(dollar_tmp),
3618                                                              make.Literal(caseLabelToPosition.get(caseLabel))).
3619                                                  setType(dollar_tmp.type)),
3620                                        elsepart);
3621                 }
3622 
3623                 ListBuffer<JCStatement> lb = new ListBuffer<>();
3624                 JCBreak breakStmt = make.Break(null);
3625                 breakStmt.target = switch1;
3626                 lb.append(elsepart).append(breakStmt);
3627 
3628                 caseBuffer.append(make.Case(JCCase.STATEMENT, List.of(make.Literal(hashCode)), lb.toList(), null));
3629             }
3630 
3631             switch1.cases = caseBuffer.toList();
3632             stmtList.append(switch1);
3633 
3634             // Make isomorphic switch tree replacing string labels
3635             // with corresponding integer ones from the label to
3636             // position map.
3637 
3638             ListBuffer<JCCase> lb = new ListBuffer<>();
3639             for(JCCase oneCase : caseList ) {
3640                 boolean isDefault = (oneCase.pats.isEmpty());
3641                 JCExpression caseExpr;
3642                 if (isDefault)
3643                     caseExpr = null;
3644                 else {
3645                     caseExpr = make.Literal(caseLabelToPosition.get((String)TreeInfo.skipParens(oneCase.pats.head).
3646                                                                     type.constValue()));
3647                 }
3648 
3649                 lb.append(make.Case(JCCase.STATEMENT, caseExpr == null ? List.nil() : List.of(caseExpr),
3650                                     oneCase.stats, null));
3651             }
3652 
3653             if (tree.hasTag(SWITCH)) {
3654                 JCSwitch switch2 = make.Switch(make.Ident(dollar_tmp), lb.toList());
3655                 // Rewire up old unlabeled break statements to the
3656                 // replacement switch being created.
3657                 patchTargets(switch2, tree, switch2);
3658 
3659                 stmtList.append(switch2);
3660 
3661                 return make.Block(0L, stmtList.toList());
3662             } else {
3663                 JCSwitchExpression switch2 = make.SwitchExpression(make.Ident(dollar_tmp), lb.toList());
3664 
3665                 // Rewire up old unlabeled break statements to the
3666                 // replacement switch being created.
3667                 patchTargets(switch2, tree, switch2);
3668 
3669                 switch2.setType(tree.type);
3670 
3671                 LetExpr res = make.LetExpr(stmtList.toList(), switch2);
3672 
3673                 res.needsCond = true;
3674                 res.setType(tree.type);
3675 
3676                 return res;
3677             }
3678         }
3679     }
3680 
3681     @Override
3682     public void visitBreak(JCBreak tree) {
3683         result = tree;
3684     }
3685 
3686     @Override
3687     public void visitYield(JCYield tree) {
3688         tree.value = translate(tree.value, tree.target.type);
3689         result = tree;
3690     }
3691 
3692     public void visitNewArray(JCNewArray tree) {
3693         tree.elemtype = translate(tree.elemtype);
3694         for (List<JCExpression> t = tree.dims; t.tail != null; t = t.tail)
3695             if (t.head != null) t.head = translate(t.head, syms.intType);
3696         tree.elems = translate(tree.elems, types.elemtype(tree.type));
3697         result = tree;
3698     }
3699 
3700     public void visitSelect(JCFieldAccess tree) {
3701         // need to special case-access of the form C.super.x
3702         // these will always need an access method, unless C
3703         // is a default interface subclassed by the current class.
3704         boolean qualifiedSuperAccess =
3705             tree.selected.hasTag(SELECT) &&
3706             TreeInfo.name(tree.selected) == names._super &&
3707             !types.isDirectSuperInterface(((JCFieldAccess)tree.selected).selected.type.tsym, currentClass);
3708         tree.selected = translate(tree.selected);
3709         if (tree.name == names._class) {
3710             result = classOf(tree.selected);
3711         }
3712         else if (tree.name == names._super &&
3713                 types.isDirectSuperInterface(tree.selected.type.tsym, currentClass)) {
3714             //default super call!! Not a classic qualified super call
3715             TypeSymbol supSym = tree.selected.type.tsym;
3716             Assert.checkNonNull(types.asSuper(currentClass.type, supSym));
3717             result = tree;
3718         }
3719         else if (tree.name == names._this || tree.name == names._super) {
3720             result = makeThis(tree.pos(), tree.selected.type.tsym);
3721         }
3722         else
3723             result = access(tree.sym, tree, enclOp, qualifiedSuperAccess);
3724     }
3725 
3726     public void visitLetExpr(LetExpr tree) {
3727         tree.defs = translate(tree.defs);
3728         tree.expr = translate(tree.expr, tree.type);
3729         result = tree;
3730     }
3731 
3732     // There ought to be nothing to rewrite here;
3733     // we don't generate code.
3734     public void visitAnnotation(JCAnnotation tree) {
3735         result = tree;
3736     }
3737 
3738     @Override
3739     public void visitTry(JCTry tree) {
3740         if (tree.resources.nonEmpty()) {
3741             result = makeTwrTry(tree);
3742             return;
3743         }
3744 
3745         boolean hasBody = tree.body.getStatements().nonEmpty();
3746         boolean hasCatchers = tree.catchers.nonEmpty();
3747         boolean hasFinally = tree.finalizer != null &&
3748                 tree.finalizer.getStatements().nonEmpty();
3749 
3750         if (!hasCatchers && !hasFinally) {
3751             result = translate(tree.body);
3752             return;
3753         }
3754 
3755         if (!hasBody) {
3756             if (hasFinally) {
3757                 result = translate(tree.finalizer);
3758             } else {
3759                 result = translate(tree.body);
3760             }
3761             return;
3762         }
3763 
3764         // no optimizations possible
3765         super.visitTry(tree);
3766     }
3767 
3768 /**************************************************************************
3769  * main method
3770  *************************************************************************/
3771 
3772     /** Translate a toplevel class and return a list consisting of
3773      *  the translated class and translated versions of all inner classes.
3774      *  @param env   The attribution environment current at the class definition.
3775      *               We need this for resolving some additional symbols.
3776      *  @param cdef  The tree representing the class definition.
3777      */
3778     public List<JCTree> translateTopLevelClass(Env<AttrContext> env, JCTree cdef, TreeMaker make) {
3779         ListBuffer<JCTree> translated = null;
3780         try {
3781             attrEnv = env;
3782             this.make = make;
3783             endPosTable = env.toplevel.endPositions;
3784             currentClass = null;
3785             currentMethodDef = null;
3786             outermostClassDef = (cdef.hasTag(CLASSDEF)) ? (JCClassDecl)cdef : null;
3787             outermostMemberDef = null;
3788             this.translated = new ListBuffer<>();
3789             classdefs = new HashMap<>();
3790             actualSymbols = new HashMap<>();
3791             freevarCache = new HashMap<>();
3792             proxies = new HashMap<>();
3793             twrVars = WriteableScope.create(syms.noSymbol);
3794             outerThisStack = List.nil();
3795             accessNums = new HashMap<>();
3796             accessSyms = new HashMap<>();
3797             accessConstrs = new HashMap<>();
3798             accessConstrTags = List.nil();
3799             accessed = new ListBuffer<>();
3800             translate(cdef, (JCExpression)null);
3801             for (List<Symbol> l = accessed.toList(); l.nonEmpty(); l = l.tail)
3802                 makeAccessible(l.head);
3803             for (EnumMapping map : enumSwitchMap.values())
3804                 map.translate();
3805             checkConflicts(this.translated.toList());
3806             checkAccessConstructorTags();
3807             translated = this.translated;
3808         } finally {
3809             // note that recursive invocations of this method fail hard
3810             attrEnv = null;
3811             this.make = null;
3812             endPosTable = null;
3813             currentClass = null;
3814             currentMethodDef = null;
3815             outermostClassDef = null;
3816             outermostMemberDef = null;
3817             this.translated = null;
3818             classdefs = null;
3819             actualSymbols = null;
3820             freevarCache = null;
3821             proxies = null;
3822             outerThisStack = null;
3823             accessNums = null;
3824             accessSyms = null;
3825             accessConstrs = null;
3826             accessConstrTags = null;
3827             accessed = null;
3828             enumSwitchMap.clear();
3829             assertionsDisabledClassCache = null;
3830         }
3831         return translated.toList();
3832     }
3833 }
3834