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