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