Sat, 14 Sep 2013 19:04:47 +0100
7047734: javac, the LVT is not generated correctly in several scenarios
Reviewed-by: jjg, mcimadamore
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 return freevarDefs(pos, freevars, owner, 0);
1483 }
1485 List<JCVariableDecl> freevarDefs(int pos, List<VarSymbol> freevars, Symbol owner,
1486 long additionalFlags) {
1487 long flags = FINAL | SYNTHETIC | additionalFlags;
1488 if (owner.kind == TYP &&
1489 target.usePrivateSyntheticFields())
1490 flags |= PRIVATE;
1491 List<JCVariableDecl> defs = List.nil();
1492 for (List<VarSymbol> l = freevars; l.nonEmpty(); l = l.tail) {
1493 VarSymbol v = l.head;
1494 VarSymbol proxy = new VarSymbol(
1495 flags, proxyName(v.name), v.erasure(types), owner);
1496 proxies.enter(proxy);
1497 JCVariableDecl vd = make.at(pos).VarDef(proxy, null);
1498 vd.vartype = access(vd.vartype);
1499 defs = defs.prepend(vd);
1500 }
1501 return defs;
1502 }
1504 /** The name of a this$n field
1505 * @param type The class referenced by the this$n field
1506 */
1507 Name outerThisName(Type type, Symbol owner) {
1508 Type t = type.getEnclosingType();
1509 int nestingLevel = 0;
1510 while (t.hasTag(CLASS)) {
1511 t = t.getEnclosingType();
1512 nestingLevel++;
1513 }
1514 Name result = names.fromString("this" + target.syntheticNameChar() + nestingLevel);
1515 while (owner.kind == TYP && ((ClassSymbol)owner).members().lookup(result).scope != null)
1516 result = names.fromString(result.toString() + target.syntheticNameChar());
1517 return result;
1518 }
1520 private VarSymbol makeOuterThisVarSymbol(Symbol owner, long flags) {
1521 if (owner.kind == TYP &&
1522 target.usePrivateSyntheticFields())
1523 flags |= PRIVATE;
1524 Type target = types.erasure(owner.enclClass().type.getEnclosingType());
1525 VarSymbol outerThis =
1526 new VarSymbol(flags, outerThisName(target, owner), target, owner);
1527 outerThisStack = outerThisStack.prepend(outerThis);
1528 return outerThis;
1529 }
1531 private JCVariableDecl makeOuterThisVarDecl(int pos, VarSymbol sym) {
1532 JCVariableDecl vd = make.at(pos).VarDef(sym, null);
1533 vd.vartype = access(vd.vartype);
1534 return vd;
1535 }
1537 /** Definition for this$n field.
1538 * @param pos The source code position of the definition.
1539 * @param owner The method in which the definition goes.
1540 */
1541 JCVariableDecl outerThisDef(int pos, MethodSymbol owner) {
1542 ClassSymbol c = owner.enclClass();
1543 boolean isMandated =
1544 // Anonymous constructors
1545 (owner.isConstructor() && owner.isAnonymous()) ||
1546 // Constructors of non-private inner member classes
1547 (owner.isConstructor() && c.isInner() &&
1548 !c.isPrivate() && !c.isStatic());
1549 long flags =
1550 FINAL | (isMandated ? MANDATED : SYNTHETIC) | PARAMETER;
1551 VarSymbol outerThis = makeOuterThisVarSymbol(owner, flags);
1552 owner.extraParams = owner.extraParams.prepend(outerThis);
1553 return makeOuterThisVarDecl(pos, outerThis);
1554 }
1556 /** Definition for this$n field.
1557 * @param pos The source code position of the definition.
1558 * @param owner The class in which the definition goes.
1559 */
1560 JCVariableDecl outerThisDef(int pos, ClassSymbol owner) {
1561 VarSymbol outerThis = makeOuterThisVarSymbol(owner, FINAL | SYNTHETIC);
1562 return makeOuterThisVarDecl(pos, outerThis);
1563 }
1565 /** Return a list of trees that load the free variables in given list,
1566 * in reverse order.
1567 * @param pos The source code position to be used for the trees.
1568 * @param freevars The list of free variables.
1569 */
1570 List<JCExpression> loadFreevars(DiagnosticPosition pos, List<VarSymbol> freevars) {
1571 List<JCExpression> args = List.nil();
1572 for (List<VarSymbol> l = freevars; l.nonEmpty(); l = l.tail)
1573 args = args.prepend(loadFreevar(pos, l.head));
1574 return args;
1575 }
1576 //where
1577 JCExpression loadFreevar(DiagnosticPosition pos, VarSymbol v) {
1578 return access(v, make.at(pos).Ident(v), null, false);
1579 }
1581 /** Construct a tree simulating the expression {@code C.this}.
1582 * @param pos The source code position to be used for the tree.
1583 * @param c The qualifier class.
1584 */
1585 JCExpression makeThis(DiagnosticPosition pos, TypeSymbol c) {
1586 if (currentClass == c) {
1587 // in this case, `this' works fine
1588 return make.at(pos).This(c.erasure(types));
1589 } else {
1590 // need to go via this$n
1591 return makeOuterThis(pos, c);
1592 }
1593 }
1595 /**
1596 * Optionally replace a try statement with the desugaring of a
1597 * try-with-resources statement. The canonical desugaring of
1598 *
1599 * try ResourceSpecification
1600 * Block
1601 *
1602 * is
1603 *
1604 * {
1605 * final VariableModifiers_minus_final R #resource = Expression;
1606 * Throwable #primaryException = null;
1607 *
1608 * try ResourceSpecificationtail
1609 * Block
1610 * catch (Throwable #t) {
1611 * #primaryException = t;
1612 * throw #t;
1613 * } finally {
1614 * if (#resource != null) {
1615 * if (#primaryException != null) {
1616 * try {
1617 * #resource.close();
1618 * } catch(Throwable #suppressedException) {
1619 * #primaryException.addSuppressed(#suppressedException);
1620 * }
1621 * } else {
1622 * #resource.close();
1623 * }
1624 * }
1625 * }
1626 *
1627 * @param tree The try statement to inspect.
1628 * @return A a desugared try-with-resources tree, or the original
1629 * try block if there are no resources to manage.
1630 */
1631 JCTree makeTwrTry(JCTry tree) {
1632 make_at(tree.pos());
1633 twrVars = twrVars.dup();
1634 JCBlock twrBlock = makeTwrBlock(tree.resources, tree.body,
1635 tree.finallyCanCompleteNormally, 0);
1636 if (tree.catchers.isEmpty() && tree.finalizer == null)
1637 result = translate(twrBlock);
1638 else
1639 result = translate(make.Try(twrBlock, tree.catchers, tree.finalizer));
1640 twrVars = twrVars.leave();
1641 return result;
1642 }
1644 private JCBlock makeTwrBlock(List<JCTree> resources, JCBlock block,
1645 boolean finallyCanCompleteNormally, int depth) {
1646 if (resources.isEmpty())
1647 return block;
1649 // Add resource declaration or expression to block statements
1650 ListBuffer<JCStatement> stats = new ListBuffer<JCStatement>();
1651 JCTree resource = resources.head;
1652 JCExpression expr = null;
1653 if (resource instanceof JCVariableDecl) {
1654 JCVariableDecl var = (JCVariableDecl) resource;
1655 expr = make.Ident(var.sym).setType(resource.type);
1656 stats.add(var);
1657 } else {
1658 Assert.check(resource instanceof JCExpression);
1659 VarSymbol syntheticTwrVar =
1660 new VarSymbol(SYNTHETIC | FINAL,
1661 makeSyntheticName(names.fromString("twrVar" +
1662 depth), twrVars),
1663 (resource.type.hasTag(BOT)) ?
1664 syms.autoCloseableType : resource.type,
1665 currentMethodSym);
1666 twrVars.enter(syntheticTwrVar);
1667 JCVariableDecl syntheticTwrVarDecl =
1668 make.VarDef(syntheticTwrVar, (JCExpression)resource);
1669 expr = (JCExpression)make.Ident(syntheticTwrVar);
1670 stats.add(syntheticTwrVarDecl);
1671 }
1673 // Add primaryException declaration
1674 VarSymbol primaryException =
1675 new VarSymbol(SYNTHETIC,
1676 makeSyntheticName(names.fromString("primaryException" +
1677 depth), twrVars),
1678 syms.throwableType,
1679 currentMethodSym);
1680 twrVars.enter(primaryException);
1681 JCVariableDecl primaryExceptionTreeDecl = make.VarDef(primaryException, makeNull());
1682 stats.add(primaryExceptionTreeDecl);
1684 // Create catch clause that saves exception and then rethrows it
1685 VarSymbol param =
1686 new VarSymbol(FINAL|SYNTHETIC,
1687 names.fromString("t" +
1688 target.syntheticNameChar()),
1689 syms.throwableType,
1690 currentMethodSym);
1691 JCVariableDecl paramTree = make.VarDef(param, null);
1692 JCStatement assign = make.Assignment(primaryException, make.Ident(param));
1693 JCStatement rethrowStat = make.Throw(make.Ident(param));
1694 JCBlock catchBlock = make.Block(0L, List.<JCStatement>of(assign, rethrowStat));
1695 JCCatch catchClause = make.Catch(paramTree, catchBlock);
1697 int oldPos = make.pos;
1698 make.at(TreeInfo.endPos(block));
1699 JCBlock finallyClause = makeTwrFinallyClause(primaryException, expr);
1700 make.at(oldPos);
1701 JCTry outerTry = make.Try(makeTwrBlock(resources.tail, block,
1702 finallyCanCompleteNormally, depth + 1),
1703 List.<JCCatch>of(catchClause),
1704 finallyClause);
1705 outerTry.finallyCanCompleteNormally = finallyCanCompleteNormally;
1706 stats.add(outerTry);
1707 JCBlock newBlock = make.Block(0L, stats.toList());
1708 return newBlock;
1709 }
1711 private JCBlock makeTwrFinallyClause(Symbol primaryException, JCExpression resource) {
1712 // primaryException.addSuppressed(catchException);
1713 VarSymbol catchException =
1714 new VarSymbol(SYNTHETIC, make.paramName(2),
1715 syms.throwableType,
1716 currentMethodSym);
1717 JCStatement addSuppressionStatement =
1718 make.Exec(makeCall(make.Ident(primaryException),
1719 names.addSuppressed,
1720 List.<JCExpression>of(make.Ident(catchException))));
1722 // try { resource.close(); } catch (e) { primaryException.addSuppressed(e); }
1723 JCBlock tryBlock =
1724 make.Block(0L, List.<JCStatement>of(makeResourceCloseInvocation(resource)));
1725 JCVariableDecl catchExceptionDecl = make.VarDef(catchException, null);
1726 JCBlock catchBlock = make.Block(0L, List.<JCStatement>of(addSuppressionStatement));
1727 List<JCCatch> catchClauses = List.<JCCatch>of(make.Catch(catchExceptionDecl, catchBlock));
1728 JCTry tryTree = make.Try(tryBlock, catchClauses, null);
1729 tryTree.finallyCanCompleteNormally = true;
1731 // if (primaryException != null) {try...} else resourceClose;
1732 JCIf closeIfStatement = make.If(makeNonNullCheck(make.Ident(primaryException)),
1733 tryTree,
1734 makeResourceCloseInvocation(resource));
1736 // if (#resource != null) { if (primaryException ... }
1737 return make.Block(0L,
1738 List.<JCStatement>of(make.If(makeNonNullCheck(resource),
1739 closeIfStatement,
1740 null)));
1741 }
1743 private JCStatement makeResourceCloseInvocation(JCExpression resource) {
1744 // convert to AutoCloseable if needed
1745 if (types.asSuper(resource.type, syms.autoCloseableType.tsym) == null) {
1746 resource = (JCExpression) convert(resource, syms.autoCloseableType);
1747 }
1749 // create resource.close() method invocation
1750 JCExpression resourceClose = makeCall(resource,
1751 names.close,
1752 List.<JCExpression>nil());
1753 return make.Exec(resourceClose);
1754 }
1756 private JCExpression makeNonNullCheck(JCExpression expression) {
1757 return makeBinary(NE, expression, makeNull());
1758 }
1760 /** Construct a tree that represents the outer instance
1761 * {@code C.this}. Never pick the current `this'.
1762 * @param pos The source code position to be used for the tree.
1763 * @param c The qualifier class.
1764 */
1765 JCExpression makeOuterThis(DiagnosticPosition pos, TypeSymbol c) {
1766 List<VarSymbol> ots = outerThisStack;
1767 if (ots.isEmpty()) {
1768 log.error(pos, "no.encl.instance.of.type.in.scope", c);
1769 Assert.error();
1770 return makeNull();
1771 }
1772 VarSymbol ot = ots.head;
1773 JCExpression tree = access(make.at(pos).Ident(ot));
1774 TypeSymbol otc = ot.type.tsym;
1775 while (otc != c) {
1776 do {
1777 ots = ots.tail;
1778 if (ots.isEmpty()) {
1779 log.error(pos,
1780 "no.encl.instance.of.type.in.scope",
1781 c);
1782 Assert.error(); // should have been caught in Attr
1783 return tree;
1784 }
1785 ot = ots.head;
1786 } while (ot.owner != otc);
1787 if (otc.owner.kind != PCK && !otc.hasOuterInstance()) {
1788 chk.earlyRefError(pos, c);
1789 Assert.error(); // should have been caught in Attr
1790 return makeNull();
1791 }
1792 tree = access(make.at(pos).Select(tree, ot));
1793 otc = ot.type.tsym;
1794 }
1795 return tree;
1796 }
1798 /** Construct a tree that represents the closest outer instance
1799 * {@code C.this} such that the given symbol is a member of C.
1800 * @param pos The source code position to be used for the tree.
1801 * @param sym The accessed symbol.
1802 * @param preciseMatch should we accept a type that is a subtype of
1803 * sym's owner, even if it doesn't contain sym
1804 * due to hiding, overriding, or non-inheritance
1805 * due to protection?
1806 */
1807 JCExpression makeOwnerThis(DiagnosticPosition pos, Symbol sym, boolean preciseMatch) {
1808 Symbol c = sym.owner;
1809 if (preciseMatch ? sym.isMemberOf(currentClass, types)
1810 : currentClass.isSubClass(sym.owner, types)) {
1811 // in this case, `this' works fine
1812 return make.at(pos).This(c.erasure(types));
1813 } else {
1814 // need to go via this$n
1815 return makeOwnerThisN(pos, sym, preciseMatch);
1816 }
1817 }
1819 /**
1820 * Similar to makeOwnerThis but will never pick "this".
1821 */
1822 JCExpression makeOwnerThisN(DiagnosticPosition pos, Symbol sym, boolean preciseMatch) {
1823 Symbol c = sym.owner;
1824 List<VarSymbol> ots = outerThisStack;
1825 if (ots.isEmpty()) {
1826 log.error(pos, "no.encl.instance.of.type.in.scope", c);
1827 Assert.error();
1828 return makeNull();
1829 }
1830 VarSymbol ot = ots.head;
1831 JCExpression tree = access(make.at(pos).Ident(ot));
1832 TypeSymbol otc = ot.type.tsym;
1833 while (!(preciseMatch ? sym.isMemberOf(otc, types) : otc.isSubClass(sym.owner, types))) {
1834 do {
1835 ots = ots.tail;
1836 if (ots.isEmpty()) {
1837 log.error(pos,
1838 "no.encl.instance.of.type.in.scope",
1839 c);
1840 Assert.error();
1841 return tree;
1842 }
1843 ot = ots.head;
1844 } while (ot.owner != otc);
1845 tree = access(make.at(pos).Select(tree, ot));
1846 otc = ot.type.tsym;
1847 }
1848 return tree;
1849 }
1851 /** Return tree simulating the assignment {@code this.name = name}, where
1852 * name is the name of a free variable.
1853 */
1854 JCStatement initField(int pos, Name name) {
1855 Scope.Entry e = proxies.lookup(name);
1856 Symbol rhs = e.sym;
1857 Assert.check(rhs.owner.kind == MTH);
1858 Symbol lhs = e.next().sym;
1859 Assert.check(rhs.owner.owner == lhs.owner);
1860 make.at(pos);
1861 return
1862 make.Exec(
1863 make.Assign(
1864 make.Select(make.This(lhs.owner.erasure(types)), lhs),
1865 make.Ident(rhs)).setType(lhs.erasure(types)));
1866 }
1868 /** Return tree simulating the assignment {@code this.this$n = this$n}.
1869 */
1870 JCStatement initOuterThis(int pos) {
1871 VarSymbol rhs = outerThisStack.head;
1872 Assert.check(rhs.owner.kind == MTH);
1873 VarSymbol lhs = outerThisStack.tail.head;
1874 Assert.check(rhs.owner.owner == lhs.owner);
1875 make.at(pos);
1876 return
1877 make.Exec(
1878 make.Assign(
1879 make.Select(make.This(lhs.owner.erasure(types)), lhs),
1880 make.Ident(rhs)).setType(lhs.erasure(types)));
1881 }
1883 /**************************************************************************
1884 * Code for .class
1885 *************************************************************************/
1887 /** Return the symbol of a class to contain a cache of
1888 * compiler-generated statics such as class$ and the
1889 * $assertionsDisabled flag. We create an anonymous nested class
1890 * (unless one already exists) and return its symbol. However,
1891 * for backward compatibility in 1.4 and earlier we use the
1892 * top-level class itself.
1893 */
1894 private ClassSymbol outerCacheClass() {
1895 ClassSymbol clazz = outermostClassDef.sym;
1896 if ((clazz.flags() & INTERFACE) == 0 &&
1897 !target.useInnerCacheClass()) return clazz;
1898 Scope s = clazz.members();
1899 for (Scope.Entry e = s.elems; e != null; e = e.sibling)
1900 if (e.sym.kind == TYP &&
1901 e.sym.name == names.empty &&
1902 (e.sym.flags() & INTERFACE) == 0) return (ClassSymbol) e.sym;
1903 return makeEmptyClass(STATIC | SYNTHETIC, clazz).sym;
1904 }
1906 /** Return symbol for "class$" method. If there is no method definition
1907 * for class$, construct one as follows:
1908 *
1909 * class class$(String x0) {
1910 * try {
1911 * return Class.forName(x0);
1912 * } catch (ClassNotFoundException x1) {
1913 * throw new NoClassDefFoundError(x1.getMessage());
1914 * }
1915 * }
1916 */
1917 private MethodSymbol classDollarSym(DiagnosticPosition pos) {
1918 ClassSymbol outerCacheClass = outerCacheClass();
1919 MethodSymbol classDollarSym =
1920 (MethodSymbol)lookupSynthetic(classDollar,
1921 outerCacheClass.members());
1922 if (classDollarSym == null) {
1923 classDollarSym = new MethodSymbol(
1924 STATIC | SYNTHETIC,
1925 classDollar,
1926 new MethodType(
1927 List.of(syms.stringType),
1928 types.erasure(syms.classType),
1929 List.<Type>nil(),
1930 syms.methodClass),
1931 outerCacheClass);
1932 enterSynthetic(pos, classDollarSym, outerCacheClass.members());
1934 JCMethodDecl md = make.MethodDef(classDollarSym, null);
1935 try {
1936 md.body = classDollarSymBody(pos, md);
1937 } catch (CompletionFailure ex) {
1938 md.body = make.Block(0, List.<JCStatement>nil());
1939 chk.completionError(pos, ex);
1940 }
1941 JCClassDecl outerCacheClassDef = classDef(outerCacheClass);
1942 outerCacheClassDef.defs = outerCacheClassDef.defs.prepend(md);
1943 }
1944 return classDollarSym;
1945 }
1947 /** Generate code for class$(String name). */
1948 JCBlock classDollarSymBody(DiagnosticPosition pos, JCMethodDecl md) {
1949 MethodSymbol classDollarSym = md.sym;
1950 ClassSymbol outerCacheClass = (ClassSymbol)classDollarSym.owner;
1952 JCBlock returnResult;
1954 // in 1.4.2 and above, we use
1955 // Class.forName(String name, boolean init, ClassLoader loader);
1956 // which requires we cache the current loader in cl$
1957 if (target.classLiteralsNoInit()) {
1958 // clsym = "private static ClassLoader cl$"
1959 VarSymbol clsym = new VarSymbol(STATIC|SYNTHETIC,
1960 names.fromString("cl" + target.syntheticNameChar()),
1961 syms.classLoaderType,
1962 outerCacheClass);
1963 enterSynthetic(pos, clsym, outerCacheClass.members());
1965 // emit "private static ClassLoader cl$;"
1966 JCVariableDecl cldef = make.VarDef(clsym, null);
1967 JCClassDecl outerCacheClassDef = classDef(outerCacheClass);
1968 outerCacheClassDef.defs = outerCacheClassDef.defs.prepend(cldef);
1970 // newcache := "new cache$1[0]"
1971 JCNewArray newcache = make.
1972 NewArray(make.Type(outerCacheClass.type),
1973 List.<JCExpression>of(make.Literal(INT, 0).setType(syms.intType)),
1974 null);
1975 newcache.type = new ArrayType(types.erasure(outerCacheClass.type),
1976 syms.arrayClass);
1978 // forNameSym := java.lang.Class.forName(
1979 // String s,boolean init,ClassLoader loader)
1980 Symbol forNameSym = lookupMethod(make_pos, names.forName,
1981 types.erasure(syms.classType),
1982 List.of(syms.stringType,
1983 syms.booleanType,
1984 syms.classLoaderType));
1985 // clvalue := "(cl$ == null) ?
1986 // $newcache.getClass().getComponentType().getClassLoader() : cl$"
1987 JCExpression clvalue =
1988 make.Conditional(
1989 makeBinary(EQ, make.Ident(clsym), makeNull()),
1990 make.Assign(
1991 make.Ident(clsym),
1992 makeCall(
1993 makeCall(makeCall(newcache,
1994 names.getClass,
1995 List.<JCExpression>nil()),
1996 names.getComponentType,
1997 List.<JCExpression>nil()),
1998 names.getClassLoader,
1999 List.<JCExpression>nil())).setType(syms.classLoaderType),
2000 make.Ident(clsym)).setType(syms.classLoaderType);
2002 // returnResult := "{ return Class.forName(param1, false, cl$); }"
2003 List<JCExpression> args = List.of(make.Ident(md.params.head.sym),
2004 makeLit(syms.booleanType, 0),
2005 clvalue);
2006 returnResult = make.
2007 Block(0, List.<JCStatement>of(make.
2008 Call(make. // return
2009 App(make.
2010 Ident(forNameSym), args))));
2011 } else {
2012 // forNameSym := java.lang.Class.forName(String s)
2013 Symbol forNameSym = lookupMethod(make_pos,
2014 names.forName,
2015 types.erasure(syms.classType),
2016 List.of(syms.stringType));
2017 // returnResult := "{ return Class.forName(param1); }"
2018 returnResult = make.
2019 Block(0, List.of(make.
2020 Call(make. // return
2021 App(make.
2022 QualIdent(forNameSym),
2023 List.<JCExpression>of(make.
2024 Ident(md.params.
2025 head.sym))))));
2026 }
2028 // catchParam := ClassNotFoundException e1
2029 VarSymbol catchParam =
2030 new VarSymbol(SYNTHETIC, make.paramName(1),
2031 syms.classNotFoundExceptionType,
2032 classDollarSym);
2034 JCStatement rethrow;
2035 if (target.hasInitCause()) {
2036 // rethrow = "throw new NoClassDefFoundError().initCause(e);
2037 JCExpression throwExpr =
2038 makeCall(makeNewClass(syms.noClassDefFoundErrorType,
2039 List.<JCExpression>nil()),
2040 names.initCause,
2041 List.<JCExpression>of(make.Ident(catchParam)));
2042 rethrow = make.Throw(throwExpr);
2043 } else {
2044 // getMessageSym := ClassNotFoundException.getMessage()
2045 Symbol getMessageSym = lookupMethod(make_pos,
2046 names.getMessage,
2047 syms.classNotFoundExceptionType,
2048 List.<Type>nil());
2049 // rethrow = "throw new NoClassDefFoundError(e.getMessage());"
2050 rethrow = make.
2051 Throw(makeNewClass(syms.noClassDefFoundErrorType,
2052 List.<JCExpression>of(make.App(make.Select(make.Ident(catchParam),
2053 getMessageSym),
2054 List.<JCExpression>nil()))));
2055 }
2057 // rethrowStmt := "( $rethrow )"
2058 JCBlock rethrowStmt = make.Block(0, List.of(rethrow));
2060 // catchBlock := "catch ($catchParam) $rethrowStmt"
2061 JCCatch catchBlock = make.Catch(make.VarDef(catchParam, null),
2062 rethrowStmt);
2064 // tryCatch := "try $returnResult $catchBlock"
2065 JCStatement tryCatch = make.Try(returnResult,
2066 List.of(catchBlock), null);
2068 return make.Block(0, List.of(tryCatch));
2069 }
2070 // where
2071 /** Create an attributed tree of the form left.name(). */
2072 private JCMethodInvocation makeCall(JCExpression left, Name name, List<JCExpression> args) {
2073 Assert.checkNonNull(left.type);
2074 Symbol funcsym = lookupMethod(make_pos, name, left.type,
2075 TreeInfo.types(args));
2076 return make.App(make.Select(left, funcsym), args);
2077 }
2079 /** The Name Of The variable to cache T.class values.
2080 * @param sig The signature of type T.
2081 */
2082 private Name cacheName(String sig) {
2083 StringBuilder buf = new StringBuilder();
2084 if (sig.startsWith("[")) {
2085 buf = buf.append("array");
2086 while (sig.startsWith("[")) {
2087 buf = buf.append(target.syntheticNameChar());
2088 sig = sig.substring(1);
2089 }
2090 if (sig.startsWith("L")) {
2091 sig = sig.substring(0, sig.length() - 1);
2092 }
2093 } else {
2094 buf = buf.append("class" + target.syntheticNameChar());
2095 }
2096 buf = buf.append(sig.replace('.', target.syntheticNameChar()));
2097 return names.fromString(buf.toString());
2098 }
2100 /** The variable symbol that caches T.class values.
2101 * If none exists yet, create a definition.
2102 * @param sig The signature of type T.
2103 * @param pos The position to report diagnostics, if any.
2104 */
2105 private VarSymbol cacheSym(DiagnosticPosition pos, String sig) {
2106 ClassSymbol outerCacheClass = outerCacheClass();
2107 Name cname = cacheName(sig);
2108 VarSymbol cacheSym =
2109 (VarSymbol)lookupSynthetic(cname, outerCacheClass.members());
2110 if (cacheSym == null) {
2111 cacheSym = new VarSymbol(
2112 STATIC | SYNTHETIC, cname, types.erasure(syms.classType), outerCacheClass);
2113 enterSynthetic(pos, cacheSym, outerCacheClass.members());
2115 JCVariableDecl cacheDef = make.VarDef(cacheSym, null);
2116 JCClassDecl outerCacheClassDef = classDef(outerCacheClass);
2117 outerCacheClassDef.defs = outerCacheClassDef.defs.prepend(cacheDef);
2118 }
2119 return cacheSym;
2120 }
2122 /** The tree simulating a T.class expression.
2123 * @param clazz The tree identifying type T.
2124 */
2125 private JCExpression classOf(JCTree clazz) {
2126 return classOfType(clazz.type, clazz.pos());
2127 }
2129 private JCExpression classOfType(Type type, DiagnosticPosition pos) {
2130 switch (type.getTag()) {
2131 case BYTE: case SHORT: case CHAR: case INT: case LONG: case FLOAT:
2132 case DOUBLE: case BOOLEAN: case VOID:
2133 // replace with <BoxedClass>.TYPE
2134 ClassSymbol c = types.boxedClass(type);
2135 Symbol typeSym =
2136 rs.accessBase(
2137 rs.findIdentInType(attrEnv, c.type, names.TYPE, VAR),
2138 pos, c.type, names.TYPE, true);
2139 if (typeSym.kind == VAR)
2140 ((VarSymbol)typeSym).getConstValue(); // ensure initializer is evaluated
2141 return make.QualIdent(typeSym);
2142 case CLASS: case ARRAY:
2143 if (target.hasClassLiterals()) {
2144 VarSymbol sym = new VarSymbol(
2145 STATIC | PUBLIC | FINAL, names._class,
2146 syms.classType, type.tsym);
2147 return make_at(pos).Select(make.Type(type), sym);
2148 }
2149 // replace with <cache == null ? cache = class$(tsig) : cache>
2150 // where
2151 // - <tsig> is the type signature of T,
2152 // - <cache> is the cache variable for tsig.
2153 String sig =
2154 writer.xClassName(type).toString().replace('/', '.');
2155 Symbol cs = cacheSym(pos, sig);
2156 return make_at(pos).Conditional(
2157 makeBinary(EQ, make.Ident(cs), makeNull()),
2158 make.Assign(
2159 make.Ident(cs),
2160 make.App(
2161 make.Ident(classDollarSym(pos)),
2162 List.<JCExpression>of(make.Literal(CLASS, sig)
2163 .setType(syms.stringType))))
2164 .setType(types.erasure(syms.classType)),
2165 make.Ident(cs)).setType(types.erasure(syms.classType));
2166 default:
2167 throw new AssertionError();
2168 }
2169 }
2171 /**************************************************************************
2172 * Code for enabling/disabling assertions.
2173 *************************************************************************/
2175 // This code is not particularly robust if the user has
2176 // previously declared a member named '$assertionsDisabled'.
2177 // The same faulty idiom also appears in the translation of
2178 // class literals above. We should report an error if a
2179 // previous declaration is not synthetic.
2181 private JCExpression assertFlagTest(DiagnosticPosition pos) {
2182 // Outermost class may be either true class or an interface.
2183 ClassSymbol outermostClass = outermostClassDef.sym;
2185 // note that this is a class, as an interface can't contain a statement.
2186 ClassSymbol container = currentClass;
2188 VarSymbol assertDisabledSym =
2189 (VarSymbol)lookupSynthetic(dollarAssertionsDisabled,
2190 container.members());
2191 if (assertDisabledSym == null) {
2192 assertDisabledSym =
2193 new VarSymbol(STATIC | FINAL | SYNTHETIC,
2194 dollarAssertionsDisabled,
2195 syms.booleanType,
2196 container);
2197 enterSynthetic(pos, assertDisabledSym, container.members());
2198 Symbol desiredAssertionStatusSym = lookupMethod(pos,
2199 names.desiredAssertionStatus,
2200 types.erasure(syms.classType),
2201 List.<Type>nil());
2202 JCClassDecl containerDef = classDef(container);
2203 make_at(containerDef.pos());
2204 JCExpression notStatus = makeUnary(NOT, make.App(make.Select(
2205 classOfType(types.erasure(outermostClass.type),
2206 containerDef.pos()),
2207 desiredAssertionStatusSym)));
2208 JCVariableDecl assertDisabledDef = make.VarDef(assertDisabledSym,
2209 notStatus);
2210 containerDef.defs = containerDef.defs.prepend(assertDisabledDef);
2211 }
2212 make_at(pos);
2213 return makeUnary(NOT, make.Ident(assertDisabledSym));
2214 }
2217 /**************************************************************************
2218 * Building blocks for let expressions
2219 *************************************************************************/
2221 interface TreeBuilder {
2222 JCTree build(JCTree arg);
2223 }
2225 /** Construct an expression using the builder, with the given rval
2226 * expression as an argument to the builder. However, the rval
2227 * expression must be computed only once, even if used multiple
2228 * times in the result of the builder. We do that by
2229 * constructing a "let" expression that saves the rvalue into a
2230 * temporary variable and then uses the temporary variable in
2231 * place of the expression built by the builder. The complete
2232 * resulting expression is of the form
2233 * <pre>
2234 * (let <b>TYPE</b> <b>TEMP</b> = <b>RVAL</b>;
2235 * in (<b>BUILDER</b>(<b>TEMP</b>)))
2236 * </pre>
2237 * where <code><b>TEMP</b></code> is a newly declared variable
2238 * in the let expression.
2239 */
2240 JCTree abstractRval(JCTree rval, Type type, TreeBuilder builder) {
2241 rval = TreeInfo.skipParens(rval);
2242 switch (rval.getTag()) {
2243 case LITERAL:
2244 return builder.build(rval);
2245 case IDENT:
2246 JCIdent id = (JCIdent) rval;
2247 if ((id.sym.flags() & FINAL) != 0 && id.sym.owner.kind == MTH)
2248 return builder.build(rval);
2249 }
2250 VarSymbol var =
2251 new VarSymbol(FINAL|SYNTHETIC,
2252 names.fromString(
2253 target.syntheticNameChar()
2254 + "" + rval.hashCode()),
2255 type,
2256 currentMethodSym);
2257 rval = convert(rval,type);
2258 JCVariableDecl def = make.VarDef(var, (JCExpression)rval); // XXX cast
2259 JCTree built = builder.build(make.Ident(var));
2260 JCTree res = make.LetExpr(def, built);
2261 res.type = built.type;
2262 return res;
2263 }
2265 // same as above, with the type of the temporary variable computed
2266 JCTree abstractRval(JCTree rval, TreeBuilder builder) {
2267 return abstractRval(rval, rval.type, builder);
2268 }
2270 // same as above, but for an expression that may be used as either
2271 // an rvalue or an lvalue. This requires special handling for
2272 // Select expressions, where we place the left-hand-side of the
2273 // select in a temporary, and for Indexed expressions, where we
2274 // place both the indexed expression and the index value in temps.
2275 JCTree abstractLval(JCTree lval, final TreeBuilder builder) {
2276 lval = TreeInfo.skipParens(lval);
2277 switch (lval.getTag()) {
2278 case IDENT:
2279 return builder.build(lval);
2280 case SELECT: {
2281 final JCFieldAccess s = (JCFieldAccess)lval;
2282 JCTree selected = TreeInfo.skipParens(s.selected);
2283 Symbol lid = TreeInfo.symbol(s.selected);
2284 if (lid != null && lid.kind == TYP) return builder.build(lval);
2285 return abstractRval(s.selected, new TreeBuilder() {
2286 public JCTree build(final JCTree selected) {
2287 return builder.build(make.Select((JCExpression)selected, s.sym));
2288 }
2289 });
2290 }
2291 case INDEXED: {
2292 final JCArrayAccess i = (JCArrayAccess)lval;
2293 return abstractRval(i.indexed, new TreeBuilder() {
2294 public JCTree build(final JCTree indexed) {
2295 return abstractRval(i.index, syms.intType, new TreeBuilder() {
2296 public JCTree build(final JCTree index) {
2297 JCTree newLval = make.Indexed((JCExpression)indexed,
2298 (JCExpression)index);
2299 newLval.setType(i.type);
2300 return builder.build(newLval);
2301 }
2302 });
2303 }
2304 });
2305 }
2306 case TYPECAST: {
2307 return abstractLval(((JCTypeCast)lval).expr, builder);
2308 }
2309 }
2310 throw new AssertionError(lval);
2311 }
2313 // evaluate and discard the first expression, then evaluate the second.
2314 JCTree makeComma(final JCTree expr1, final JCTree expr2) {
2315 return abstractRval(expr1, new TreeBuilder() {
2316 public JCTree build(final JCTree discarded) {
2317 return expr2;
2318 }
2319 });
2320 }
2322 /**************************************************************************
2323 * Translation methods
2324 *************************************************************************/
2326 /** Visitor argument: enclosing operator node.
2327 */
2328 private JCExpression enclOp;
2330 /** Visitor method: Translate a single node.
2331 * Attach the source position from the old tree to its replacement tree.
2332 */
2333 public <T extends JCTree> T translate(T tree) {
2334 if (tree == null) {
2335 return null;
2336 } else {
2337 make_at(tree.pos());
2338 T result = super.translate(tree);
2339 if (endPosTable != null && result != tree) {
2340 endPosTable.replaceTree(tree, result);
2341 }
2342 return result;
2343 }
2344 }
2346 /** Visitor method: Translate a single node, boxing or unboxing if needed.
2347 */
2348 public <T extends JCTree> T translate(T tree, Type type) {
2349 return (tree == null) ? null : boxIfNeeded(translate(tree), type);
2350 }
2352 /** Visitor method: Translate tree.
2353 */
2354 public <T extends JCTree> T translate(T tree, JCExpression enclOp) {
2355 JCExpression prevEnclOp = this.enclOp;
2356 this.enclOp = enclOp;
2357 T res = translate(tree);
2358 this.enclOp = prevEnclOp;
2359 return res;
2360 }
2362 /** Visitor method: Translate list of trees.
2363 */
2364 public <T extends JCTree> List<T> translate(List<T> trees, JCExpression enclOp) {
2365 JCExpression prevEnclOp = this.enclOp;
2366 this.enclOp = enclOp;
2367 List<T> res = translate(trees);
2368 this.enclOp = prevEnclOp;
2369 return res;
2370 }
2372 /** Visitor method: Translate list of trees.
2373 */
2374 public <T extends JCTree> List<T> translate(List<T> trees, Type type) {
2375 if (trees == null) return null;
2376 for (List<T> l = trees; l.nonEmpty(); l = l.tail)
2377 l.head = translate(l.head, type);
2378 return trees;
2379 }
2381 public void visitTopLevel(JCCompilationUnit tree) {
2382 if (needPackageInfoClass(tree)) {
2383 Name name = names.package_info;
2384 long flags = Flags.ABSTRACT | Flags.INTERFACE;
2385 if (target.isPackageInfoSynthetic())
2386 // package-info is marked SYNTHETIC in JDK 1.6 and later releases
2387 flags = flags | Flags.SYNTHETIC;
2388 JCClassDecl packageAnnotationsClass
2389 = make.ClassDef(make.Modifiers(flags,
2390 tree.packageAnnotations),
2391 name, List.<JCTypeParameter>nil(),
2392 null, List.<JCExpression>nil(), List.<JCTree>nil());
2393 ClassSymbol c = tree.packge.package_info;
2394 c.flags_field |= flags;
2395 c.setAttributes(tree.packge);
2396 ClassType ctype = (ClassType) c.type;
2397 ctype.supertype_field = syms.objectType;
2398 ctype.interfaces_field = List.nil();
2399 packageAnnotationsClass.sym = c;
2401 translated.append(packageAnnotationsClass);
2402 }
2403 }
2404 // where
2405 private boolean needPackageInfoClass(JCCompilationUnit tree) {
2406 switch (pkginfoOpt) {
2407 case ALWAYS:
2408 return true;
2409 case LEGACY:
2410 return tree.packageAnnotations.nonEmpty();
2411 case NONEMPTY:
2412 for (Attribute.Compound a :
2413 tree.packge.getDeclarationAttributes()) {
2414 Attribute.RetentionPolicy p = types.getRetention(a);
2415 if (p != Attribute.RetentionPolicy.SOURCE)
2416 return true;
2417 }
2418 return false;
2419 }
2420 throw new AssertionError();
2421 }
2423 public void visitClassDef(JCClassDecl tree) {
2424 ClassSymbol currentClassPrev = currentClass;
2425 MethodSymbol currentMethodSymPrev = currentMethodSym;
2426 currentClass = tree.sym;
2427 currentMethodSym = null;
2428 classdefs.put(currentClass, tree);
2430 proxies = proxies.dup(currentClass);
2431 List<VarSymbol> prevOuterThisStack = outerThisStack;
2433 // If this is an enum definition
2434 if ((tree.mods.flags & ENUM) != 0 &&
2435 (types.supertype(currentClass.type).tsym.flags() & ENUM) == 0)
2436 visitEnumDef(tree);
2438 // If this is a nested class, define a this$n field for
2439 // it and add to proxies.
2440 JCVariableDecl otdef = null;
2441 if (currentClass.hasOuterInstance())
2442 otdef = outerThisDef(tree.pos, currentClass);
2444 // If this is a local class, define proxies for all its free variables.
2445 List<JCVariableDecl> fvdefs = freevarDefs(
2446 tree.pos, freevars(currentClass), currentClass);
2448 // Recursively translate superclass, interfaces.
2449 tree.extending = translate(tree.extending);
2450 tree.implementing = translate(tree.implementing);
2452 if (currentClass.isLocal()) {
2453 ClassSymbol encl = currentClass.owner.enclClass();
2454 if (encl.trans_local == null) {
2455 encl.trans_local = List.nil();
2456 }
2457 encl.trans_local = encl.trans_local.prepend(currentClass);
2458 }
2460 // Recursively translate members, taking into account that new members
2461 // might be created during the translation and prepended to the member
2462 // list `tree.defs'.
2463 List<JCTree> seen = List.nil();
2464 while (tree.defs != seen) {
2465 List<JCTree> unseen = tree.defs;
2466 for (List<JCTree> l = unseen; l.nonEmpty() && l != seen; l = l.tail) {
2467 JCTree outermostMemberDefPrev = outermostMemberDef;
2468 if (outermostMemberDefPrev == null) outermostMemberDef = l.head;
2469 l.head = translate(l.head);
2470 outermostMemberDef = outermostMemberDefPrev;
2471 }
2472 seen = unseen;
2473 }
2475 // Convert a protected modifier to public, mask static modifier.
2476 if ((tree.mods.flags & PROTECTED) != 0) tree.mods.flags |= PUBLIC;
2477 tree.mods.flags &= ClassFlags;
2479 // Convert name to flat representation, replacing '.' by '$'.
2480 tree.name = Convert.shortName(currentClass.flatName());
2482 // Add this$n and free variables proxy definitions to class.
2484 for (List<JCVariableDecl> l = fvdefs; l.nonEmpty(); l = l.tail) {
2485 tree.defs = tree.defs.prepend(l.head);
2486 enterSynthetic(tree.pos(), l.head.sym, currentClass.members());
2487 }
2488 if (currentClass.hasOuterInstance()) {
2489 tree.defs = tree.defs.prepend(otdef);
2490 enterSynthetic(tree.pos(), otdef.sym, currentClass.members());
2491 }
2493 proxies = proxies.leave();
2494 outerThisStack = prevOuterThisStack;
2496 // Append translated tree to `translated' queue.
2497 translated.append(tree);
2499 currentClass = currentClassPrev;
2500 currentMethodSym = currentMethodSymPrev;
2502 // Return empty block {} as a placeholder for an inner class.
2503 result = make_at(tree.pos()).Block(0, List.<JCStatement>nil());
2504 }
2506 /** Translate an enum class. */
2507 private void visitEnumDef(JCClassDecl tree) {
2508 make_at(tree.pos());
2510 // add the supertype, if needed
2511 if (tree.extending == null)
2512 tree.extending = make.Type(types.supertype(tree.type));
2514 // classOfType adds a cache field to tree.defs unless
2515 // target.hasClassLiterals().
2516 JCExpression e_class = classOfType(tree.sym.type, tree.pos()).
2517 setType(types.erasure(syms.classType));
2519 // process each enumeration constant, adding implicit constructor parameters
2520 int nextOrdinal = 0;
2521 ListBuffer<JCExpression> values = new ListBuffer<JCExpression>();
2522 ListBuffer<JCTree> enumDefs = new ListBuffer<JCTree>();
2523 ListBuffer<JCTree> otherDefs = new ListBuffer<JCTree>();
2524 for (List<JCTree> defs = tree.defs;
2525 defs.nonEmpty();
2526 defs=defs.tail) {
2527 if (defs.head.hasTag(VARDEF) && (((JCVariableDecl) defs.head).mods.flags & ENUM) != 0) {
2528 JCVariableDecl var = (JCVariableDecl)defs.head;
2529 visitEnumConstantDef(var, nextOrdinal++);
2530 values.append(make.QualIdent(var.sym));
2531 enumDefs.append(var);
2532 } else {
2533 otherDefs.append(defs.head);
2534 }
2535 }
2537 // private static final T[] #VALUES = { a, b, c };
2538 Name valuesName = names.fromString(target.syntheticNameChar() + "VALUES");
2539 while (tree.sym.members().lookup(valuesName).scope != null) // avoid name clash
2540 valuesName = names.fromString(valuesName + "" + target.syntheticNameChar());
2541 Type arrayType = new ArrayType(types.erasure(tree.type), syms.arrayClass);
2542 VarSymbol valuesVar = new VarSymbol(PRIVATE|FINAL|STATIC|SYNTHETIC,
2543 valuesName,
2544 arrayType,
2545 tree.type.tsym);
2546 JCNewArray newArray = make.NewArray(make.Type(types.erasure(tree.type)),
2547 List.<JCExpression>nil(),
2548 values.toList());
2549 newArray.type = arrayType;
2550 enumDefs.append(make.VarDef(valuesVar, newArray));
2551 tree.sym.members().enter(valuesVar);
2553 Symbol valuesSym = lookupMethod(tree.pos(), names.values,
2554 tree.type, List.<Type>nil());
2555 List<JCStatement> valuesBody;
2556 if (useClone()) {
2557 // return (T[]) $VALUES.clone();
2558 JCTypeCast valuesResult =
2559 make.TypeCast(valuesSym.type.getReturnType(),
2560 make.App(make.Select(make.Ident(valuesVar),
2561 syms.arrayCloneMethod)));
2562 valuesBody = List.<JCStatement>of(make.Return(valuesResult));
2563 } else {
2564 // template: T[] $result = new T[$values.length];
2565 Name resultName = names.fromString(target.syntheticNameChar() + "result");
2566 while (tree.sym.members().lookup(resultName).scope != null) // avoid name clash
2567 resultName = names.fromString(resultName + "" + target.syntheticNameChar());
2568 VarSymbol resultVar = new VarSymbol(FINAL|SYNTHETIC,
2569 resultName,
2570 arrayType,
2571 valuesSym);
2572 JCNewArray resultArray = make.NewArray(make.Type(types.erasure(tree.type)),
2573 List.of(make.Select(make.Ident(valuesVar), syms.lengthVar)),
2574 null);
2575 resultArray.type = arrayType;
2576 JCVariableDecl decl = make.VarDef(resultVar, resultArray);
2578 // template: System.arraycopy($VALUES, 0, $result, 0, $VALUES.length);
2579 if (systemArraycopyMethod == null) {
2580 systemArraycopyMethod =
2581 new MethodSymbol(PUBLIC | STATIC,
2582 names.fromString("arraycopy"),
2583 new MethodType(List.<Type>of(syms.objectType,
2584 syms.intType,
2585 syms.objectType,
2586 syms.intType,
2587 syms.intType),
2588 syms.voidType,
2589 List.<Type>nil(),
2590 syms.methodClass),
2591 syms.systemType.tsym);
2592 }
2593 JCStatement copy =
2594 make.Exec(make.App(make.Select(make.Ident(syms.systemType.tsym),
2595 systemArraycopyMethod),
2596 List.of(make.Ident(valuesVar), make.Literal(0),
2597 make.Ident(resultVar), make.Literal(0),
2598 make.Select(make.Ident(valuesVar), syms.lengthVar))));
2600 // template: return $result;
2601 JCStatement ret = make.Return(make.Ident(resultVar));
2602 valuesBody = List.<JCStatement>of(decl, copy, ret);
2603 }
2605 JCMethodDecl valuesDef =
2606 make.MethodDef((MethodSymbol)valuesSym, make.Block(0, valuesBody));
2608 enumDefs.append(valuesDef);
2610 if (debugLower)
2611 System.err.println(tree.sym + ".valuesDef = " + valuesDef);
2613 /** The template for the following code is:
2614 *
2615 * public static E valueOf(String name) {
2616 * return (E)Enum.valueOf(E.class, name);
2617 * }
2618 *
2619 * where E is tree.sym
2620 */
2621 MethodSymbol valueOfSym = lookupMethod(tree.pos(),
2622 names.valueOf,
2623 tree.sym.type,
2624 List.of(syms.stringType));
2625 Assert.check((valueOfSym.flags() & STATIC) != 0);
2626 VarSymbol nameArgSym = valueOfSym.params.head;
2627 JCIdent nameVal = make.Ident(nameArgSym);
2628 JCStatement enum_ValueOf =
2629 make.Return(make.TypeCast(tree.sym.type,
2630 makeCall(make.Ident(syms.enumSym),
2631 names.valueOf,
2632 List.of(e_class, nameVal))));
2633 JCMethodDecl valueOf = make.MethodDef(valueOfSym,
2634 make.Block(0, List.of(enum_ValueOf)));
2635 nameVal.sym = valueOf.params.head.sym;
2636 if (debugLower)
2637 System.err.println(tree.sym + ".valueOf = " + valueOf);
2638 enumDefs.append(valueOf);
2640 enumDefs.appendList(otherDefs.toList());
2641 tree.defs = enumDefs.toList();
2642 }
2643 // where
2644 private MethodSymbol systemArraycopyMethod;
2645 private boolean useClone() {
2646 try {
2647 Scope.Entry e = syms.objectType.tsym.members().lookup(names.clone);
2648 return (e.sym != null);
2649 }
2650 catch (CompletionFailure e) {
2651 return false;
2652 }
2653 }
2655 /** Translate an enumeration constant and its initializer. */
2656 private void visitEnumConstantDef(JCVariableDecl var, int ordinal) {
2657 JCNewClass varDef = (JCNewClass)var.init;
2658 varDef.args = varDef.args.
2659 prepend(makeLit(syms.intType, ordinal)).
2660 prepend(makeLit(syms.stringType, var.name.toString()));
2661 }
2663 public void visitMethodDef(JCMethodDecl tree) {
2664 if (tree.name == names.init && (currentClass.flags_field&ENUM) != 0) {
2665 // Add "String $enum$name, int $enum$ordinal" to the beginning of the
2666 // argument list for each constructor of an enum.
2667 JCVariableDecl nameParam = make_at(tree.pos()).
2668 Param(names.fromString(target.syntheticNameChar() +
2669 "enum" + target.syntheticNameChar() + "name"),
2670 syms.stringType, tree.sym);
2671 nameParam.mods.flags |= SYNTHETIC; nameParam.sym.flags_field |= SYNTHETIC;
2672 JCVariableDecl ordParam = make.
2673 Param(names.fromString(target.syntheticNameChar() +
2674 "enum" + target.syntheticNameChar() +
2675 "ordinal"),
2676 syms.intType, tree.sym);
2677 ordParam.mods.flags |= SYNTHETIC; ordParam.sym.flags_field |= SYNTHETIC;
2679 tree.params = tree.params.prepend(ordParam).prepend(nameParam);
2681 MethodSymbol m = tree.sym;
2682 m.extraParams = m.extraParams.prepend(ordParam.sym);
2683 m.extraParams = m.extraParams.prepend(nameParam.sym);
2684 Type olderasure = m.erasure(types);
2685 m.erasure_field = new MethodType(
2686 olderasure.getParameterTypes().prepend(syms.intType).prepend(syms.stringType),
2687 olderasure.getReturnType(),
2688 olderasure.getThrownTypes(),
2689 syms.methodClass);
2690 }
2692 JCMethodDecl prevMethodDef = currentMethodDef;
2693 MethodSymbol prevMethodSym = currentMethodSym;
2694 try {
2695 currentMethodDef = tree;
2696 currentMethodSym = tree.sym;
2697 visitMethodDefInternal(tree);
2698 } finally {
2699 currentMethodDef = prevMethodDef;
2700 currentMethodSym = prevMethodSym;
2701 }
2702 }
2703 //where
2704 private void visitMethodDefInternal(JCMethodDecl tree) {
2705 if (tree.name == names.init &&
2706 (currentClass.isInner() || currentClass.isLocal())) {
2707 // We are seeing a constructor of an inner class.
2708 MethodSymbol m = tree.sym;
2710 // Push a new proxy scope for constructor parameters.
2711 // and create definitions for any this$n and proxy parameters.
2712 proxies = proxies.dup(m);
2713 List<VarSymbol> prevOuterThisStack = outerThisStack;
2714 List<VarSymbol> fvs = freevars(currentClass);
2715 JCVariableDecl otdef = null;
2716 if (currentClass.hasOuterInstance())
2717 otdef = outerThisDef(tree.pos, m);
2718 List<JCVariableDecl> fvdefs = freevarDefs(tree.pos, fvs, m, PARAMETER);
2720 // Recursively translate result type, parameters and thrown list.
2721 tree.restype = translate(tree.restype);
2722 tree.params = translateVarDefs(tree.params);
2723 tree.thrown = translate(tree.thrown);
2725 // when compiling stubs, don't process body
2726 if (tree.body == null) {
2727 result = tree;
2728 return;
2729 }
2731 // Add this$n (if needed) in front of and free variables behind
2732 // constructor parameter list.
2733 tree.params = tree.params.appendList(fvdefs);
2734 if (currentClass.hasOuterInstance())
2735 tree.params = tree.params.prepend(otdef);
2737 // If this is an initial constructor, i.e., it does not start with
2738 // this(...), insert initializers for this$n and proxies
2739 // before (pre-1.4, after) the call to superclass constructor.
2740 JCStatement selfCall = translate(tree.body.stats.head);
2742 List<JCStatement> added = List.nil();
2743 if (fvs.nonEmpty()) {
2744 List<Type> addedargtypes = List.nil();
2745 for (List<VarSymbol> l = fvs; l.nonEmpty(); l = l.tail) {
2746 if (TreeInfo.isInitialConstructor(tree)) {
2747 final Name pName = proxyName(l.head.name);
2748 m.capturedLocals =
2749 m.capturedLocals.append((VarSymbol)
2750 (proxies.lookup(pName).sym));
2751 added = added.prepend(
2752 initField(tree.body.pos, pName));
2753 }
2754 addedargtypes = addedargtypes.prepend(l.head.erasure(types));
2755 }
2756 Type olderasure = m.erasure(types);
2757 m.erasure_field = new MethodType(
2758 olderasure.getParameterTypes().appendList(addedargtypes),
2759 olderasure.getReturnType(),
2760 olderasure.getThrownTypes(),
2761 syms.methodClass);
2762 }
2763 if (currentClass.hasOuterInstance() &&
2764 TreeInfo.isInitialConstructor(tree))
2765 {
2766 added = added.prepend(initOuterThis(tree.body.pos));
2767 }
2769 // pop local variables from proxy stack
2770 proxies = proxies.leave();
2772 // recursively translate following local statements and
2773 // combine with this- or super-call
2774 List<JCStatement> stats = translate(tree.body.stats.tail);
2775 if (target.initializeFieldsBeforeSuper())
2776 tree.body.stats = stats.prepend(selfCall).prependList(added);
2777 else
2778 tree.body.stats = stats.prependList(added).prepend(selfCall);
2780 outerThisStack = prevOuterThisStack;
2781 } else {
2782 Map<Symbol, Symbol> prevLambdaTranslationMap =
2783 lambdaTranslationMap;
2784 try {
2785 lambdaTranslationMap = (tree.sym.flags() & SYNTHETIC) != 0 &&
2786 tree.sym.name.startsWith(names.lambda) ?
2787 makeTranslationMap(tree) : null;
2788 super.visitMethodDef(tree);
2789 } finally {
2790 lambdaTranslationMap = prevLambdaTranslationMap;
2791 }
2792 }
2793 result = tree;
2794 }
2795 //where
2796 private Map<Symbol, Symbol> makeTranslationMap(JCMethodDecl tree) {
2797 Map<Symbol, Symbol> translationMap = new HashMap<Symbol,Symbol>();
2798 for (JCVariableDecl vd : tree.params) {
2799 Symbol p = vd.sym;
2800 if (p != p.baseSymbol()) {
2801 translationMap.put(p.baseSymbol(), p);
2802 }
2803 }
2804 return translationMap;
2805 }
2807 public void visitAnnotatedType(JCAnnotatedType tree) {
2808 // No need to retain type annotations in the tree
2809 // tree.annotations = translate(tree.annotations);
2810 tree.annotations = List.nil();
2811 tree.underlyingType = translate(tree.underlyingType);
2812 // but maintain type annotations in the type.
2813 if (tree.type.isAnnotated()) {
2814 if (tree.underlyingType.type.isAnnotated()) {
2815 // The erasure of a type variable might be annotated.
2816 // Merge all annotations.
2817 AnnotatedType newat = (AnnotatedType) tree.underlyingType.type;
2818 AnnotatedType at = (AnnotatedType) tree.type;
2819 at.underlyingType = newat.underlyingType;
2820 newat.typeAnnotations = at.typeAnnotations.appendList(newat.typeAnnotations);
2821 tree.type = newat;
2822 } else {
2823 // Create a new AnnotatedType to have the correct tag.
2824 AnnotatedType oldat = (AnnotatedType) tree.type;
2825 tree.type = new AnnotatedType(tree.underlyingType.type);
2826 ((AnnotatedType) tree.type).typeAnnotations = oldat.typeAnnotations;
2827 }
2828 }
2829 result = tree;
2830 }
2832 public void visitTypeCast(JCTypeCast tree) {
2833 tree.clazz = translate(tree.clazz);
2834 if (tree.type.isPrimitive() != tree.expr.type.isPrimitive())
2835 tree.expr = translate(tree.expr, tree.type);
2836 else
2837 tree.expr = translate(tree.expr);
2838 result = tree;
2839 }
2841 public void visitNewClass(JCNewClass tree) {
2842 ClassSymbol c = (ClassSymbol)tree.constructor.owner;
2844 // Box arguments, if necessary
2845 boolean isEnum = (tree.constructor.owner.flags() & ENUM) != 0;
2846 List<Type> argTypes = tree.constructor.type.getParameterTypes();
2847 if (isEnum) argTypes = argTypes.prepend(syms.intType).prepend(syms.stringType);
2848 tree.args = boxArgs(argTypes, tree.args, tree.varargsElement);
2849 tree.varargsElement = null;
2851 // If created class is local, add free variables after
2852 // explicit constructor arguments.
2853 if (c.isLocal()) {
2854 tree.args = tree.args.appendList(loadFreevars(tree.pos(), freevars(c)));
2855 }
2857 // If an access constructor is used, append null as a last argument.
2858 Symbol constructor = accessConstructor(tree.pos(), tree.constructor);
2859 if (constructor != tree.constructor) {
2860 tree.args = tree.args.append(makeNull());
2861 tree.constructor = constructor;
2862 }
2864 // If created class has an outer instance, and new is qualified, pass
2865 // qualifier as first argument. If new is not qualified, pass the
2866 // correct outer instance as first argument.
2867 if (c.hasOuterInstance()) {
2868 JCExpression thisArg;
2869 if (tree.encl != null) {
2870 thisArg = attr.makeNullCheck(translate(tree.encl));
2871 thisArg.type = tree.encl.type;
2872 } else if (c.isLocal()) {
2873 // local class
2874 thisArg = makeThis(tree.pos(), c.type.getEnclosingType().tsym);
2875 } else {
2876 // nested class
2877 thisArg = makeOwnerThis(tree.pos(), c, false);
2878 }
2879 tree.args = tree.args.prepend(thisArg);
2880 }
2881 tree.encl = null;
2883 // If we have an anonymous class, create its flat version, rather
2884 // than the class or interface following new.
2885 if (tree.def != null) {
2886 translate(tree.def);
2887 tree.clazz = access(make_at(tree.clazz.pos()).Ident(tree.def.sym));
2888 tree.def = null;
2889 } else {
2890 tree.clazz = access(c, tree.clazz, enclOp, false);
2891 }
2892 result = tree;
2893 }
2895 // Simplify conditionals with known constant controlling expressions.
2896 // This allows us to avoid generating supporting declarations for
2897 // the dead code, which will not be eliminated during code generation.
2898 // Note that Flow.isFalse and Flow.isTrue only return true
2899 // for constant expressions in the sense of JLS 15.27, which
2900 // are guaranteed to have no side-effects. More aggressive
2901 // constant propagation would require that we take care to
2902 // preserve possible side-effects in the condition expression.
2904 /** Visitor method for conditional expressions.
2905 */
2906 @Override
2907 public void visitConditional(JCConditional tree) {
2908 JCTree cond = tree.cond = translate(tree.cond, syms.booleanType);
2909 if (cond.type.isTrue()) {
2910 result = convert(translate(tree.truepart, tree.type), tree.type);
2911 addPrunedInfo(cond);
2912 } else if (cond.type.isFalse()) {
2913 result = convert(translate(tree.falsepart, tree.type), tree.type);
2914 addPrunedInfo(cond);
2915 } else {
2916 // Condition is not a compile-time constant.
2917 tree.truepart = translate(tree.truepart, tree.type);
2918 tree.falsepart = translate(tree.falsepart, tree.type);
2919 result = tree;
2920 }
2921 }
2922 //where
2923 private JCTree convert(JCTree tree, Type pt) {
2924 if (tree.type == pt || tree.type.hasTag(BOT))
2925 return tree;
2926 JCTree result = make_at(tree.pos()).TypeCast(make.Type(pt), (JCExpression)tree);
2927 result.type = (tree.type.constValue() != null) ? cfolder.coerce(tree.type, pt)
2928 : pt;
2929 return result;
2930 }
2932 /** Visitor method for if statements.
2933 */
2934 public void visitIf(JCIf tree) {
2935 JCTree cond = tree.cond = translate(tree.cond, syms.booleanType);
2936 if (cond.type.isTrue()) {
2937 result = translate(tree.thenpart);
2938 addPrunedInfo(cond);
2939 } else if (cond.type.isFalse()) {
2940 if (tree.elsepart != null) {
2941 result = translate(tree.elsepart);
2942 } else {
2943 result = make.Skip();
2944 }
2945 addPrunedInfo(cond);
2946 } else {
2947 // Condition is not a compile-time constant.
2948 tree.thenpart = translate(tree.thenpart);
2949 tree.elsepart = translate(tree.elsepart);
2950 result = tree;
2951 }
2952 }
2954 /** Visitor method for assert statements. Translate them away.
2955 */
2956 public void visitAssert(JCAssert tree) {
2957 DiagnosticPosition detailPos = (tree.detail == null) ? tree.pos() : tree.detail.pos();
2958 tree.cond = translate(tree.cond, syms.booleanType);
2959 if (!tree.cond.type.isTrue()) {
2960 JCExpression cond = assertFlagTest(tree.pos());
2961 List<JCExpression> exnArgs = (tree.detail == null) ?
2962 List.<JCExpression>nil() : List.of(translate(tree.detail));
2963 if (!tree.cond.type.isFalse()) {
2964 cond = makeBinary
2965 (AND,
2966 cond,
2967 makeUnary(NOT, tree.cond));
2968 }
2969 result =
2970 make.If(cond,
2971 make_at(tree).
2972 Throw(makeNewClass(syms.assertionErrorType, exnArgs)),
2973 null);
2974 } else {
2975 result = make.Skip();
2976 }
2977 }
2979 public void visitApply(JCMethodInvocation tree) {
2980 Symbol meth = TreeInfo.symbol(tree.meth);
2981 List<Type> argtypes = meth.type.getParameterTypes();
2982 if (allowEnums &&
2983 meth.name==names.init &&
2984 meth.owner == syms.enumSym)
2985 argtypes = argtypes.tail.tail;
2986 tree.args = boxArgs(argtypes, tree.args, tree.varargsElement);
2987 tree.varargsElement = null;
2988 Name methName = TreeInfo.name(tree.meth);
2989 if (meth.name==names.init) {
2990 // We are seeing a this(...) or super(...) constructor call.
2991 // If an access constructor is used, append null as a last argument.
2992 Symbol constructor = accessConstructor(tree.pos(), meth);
2993 if (constructor != meth) {
2994 tree.args = tree.args.append(makeNull());
2995 TreeInfo.setSymbol(tree.meth, constructor);
2996 }
2998 // If we are calling a constructor of a local class, add
2999 // free variables after explicit constructor arguments.
3000 ClassSymbol c = (ClassSymbol)constructor.owner;
3001 if (c.isLocal()) {
3002 tree.args = tree.args.appendList(loadFreevars(tree.pos(), freevars(c)));
3003 }
3005 // If we are calling a constructor of an enum class, pass
3006 // along the name and ordinal arguments
3007 if ((c.flags_field&ENUM) != 0 || c.getQualifiedName() == names.java_lang_Enum) {
3008 List<JCVariableDecl> params = currentMethodDef.params;
3009 if (currentMethodSym.owner.hasOuterInstance())
3010 params = params.tail; // drop this$n
3011 tree.args = tree.args
3012 .prepend(make_at(tree.pos()).Ident(params.tail.head.sym)) // ordinal
3013 .prepend(make.Ident(params.head.sym)); // name
3014 }
3016 // If we are calling a constructor of a class with an outer
3017 // instance, and the call
3018 // is qualified, pass qualifier as first argument in front of
3019 // the explicit constructor arguments. If the call
3020 // is not qualified, pass the correct outer instance as
3021 // first argument.
3022 if (c.hasOuterInstance()) {
3023 JCExpression thisArg;
3024 if (tree.meth.hasTag(SELECT)) {
3025 thisArg = attr.
3026 makeNullCheck(translate(((JCFieldAccess) tree.meth).selected));
3027 tree.meth = make.Ident(constructor);
3028 ((JCIdent) tree.meth).name = methName;
3029 } else if (c.isLocal() || methName == names._this){
3030 // local class or this() call
3031 thisArg = makeThis(tree.meth.pos(), c.type.getEnclosingType().tsym);
3032 } else {
3033 // super() call of nested class - never pick 'this'
3034 thisArg = makeOwnerThisN(tree.meth.pos(), c, false);
3035 }
3036 tree.args = tree.args.prepend(thisArg);
3037 }
3038 } else {
3039 // We are seeing a normal method invocation; translate this as usual.
3040 tree.meth = translate(tree.meth);
3042 // If the translated method itself is an Apply tree, we are
3043 // seeing an access method invocation. In this case, append
3044 // the method arguments to the arguments of the access method.
3045 if (tree.meth.hasTag(APPLY)) {
3046 JCMethodInvocation app = (JCMethodInvocation)tree.meth;
3047 app.args = tree.args.prependList(app.args);
3048 result = app;
3049 return;
3050 }
3051 }
3052 result = tree;
3053 }
3055 List<JCExpression> boxArgs(List<Type> parameters, List<JCExpression> _args, Type varargsElement) {
3056 List<JCExpression> args = _args;
3057 if (parameters.isEmpty()) return args;
3058 boolean anyChanges = false;
3059 ListBuffer<JCExpression> result = new ListBuffer<JCExpression>();
3060 while (parameters.tail.nonEmpty()) {
3061 JCExpression arg = translate(args.head, parameters.head);
3062 anyChanges |= (arg != args.head);
3063 result.append(arg);
3064 args = args.tail;
3065 parameters = parameters.tail;
3066 }
3067 Type parameter = parameters.head;
3068 if (varargsElement != null) {
3069 anyChanges = true;
3070 ListBuffer<JCExpression> elems = new ListBuffer<JCExpression>();
3071 while (args.nonEmpty()) {
3072 JCExpression arg = translate(args.head, varargsElement);
3073 elems.append(arg);
3074 args = args.tail;
3075 }
3076 JCNewArray boxedArgs = make.NewArray(make.Type(varargsElement),
3077 List.<JCExpression>nil(),
3078 elems.toList());
3079 boxedArgs.type = new ArrayType(varargsElement, syms.arrayClass);
3080 result.append(boxedArgs);
3081 } else {
3082 if (args.length() != 1) throw new AssertionError(args);
3083 JCExpression arg = translate(args.head, parameter);
3084 anyChanges |= (arg != args.head);
3085 result.append(arg);
3086 if (!anyChanges) return _args;
3087 }
3088 return result.toList();
3089 }
3091 /** Expand a boxing or unboxing conversion if needed. */
3092 @SuppressWarnings("unchecked") // XXX unchecked
3093 <T extends JCTree> T boxIfNeeded(T tree, Type type) {
3094 boolean havePrimitive = tree.type.isPrimitive();
3095 if (havePrimitive == type.isPrimitive())
3096 return tree;
3097 if (havePrimitive) {
3098 Type unboxedTarget = types.unboxedType(type);
3099 if (!unboxedTarget.hasTag(NONE)) {
3100 if (!types.isSubtype(tree.type, unboxedTarget)) //e.g. Character c = 89;
3101 tree.type = unboxedTarget.constType(tree.type.constValue());
3102 return (T)boxPrimitive((JCExpression)tree, type);
3103 } else {
3104 tree = (T)boxPrimitive((JCExpression)tree);
3105 }
3106 } else {
3107 tree = (T)unbox((JCExpression)tree, type);
3108 }
3109 return tree;
3110 }
3112 /** Box up a single primitive expression. */
3113 JCExpression boxPrimitive(JCExpression tree) {
3114 return boxPrimitive(tree, types.boxedClass(tree.type).type);
3115 }
3117 /** Box up a single primitive expression. */
3118 JCExpression boxPrimitive(JCExpression tree, Type box) {
3119 make_at(tree.pos());
3120 if (target.boxWithConstructors()) {
3121 Symbol ctor = lookupConstructor(tree.pos(),
3122 box,
3123 List.<Type>nil()
3124 .prepend(tree.type));
3125 return make.Create(ctor, List.of(tree));
3126 } else {
3127 Symbol valueOfSym = lookupMethod(tree.pos(),
3128 names.valueOf,
3129 box,
3130 List.<Type>nil()
3131 .prepend(tree.type));
3132 return make.App(make.QualIdent(valueOfSym), List.of(tree));
3133 }
3134 }
3136 /** Unbox an object to a primitive value. */
3137 JCExpression unbox(JCExpression tree, Type primitive) {
3138 Type unboxedType = types.unboxedType(tree.type);
3139 if (unboxedType.hasTag(NONE)) {
3140 unboxedType = primitive;
3141 if (!unboxedType.isPrimitive())
3142 throw new AssertionError(unboxedType);
3143 make_at(tree.pos());
3144 tree = make.TypeCast(types.boxedClass(unboxedType).type, tree);
3145 } else {
3146 // There must be a conversion from unboxedType to primitive.
3147 if (!types.isSubtype(unboxedType, primitive))
3148 throw new AssertionError(tree);
3149 }
3150 make_at(tree.pos());
3151 Symbol valueSym = lookupMethod(tree.pos(),
3152 unboxedType.tsym.name.append(names.Value), // x.intValue()
3153 tree.type,
3154 List.<Type>nil());
3155 return make.App(make.Select(tree, valueSym));
3156 }
3158 /** Visitor method for parenthesized expressions.
3159 * If the subexpression has changed, omit the parens.
3160 */
3161 public void visitParens(JCParens tree) {
3162 JCTree expr = translate(tree.expr);
3163 result = ((expr == tree.expr) ? tree : expr);
3164 }
3166 public void visitIndexed(JCArrayAccess tree) {
3167 tree.indexed = translate(tree.indexed);
3168 tree.index = translate(tree.index, syms.intType);
3169 result = tree;
3170 }
3172 public void visitAssign(JCAssign tree) {
3173 tree.lhs = translate(tree.lhs, tree);
3174 tree.rhs = translate(tree.rhs, tree.lhs.type);
3176 // If translated left hand side is an Apply, we are
3177 // seeing an access method invocation. In this case, append
3178 // right hand side as last argument of the access method.
3179 if (tree.lhs.hasTag(APPLY)) {
3180 JCMethodInvocation app = (JCMethodInvocation)tree.lhs;
3181 app.args = List.of(tree.rhs).prependList(app.args);
3182 result = app;
3183 } else {
3184 result = tree;
3185 }
3186 }
3188 public void visitAssignop(final JCAssignOp tree) {
3189 JCTree lhsAccess = access(TreeInfo.skipParens(tree.lhs));
3190 final boolean boxingReq = !tree.lhs.type.isPrimitive() &&
3191 tree.operator.type.getReturnType().isPrimitive();
3193 if (boxingReq || lhsAccess.hasTag(APPLY)) {
3194 // boxing required; need to rewrite as x = (unbox typeof x)(x op y);
3195 // or if x == (typeof x)z then z = (unbox typeof x)((typeof x)z op y)
3196 // (but without recomputing x)
3197 JCTree newTree = abstractLval(tree.lhs, new TreeBuilder() {
3198 public JCTree build(final JCTree lhs) {
3199 JCTree.Tag newTag = tree.getTag().noAssignOp();
3200 // Erasure (TransTypes) can change the type of
3201 // tree.lhs. However, we can still get the
3202 // unerased type of tree.lhs as it is stored
3203 // in tree.type in Attr.
3204 Symbol newOperator = rs.resolveBinaryOperator(tree.pos(),
3205 newTag,
3206 attrEnv,
3207 tree.type,
3208 tree.rhs.type);
3209 JCExpression expr = (JCExpression)lhs;
3210 if (expr.type != tree.type)
3211 expr = make.TypeCast(tree.type, expr);
3212 JCBinary opResult = make.Binary(newTag, expr, tree.rhs);
3213 opResult.operator = newOperator;
3214 opResult.type = newOperator.type.getReturnType();
3215 JCExpression newRhs = boxingReq ?
3216 make.TypeCast(types.unboxedType(tree.type), opResult) :
3217 opResult;
3218 return make.Assign((JCExpression)lhs, newRhs).setType(tree.type);
3219 }
3220 });
3221 result = translate(newTree);
3222 return;
3223 }
3224 tree.lhs = translate(tree.lhs, tree);
3225 tree.rhs = translate(tree.rhs, tree.operator.type.getParameterTypes().tail.head);
3227 // If translated left hand side is an Apply, we are
3228 // seeing an access method invocation. In this case, append
3229 // right hand side as last argument of the access method.
3230 if (tree.lhs.hasTag(APPLY)) {
3231 JCMethodInvocation app = (JCMethodInvocation)tree.lhs;
3232 // if operation is a += on strings,
3233 // make sure to convert argument to string
3234 JCExpression rhs = (((OperatorSymbol)tree.operator).opcode == string_add)
3235 ? makeString(tree.rhs)
3236 : tree.rhs;
3237 app.args = List.of(rhs).prependList(app.args);
3238 result = app;
3239 } else {
3240 result = tree;
3241 }
3242 }
3244 /** Lower a tree of the form e++ or e-- where e is an object type */
3245 JCTree lowerBoxedPostop(final JCUnary tree) {
3246 // translate to tmp1=lval(e); tmp2=tmp1; tmp1 OP 1; tmp2
3247 // or
3248 // translate to tmp1=lval(e); tmp2=tmp1; (typeof tree)tmp1 OP 1; tmp2
3249 // where OP is += or -=
3250 final boolean cast = TreeInfo.skipParens(tree.arg).hasTag(TYPECAST);
3251 return abstractLval(tree.arg, new TreeBuilder() {
3252 public JCTree build(final JCTree tmp1) {
3253 return abstractRval(tmp1, tree.arg.type, new TreeBuilder() {
3254 public JCTree build(final JCTree tmp2) {
3255 JCTree.Tag opcode = (tree.hasTag(POSTINC))
3256 ? PLUS_ASG : MINUS_ASG;
3257 JCTree lhs = cast
3258 ? make.TypeCast(tree.arg.type, (JCExpression)tmp1)
3259 : tmp1;
3260 JCTree update = makeAssignop(opcode,
3261 lhs,
3262 make.Literal(1));
3263 return makeComma(update, tmp2);
3264 }
3265 });
3266 }
3267 });
3268 }
3270 public void visitUnary(JCUnary tree) {
3271 boolean isUpdateOperator = tree.getTag().isIncOrDecUnaryOp();
3272 if (isUpdateOperator && !tree.arg.type.isPrimitive()) {
3273 switch(tree.getTag()) {
3274 case PREINC: // ++ e
3275 // translate to e += 1
3276 case PREDEC: // -- e
3277 // translate to e -= 1
3278 {
3279 JCTree.Tag opcode = (tree.hasTag(PREINC))
3280 ? PLUS_ASG : MINUS_ASG;
3281 JCAssignOp newTree = makeAssignop(opcode,
3282 tree.arg,
3283 make.Literal(1));
3284 result = translate(newTree, tree.type);
3285 return;
3286 }
3287 case POSTINC: // e ++
3288 case POSTDEC: // e --
3289 {
3290 result = translate(lowerBoxedPostop(tree), tree.type);
3291 return;
3292 }
3293 }
3294 throw new AssertionError(tree);
3295 }
3297 tree.arg = boxIfNeeded(translate(tree.arg, tree), tree.type);
3299 if (tree.hasTag(NOT) && tree.arg.type.constValue() != null) {
3300 tree.type = cfolder.fold1(bool_not, tree.arg.type);
3301 }
3303 // If translated left hand side is an Apply, we are
3304 // seeing an access method invocation. In this case, return
3305 // that access method invocation as result.
3306 if (isUpdateOperator && tree.arg.hasTag(APPLY)) {
3307 result = tree.arg;
3308 } else {
3309 result = tree;
3310 }
3311 }
3313 public void visitBinary(JCBinary tree) {
3314 List<Type> formals = tree.operator.type.getParameterTypes();
3315 JCTree lhs = tree.lhs = translate(tree.lhs, formals.head);
3316 switch (tree.getTag()) {
3317 case OR:
3318 if (lhs.type.isTrue()) {
3319 result = lhs;
3320 return;
3321 }
3322 if (lhs.type.isFalse()) {
3323 result = translate(tree.rhs, formals.tail.head);
3324 return;
3325 }
3326 break;
3327 case AND:
3328 if (lhs.type.isFalse()) {
3329 result = lhs;
3330 return;
3331 }
3332 if (lhs.type.isTrue()) {
3333 result = translate(tree.rhs, formals.tail.head);
3334 return;
3335 }
3336 break;
3337 }
3338 tree.rhs = translate(tree.rhs, formals.tail.head);
3339 result = tree;
3340 }
3342 public void visitIdent(JCIdent tree) {
3343 result = access(tree.sym, tree, enclOp, false);
3344 }
3346 /** Translate away the foreach loop. */
3347 public void visitForeachLoop(JCEnhancedForLoop tree) {
3348 if (types.elemtype(tree.expr.type) == null)
3349 visitIterableForeachLoop(tree);
3350 else
3351 visitArrayForeachLoop(tree);
3352 }
3353 // where
3354 /**
3355 * A statement of the form
3356 *
3357 * <pre>
3358 * for ( T v : arrayexpr ) stmt;
3359 * </pre>
3360 *
3361 * (where arrayexpr is of an array type) gets translated to
3362 *
3363 * <pre>{@code
3364 * for ( { arraytype #arr = arrayexpr;
3365 * int #len = array.length;
3366 * int #i = 0; };
3367 * #i < #len; i$++ ) {
3368 * T v = arr$[#i];
3369 * stmt;
3370 * }
3371 * }</pre>
3372 *
3373 * where #arr, #len, and #i are freshly named synthetic local variables.
3374 */
3375 private void visitArrayForeachLoop(JCEnhancedForLoop tree) {
3376 make_at(tree.expr.pos());
3377 VarSymbol arraycache = new VarSymbol(SYNTHETIC,
3378 names.fromString("arr" + target.syntheticNameChar()),
3379 tree.expr.type,
3380 currentMethodSym);
3381 JCStatement arraycachedef = make.VarDef(arraycache, tree.expr);
3382 VarSymbol lencache = new VarSymbol(SYNTHETIC,
3383 names.fromString("len" + target.syntheticNameChar()),
3384 syms.intType,
3385 currentMethodSym);
3386 JCStatement lencachedef = make.
3387 VarDef(lencache, make.Select(make.Ident(arraycache), syms.lengthVar));
3388 VarSymbol index = new VarSymbol(SYNTHETIC,
3389 names.fromString("i" + target.syntheticNameChar()),
3390 syms.intType,
3391 currentMethodSym);
3393 JCVariableDecl indexdef = make.VarDef(index, make.Literal(INT, 0));
3394 indexdef.init.type = indexdef.type = syms.intType.constType(0);
3396 List<JCStatement> loopinit = List.of(arraycachedef, lencachedef, indexdef);
3397 JCBinary cond = makeBinary(LT, make.Ident(index), make.Ident(lencache));
3399 JCExpressionStatement step = make.Exec(makeUnary(PREINC, make.Ident(index)));
3401 Type elemtype = types.elemtype(tree.expr.type);
3402 JCExpression loopvarinit = make.Indexed(make.Ident(arraycache),
3403 make.Ident(index)).setType(elemtype);
3404 JCVariableDecl loopvardef = (JCVariableDecl)make.VarDef(tree.var.mods,
3405 tree.var.name,
3406 tree.var.vartype,
3407 loopvarinit).setType(tree.var.type);
3408 loopvardef.sym = tree.var.sym;
3409 JCBlock body = make.
3410 Block(0, List.of(loopvardef, tree.body));
3412 result = translate(make.
3413 ForLoop(loopinit,
3414 cond,
3415 List.of(step),
3416 body));
3417 patchTargets(body, tree, result);
3418 }
3419 /** Patch up break and continue targets. */
3420 private void patchTargets(JCTree body, final JCTree src, final JCTree dest) {
3421 class Patcher extends TreeScanner {
3422 public void visitBreak(JCBreak tree) {
3423 if (tree.target == src)
3424 tree.target = dest;
3425 }
3426 public void visitContinue(JCContinue tree) {
3427 if (tree.target == src)
3428 tree.target = dest;
3429 }
3430 public void visitClassDef(JCClassDecl tree) {}
3431 }
3432 new Patcher().scan(body);
3433 }
3434 /**
3435 * A statement of the form
3436 *
3437 * <pre>
3438 * for ( T v : coll ) stmt ;
3439 * </pre>
3440 *
3441 * (where coll implements {@code Iterable<? extends T>}) gets translated to
3442 *
3443 * <pre>{@code
3444 * for ( Iterator<? extends T> #i = coll.iterator(); #i.hasNext(); ) {
3445 * T v = (T) #i.next();
3446 * stmt;
3447 * }
3448 * }</pre>
3449 *
3450 * where #i is a freshly named synthetic local variable.
3451 */
3452 private void visitIterableForeachLoop(JCEnhancedForLoop tree) {
3453 make_at(tree.expr.pos());
3454 Type iteratorTarget = syms.objectType;
3455 Type iterableType = types.asSuper(types.upperBound(tree.expr.type),
3456 syms.iterableType.tsym);
3457 if (iterableType.getTypeArguments().nonEmpty())
3458 iteratorTarget = types.erasure(iterableType.getTypeArguments().head);
3459 Type eType = tree.expr.type;
3460 while (eType.hasTag(TYPEVAR)) {
3461 eType = eType.getUpperBound();
3462 }
3463 tree.expr.type = types.erasure(eType);
3464 if (eType.isCompound())
3465 tree.expr = make.TypeCast(types.erasure(iterableType), tree.expr);
3466 Symbol iterator = lookupMethod(tree.expr.pos(),
3467 names.iterator,
3468 eType,
3469 List.<Type>nil());
3470 VarSymbol itvar = new VarSymbol(SYNTHETIC, names.fromString("i" + target.syntheticNameChar()),
3471 types.erasure(types.asSuper(iterator.type.getReturnType(), syms.iteratorType.tsym)),
3472 currentMethodSym);
3474 JCStatement init = make.
3475 VarDef(itvar, make.App(make.Select(tree.expr, iterator)
3476 .setType(types.erasure(iterator.type))));
3478 Symbol hasNext = lookupMethod(tree.expr.pos(),
3479 names.hasNext,
3480 itvar.type,
3481 List.<Type>nil());
3482 JCMethodInvocation cond = make.App(make.Select(make.Ident(itvar), hasNext));
3483 Symbol next = lookupMethod(tree.expr.pos(),
3484 names.next,
3485 itvar.type,
3486 List.<Type>nil());
3487 JCExpression vardefinit = make.App(make.Select(make.Ident(itvar), next));
3488 if (tree.var.type.isPrimitive())
3489 vardefinit = make.TypeCast(types.upperBound(iteratorTarget), vardefinit);
3490 else
3491 vardefinit = make.TypeCast(tree.var.type, vardefinit);
3492 JCVariableDecl indexDef = (JCVariableDecl)make.VarDef(tree.var.mods,
3493 tree.var.name,
3494 tree.var.vartype,
3495 vardefinit).setType(tree.var.type);
3496 indexDef.sym = tree.var.sym;
3497 JCBlock body = make.Block(0, List.of(indexDef, tree.body));
3498 body.endpos = TreeInfo.endPos(tree.body);
3499 result = translate(make.
3500 ForLoop(List.of(init),
3501 cond,
3502 List.<JCExpressionStatement>nil(),
3503 body));
3504 patchTargets(body, tree, result);
3505 }
3507 public void visitVarDef(JCVariableDecl tree) {
3508 MethodSymbol oldMethodSym = currentMethodSym;
3509 tree.mods = translate(tree.mods);
3510 tree.vartype = translate(tree.vartype);
3511 if (currentMethodSym == null) {
3512 // A class or instance field initializer.
3513 currentMethodSym =
3514 new MethodSymbol((tree.mods.flags&STATIC) | BLOCK,
3515 names.empty, null,
3516 currentClass);
3517 }
3518 if (tree.init != null) tree.init = translate(tree.init, tree.type);
3519 result = tree;
3520 currentMethodSym = oldMethodSym;
3521 }
3523 public void visitBlock(JCBlock tree) {
3524 MethodSymbol oldMethodSym = currentMethodSym;
3525 if (currentMethodSym == null) {
3526 // Block is a static or instance initializer.
3527 currentMethodSym =
3528 new MethodSymbol(tree.flags | BLOCK,
3529 names.empty, null,
3530 currentClass);
3531 }
3532 super.visitBlock(tree);
3533 currentMethodSym = oldMethodSym;
3534 }
3536 public void visitDoLoop(JCDoWhileLoop tree) {
3537 tree.body = translate(tree.body);
3538 tree.cond = translate(tree.cond, syms.booleanType);
3539 result = tree;
3540 }
3542 public void visitWhileLoop(JCWhileLoop tree) {
3543 tree.cond = translate(tree.cond, syms.booleanType);
3544 tree.body = translate(tree.body);
3545 result = tree;
3546 }
3548 public void visitForLoop(JCForLoop tree) {
3549 tree.init = translate(tree.init);
3550 if (tree.cond != null)
3551 tree.cond = translate(tree.cond, syms.booleanType);
3552 tree.step = translate(tree.step);
3553 tree.body = translate(tree.body);
3554 result = tree;
3555 }
3557 public void visitReturn(JCReturn tree) {
3558 if (tree.expr != null)
3559 tree.expr = translate(tree.expr,
3560 types.erasure(currentMethodDef
3561 .restype.type));
3562 result = tree;
3563 }
3565 public void visitSwitch(JCSwitch tree) {
3566 Type selsuper = types.supertype(tree.selector.type);
3567 boolean enumSwitch = selsuper != null &&
3568 (tree.selector.type.tsym.flags() & ENUM) != 0;
3569 boolean stringSwitch = selsuper != null &&
3570 types.isSameType(tree.selector.type, syms.stringType);
3571 Type target = enumSwitch ? tree.selector.type :
3572 (stringSwitch? syms.stringType : syms.intType);
3573 tree.selector = translate(tree.selector, target);
3574 tree.cases = translateCases(tree.cases);
3575 if (enumSwitch) {
3576 result = visitEnumSwitch(tree);
3577 } else if (stringSwitch) {
3578 result = visitStringSwitch(tree);
3579 } else {
3580 result = tree;
3581 }
3582 }
3584 public JCTree visitEnumSwitch(JCSwitch tree) {
3585 TypeSymbol enumSym = tree.selector.type.tsym;
3586 EnumMapping map = mapForEnum(tree.pos(), enumSym);
3587 make_at(tree.pos());
3588 Symbol ordinalMethod = lookupMethod(tree.pos(),
3589 names.ordinal,
3590 tree.selector.type,
3591 List.<Type>nil());
3592 JCArrayAccess selector = make.Indexed(map.mapVar,
3593 make.App(make.Select(tree.selector,
3594 ordinalMethod)));
3595 ListBuffer<JCCase> cases = new ListBuffer<JCCase>();
3596 for (JCCase c : tree.cases) {
3597 if (c.pat != null) {
3598 VarSymbol label = (VarSymbol)TreeInfo.symbol(c.pat);
3599 JCLiteral pat = map.forConstant(label);
3600 cases.append(make.Case(pat, c.stats));
3601 } else {
3602 cases.append(c);
3603 }
3604 }
3605 JCSwitch enumSwitch = make.Switch(selector, cases.toList());
3606 patchTargets(enumSwitch, tree, enumSwitch);
3607 return enumSwitch;
3608 }
3610 public JCTree visitStringSwitch(JCSwitch tree) {
3611 List<JCCase> caseList = tree.getCases();
3612 int alternatives = caseList.size();
3614 if (alternatives == 0) { // Strange but legal possibility
3615 return make.at(tree.pos()).Exec(attr.makeNullCheck(tree.getExpression()));
3616 } else {
3617 /*
3618 * The general approach used is to translate a single
3619 * string switch statement into a series of two chained
3620 * switch statements: the first a synthesized statement
3621 * switching on the argument string's hash value and
3622 * computing a string's position in the list of original
3623 * case labels, if any, followed by a second switch on the
3624 * computed integer value. The second switch has the same
3625 * code structure as the original string switch statement
3626 * except that the string case labels are replaced with
3627 * positional integer constants starting at 0.
3628 *
3629 * The first switch statement can be thought of as an
3630 * inlined map from strings to their position in the case
3631 * label list. An alternate implementation would use an
3632 * actual Map for this purpose, as done for enum switches.
3633 *
3634 * With some additional effort, it would be possible to
3635 * use a single switch statement on the hash code of the
3636 * argument, but care would need to be taken to preserve
3637 * the proper control flow in the presence of hash
3638 * collisions and other complications, such as
3639 * fallthroughs. Switch statements with one or two
3640 * alternatives could also be specially translated into
3641 * if-then statements to omit the computation of the hash
3642 * code.
3643 *
3644 * The generated code assumes that the hashing algorithm
3645 * of String is the same in the compilation environment as
3646 * in the environment the code will run in. The string
3647 * hashing algorithm in the SE JDK has been unchanged
3648 * since at least JDK 1.2. Since the algorithm has been
3649 * specified since that release as well, it is very
3650 * unlikely to be changed in the future.
3651 *
3652 * Different hashing algorithms, such as the length of the
3653 * strings or a perfect hashing algorithm over the
3654 * particular set of case labels, could potentially be
3655 * used instead of String.hashCode.
3656 */
3658 ListBuffer<JCStatement> stmtList = new ListBuffer<JCStatement>();
3660 // Map from String case labels to their original position in
3661 // the list of case labels.
3662 Map<String, Integer> caseLabelToPosition =
3663 new LinkedHashMap<String, Integer>(alternatives + 1, 1.0f);
3665 // Map of hash codes to the string case labels having that hashCode.
3666 Map<Integer, Set<String>> hashToString =
3667 new LinkedHashMap<Integer, Set<String>>(alternatives + 1, 1.0f);
3669 int casePosition = 0;
3670 for(JCCase oneCase : caseList) {
3671 JCExpression expression = oneCase.getExpression();
3673 if (expression != null) { // expression for a "default" case is null
3674 String labelExpr = (String) expression.type.constValue();
3675 Integer mapping = caseLabelToPosition.put(labelExpr, casePosition);
3676 Assert.checkNull(mapping);
3677 int hashCode = labelExpr.hashCode();
3679 Set<String> stringSet = hashToString.get(hashCode);
3680 if (stringSet == null) {
3681 stringSet = new LinkedHashSet<String>(1, 1.0f);
3682 stringSet.add(labelExpr);
3683 hashToString.put(hashCode, stringSet);
3684 } else {
3685 boolean added = stringSet.add(labelExpr);
3686 Assert.check(added);
3687 }
3688 }
3689 casePosition++;
3690 }
3692 // Synthesize a switch statement that has the effect of
3693 // mapping from a string to the integer position of that
3694 // string in the list of case labels. This is done by
3695 // switching on the hashCode of the string followed by an
3696 // if-then-else chain comparing the input for equality
3697 // with all the case labels having that hash value.
3699 /*
3700 * s$ = top of stack;
3701 * tmp$ = -1;
3702 * switch($s.hashCode()) {
3703 * case caseLabel.hashCode:
3704 * if (s$.equals("caseLabel_1")
3705 * tmp$ = caseLabelToPosition("caseLabel_1");
3706 * else if (s$.equals("caseLabel_2"))
3707 * tmp$ = caseLabelToPosition("caseLabel_2");
3708 * ...
3709 * break;
3710 * ...
3711 * }
3712 */
3714 VarSymbol dollar_s = new VarSymbol(FINAL|SYNTHETIC,
3715 names.fromString("s" + tree.pos + target.syntheticNameChar()),
3716 syms.stringType,
3717 currentMethodSym);
3718 stmtList.append(make.at(tree.pos()).VarDef(dollar_s, tree.getExpression()).setType(dollar_s.type));
3720 VarSymbol dollar_tmp = new VarSymbol(SYNTHETIC,
3721 names.fromString("tmp" + tree.pos + target.syntheticNameChar()),
3722 syms.intType,
3723 currentMethodSym);
3724 JCVariableDecl dollar_tmp_def =
3725 (JCVariableDecl)make.VarDef(dollar_tmp, make.Literal(INT, -1)).setType(dollar_tmp.type);
3726 dollar_tmp_def.init.type = dollar_tmp.type = syms.intType;
3727 stmtList.append(dollar_tmp_def);
3728 ListBuffer<JCCase> caseBuffer = ListBuffer.lb();
3729 // hashCode will trigger nullcheck on original switch expression
3730 JCMethodInvocation hashCodeCall = makeCall(make.Ident(dollar_s),
3731 names.hashCode,
3732 List.<JCExpression>nil()).setType(syms.intType);
3733 JCSwitch switch1 = make.Switch(hashCodeCall,
3734 caseBuffer.toList());
3735 for(Map.Entry<Integer, Set<String>> entry : hashToString.entrySet()) {
3736 int hashCode = entry.getKey();
3737 Set<String> stringsWithHashCode = entry.getValue();
3738 Assert.check(stringsWithHashCode.size() >= 1);
3740 JCStatement elsepart = null;
3741 for(String caseLabel : stringsWithHashCode ) {
3742 JCMethodInvocation stringEqualsCall = makeCall(make.Ident(dollar_s),
3743 names.equals,
3744 List.<JCExpression>of(make.Literal(caseLabel)));
3745 elsepart = make.If(stringEqualsCall,
3746 make.Exec(make.Assign(make.Ident(dollar_tmp),
3747 make.Literal(caseLabelToPosition.get(caseLabel))).
3748 setType(dollar_tmp.type)),
3749 elsepart);
3750 }
3752 ListBuffer<JCStatement> lb = ListBuffer.lb();
3753 JCBreak breakStmt = make.Break(null);
3754 breakStmt.target = switch1;
3755 lb.append(elsepart).append(breakStmt);
3757 caseBuffer.append(make.Case(make.Literal(hashCode), lb.toList()));
3758 }
3760 switch1.cases = caseBuffer.toList();
3761 stmtList.append(switch1);
3763 // Make isomorphic switch tree replacing string labels
3764 // with corresponding integer ones from the label to
3765 // position map.
3767 ListBuffer<JCCase> lb = ListBuffer.lb();
3768 JCSwitch switch2 = make.Switch(make.Ident(dollar_tmp), lb.toList());
3769 for(JCCase oneCase : caseList ) {
3770 // Rewire up old unlabeled break statements to the
3771 // replacement switch being created.
3772 patchTargets(oneCase, tree, switch2);
3774 boolean isDefault = (oneCase.getExpression() == null);
3775 JCExpression caseExpr;
3776 if (isDefault)
3777 caseExpr = null;
3778 else {
3779 caseExpr = make.Literal(caseLabelToPosition.get((String)TreeInfo.skipParens(oneCase.
3780 getExpression()).
3781 type.constValue()));
3782 }
3784 lb.append(make.Case(caseExpr,
3785 oneCase.getStatements()));
3786 }
3788 switch2.cases = lb.toList();
3789 stmtList.append(switch2);
3791 return make.Block(0L, stmtList.toList());
3792 }
3793 }
3795 public void visitNewArray(JCNewArray tree) {
3796 tree.elemtype = translate(tree.elemtype);
3797 for (List<JCExpression> t = tree.dims; t.tail != null; t = t.tail)
3798 if (t.head != null) t.head = translate(t.head, syms.intType);
3799 tree.elems = translate(tree.elems, types.elemtype(tree.type));
3800 result = tree;
3801 }
3803 public void visitSelect(JCFieldAccess tree) {
3804 // need to special case-access of the form C.super.x
3805 // these will always need an access method, unless C
3806 // is a default interface subclassed by the current class.
3807 boolean qualifiedSuperAccess =
3808 tree.selected.hasTag(SELECT) &&
3809 TreeInfo.name(tree.selected) == names._super &&
3810 !types.isDirectSuperInterface(((JCFieldAccess)tree.selected).selected.type.tsym, currentClass);
3811 tree.selected = translate(tree.selected);
3812 if (tree.name == names._class) {
3813 result = classOf(tree.selected);
3814 }
3815 else if (tree.name == names._super &&
3816 types.isDirectSuperInterface(tree.selected.type.tsym, currentClass)) {
3817 //default super call!! Not a classic qualified super call
3818 TypeSymbol supSym = tree.selected.type.tsym;
3819 Assert.checkNonNull(types.asSuper(currentClass.type, supSym));
3820 result = tree;
3821 }
3822 else if (tree.name == names._this || tree.name == names._super) {
3823 result = makeThis(tree.pos(), tree.selected.type.tsym);
3824 }
3825 else
3826 result = access(tree.sym, tree, enclOp, qualifiedSuperAccess);
3827 }
3829 public void visitLetExpr(LetExpr tree) {
3830 tree.defs = translateVarDefs(tree.defs);
3831 tree.expr = translate(tree.expr, tree.type);
3832 result = tree;
3833 }
3835 // There ought to be nothing to rewrite here;
3836 // we don't generate code.
3837 public void visitAnnotation(JCAnnotation tree) {
3838 result = tree;
3839 }
3841 @Override
3842 public void visitTry(JCTry tree) {
3843 if (tree.resources.nonEmpty()) {
3844 result = makeTwrTry(tree);
3845 return;
3846 }
3848 boolean hasBody = tree.body.getStatements().nonEmpty();
3849 boolean hasCatchers = tree.catchers.nonEmpty();
3850 boolean hasFinally = tree.finalizer != null &&
3851 tree.finalizer.getStatements().nonEmpty();
3853 if (!hasCatchers && !hasFinally) {
3854 result = translate(tree.body);
3855 return;
3856 }
3858 if (!hasBody) {
3859 if (hasFinally) {
3860 result = translate(tree.finalizer);
3861 } else {
3862 result = translate(tree.body);
3863 }
3864 return;
3865 }
3867 // no optimizations possible
3868 super.visitTry(tree);
3869 }
3871 /**************************************************************************
3872 * main method
3873 *************************************************************************/
3875 /** Translate a toplevel class and return a list consisting of
3876 * the translated class and translated versions of all inner classes.
3877 * @param env The attribution environment current at the class definition.
3878 * We need this for resolving some additional symbols.
3879 * @param cdef The tree representing the class definition.
3880 */
3881 public List<JCTree> translateTopLevelClass(Env<AttrContext> env, JCTree cdef, TreeMaker make) {
3882 ListBuffer<JCTree> translated = null;
3883 try {
3884 attrEnv = env;
3885 this.make = make;
3886 endPosTable = env.toplevel.endPositions;
3887 currentClass = null;
3888 currentMethodDef = null;
3889 outermostClassDef = (cdef.hasTag(CLASSDEF)) ? (JCClassDecl)cdef : null;
3890 outermostMemberDef = null;
3891 this.translated = new ListBuffer<JCTree>();
3892 classdefs = new HashMap<ClassSymbol,JCClassDecl>();
3893 actualSymbols = new HashMap<Symbol,Symbol>();
3894 freevarCache = new HashMap<ClassSymbol,List<VarSymbol>>();
3895 proxies = new Scope(syms.noSymbol);
3896 twrVars = new Scope(syms.noSymbol);
3897 outerThisStack = List.nil();
3898 accessNums = new HashMap<Symbol,Integer>();
3899 accessSyms = new HashMap<Symbol,MethodSymbol[]>();
3900 accessConstrs = new HashMap<Symbol,MethodSymbol>();
3901 accessConstrTags = List.nil();
3902 accessed = new ListBuffer<Symbol>();
3903 translate(cdef, (JCExpression)null);
3904 for (List<Symbol> l = accessed.toList(); l.nonEmpty(); l = l.tail)
3905 makeAccessible(l.head);
3906 for (EnumMapping map : enumSwitchMap.values())
3907 map.translate();
3908 checkConflicts(this.translated.toList());
3909 checkAccessConstructorTags();
3910 translated = this.translated;
3911 } finally {
3912 // note that recursive invocations of this method fail hard
3913 attrEnv = null;
3914 this.make = null;
3915 endPosTable = null;
3916 currentClass = null;
3917 currentMethodDef = null;
3918 outermostClassDef = null;
3919 outermostMemberDef = null;
3920 this.translated = null;
3921 classdefs = null;
3922 actualSymbols = null;
3923 freevarCache = null;
3924 proxies = null;
3925 outerThisStack = null;
3926 accessNums = null;
3927 accessSyms = null;
3928 accessConstrs = null;
3929 accessConstrTags = null;
3930 accessed = null;
3931 enumSwitchMap.clear();
3932 }
3933 return translated.toList();
3934 }
3935 }