001 /*
002 * Copyright 1999-2008 Sun Microsystems, Inc. All Rights Reserved.
003 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
004 *
005 * This code is free software; you can redistribute it and/or modify it
006 * under the terms of the GNU General Public License version 2 only, as
007 * published by the Free Software Foundation. Sun designates this
008 * particular file as subject to the "Classpath" exception as provided
009 * by Sun in the LICENSE file that accompanied this code.
010 *
011 * This code is distributed in the hope that it will be useful, but WITHOUT
012 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
013 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
014 * version 2 for more details (a copy is included in the LICENSE file that
015 * accompanied this code).
016 *
017 * You should have received a copy of the GNU General Public License version
018 * 2 along with this work; if not, write to the Free Software Foundation,
019 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
020 *
021 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
022 * CA 95054 USA or visit www.sun.com if you need additional information or
023 * have any questions.
024 */
025
026 package com.sun.tools.javac.comp;
027
028 import java.util.*;
029
030 import com.sun.tools.javac.code.*;
031 import com.sun.tools.javac.jvm.*;
032 import com.sun.tools.javac.tree.*;
033 import com.sun.tools.javac.util.*;
034 import com.sun.tools.javac.util.JCDiagnostic.DiagnosticPosition;
035 import com.sun.tools.javac.util.List;
036
037 import com.sun.tools.javac.code.Symbol.*;
038 import com.sun.tools.javac.tree.JCTree.*;
039 import com.sun.tools.javac.code.Type.*;
040
041 import com.sun.tools.javac.jvm.Target;
042
043 import static com.sun.tools.javac.code.Flags.*;
044 import static com.sun.tools.javac.code.Kinds.*;
045 import static com.sun.tools.javac.code.TypeTags.*;
046 import static com.sun.tools.javac.jvm.ByteCodes.*;
047
048 import edu.rice.cs.mint.comp.*;
049
050 /** This pass translates away some syntactic sugar: inner classes,
051 * class literals, assertions, foreach loops, etc.
052 *
053 * <p><b>This is NOT part of any API supported by Sun Microsystems. If
054 * you write code that depends on this, you do so at your own risk.
055 * This code and its internal interfaces are subject to change or
056 * deletion without notice.</b>
057 */
058 public class Lower extends TreeTranslator {
059 protected static final Context.Key<Lower> lowerKey =
060 new Context.Key<Lower>();
061
062 public static Lower instance(Context context) {
063 Lower instance = context.get(lowerKey);
064 if (instance == null)
065 instance = new Lower(context);
066 return instance;
067 }
068
069 private Names names;
070 private Log log;
071 private Symtab syms;
072 private Resolve rs;
073 private Check chk;
074 private Attr attr;
075 private TreeMaker make;
076 private DiagnosticPosition make_pos;
077 private ClassWriter writer;
078 private ClassReader reader;
079 private ConstFold cfolder;
080 private Target target;
081 private Source source;
082 private boolean allowEnums;
083 private final Name dollarAssertionsDisabled;
084 private final Name classDollar;
085 private Types types;
086 private boolean debugLower;
087
088 protected Lower(Context context) {
089 context.put(lowerKey, this);
090 names = Names.instance(context);
091 log = Log.instance(context);
092 syms = Symtab.instance(context);
093 rs = Resolve.instance(context);
094 chk = Check.instance(context);
095 attr = Attr.instance(context);
096 make = TreeMaker.instance(context);
097 writer = ClassWriter.instance(context);
098 reader = ClassReader.instance(context);
099 cfolder = ConstFold.instance(context);
100 target = Target.instance(context);
101 source = Source.instance(context);
102 allowEnums = source.allowEnums();
103 dollarAssertionsDisabled = names.
104 fromString(target.syntheticNameChar() + "assertionsDisabled");
105 classDollar = names.
106 fromString("class" + target.syntheticNameChar());
107
108 types = Types.instance(context);
109 Options options = Options.instance(context);
110 debugLower = options.get("debuglower") != null;
111 }
112
113 /** The currently enclosing class.
114 */
115 ClassSymbol currentClass;
116
117 /** A queue of all translated classes.
118 */
119 ListBuffer<JCTree> translated;
120
121 /** Environment for symbol lookup, set by translateTopLevelClass.
122 */
123 Env<AttrContext> attrEnv;
124
125 /** A hash table mapping syntax trees to their ending source positions.
126 */
127 Map<JCTree, Integer> endPositions;
128
129 /**************************************************************************
130 * Global mappings
131 *************************************************************************/
132
133 /** A hash table mapping local classes to their definitions.
134 */
135 Map<ClassSymbol, JCClassDecl> classdefs;
136
137 /** A hash table mapping virtual accessed symbols in outer subclasses
138 * to the actually referred symbol in superclasses.
139 */
140 Map<Symbol,Symbol> actualSymbols;
141
142 /** The current method definition.
143 */
144 JCMethodDecl currentMethodDef;
145
146 /** The current method symbol.
147 */
148 MethodSymbol currentMethodSym;
149
150 /** The currently enclosing outermost class definition.
151 */
152 JCClassDecl outermostClassDef;
153
154 /** The currently enclosing outermost member definition.
155 */
156 JCTree outermostMemberDef;
157
158 /** A navigator class for assembling a mapping from local class symbols
159 * to class definition trees.
160 * There is only one case; all other cases simply traverse down the tree.
161 */
162 class ClassMap extends TreeScanner {
163
164 /** All encountered class defs are entered into classdefs table.
165 */
166 public void visitClassDef(JCClassDecl tree) {
167 classdefs.put(tree.sym, tree);
168 super.visitClassDef(tree);
169 }
170 }
171 ClassMap classMap = new ClassMap();
172
173 /** Map a class symbol to its definition.
174 * @param c The class symbol of which we want to determine the definition.
175 */
176 JCClassDecl classDef(ClassSymbol c) {
177 // First lookup the class in the classdefs table.
178 JCClassDecl def = classdefs.get(c);
179 if (def == null && outermostMemberDef != null) {
180 // If this fails, traverse outermost member definition, entering all
181 // local classes into classdefs, and try again.
182 classMap.scan(outermostMemberDef);
183 def = classdefs.get(c);
184 }
185 if (def == null) {
186 // If this fails, traverse outermost class definition, entering all
187 // local classes into classdefs, and try again.
188 classMap.scan(outermostClassDef);
189 def = classdefs.get(c);
190 }
191 return def;
192 }
193
194 /** A hash table mapping class symbols to lists of free variables.
195 * accessed by them. Only free variables of the method immediately containing
196 * a class are associated with that class.
197 */
198 Map<ClassSymbol,List<VarSymbol>> freevarCache;
199
200 /** A navigator class for collecting the free variables accessed
201 * from a local class.
202 * There is only one case; all other cases simply traverse down the tree.
203 */
204 class FreeVarCollector extends TreeScanner {
205
206 /** The owner of the local class.
207 */
208 Symbol owner;
209
210 /** The local class.
211 */
212 ClassSymbol clazz;
213
214 /** The list of owner's variables accessed from within the local class,
215 * without any duplicates.
216 */
217 List<VarSymbol> fvs;
218
219 FreeVarCollector(ClassSymbol clazz) {
220 this.clazz = clazz;
221 this.owner = clazz.owner;
222 this.fvs = List.nil();
223 }
224
225 /** Add free variable to fvs list unless it is already there.
226 */
227 private void addFreeVar(VarSymbol v) {
228 for (List<VarSymbol> l = fvs; l.nonEmpty(); l = l.tail)
229 if (l.head == v) return;
230 fvs = fvs.prepend(v);
231 }
232
233 /** Add all free variables of class c to fvs list
234 * unless they are already there.
235 */
236 private void addFreeVars(ClassSymbol c) {
237 List<VarSymbol> fvs = freevarCache.get(c);
238 if (fvs != null) {
239 for (List<VarSymbol> l = fvs; l.nonEmpty(); l = l.tail) {
240 addFreeVar(l.head);
241 }
242 }
243 }
244
245 /** If tree refers to a variable in owner of local class, add it to
246 * free variables list.
247 */
248 public void visitIdent(JCIdent tree) {
249 result = tree;
250 visitSymbol(tree.sym);
251 }
252 // where
253 private void visitSymbol(Symbol _sym) {
254 Symbol sym = _sym;
255 if (sym.kind == VAR || sym.kind == MTH) {
256 while (sym != null && sym.owner != owner)
257 sym = proxies.lookup(proxyName(sym.name)).sym;
258 if (sym != null && sym.owner == owner) {
259 VarSymbol v = (VarSymbol)sym;
260 if (v.getConstValue() == null) {
261 addFreeVar(v);
262 }
263 } else {
264 if (outerThisStack.head != null &&
265 outerThisStack.head != _sym)
266 visitSymbol(outerThisStack.head);
267 }
268 }
269 }
270
271 /** If tree refers to a class instance creation expression
272 * add all free variables of the freshly created class.
273 */
274 public void visitNewClass(JCNewClass tree) {
275 ClassSymbol c = (ClassSymbol)tree.constructor.owner;
276 addFreeVars(c);
277 if (tree.encl == null &&
278 c.hasOuterInstance() &&
279 outerThisStack.head != null)
280 visitSymbol(outerThisStack.head);
281 super.visitNewClass(tree);
282 }
283
284 /** If tree refers to a qualified this or super expression
285 * for anything but the current class, add the outer this
286 * stack as a free variable.
287 */
288 public void visitSelect(JCFieldAccess tree) {
289 if ((tree.name == names._this || tree.name == names._super) &&
290 tree.selected.type.tsym != clazz &&
291 outerThisStack.head != null)
292 visitSymbol(outerThisStack.head);
293 super.visitSelect(tree);
294 }
295
296 /** If tree refers to a superclass constructor call,
297 * add all free variables of the superclass.
298 */
299 public void visitApply(JCMethodInvocation tree) {
300 if (TreeInfo.name(tree.meth) == names._super) {
301 addFreeVars((ClassSymbol) TreeInfo.symbol(tree.meth).owner);
302 Symbol constructor = TreeInfo.symbol(tree.meth);
303 ClassSymbol c = (ClassSymbol)constructor.owner;
304 if (c.hasOuterInstance() &&
305 tree.meth.getTag() != JCTree.SELECT &&
306 outerThisStack.head != null)
307 visitSymbol(outerThisStack.head);
308 }
309 super.visitApply(tree);
310 }
311 }
312
313 /** Return the variables accessed from within a local class, which
314 * are declared in the local class' owner.
315 * (in reverse order of first access).
316 */
317 List<VarSymbol> freevars(ClassSymbol c) {
318 if ((c.owner.kind & (VAR | MTH)) != 0) {
319 List<VarSymbol> fvs = freevarCache.get(c);
320 if (fvs == null) {
321 FreeVarCollector collector = new FreeVarCollector(c);
322 collector.scan(classDef(c));
323 fvs = collector.fvs;
324 freevarCache.put(c, fvs);
325 }
326 return fvs;
327 } else {
328 return List.nil();
329 }
330 }
331
332 Map<TypeSymbol,EnumMapping> enumSwitchMap = new LinkedHashMap<TypeSymbol,EnumMapping>();
333
334 EnumMapping mapForEnum(DiagnosticPosition pos, TypeSymbol enumClass) {
335 EnumMapping map = enumSwitchMap.get(enumClass);
336 if (map == null)
337 enumSwitchMap.put(enumClass, map = new EnumMapping(pos, enumClass));
338 return map;
339 }
340
341 /** This map gives a translation table to be used for enum
342 * switches.
343 *
344 * <p>For each enum that appears as the type of a switch
345 * expression, we maintain an EnumMapping to assist in the
346 * translation, as exemplified by the following example:
347 *
348 * <p>we translate
349 * <pre>
350 * switch(colorExpression) {
351 * case red: stmt1;
352 * case green: stmt2;
353 * }
354 * </pre>
355 * into
356 * <pre>
357 * switch(Outer$0.$EnumMap$Color[colorExpression.ordinal()]) {
358 * case 1: stmt1;
359 * case 2: stmt2
360 * }
361 * </pre>
362 * with the auxilliary table intialized as follows:
363 * <pre>
364 * class Outer$0 {
365 * synthetic final int[] $EnumMap$Color = new int[Color.values().length];
366 * static {
367 * try { $EnumMap$Color[red.ordinal()] = 1; } catch (NoSuchFieldError ex) {}
368 * try { $EnumMap$Color[green.ordinal()] = 2; } catch (NoSuchFieldError ex) {}
369 * }
370 * }
371 * </pre>
372 * class EnumMapping provides mapping data and support methods for this translation.
373 */
374 class EnumMapping {
375 EnumMapping(DiagnosticPosition pos, TypeSymbol forEnum) {
376 this.forEnum = forEnum;
377 this.values = new LinkedHashMap<VarSymbol,Integer>();
378 this.pos = pos;
379 Name varName = names
380 .fromString(target.syntheticNameChar() +
381 "SwitchMap" +
382 target.syntheticNameChar() +
383 writer.xClassName(forEnum.type).toString()
384 .replace('/', '.')
385 .replace('.', target.syntheticNameChar()));
386 ClassSymbol outerCacheClass = outerCacheClass();
387 this.mapVar = new VarSymbol(STATIC | SYNTHETIC | FINAL,
388 varName,
389 new ArrayType(syms.intType, syms.arrayClass),
390 outerCacheClass);
391 enterSynthetic(pos, mapVar, outerCacheClass.members());
392 }
393
394 DiagnosticPosition pos = null;
395
396 // the next value to use
397 int next = 1; // 0 (unused map elements) go to the default label
398
399 // the enum for which this is a map
400 final TypeSymbol forEnum;
401
402 // the field containing the map
403 final VarSymbol mapVar;
404
405 // the mapped values
406 final Map<VarSymbol,Integer> values;
407
408 JCLiteral forConstant(VarSymbol v) {
409 Integer result = values.get(v);
410 if (result == null)
411 values.put(v, result = next++);
412 return make.Literal(result);
413 }
414
415 // generate the field initializer for the map
416 void translate() {
417 make.at(pos.getStartPosition());
418 JCClassDecl owner = classDef((ClassSymbol)mapVar.owner);
419
420 // synthetic static final int[] $SwitchMap$Color = new int[Color.values().length];
421 MethodSymbol valuesMethod = lookupMethod(pos,
422 names.values,
423 forEnum.type,
424 List.<Type>nil());
425 JCExpression size = make // Color.values().length
426 .Select(make.App(make.QualIdent(valuesMethod)),
427 syms.lengthVar);
428 JCExpression mapVarInit = make
429 .NewArray(make.Type(syms.intType), List.of(size), null)
430 .setType(new ArrayType(syms.intType, syms.arrayClass));
431
432 // try { $SwitchMap$Color[red.ordinal()] = 1; } catch (java.lang.NoSuchFieldError ex) {}
433 ListBuffer<JCStatement> stmts = new ListBuffer<JCStatement>();
434 Symbol ordinalMethod = lookupMethod(pos,
435 names.ordinal,
436 forEnum.type,
437 List.<Type>nil());
438 List<JCCatch> catcher = List.<JCCatch>nil()
439 .prepend(make.Catch(make.VarDef(new VarSymbol(PARAMETER, names.ex,
440 syms.noSuchFieldErrorType,
441 syms.noSymbol),
442 null),
443 make.Block(0, List.<JCStatement>nil())));
444 for (Map.Entry<VarSymbol,Integer> e : values.entrySet()) {
445 VarSymbol enumerator = e.getKey();
446 Integer mappedValue = e.getValue();
447 JCExpression assign = make
448 .Assign(make.Indexed(mapVar,
449 make.App(make.Select(make.QualIdent(enumerator),
450 ordinalMethod))),
451 make.Literal(mappedValue))
452 .setType(syms.intType);
453 JCStatement exec = make.Exec(assign);
454 JCStatement _try = make.Try(make.Block(0, List.of(exec)), catcher, null);
455 stmts.append(_try);
456 }
457
458 owner.defs = owner.defs
459 .prepend(make.Block(STATIC, stmts.toList()))
460 .prepend(make.VarDef(mapVar, mapVarInit));
461 }
462 }
463
464
465 /**************************************************************************
466 * Tree building blocks
467 *************************************************************************/
468
469 /** Equivalent to make.at(pos.getStartPosition()) with side effect of caching
470 * pos as make_pos, for use in diagnostics.
471 **/
472 TreeMaker make_at(DiagnosticPosition pos) {
473 make_pos = pos;
474 return make.at(pos);
475 }
476
477 /** Make an attributed tree representing a literal. This will be an
478 * Ident node in the case of boolean literals, a Literal node in all
479 * other cases.
480 * @param type The literal's type.
481 * @param value The literal's value.
482 */
483 JCExpression makeLit(Type type, Object value) {
484 return make.Literal(type.tag, value).setType(type.constType(value));
485 }
486
487 /** Make an attributed tree representing null.
488 */
489 JCExpression makeNull() {
490 return makeLit(syms.botType, null);
491 }
492
493 /** Make an attributed class instance creation expression.
494 * @param ctype The class type.
495 * @param args The constructor arguments.
496 */
497 JCNewClass makeNewClass(Type ctype, List<JCExpression> args) {
498 JCNewClass tree = make.NewClass(null,
499 null, make.QualIdent(ctype.tsym), args, null);
500 tree.constructor = rs.resolveConstructor(
501 make_pos, attrEnv, ctype, TreeInfo.types(args), null, false, false);
502 tree.type = ctype;
503 return tree;
504 }
505
506 /** Make an attributed unary expression.
507 * @param optag The operators tree tag.
508 * @param arg The operator's argument.
509 */
510 JCUnary makeUnary(int optag, JCExpression arg) {
511 JCUnary tree = make.Unary(optag, arg);
512 tree.operator = rs.resolveUnaryOperator(
513 make_pos, optag, attrEnv, arg.type);
514 tree.type = tree.operator.type.getReturnType();
515 return tree;
516 }
517
518 /** Make an attributed binary expression.
519 * @param optag The operators tree tag.
520 * @param lhs The operator's left argument.
521 * @param rhs The operator's right argument.
522 */
523 JCBinary makeBinary(int optag, JCExpression lhs, JCExpression rhs) {
524 JCBinary tree = make.Binary(optag, lhs, rhs);
525 tree.operator = rs.resolveBinaryOperator(
526 make_pos, optag, attrEnv, lhs.type, rhs.type);
527 tree.type = tree.operator.type.getReturnType();
528 return tree;
529 }
530
531 /** Make an attributed assignop expression.
532 * @param optag The operators tree tag.
533 * @param lhs The operator's left argument.
534 * @param rhs The operator's right argument.
535 */
536 JCAssignOp makeAssignop(int optag, JCTree lhs, JCTree rhs) {
537 JCAssignOp tree = make.Assignop(optag, lhs, rhs);
538 tree.operator = rs.resolveBinaryOperator(
539 make_pos, tree.getTag() - JCTree.ASGOffset, attrEnv, lhs.type, rhs.type);
540 tree.type = lhs.type;
541 return tree;
542 }
543
544 /** Convert tree into string object, unless it has already a
545 * reference type..
546 */
547 JCExpression makeString(JCExpression tree) {
548 if (tree.type.tag >= CLASS) {
549 return tree;
550 } else {
551 Symbol valueOfSym = lookupMethod(tree.pos(),
552 names.valueOf,
553 syms.stringType,
554 List.of(tree.type));
555 return make.App(make.QualIdent(valueOfSym), List.of(tree));
556 }
557 }
558
559 /** Create an empty anonymous class definition and enter and complete
560 * its symbol. Return the class definition's symbol.
561 * and create
562 * @param flags The class symbol's flags
563 * @param owner The class symbol's owner
564 */
565 ClassSymbol makeEmptyClass(long flags, ClassSymbol owner) {
566 // Create class symbol.
567 ClassSymbol c = reader.defineClass(names.empty, owner);
568 c.flatname = chk.localClassName(c);
569 c.sourcefile = owner.sourcefile;
570 c.completer = null;
571 c.members_field = new Scope(c);
572 c.flags_field = flags;
573 ClassType ctype = (ClassType) c.type;
574 ctype.supertype_field = syms.objectType;
575 ctype.interfaces_field = List.nil();
576
577 JCClassDecl odef = classDef(owner);
578
579 // Enter class symbol in owner scope and compiled table.
580 enterSynthetic(odef.pos(), c, owner.members());
581 chk.compiled.put(c.flatname, c);
582
583 // Create class definition tree.
584 JCClassDecl cdef = make.ClassDef(
585 make.Modifiers(flags), names.empty,
586 List.<JCTypeParameter>nil(),
587 null, List.<JCExpression>nil(), List.<JCTree>nil());
588 cdef.sym = c;
589 cdef.type = c.type;
590
591 // Append class definition tree to owner's definitions.
592 odef.defs = odef.defs.prepend(cdef);
593
594 return c;
595 }
596
597 /**************************************************************************
598 * Symbol manipulation utilities
599 *************************************************************************/
600
601 /** Report a conflict between a user symbol and a synthetic symbol.
602 */
603 private void duplicateError(DiagnosticPosition pos, Symbol sym) {
604 if (!sym.type.isErroneous()) {
605 log.error(pos, "synthetic.name.conflict", sym, sym.location());
606 }
607 }
608
609 /** Enter a synthetic symbol in a given scope, but complain if there was already one there.
610 * @param pos Position for error reporting.
611 * @param sym The symbol.
612 * @param s The scope.
613 */
614 private void enterSynthetic(DiagnosticPosition pos, Symbol sym, Scope s) {
615 if (sym.name != names.error && sym.name != names.empty) {
616 for (Scope.Entry e = s.lookup(sym.name); e.scope == s; e = e.next()) {
617 if (sym != e.sym && sym.kind == e.sym.kind) {
618 // VM allows methods and variables with differing types
619 if ((sym.kind & (MTH|VAR)) != 0 &&
620 !types.erasure(sym.type).equals(types.erasure(e.sym.type)))
621 continue;
622 duplicateError(pos, e.sym);
623 break;
624 }
625 }
626 }
627 s.enter(sym);
628 }
629
630 /** Look up a synthetic name in a given scope.
631 * @param scope The scope.
632 * @param name The name.
633 */
634 private Symbol lookupSynthetic(Name name, Scope s) {
635 Symbol sym = s.lookup(name).sym;
636 return (sym==null || (sym.flags()&SYNTHETIC)==0) ? null : sym;
637 }
638
639 /** Look up a method in a given scope.
640 */
641 private MethodSymbol lookupMethod(DiagnosticPosition pos, Name name, Type qual, List<Type> args) {
642 return rs.resolveInternalMethod(pos, attrEnv, qual, name, args, null);
643 }
644
645 /** Look up a constructor.
646 */
647 private MethodSymbol lookupConstructor(DiagnosticPosition pos, Type qual, List<Type> args) {
648 return rs.resolveInternalConstructor(pos, attrEnv, qual, args, null);
649 }
650
651 /** Look up a field.
652 */
653 private VarSymbol lookupField(DiagnosticPosition pos, Type qual, Name name) {
654 return rs.resolveInternalField(pos, attrEnv, qual, name);
655 }
656
657 /**************************************************************************
658 * Access methods
659 *************************************************************************/
660
661 /** Access codes for dereferencing, assignment,
662 * and pre/post increment/decrement.
663 * Access codes for assignment operations are determined by method accessCode
664 * below.
665 *
666 * All access codes for accesses to the current class are even.
667 * If a member of the superclass should be accessed instead (because
668 * access was via a qualified super), add one to the corresponding code
669 * for the current class, making the number odd.
670 * This numbering scheme is used by the backend to decide whether
671 * to issue an invokevirtual or invokespecial call.
672 *
673 * @see Gen.visitSelect(Select tree)
674 */
675 private static final int
676 DEREFcode = 0,
677 ASSIGNcode = 2,
678 PREINCcode = 4,
679 PREDECcode = 6,
680 POSTINCcode = 8,
681 POSTDECcode = 10,
682 FIRSTASGOPcode = 12;
683
684 /** Number of access codes
685 */
686 private static final int NCODES = accessCode(ByteCodes.lushrl) + 2;
687
688 /** A mapping from symbols to their access numbers.
689 */
690 private Map<Symbol,Integer> accessNums;
691
692 /** A mapping from symbols to an array of access symbols, indexed by
693 * access code.
694 */
695 private Map<Symbol,MethodSymbol[]> accessSyms;
696
697 /** A mapping from (constructor) symbols to access constructor symbols.
698 */
699 private Map<Symbol,MethodSymbol> accessConstrs;
700
701 /** A queue for all accessed symbols.
702 */
703 private ListBuffer<Symbol> accessed;
704
705 /** Map bytecode of binary operation to access code of corresponding
706 * assignment operation. This is always an even number.
707 */
708 private static int accessCode(int bytecode) {
709 if (ByteCodes.iadd <= bytecode && bytecode <= ByteCodes.lxor)
710 return (bytecode - iadd) * 2 + FIRSTASGOPcode;
711 else if (bytecode == ByteCodes.string_add)
712 return (ByteCodes.lxor + 1 - iadd) * 2 + FIRSTASGOPcode;
713 else if (ByteCodes.ishll <= bytecode && bytecode <= ByteCodes.lushrl)
714 return (bytecode - ishll + ByteCodes.lxor + 2 - iadd) * 2 + FIRSTASGOPcode;
715 else
716 return -1;
717 }
718
719 /** return access code for identifier,
720 * @param tree The tree representing the identifier use.
721 * @param enclOp The closest enclosing operation node of tree,
722 * null if tree is not a subtree of an operation.
723 */
724 private static int accessCode(JCTree tree, JCTree enclOp) {
725 if (enclOp == null)
726 return DEREFcode;
727 else if (enclOp.getTag() == JCTree.ASSIGN &&
728 tree == TreeInfo.skipParens(((JCAssign) enclOp).lhs))
729 return ASSIGNcode;
730 else if (JCTree.PREINC <= enclOp.getTag() && enclOp.getTag() <= JCTree.POSTDEC &&
731 tree == TreeInfo.skipParens(((JCUnary) enclOp).arg))
732 return (enclOp.getTag() - JCTree.PREINC) * 2 + PREINCcode;
733 else if (JCTree.BITOR_ASG <= enclOp.getTag() && enclOp.getTag() <= JCTree.MOD_ASG &&
734 tree == TreeInfo.skipParens(((JCAssignOp) enclOp).lhs))
735 return accessCode(((OperatorSymbol) ((JCAssignOp) enclOp).operator).opcode);
736 else
737 return DEREFcode;
738 }
739
740 /** Return binary operator that corresponds to given access code.
741 */
742 private OperatorSymbol binaryAccessOperator(int acode) {
743 for (Scope.Entry e = syms.predefClass.members().elems;
744 e != null;
745 e = e.sibling) {
746 if (e.sym instanceof OperatorSymbol) {
747 OperatorSymbol op = (OperatorSymbol)e.sym;
748 if (accessCode(op.opcode) == acode) return op;
749 }
750 }
751 return null;
752 }
753
754 /** Return tree tag for assignment operation corresponding
755 * to given binary operator.
756 */
757 private static int treeTag(OperatorSymbol operator) {
758 switch (operator.opcode) {
759 case ByteCodes.ior: case ByteCodes.lor:
760 return JCTree.BITOR_ASG;
761 case ByteCodes.ixor: case ByteCodes.lxor:
762 return JCTree.BITXOR_ASG;
763 case ByteCodes.iand: case ByteCodes.land:
764 return JCTree.BITAND_ASG;
765 case ByteCodes.ishl: case ByteCodes.lshl:
766 case ByteCodes.ishll: case ByteCodes.lshll:
767 return JCTree.SL_ASG;
768 case ByteCodes.ishr: case ByteCodes.lshr:
769 case ByteCodes.ishrl: case ByteCodes.lshrl:
770 return JCTree.SR_ASG;
771 case ByteCodes.iushr: case ByteCodes.lushr:
772 case ByteCodes.iushrl: case ByteCodes.lushrl:
773 return JCTree.USR_ASG;
774 case ByteCodes.iadd: case ByteCodes.ladd:
775 case ByteCodes.fadd: case ByteCodes.dadd:
776 case ByteCodes.string_add:
777 return JCTree.PLUS_ASG;
778 case ByteCodes.isub: case ByteCodes.lsub:
779 case ByteCodes.fsub: case ByteCodes.dsub:
780 return JCTree.MINUS_ASG;
781 case ByteCodes.imul: case ByteCodes.lmul:
782 case ByteCodes.fmul: case ByteCodes.dmul:
783 return JCTree.MUL_ASG;
784 case ByteCodes.idiv: case ByteCodes.ldiv:
785 case ByteCodes.fdiv: case ByteCodes.ddiv:
786 return JCTree.DIV_ASG;
787 case ByteCodes.imod: case ByteCodes.lmod:
788 case ByteCodes.fmod: case ByteCodes.dmod:
789 return JCTree.MOD_ASG;
790 default:
791 throw new AssertionError();
792 }
793 }
794
795 /** The name of the access method with number `anum' and access code `acode'.
796 */
797 Name accessName(int anum, int acode) {
798 return names.fromString(
799 "access" + target.syntheticNameChar() + anum + acode / 10 + acode % 10);
800 }
801
802 /** Return access symbol for a private or protected symbol from an inner class.
803 * @param sym The accessed private symbol.
804 * @param tree The accessing tree.
805 * @param enclOp The closest enclosing operation node of tree,
806 * null if tree is not a subtree of an operation.
807 * @param protAccess Is access to a protected symbol in another
808 * package?
809 * @param refSuper Is access via a (qualified) C.super?
810 */
811 MethodSymbol accessSymbol(Symbol sym, JCTree tree, JCTree enclOp,
812 boolean protAccess, boolean refSuper) {
813 ClassSymbol accOwner = refSuper && protAccess
814 // For access via qualified super (T.super.x), place the
815 // access symbol on T.
816 ? (ClassSymbol)((JCFieldAccess) tree).selected.type.tsym
817 // Otherwise pretend that the owner of an accessed
818 // protected symbol is the enclosing class of the current
819 // class which is a subclass of the symbol's owner.
820 : accessClass(sym, protAccess, tree);
821
822 Symbol vsym = sym;
823 if (sym.owner != accOwner) {
824 vsym = sym.clone(accOwner);
825 actualSymbols.put(vsym, sym);
826 }
827
828 Integer anum // The access number of the access method.
829 = accessNums.get(vsym);
830 if (anum == null) {
831 anum = accessed.length();
832 accessNums.put(vsym, anum);
833 accessSyms.put(vsym, new MethodSymbol[NCODES]);
834 accessed.append(vsym);
835 // System.out.println("accessing " + vsym + " in " + vsym.location());
836 }
837
838 int acode; // The access code of the access method.
839 List<Type> argtypes; // The argument types of the access method.
840 Type restype; // The result type of the access method.
841 List<Type> thrown; // The thrown execeptions of the access method.
842 switch (vsym.kind) {
843 case VAR:
844 acode = accessCode(tree, enclOp);
845 if (acode >= FIRSTASGOPcode) {
846 OperatorSymbol operator = binaryAccessOperator(acode);
847 if (operator.opcode == string_add)
848 argtypes = List.of(syms.objectType);
849 else
850 argtypes = operator.type.getParameterTypes().tail;
851 } else if (acode == ASSIGNcode)
852 argtypes = List.of(vsym.erasure(types));
853 else
854 argtypes = List.nil();
855 restype = vsym.erasure(types);
856 thrown = List.nil();
857 break;
858 case MTH:
859 acode = DEREFcode;
860 argtypes = vsym.erasure(types).getParameterTypes();
861 restype = vsym.erasure(types).getReturnType();
862 thrown = vsym.type.getThrownTypes();
863 break;
864 default:
865 throw new AssertionError();
866 }
867
868 // For references via qualified super, increment acode by one,
869 // making it odd.
870 if (protAccess && refSuper) acode++;
871
872 // Instance access methods get instance as first parameter.
873 // For protected symbols this needs to be the instance as a member
874 // of the type containing the accessed symbol, not the class
875 // containing the access method.
876 if ((vsym.flags() & STATIC) == 0) {
877 argtypes = argtypes.prepend(vsym.owner.erasure(types));
878 }
879 MethodSymbol[] accessors = accessSyms.get(vsym);
880 MethodSymbol accessor = accessors[acode];
881 if (accessor == null) {
882 accessor = new MethodSymbol(
883 STATIC | SYNTHETIC,
884 accessName(anum.intValue(), acode),
885 new MethodType(argtypes, restype, thrown, syms.methodClass),
886 accOwner);
887 enterSynthetic(tree.pos(), accessor, accOwner.members());
888 accessors[acode] = accessor;
889 }
890 return accessor;
891 }
892
893 /** The qualifier to be used for accessing a symbol in an outer class.
894 * This is either C.sym or C.this.sym, depending on whether or not
895 * sym is static.
896 * @param sym The accessed symbol.
897 */
898 JCExpression accessBase(DiagnosticPosition pos, Symbol sym) {
899 return (sym.flags() & STATIC) != 0
900 ? access(make.at(pos.getStartPosition()).QualIdent(sym.owner))
901 : makeOwnerThis(pos, sym, true);
902 }
903
904 /** Do we need an access method to reference private symbol?
905 */
906 boolean needsPrivateAccess(Symbol sym) {
907 if ((sym.flags() & PRIVATE) == 0 || sym.owner == currentClass) {
908 return false;
909 } else if (sym.name == names.init && (sym.owner.owner.kind & (VAR | MTH)) != 0) {
910 // private constructor in local class: relax protection
911 sym.flags_field &= ~PRIVATE;
912 return false;
913 } else {
914 return true;
915 }
916 }
917
918 /** Do we need an access method to reference symbol in other package?
919 */
920 boolean needsProtectedAccess(Symbol sym, JCTree tree) {
921 if ((sym.flags() & PROTECTED) == 0 ||
922 sym.owner.owner == currentClass.owner || // fast special case
923 sym.packge() == currentClass.packge())
924 return false;
925 if (!currentClass.isSubClass(sym.owner, types))
926 return true;
927 if ((sym.flags() & STATIC) != 0 ||
928 tree.getTag() != JCTree.SELECT ||
929 TreeInfo.name(((JCFieldAccess) tree).selected) == names._super)
930 return false;
931 return !((JCFieldAccess) tree).selected.type.tsym.isSubClass(currentClass, types);
932 }
933
934 /** The class in which an access method for given symbol goes.
935 * @param sym The access symbol
936 * @param protAccess Is access to a protected symbol in another
937 * package?
938 */
939 ClassSymbol accessClass(Symbol sym, boolean protAccess, JCTree tree) {
940 if (protAccess) {
941 Symbol qualifier = null;
942 ClassSymbol c = currentClass;
943 if (tree.getTag() == JCTree.SELECT && (sym.flags() & STATIC) == 0) {
944 qualifier = ((JCFieldAccess) tree).selected.type.tsym;
945 while (!qualifier.isSubClass(c, types)) {
946 c = c.owner.enclClass();
947 }
948 return c;
949 } else {
950 while (!c.isSubClass(sym.owner, types)) {
951 c = c.owner.enclClass();
952 }
953 }
954 return c;
955 } else {
956 // the symbol is private
957 return sym.owner.enclClass();
958 }
959 }
960
961 /** Ensure that identifier is accessible, return tree accessing the identifier.
962 * @param sym The accessed symbol.
963 * @param tree The tree referring to the symbol.
964 * @param enclOp The closest enclosing operation node of tree,
965 * null if tree is not a subtree of an operation.
966 * @param refSuper Is access via a (qualified) C.super?
967 */
968 JCExpression access(Symbol sym, JCExpression tree, JCExpression enclOp, boolean refSuper) {
969 // Access a free variable via its proxy, or its proxy's proxy
970 while (sym.kind == VAR && sym.owner.kind == MTH &&
971 sym.owner.enclClass() != currentClass) {
972 // A constant is replaced by its constant value.
973 Object cv = ((VarSymbol)sym).getConstValue();
974 if (cv != null) {
975 make.at(tree.pos);
976 return makeLit(sym.type, cv);
977 }
978 // Otherwise replace the variable by its proxy.
979 sym = proxies.lookup(proxyName(sym.name)).sym;
980 assert sym != null && (sym.flags_field & FINAL) != 0;
981 tree = make.at(tree.pos).Ident(sym);
982 }
983 JCExpression base = (tree.getTag() == JCTree.SELECT) ? ((JCFieldAccess) tree).selected : null;
984 switch (sym.kind) {
985 case TYP:
986 if (sym.owner.kind != PCK) {
987 // Convert type idents to
988 // <flat name> or <package name> . <flat name>
989 Name flatname = Convert.shortName(sym.flatName());
990 while (base != null &&
991 TreeInfo.symbol(base) != null &&
992 TreeInfo.symbol(base).kind != PCK) {
993 base = (base.getTag() == JCTree.SELECT)
994 ? ((JCFieldAccess) base).selected
995 : null;
996 }
997 if (tree.getTag() == JCTree.IDENT) {
998 ((JCIdent) tree).name = flatname;
999 } else if (base == null) {
1000 tree = make.at(tree.pos).Ident(sym);
1001 ((JCIdent) tree).name = flatname;
1002 } else {
1003 ((JCFieldAccess) tree).selected = base;
1004 ((JCFieldAccess) tree).name = flatname;
1005 }
1006 }
1007 break;
1008 case MTH: case VAR:
1009 if (sym.owner.kind == TYP) {
1010
1011 // Access methods are required for
1012 // - private members,
1013 // - protected members in a superclass of an
1014 // enclosing class contained in another package.
1015 // - all non-private members accessed via a qualified super.
1016 boolean protAccess = refSuper && !needsPrivateAccess(sym)
1017 || needsProtectedAccess(sym, tree);
1018 boolean accReq = protAccess || needsPrivateAccess(sym);
1019
1020 // A base has to be supplied for
1021 // - simple identifiers accessing variables in outer classes.
1022 boolean baseReq =
1023 base == null &&
1024 sym.owner != syms.predefClass &&
1025 !sym.isMemberOf(currentClass, types);
1026
1027 if (accReq || baseReq) {
1028 make.at(tree.pos);
1029
1030 // Constants are replaced by their constant value.
1031 if (sym.kind == VAR) {
1032 Object cv = ((VarSymbol)sym).getConstValue();
1033 if (cv != null) return makeLit(sym.type, cv);
1034 }
1035
1036 // Private variables and methods are replaced by calls
1037 // to their access methods.
1038 if (accReq) {
1039 List<JCExpression> args = List.nil();
1040 if ((sym.flags() & STATIC) == 0) {
1041 // Instance access methods get instance
1042 // as first parameter.
1043 if (base == null)
1044 base = makeOwnerThis(tree.pos(), sym, true);
1045 args = args.prepend(base);
1046 base = null; // so we don't duplicate code
1047 }
1048 Symbol access = accessSymbol(sym, tree,
1049 enclOp, protAccess,
1050 refSuper);
1051 JCExpression receiver = make.Select(
1052 base != null ? base : make.QualIdent(access.owner),
1053 access);
1054 return make.App(receiver, args);
1055
1056 // Other accesses to members of outer classes get a
1057 // qualifier.
1058 } else if (baseReq) {
1059 return make.at(tree.pos).Select(
1060 accessBase(tree.pos(), sym), sym).setType(tree.type);
1061 }
1062 }
1063 }
1064 }
1065 return tree;
1066 }
1067
1068 /** Ensure that identifier is accessible, return tree accessing the identifier.
1069 * @param tree The identifier tree.
1070 */
1071 JCExpression access(JCExpression tree) {
1072 Symbol sym = TreeInfo.symbol(tree);
1073 return sym == null ? tree : access(sym, tree, null, false);
1074 }
1075
1076 /** Return access constructor for a private constructor,
1077 * or the constructor itself, if no access constructor is needed.
1078 * @param pos The position to report diagnostics, if any.
1079 * @param constr The private constructor.
1080 */
1081 Symbol accessConstructor(DiagnosticPosition pos, Symbol constr) {
1082 if (needsPrivateAccess(constr)) {
1083 ClassSymbol accOwner = constr.owner.enclClass();
1084 MethodSymbol aconstr = accessConstrs.get(constr);
1085 if (aconstr == null) {
1086 List<Type> argtypes = constr.type.getParameterTypes();
1087 if ((accOwner.flags_field & ENUM) != 0)
1088 argtypes = argtypes
1089 .prepend(syms.intType)
1090 .prepend(syms.stringType);
1091 aconstr = new MethodSymbol(
1092 SYNTHETIC,
1093 names.init,
1094 new MethodType(
1095 argtypes.append(
1096 accessConstructorTag().erasure(types)),
1097 constr.type.getReturnType(),
1098 constr.type.getThrownTypes(),
1099 syms.methodClass),
1100 accOwner);
1101 enterSynthetic(pos, aconstr, accOwner.members());
1102 accessConstrs.put(constr, aconstr);
1103 accessed.append(constr);
1104 }
1105 return aconstr;
1106 } else {
1107 return constr;
1108 }
1109 }
1110
1111 /** Return an anonymous class nested in this toplevel class.
1112 */
1113 ClassSymbol accessConstructorTag() {
1114 ClassSymbol topClass = currentClass.outermostClass();
1115 Name flatname = names.fromString("" + topClass.getQualifiedName() +
1116 target.syntheticNameChar() +
1117 "1");
1118 ClassSymbol ctag = chk.compiled.get(flatname);
1119 if (ctag == null)
1120 ctag = makeEmptyClass(STATIC | SYNTHETIC, topClass);
1121 return ctag;
1122 }
1123
1124 /** Add all required access methods for a private symbol to enclosing class.
1125 * @param sym The symbol.
1126 */
1127 void makeAccessible(Symbol sym) {
1128 JCClassDecl cdef = classDef(sym.owner.enclClass());
1129 assert cdef != null : "class def not found: " + sym + " in " + sym.owner;
1130 if (sym.name == names.init) {
1131 cdef.defs = cdef.defs.prepend(
1132 accessConstructorDef(cdef.pos, sym, accessConstrs.get(sym)));
1133 } else {
1134 MethodSymbol[] accessors = accessSyms.get(sym);
1135 for (int i = 0; i < NCODES; i++) {
1136 if (accessors[i] != null)
1137 cdef.defs = cdef.defs.prepend(
1138 accessDef(cdef.pos, sym, accessors[i], i));
1139 }
1140 }
1141 }
1142
1143 /** Construct definition of an access method.
1144 * @param pos The source code position of the definition.
1145 * @param vsym The private or protected symbol.
1146 * @param accessor The access method for the symbol.
1147 * @param acode The access code.
1148 */
1149 JCTree accessDef(int pos, Symbol vsym, MethodSymbol accessor, int acode) {
1150 // System.err.println("access " + vsym + " with " + accessor);//DEBUG
1151 currentClass = vsym.owner.enclClass();
1152 // System.out.println("========accessDef, currentClass = "+currentClass+", type = "+((currentClass!=null)?currentClass.type.toString():"n/a"));
1153 make.at(pos);
1154 JCMethodDecl md = make.MethodDef(accessor, null);
1155
1156 // Find actual symbol
1157 Symbol sym = actualSymbols.get(vsym);
1158 if (sym == null) sym = vsym;
1159
1160 JCExpression ref; // The tree referencing the private symbol.
1161 List<JCExpression> args; // Any additional arguments to be passed along.
1162 if ((sym.flags() & STATIC) != 0) {
1163 ref = make.Ident(sym);
1164 args = make.Idents(md.params);
1165 } else {
1166 ref = make.Select(make.Ident(md.params.head), sym);
1167 args = make.Idents(md.params.tail);
1168 }
1169 JCStatement stat; // The statement accessing the private symbol.
1170 if (sym.kind == VAR) {
1171 // Normalize out all odd access codes by taking floor modulo 2:
1172 int acode1 = acode - (acode & 1);
1173
1174 JCExpression expr; // The access method's return value.
1175 switch (acode1) {
1176 case DEREFcode:
1177 expr = ref;
1178 break;
1179 case ASSIGNcode:
1180 expr = make.Assign(ref, args.head);
1181 break;
1182 case PREINCcode: case POSTINCcode: case PREDECcode: case POSTDECcode:
1183 expr = makeUnary(
1184 ((acode1 - PREINCcode) >> 1) + JCTree.PREINC, ref);
1185 break;
1186 default:
1187 expr = make.Assignop(
1188 treeTag(binaryAccessOperator(acode1)), ref, args.head);
1189 ((JCAssignOp) expr).operator = binaryAccessOperator(acode1);
1190 }
1191 stat = make.Return(expr.setType(sym.type));
1192 } else {
1193 stat = make.Call(make.App(ref, args));
1194 }
1195 md.body = make.Block(0, List.of(stat));
1196
1197 // Make sure all parameters, result types and thrown exceptions
1198 // are accessible.
1199 for (List<JCVariableDecl> l = md.params; l.nonEmpty(); l = l.tail)
1200 l.head.vartype = access(l.head.vartype);
1201 md.restype = access(md.restype);
1202 for (List<JCExpression> l = md.thrown; l.nonEmpty(); l = l.tail)
1203 l.head = access(l.head);
1204
1205 return md;
1206 }
1207
1208 /** Construct definition of an access constructor.
1209 * @param pos The source code position of the definition.
1210 * @param constr The private constructor.
1211 * @param accessor The access method for the constructor.
1212 */
1213 JCTree accessConstructorDef(int pos, Symbol constr, MethodSymbol accessor) {
1214 make.at(pos);
1215 JCMethodDecl md = make.MethodDef(accessor,
1216 accessor.externalType(types),
1217 null);
1218 JCIdent callee = make.Ident(names._this);
1219 callee.sym = constr;
1220 callee.type = constr.type;
1221 md.body =
1222 make.Block(0, List.<JCStatement>of(
1223 make.Call(
1224 make.App(
1225 callee,
1226 make.Idents(md.params.reverse().tail.reverse())))));
1227 return md;
1228 }
1229
1230 /**************************************************************************
1231 * Free variables proxies and this$n
1232 *************************************************************************/
1233
1234 /** A scope containing all free variable proxies for currently translated
1235 * class, as well as its this$n symbol (if needed).
1236 * Proxy scopes are nested in the same way classes are.
1237 * Inside a constructor, proxies and any this$n symbol are duplicated
1238 * in an additional innermost scope, where they represent the constructor
1239 * parameters.
1240 */
1241 Scope proxies;
1242
1243 /** A stack containing the this$n field of the currently translated
1244 * classes (if needed) in innermost first order.
1245 * Inside a constructor, proxies and any this$n symbol are duplicated
1246 * in an additional innermost scope, where they represent the constructor
1247 * parameters.
1248 */
1249 List<VarSymbol> outerThisStack;
1250
1251 /** The name of a free variable proxy.
1252 */
1253 Name proxyName(Name name) {
1254 return names.fromString("val" + target.syntheticNameChar() + name);
1255 }
1256
1257 /** Proxy definitions for all free variables in given list, in reverse order.
1258 * @param pos The source code position of the definition.
1259 * @param freevars The free variables.
1260 * @param owner The class in which the definitions go.
1261 */
1262 List<JCVariableDecl> freevarDefs(int pos, List<VarSymbol> freevars, Symbol owner) {
1263 long flags = FINAL | SYNTHETIC;
1264 if (owner.kind == TYP &&
1265 target.usePrivateSyntheticFields())
1266 flags |= PRIVATE;
1267 List<JCVariableDecl> defs = List.nil();
1268 for (List<VarSymbol> l = freevars; l.nonEmpty(); l = l.tail) {
1269 VarSymbol v = l.head;
1270 VarSymbol proxy = new VarSymbol(
1271 flags, proxyName(v.name), v.erasure(types), owner);
1272 proxies.enter(proxy);
1273 JCVariableDecl vd = make.at(pos).VarDef(proxy, null);
1274 vd.vartype = access(vd.vartype);
1275 defs = defs.prepend(vd);
1276 }
1277 return defs;
1278 }
1279
1280 /** The name of a this$n field
1281 * @param type The class referenced by the this$n field
1282 */
1283 Name outerThisName(Type type, Symbol owner) {
1284 Type t = type.getEnclosingType();
1285 int nestingLevel = 0;
1286 while (t.tag == CLASS) {
1287 t = t.getEnclosingType();
1288 nestingLevel++;
1289 }
1290 Name result = names.fromString("this" + target.syntheticNameChar() + nestingLevel);
1291 while (owner.kind == TYP && ((ClassSymbol)owner).members().lookup(result).scope != null)
1292 result = names.fromString(result.toString() + target.syntheticNameChar());
1293 return result;
1294 }
1295
1296 /** Definition for this$n field.
1297 * @param pos The source code position of the definition.
1298 * @param owner The class in which the definition goes.
1299 */
1300 JCVariableDecl outerThisDef(int pos, Symbol owner) {
1301 long flags = FINAL | SYNTHETIC;
1302 if (owner.kind == TYP &&
1303 target.usePrivateSyntheticFields())
1304 flags |= PRIVATE;
1305 Type target = types.erasure(owner.enclClass().type.getEnclosingType());
1306 VarSymbol outerThis = new VarSymbol(
1307 flags, outerThisName(target, owner), target, owner);
1308 outerThisStack = outerThisStack.prepend(outerThis);
1309 JCVariableDecl vd = make.at(pos).VarDef(outerThis, null);
1310 vd.vartype = access(vd.vartype);
1311 // System.out.print("outerThisDef owner="+owner+" outerThisStack=");
1312 // for(VarSymbol vs: outerThisStack) { System.out.print(vs+"("+vs.type+") "); }
1313 // System.out.println();
1314 return vd;
1315 }
1316
1317 /** Return a list of trees that load the free variables in given list,
1318 * in reverse order.
1319 * @param pos The source code position to be used for the trees.
1320 * @param freevars The list of free variables.
1321 */
1322 List<JCExpression> loadFreevars(DiagnosticPosition pos, List<VarSymbol> freevars) {
1323 List<JCExpression> args = List.nil();
1324 for (List<VarSymbol> l = freevars; l.nonEmpty(); l = l.tail)
1325 args = args.prepend(loadFreevar(pos, l.head));
1326 return args;
1327 }
1328 //where
1329 JCExpression loadFreevar(DiagnosticPosition pos, VarSymbol v) {
1330 return access(v, make.at(pos).Ident(v), null, false);
1331 }
1332
1333 /** Construct a tree simulating the expression <C.this>.
1334 * @param pos The source code position to be used for the tree.
1335 * @param c The qualifier class.
1336 */
1337 JCExpression makeThis(DiagnosticPosition pos, TypeSymbol c) {
1338 // System.out.println("\tmakeThis, currentClass="+currentClass+", c="+c);
1339 if (currentClass == c) {
1340 // in this case, `this' works fine
1341 return make.at(pos).This(c.erasure(types));
1342 } else {
1343 // need to go via this$n
1344 return makeOuterThis(pos, c);
1345 }
1346 }
1347
1348 /** Construct a tree that represents the outer instance
1349 * <C.this>. Never pick the current `this'.
1350 * @param pos The source code position to be used for the tree.
1351 * @param c The qualifier class.
1352 */
1353 JCExpression makeOuterThis(DiagnosticPosition pos, TypeSymbol c) {
1354 List<VarSymbol> ots = outerThisStack;
1355 // System.out.println("\tots = "+ots);
1356 if (ots.isEmpty()) {
1357 log.error(pos, "no.encl.instance.of.type.in.scope", c);
1358 assert false;
1359 return makeNull();
1360 }
1361 VarSymbol ot = ots.head;
1362 JCExpression tree = access(make.at(pos).Ident(ot));
1363 TypeSymbol otc = ot.type.tsym;
1364 while (otc != c) {
1365 do {
1366 ots = ots.tail;
1367 if (ots.isEmpty()) {
1368 log.error(pos,
1369 "no.encl.instance.of.type.in.scope",
1370 c);
1371 assert false; // should have been caught in Attr
1372 return tree;
1373 }
1374 ot = ots.head;
1375 } while (ot.owner != otc);
1376 if (otc.owner.kind != PCK && !otc.hasOuterInstance()) {
1377 chk.earlyRefError(pos, c);
1378 assert false; // should have been caught in Attr
1379 return makeNull();
1380 }
1381 tree = access(make.at(pos).Select(tree, ot));
1382 otc = ot.type.tsym;
1383 }
1384 return tree;
1385 }
1386
1387 /** Construct a tree that represents the closest outer instance
1388 * <C.this> such that the given symbol is a member of C.
1389 * @param pos The source code position to be used for the tree.
1390 * @param sym The accessed symbol.
1391 * @param preciseMatch should we accept a type that is a subtype of
1392 * sym's owner, even if it doesn't contain sym
1393 * due to hiding, overriding, or non-inheritance
1394 * due to protection?
1395 */
1396 JCExpression makeOwnerThis(DiagnosticPosition pos, Symbol sym, boolean preciseMatch) {
1397 Symbol c = sym.owner;
1398 if (preciseMatch ? sym.isMemberOf(currentClass, types)
1399 : currentClass.isSubClass(sym.owner, types)) {
1400 // in this case, `this' works fine
1401 return make.at(pos).This(c.erasure(types));
1402 } else {
1403 // need to go via this$n
1404 return makeOwnerThisN(pos, sym, preciseMatch);
1405 }
1406 }
1407
1408 /**
1409 * Similar to makeOwnerThis but will never pick "this".
1410 */
1411 JCExpression makeOwnerThisN(DiagnosticPosition pos, Symbol sym, boolean preciseMatch) {
1412 Symbol c = sym.owner;
1413 List<VarSymbol> ots = outerThisStack;
1414 if (ots.isEmpty()) {
1415 log.error(pos, "no.encl.instance.of.type.in.scope", c);
1416 assert false;
1417 return makeNull();
1418 }
1419 VarSymbol ot = ots.head;
1420 JCExpression tree = access(make.at(pos).Ident(ot));
1421 TypeSymbol otc = ot.type.tsym;
1422 while (!(preciseMatch ? sym.isMemberOf(otc, types) : otc.isSubClass(sym.owner, types))) {
1423 do {
1424 ots = ots.tail;
1425 if (ots.isEmpty()) {
1426 log.error(pos,
1427 "no.encl.instance.of.type.in.scope",
1428 c);
1429 assert false;
1430 return tree;
1431 }
1432 ot = ots.head;
1433 } while (ot.owner != otc);
1434 tree = access(make.at(pos).Select(tree, ot));
1435 otc = ot.type.tsym;
1436 }
1437 return tree;
1438 }
1439
1440 /** Return tree simulating the assignment <this.name = name>, where
1441 * name is the name of a free variable.
1442 */
1443 JCStatement initField(int pos, Name name) {
1444 Scope.Entry e = proxies.lookup(name);
1445 Symbol rhs = e.sym;
1446 assert rhs.owner.kind == MTH;
1447 Symbol lhs = e.next().sym;
1448 assert rhs.owner.owner == lhs.owner;
1449 make.at(pos);
1450 return
1451 make.Exec(
1452 make.Assign(
1453 make.Select(make.This(lhs.owner.erasure(types)), lhs),
1454 make.Ident(rhs)).setType(lhs.erasure(types)));
1455 }
1456
1457 /** Return tree simulating the assignment <this.this$n = this$n>.
1458 */
1459 JCStatement initOuterThis(int pos) {
1460 VarSymbol rhs = outerThisStack.head;
1461 assert rhs.owner.kind == MTH;
1462 VarSymbol lhs = outerThisStack.tail.head;
1463 assert rhs.owner.owner == lhs.owner;
1464 make.at(pos);
1465 return
1466 make.Exec(
1467 make.Assign(
1468 make.Select(make.This(lhs.owner.erasure(types)), lhs),
1469 make.Ident(rhs)).setType(lhs.erasure(types)));
1470 }
1471
1472 /**************************************************************************
1473 * Code for .class
1474 *************************************************************************/
1475
1476 /** Return the symbol of a class to contain a cache of
1477 * compiler-generated statics such as class$ and the
1478 * $assertionsDisabled flag. We create an anonymous nested class
1479 * (unless one already exists) and return its symbol. However,
1480 * for backward compatibility in 1.4 and earlier we use the
1481 * top-level class itself.
1482 */
1483 private ClassSymbol outerCacheClass() {
1484 ClassSymbol clazz = outermostClassDef.sym;
1485 if ((clazz.flags() & INTERFACE) == 0 &&
1486 !target.useInnerCacheClass()) return clazz;
1487 Scope s = clazz.members();
1488 for (Scope.Entry e = s.elems; e != null; e = e.sibling)
1489 if (e.sym.kind == TYP &&
1490 e.sym.name == names.empty &&
1491 (e.sym.flags() & INTERFACE) == 0) return (ClassSymbol) e.sym;
1492 return makeEmptyClass(STATIC | SYNTHETIC, clazz);
1493 }
1494
1495 /** Return symbol for "class$" method. If there is no method definition
1496 * for class$, construct one as follows:
1497 *
1498 * class class$(String x0) {
1499 * try {
1500 * return Class.forName(x0);
1501 * } catch (ClassNotFoundException x1) {
1502 * throw new NoClassDefFoundError(x1.getMessage());
1503 * }
1504 * }
1505 */
1506 private MethodSymbol classDollarSym(DiagnosticPosition pos) {
1507 ClassSymbol outerCacheClass = outerCacheClass();
1508 MethodSymbol classDollarSym =
1509 (MethodSymbol)lookupSynthetic(classDollar,
1510 outerCacheClass.members());
1511 if (classDollarSym == null) {
1512 classDollarSym = new MethodSymbol(
1513 STATIC | SYNTHETIC,
1514 classDollar,
1515 new MethodType(
1516 List.of(syms.stringType),
1517 types.erasure(syms.classType),
1518 List.<Type>nil(),
1519 syms.methodClass),
1520 outerCacheClass);
1521 enterSynthetic(pos, classDollarSym, outerCacheClass.members());
1522
1523 JCMethodDecl md = make.MethodDef(classDollarSym, null);
1524 try {
1525 md.body = classDollarSymBody(pos, md);
1526 } catch (CompletionFailure ex) {
1527 md.body = make.Block(0, List.<JCStatement>nil());
1528 chk.completionError(pos, ex);
1529 }
1530 JCClassDecl outerCacheClassDef = classDef(outerCacheClass);
1531 outerCacheClassDef.defs = outerCacheClassDef.defs.prepend(md);
1532 }
1533 return classDollarSym;
1534 }
1535
1536 /** Generate code for class$(String name). */
1537 JCBlock classDollarSymBody(DiagnosticPosition pos, JCMethodDecl md) {
1538 MethodSymbol classDollarSym = md.sym;
1539 ClassSymbol outerCacheClass = (ClassSymbol)classDollarSym.owner;
1540
1541 JCBlock returnResult;
1542
1543 // in 1.4.2 and above, we use
1544 // Class.forName(String name, boolean init, ClassLoader loader);
1545 // which requires we cache the current loader in cl$
1546 if (target.classLiteralsNoInit()) {
1547 // clsym = "private static ClassLoader cl$"
1548 VarSymbol clsym = new VarSymbol(STATIC|SYNTHETIC,
1549 names.fromString("cl" + target.syntheticNameChar()),
1550 syms.classLoaderType,
1551 outerCacheClass);
1552 enterSynthetic(pos, clsym, outerCacheClass.members());
1553
1554 // emit "private static ClassLoader cl$;"
1555 JCVariableDecl cldef = make.VarDef(clsym, null);
1556 JCClassDecl outerCacheClassDef = classDef(outerCacheClass);
1557 outerCacheClassDef.defs = outerCacheClassDef.defs.prepend(cldef);
1558
1559 // newcache := "new cache$1[0]"
1560 JCNewArray newcache = make.
1561 NewArray(make.Type(outerCacheClass.type),
1562 List.<JCExpression>of(make.Literal(INT, 0).setType(syms.intType)),
1563 null);
1564 newcache.type = new ArrayType(types.erasure(outerCacheClass.type),
1565 syms.arrayClass);
1566
1567 // forNameSym := java.lang.Class.forName(
1568 // String s,boolean init,ClassLoader loader)
1569 Symbol forNameSym = lookupMethod(make_pos, names.forName,
1570 types.erasure(syms.classType),
1571 List.of(syms.stringType,
1572 syms.booleanType,
1573 syms.classLoaderType));
1574 // clvalue := "(cl$ == null) ?
1575 // $newcache.getClass().getComponentType().getClassLoader() : cl$"
1576 JCExpression clvalue =
1577 make.Conditional(
1578 makeBinary(JCTree.EQ, make.Ident(clsym), makeNull()),
1579 make.Assign(
1580 make.Ident(clsym),
1581 makeCall(
1582 makeCall(makeCall(newcache,
1583 names.getClass,
1584 List.<JCExpression>nil()),
1585 names.getComponentType,
1586 List.<JCExpression>nil()),
1587 names.getClassLoader,
1588 List.<JCExpression>nil())).setType(syms.classLoaderType),
1589 make.Ident(clsym)).setType(syms.classLoaderType);
1590
1591 // returnResult := "{ return Class.forName(param1, false, cl$); }"
1592 List<JCExpression> args = List.of(make.Ident(md.params.head.sym),
1593 makeLit(syms.booleanType, 0),
1594 clvalue);
1595 returnResult = make.
1596 Block(0, List.<JCStatement>of(make.
1597 Call(make. // return
1598 App(make.
1599 Ident(forNameSym), args))));
1600 } else {
1601 // forNameSym := java.lang.Class.forName(String s)
1602 Symbol forNameSym = lookupMethod(make_pos,
1603 names.forName,
1604 types.erasure(syms.classType),
1605 List.of(syms.stringType));
1606 // returnResult := "{ return Class.forName(param1); }"
1607 returnResult = make.
1608 Block(0, List.of(make.
1609 Call(make. // return
1610 App(make.
1611 QualIdent(forNameSym),
1612 List.<JCExpression>of(make.
1613 Ident(md.params.
1614 head.sym))))));
1615 }
1616
1617 // catchParam := ClassNotFoundException e1
1618 VarSymbol catchParam =
1619 new VarSymbol(0, make.paramName(1),
1620 syms.classNotFoundExceptionType,
1621 classDollarSym);
1622
1623 JCStatement rethrow;
1624 if (target.hasInitCause()) {
1625 // rethrow = "throw new NoClassDefFoundError().initCause(e);
1626 JCTree throwExpr =
1627 makeCall(makeNewClass(syms.noClassDefFoundErrorType,
1628 List.<JCExpression>nil()),
1629 names.initCause,
1630 List.<JCExpression>of(make.Ident(catchParam)));
1631 rethrow = make.Throw(throwExpr);
1632 } else {
1633 // getMessageSym := ClassNotFoundException.getMessage()
1634 Symbol getMessageSym = lookupMethod(make_pos,
1635 names.getMessage,
1636 syms.classNotFoundExceptionType,
1637 List.<Type>nil());
1638 // rethrow = "throw new NoClassDefFoundError(e.getMessage());"
1639 rethrow = make.
1640 Throw(makeNewClass(syms.noClassDefFoundErrorType,
1641 List.<JCExpression>of(make.App(make.Select(make.Ident(catchParam),
1642 getMessageSym),
1643 List.<JCExpression>nil()))));
1644 }
1645
1646 // rethrowStmt := "( $rethrow )"
1647 JCBlock rethrowStmt = make.Block(0, List.of(rethrow));
1648
1649 // catchBlock := "catch ($catchParam) $rethrowStmt"
1650 JCCatch catchBlock = make.Catch(make.VarDef(catchParam, null),
1651 rethrowStmt);
1652
1653 // tryCatch := "try $returnResult $catchBlock"
1654 JCStatement tryCatch = make.Try(returnResult,
1655 List.of(catchBlock), null);
1656
1657 return make.Block(0, List.of(tryCatch));
1658 }
1659 // where
1660 /** Create an attributed tree of the form left.name(). */
1661 private JCMethodInvocation makeCall(JCExpression left, Name name, List<JCExpression> args) {
1662 assert left.type != null;
1663 Symbol funcsym = lookupMethod(make_pos, name, left.type,
1664 TreeInfo.types(args));
1665 return make.App(make.Select(left, funcsym), args);
1666 }
1667
1668 /** The Name Of The variable to cache T.class values.
1669 * @param sig The signature of type T.
1670 */
1671 private Name cacheName(String sig) {
1672 StringBuffer buf = new StringBuffer();
1673 if (sig.startsWith("[")) {
1674 buf = buf.append("array");
1675 while (sig.startsWith("[")) {
1676 buf = buf.append(target.syntheticNameChar());
1677 sig = sig.substring(1);
1678 }
1679 if (sig.startsWith("L")) {
1680 sig = sig.substring(0, sig.length() - 1);
1681 }
1682 } else {
1683 buf = buf.append("class" + target.syntheticNameChar());
1684 }
1685 buf = buf.append(sig.replace('.', target.syntheticNameChar()));
1686 return names.fromString(buf.toString());
1687 }
1688
1689 /** The variable symbol that caches T.class values.
1690 * If none exists yet, create a definition.
1691 * @param sig The signature of type T.
1692 * @param pos The position to report diagnostics, if any.
1693 */
1694 private VarSymbol cacheSym(DiagnosticPosition pos, String sig) {
1695 ClassSymbol outerCacheClass = outerCacheClass();
1696 Name cname = cacheName(sig);
1697 VarSymbol cacheSym =
1698 (VarSymbol)lookupSynthetic(cname, outerCacheClass.members());
1699 if (cacheSym == null) {
1700 cacheSym = new VarSymbol(
1701 STATIC | SYNTHETIC, cname, types.erasure(syms.classType), outerCacheClass);
1702 enterSynthetic(pos, cacheSym, outerCacheClass.members());
1703
1704 JCVariableDecl cacheDef = make.VarDef(cacheSym, null);
1705 JCClassDecl outerCacheClassDef = classDef(outerCacheClass);
1706 outerCacheClassDef.defs = outerCacheClassDef.defs.prepend(cacheDef);
1707 }
1708 return cacheSym;
1709 }
1710
1711 /** The tree simulating a T.class expression.
1712 * @param clazz The tree identifying type T.
1713 */
1714 private JCExpression classOf(JCTree clazz) {
1715 return classOfType(clazz.type, clazz.pos());
1716 }
1717
1718 private JCExpression classOfType(Type type, DiagnosticPosition pos) {
1719 switch (type.tag) {
1720 case BYTE: case SHORT: case CHAR: case INT: case LONG: case FLOAT:
1721 case DOUBLE: case BOOLEAN: case VOID:
1722 // replace with <BoxedClass>.TYPE
1723 ClassSymbol c = types.boxedClass(type);
1724 Symbol typeSym =
1725 rs.access(
1726 rs.findIdentInType(attrEnv, c.type, names.TYPE, VAR),
1727 pos, c.type, names.TYPE, true);
1728 if (typeSym.kind == VAR)
1729 ((VarSymbol)typeSym).getConstValue(); // ensure initializer is evaluated
1730 return make.QualIdent(typeSym);
1731 case CLASS: case ARRAY:
1732 if (target.hasClassLiterals()) {
1733 VarSymbol sym = new VarSymbol(
1734 STATIC | PUBLIC | FINAL, names._class,
1735 syms.classType, type.tsym);
1736 return make_at(pos).Select(make.Type(type), sym);
1737 }
1738 // replace with <cache == null ? cache = class$(tsig) : cache>
1739 // where
1740 // - <tsig> is the type signature of T,
1741 // - <cache> is the cache variable for tsig.
1742 String sig =
1743 writer.xClassName(type).toString().replace('/', '.');
1744 Symbol cs = cacheSym(pos, sig);
1745 return make_at(pos).Conditional(
1746 makeBinary(JCTree.EQ, make.Ident(cs), makeNull()),
1747 make.Assign(
1748 make.Ident(cs),
1749 make.App(
1750 make.Ident(classDollarSym(pos)),
1751 List.<JCExpression>of(make.Literal(CLASS, sig)
1752 .setType(syms.stringType))))
1753 .setType(types.erasure(syms.classType)),
1754 make.Ident(cs)).setType(types.erasure(syms.classType));
1755 default:
1756 throw new AssertionError();
1757 }
1758 }
1759
1760 /**************************************************************************
1761 * Code for enabling/disabling assertions.
1762 *************************************************************************/
1763
1764 // This code is not particularly robust if the user has
1765 // previously declared a member named '$assertionsDisabled'.
1766 // The same faulty idiom also appears in the translation of
1767 // class literals above. We should report an error if a
1768 // previous declaration is not synthetic.
1769
1770 private JCExpression assertFlagTest(DiagnosticPosition pos) {
1771 // Outermost class may be either true class or an interface.
1772 ClassSymbol outermostClass = outermostClassDef.sym;
1773
1774 // note that this is a class, as an interface can't contain a statement.
1775 ClassSymbol container = currentClass;
1776
1777 VarSymbol assertDisabledSym =
1778 (VarSymbol)lookupSynthetic(dollarAssertionsDisabled,
1779 container.members());
1780 if (assertDisabledSym == null) {
1781 assertDisabledSym =
1782 new VarSymbol(STATIC | FINAL | SYNTHETIC,
1783 dollarAssertionsDisabled,
1784 syms.booleanType,
1785 container);
1786 enterSynthetic(pos, assertDisabledSym, container.members());
1787 Symbol desiredAssertionStatusSym = lookupMethod(pos,
1788 names.desiredAssertionStatus,
1789 types.erasure(syms.classType),
1790 List.<Type>nil());
1791 JCClassDecl containerDef = classDef(container);
1792 make_at(containerDef.pos());
1793 JCExpression notStatus = makeUnary(JCTree.NOT, make.App(make.Select(
1794 classOfType(types.erasure(outermostClass.type),
1795 containerDef.pos()),
1796 desiredAssertionStatusSym)));
1797 JCVariableDecl assertDisabledDef = make.VarDef(assertDisabledSym,
1798 notStatus);
1799 containerDef.defs = containerDef.defs.prepend(assertDisabledDef);
1800 }
1801 make_at(pos);
1802 return makeUnary(JCTree.NOT, make.Ident(assertDisabledSym));
1803 }
1804
1805
1806 /**************************************************************************
1807 * Building blocks for let expressions
1808 *************************************************************************/
1809
1810 interface TreeBuilder {
1811 JCTree build(JCTree arg);
1812 }
1813
1814 /** Construct an expression using the builder, with the given rval
1815 * expression as an argument to the builder. However, the rval
1816 * expression must be computed only once, even if used multiple
1817 * times in the result of the builder. We do that by
1818 * constructing a "let" expression that saves the rvalue into a
1819 * temporary variable and then uses the temporary variable in
1820 * place of the expression built by the builder. The complete
1821 * resulting expression is of the form
1822 * <pre>
1823 * (let <b>TYPE</b> <b>TEMP</b> = <b>RVAL</b>;
1824 * in (<b>BUILDER</b>(<b>TEMP</b>)))
1825 * </pre>
1826 * where <code><b>TEMP</b></code> is a newly declared variable
1827 * in the let expression.
1828 */
1829 JCTree abstractRval(JCTree rval, Type type, TreeBuilder builder) {
1830 rval = TreeInfo.skipParens(rval);
1831 switch (rval.getTag()) {
1832 case JCTree.LITERAL:
1833 return builder.build(rval);
1834 case JCTree.IDENT:
1835 JCIdent id = (JCIdent) rval;
1836 if ((id.sym.flags() & FINAL) != 0 && id.sym.owner.kind == MTH)
1837 return builder.build(rval);
1838 }
1839 VarSymbol var =
1840 new VarSymbol(FINAL|SYNTHETIC,
1841 names.fromString(
1842 target.syntheticNameChar()
1843 + "" + rval.hashCode()),
1844 type,
1845 currentMethodSym);
1846 rval = convert(rval,type);
1847 JCVariableDecl def = make.VarDef(var, (JCExpression)rval); // XXX cast
1848 JCTree built = builder.build(make.Ident(var));
1849 JCTree res = make.LetExpr(def, built);
1850 res.type = built.type;
1851 return res;
1852 }
1853
1854 // same as above, with the type of the temporary variable computed
1855 JCTree abstractRval(JCTree rval, TreeBuilder builder) {
1856 return abstractRval(rval, rval.type, builder);
1857 }
1858
1859 // same as above, but for an expression that may be used as either
1860 // an rvalue or an lvalue. This requires special handling for
1861 // Select expressions, where we place the left-hand-side of the
1862 // select in a temporary, and for Indexed expressions, where we
1863 // place both the indexed expression and the index value in temps.
1864 JCTree abstractLval(JCTree lval, final TreeBuilder builder) {
1865 lval = TreeInfo.skipParens(lval);
1866 switch (lval.getTag()) {
1867 case JCTree.IDENT:
1868 return builder.build(lval);
1869 case JCTree.SELECT: {
1870 final JCFieldAccess s = (JCFieldAccess)lval;
1871 JCTree selected = TreeInfo.skipParens(s.selected);
1872 Symbol lid = TreeInfo.symbol(s.selected);
1873 if (lid != null && lid.kind == TYP) return builder.build(lval);
1874 return abstractRval(s.selected, new TreeBuilder() {
1875 public JCTree build(final JCTree selected) {
1876 return builder.build(make.Select((JCExpression)selected, s.sym));
1877 }
1878 });
1879 }
1880 case JCTree.INDEXED: {
1881 final JCArrayAccess i = (JCArrayAccess)lval;
1882 return abstractRval(i.indexed, new TreeBuilder() {
1883 public JCTree build(final JCTree indexed) {
1884 return abstractRval(i.index, syms.intType, new TreeBuilder() {
1885 public JCTree build(final JCTree index) {
1886 JCTree newLval = make.Indexed((JCExpression)indexed,
1887 (JCExpression)index);
1888 newLval.setType(i.type);
1889 return builder.build(newLval);
1890 }
1891 });
1892 }
1893 });
1894 }
1895 case JCTree.TYPECAST: {
1896 return abstractLval(((JCTypeCast)lval).expr, builder);
1897 }
1898 }
1899 throw new AssertionError(lval);
1900 }
1901
1902 // evaluate and discard the first expression, then evaluate the second.
1903 JCTree makeComma(final JCTree expr1, final JCTree expr2) {
1904 return abstractRval(expr1, new TreeBuilder() {
1905 public JCTree build(final JCTree discarded) {
1906 return expr2;
1907 }
1908 });
1909 }
1910
1911 /**************************************************************************
1912 * Translation methods
1913 *************************************************************************/
1914
1915 /** Visitor argument: enclosing operator node.
1916 */
1917 private JCExpression enclOp;
1918
1919 /** Visitor method: Translate a single node.
1920 * Attach the source position from the old tree to its replacement tree.
1921 */
1922 public <T extends JCTree> T translate(T tree) {
1923 if (tree == null) {
1924 return null;
1925 } else {
1926 make_at(tree.pos());
1927 T result = super.translate(tree);
1928 if (endPositions != null && result != tree) {
1929 Integer endPos = endPositions.remove(tree);
1930 if (endPos != null) endPositions.put(result, endPos);
1931 }
1932 return result;
1933 }
1934 }
1935
1936 /** Visitor method: Translate a single node, boxing or unboxing if needed.
1937 */
1938 public <T extends JCTree> T translate(T tree, Type type) {
1939 return (tree == null) ? null : boxIfNeeded(translate(tree), type);
1940 }
1941
1942 /** Visitor method: Translate tree.
1943 */
1944 public <T extends JCTree> T translate(T tree, JCExpression enclOp) {
1945 JCExpression prevEnclOp = this.enclOp;
1946 this.enclOp = enclOp;
1947 T res = translate(tree);
1948 this.enclOp = prevEnclOp;
1949 return res;
1950 }
1951
1952 /** Visitor method: Translate list of trees.
1953 */
1954 public <T extends JCTree> List<T> translate(List<T> trees, JCExpression enclOp) {
1955 JCExpression prevEnclOp = this.enclOp;
1956 this.enclOp = enclOp;
1957 List<T> res = translate(trees);
1958 this.enclOp = prevEnclOp;
1959 return res;
1960 }
1961
1962 /** Visitor method: Translate list of trees.
1963 */
1964 public <T extends JCTree> List<T> translate(List<T> trees, Type type) {
1965 if (trees == null) return null;
1966 for (List<T> l = trees; l.nonEmpty(); l = l.tail)
1967 l.head = translate(l.head, type);
1968 return trees;
1969 }
1970
1971 public void visitTopLevel(JCCompilationUnit tree) {
1972 if (tree.packageAnnotations.nonEmpty()) {
1973 Name name = names.package_info;
1974 long flags = Flags.ABSTRACT | Flags.INTERFACE;
1975 if (target.isPackageInfoSynthetic())
1976 // package-info is marked SYNTHETIC in JDK 1.6 and later releases
1977 flags = flags | Flags.SYNTHETIC;
1978 JCClassDecl packageAnnotationsClass
1979 = make.ClassDef(make.Modifiers(flags,
1980 tree.packageAnnotations),
1981 name, List.<JCTypeParameter>nil(),
1982 null, List.<JCExpression>nil(), List.<JCTree>nil());
1983 ClassSymbol c = reader.enterClass(name, tree.packge);
1984 c.flatname = names.fromString(tree.packge + "." + name);
1985 c.sourcefile = tree.sourcefile;
1986 c.completer = null;
1987 c.members_field = new Scope(c);
1988 c.flags_field = flags;
1989 c.attributes_field = tree.packge.attributes_field;
1990 tree.packge.attributes_field = List.nil();
1991 ClassType ctype = (ClassType) c.type;
1992 ctype.supertype_field = syms.objectType;
1993 ctype.interfaces_field = List.nil();
1994 packageAnnotationsClass.sym = c;
1995
1996
1997 translated.append(packageAnnotationsClass);
1998 }
1999 }
2000
2001 public void visitClassDef(JCClassDecl tree) {
2002 ClassSymbol currentClassPrev = currentClass;
2003 MethodSymbol currentMethodSymPrev = currentMethodSym;
2004 currentClass = tree.sym;
2005 // System.out.println("========visitClassDef, currentClass = "+currentClass+", type = "+((currentClass!=null)?currentClass.type.toString():"n/a"));
2006 currentMethodSym = null;
2007 classdefs.put(currentClass, tree);
2008
2009 proxies = proxies.dup(currentClass);
2010 List<VarSymbol> prevOuterThisStack = outerThisStack;
2011
2012 // If this is an enum definition
2013 if ((tree.mods.flags & ENUM) != 0 &&
2014 (types.supertype(currentClass.type).tsym.flags() & ENUM) == 0)
2015 visitEnumDef(tree);
2016
2017 // If this is a nested class, define a this$n field for
2018 // it and add to proxies.
2019 JCVariableDecl otdef = null;
2020 if (currentClass.hasOuterInstance())
2021 otdef = outerThisDef(tree.pos, currentClass);
2022
2023 // If this is a local class, define proxies for all its free variables.
2024 List<JCVariableDecl> fvdefs = freevarDefs(
2025 tree.pos, freevars(currentClass), currentClass);
2026
2027 // Recursively translate superclass, interfaces.
2028 tree.extending = translate(tree.extending);
2029 tree.implementing = translate(tree.implementing);
2030
2031 // Recursively translate members, taking into account that new members
2032 // might be created during the translation and prepended to the member
2033 // list `tree.defs'.
2034 List<JCTree> seen = List.nil();
2035 while (tree.defs != seen) {
2036 List<JCTree> unseen = tree.defs;
2037 for (List<JCTree> l = unseen; l.nonEmpty() && l != seen; l = l.tail) {
2038 JCTree outermostMemberDefPrev = outermostMemberDef;
2039 if (outermostMemberDefPrev == null) outermostMemberDef = l.head;
2040 l.head = translate(l.head);
2041 outermostMemberDef = outermostMemberDefPrev;
2042 }
2043 seen = unseen;
2044 }
2045
2046 // Convert a protected modifier to public, mask static modifier.
2047 if ((tree.mods.flags & PROTECTED) != 0) tree.mods.flags |= PUBLIC;
2048 tree.mods.flags &= ClassFlags;
2049
2050 // Convert name to flat representation, replacing '.' by '$'.
2051 tree.name = Convert.shortName(currentClass.flatName());
2052
2053 // Add this$n and free variables proxy definitions to class.
2054 for (List<JCVariableDecl> l = fvdefs; l.nonEmpty(); l = l.tail) {
2055 tree.defs = tree.defs.prepend(l.head);
2056 enterSynthetic(tree.pos(), l.head.sym, currentClass.members());
2057 }
2058 if (currentClass.hasOuterInstance()) {
2059 tree.defs = tree.defs.prepend(otdef);
2060 enterSynthetic(tree.pos(), otdef.sym, currentClass.members());
2061 }
2062
2063 proxies = proxies.leave();
2064 outerThisStack = prevOuterThisStack;
2065
2066 // Append translated tree to `translated' queue.
2067 translated.append(tree);
2068
2069 currentClass = currentClassPrev;
2070 // System.out.println("========end visitClassDef, currentClass = "+currentClass+", type = "+((currentClass!=null)?currentClass.type.toString():"n/a"));
2071 currentMethodSym = currentMethodSymPrev;
2072
2073 // Return empty block {} as a placeholder for an inner class.
2074 result = make_at(tree.pos()).Block(0, List.<JCStatement>nil());
2075 }
2076
2077 /** Translate an enum class. */
2078 private void visitEnumDef(JCClassDecl tree) {
2079 make_at(tree.pos());
2080
2081 // add the supertype, if needed
2082 if (tree.extending == null)
2083 tree.extending = make.Type(types.supertype(tree.type));
2084
2085 // classOfType adds a cache field to tree.defs unless
2086 // target.hasClassLiterals().
2087 JCExpression e_class = classOfType(tree.sym.type, tree.pos()).
2088 setType(types.erasure(syms.classType));
2089
2090 // process each enumeration constant, adding implicit constructor parameters
2091 int nextOrdinal = 0;
2092 ListBuffer<JCExpression> values = new ListBuffer<JCExpression>();
2093 ListBuffer<JCTree> enumDefs = new ListBuffer<JCTree>();
2094 ListBuffer<JCTree> otherDefs = new ListBuffer<JCTree>();
2095 for (List<JCTree> defs = tree.defs;
2096 defs.nonEmpty();
2097 defs=defs.tail) {
2098 if (defs.head.getTag() == JCTree.VARDEF && (((JCVariableDecl) defs.head).mods.flags & ENUM) != 0) {
2099 JCVariableDecl var = (JCVariableDecl)defs.head;
2100 visitEnumConstantDef(var, nextOrdinal++);
2101 values.append(make.QualIdent(var.sym));
2102 enumDefs.append(var);
2103 } else {
2104 otherDefs.append(defs.head);
2105 }
2106 }
2107
2108 // private static final T[] #VALUES = { a, b, c };
2109 Name valuesName = names.fromString(target.syntheticNameChar() + "VALUES");
2110 while (tree.sym.members().lookup(valuesName).scope != null) // avoid name clash
2111 valuesName = names.fromString(valuesName + "" + target.syntheticNameChar());
2112 Type arrayType = new ArrayType(types.erasure(tree.type), syms.arrayClass);
2113 VarSymbol valuesVar = new VarSymbol(PRIVATE|FINAL|STATIC|SYNTHETIC,
2114 valuesName,
2115 arrayType,
2116 tree.type.tsym);
2117 JCNewArray newArray = make.NewArray(make.Type(types.erasure(tree.type)),
2118 List.<JCExpression>nil(),
2119 values.toList());
2120 newArray.type = arrayType;
2121 enumDefs.append(make.VarDef(valuesVar, newArray));
2122 tree.sym.members().enter(valuesVar);
2123
2124 Symbol valuesSym = lookupMethod(tree.pos(), names.values,
2125 tree.type, List.<Type>nil());
2126 List<JCStatement> valuesBody;
2127 if (useClone()) {
2128 // return (T[]) $VALUES.clone();
2129 JCTypeCast valuesResult =
2130 make.TypeCast(valuesSym.type.getReturnType(),
2131 make.App(make.Select(make.Ident(valuesVar),
2132 syms.arrayCloneMethod)));
2133 valuesBody = List.<JCStatement>of(make.Return(valuesResult));
2134 } else {
2135 // template: T[] $result = new T[$values.length];
2136 Name resultName = names.fromString(target.syntheticNameChar() + "result");
2137 while (tree.sym.members().lookup(resultName).scope != null) // avoid name clash
2138 resultName = names.fromString(resultName + "" + target.syntheticNameChar());
2139 VarSymbol resultVar = new VarSymbol(FINAL|SYNTHETIC,
2140 resultName,
2141 arrayType,
2142 valuesSym);
2143 JCNewArray resultArray = make.NewArray(make.Type(types.erasure(tree.type)),
2144 List.of(make.Select(make.Ident(valuesVar), syms.lengthVar)),
2145 null);
2146 resultArray.type = arrayType;
2147 JCVariableDecl decl = make.VarDef(resultVar, resultArray);
2148
2149 // template: System.arraycopy($VALUES, 0, $result, 0, $VALUES.length);
2150 if (systemArraycopyMethod == null) {
2151 systemArraycopyMethod =
2152 new MethodSymbol(PUBLIC | STATIC,
2153 names.fromString("arraycopy"),
2154 new MethodType(List.<Type>of(syms.objectType,
2155 syms.intType,
2156 syms.objectType,
2157 syms.intType,
2158 syms.intType),
2159 syms.voidType,
2160 List.<Type>nil(),
2161 syms.methodClass),
2162 syms.systemType.tsym);
2163 }
2164 JCStatement copy =
2165 make.Exec(make.App(make.Select(make.Ident(syms.systemType.tsym),
2166 systemArraycopyMethod),
2167 List.of(make.Ident(valuesVar), make.Literal(0),
2168 make.Ident(resultVar), make.Literal(0),
2169 make.Select(make.Ident(valuesVar), syms.lengthVar))));
2170
2171 // template: return $result;
2172 JCStatement ret = make.Return(make.Ident(resultVar));
2173 valuesBody = List.<JCStatement>of(decl, copy, ret);
2174 }
2175
2176 JCMethodDecl valuesDef =
2177 make.MethodDef((MethodSymbol)valuesSym, make.Block(0, valuesBody));
2178
2179 enumDefs.append(valuesDef);
2180
2181 if (debugLower)
2182 System.err.println(tree.sym + ".valuesDef = " + valuesDef);
2183
2184 /** The template for the following code is:
2185 *
2186 * public static E valueOf(String name) {
2187 * return (E)Enum.valueOf(E.class, name);
2188 * }
2189 *
2190 * where E is tree.sym
2191 */
2192 MethodSymbol valueOfSym = lookupMethod(tree.pos(),
2193 names.valueOf,
2194 tree.sym.type,
2195 List.of(syms.stringType));
2196 assert (valueOfSym.flags() & STATIC) != 0;
2197 VarSymbol nameArgSym = valueOfSym.params.head;
2198 JCIdent nameVal = make.Ident(nameArgSym);
2199 JCStatement enum_ValueOf =
2200 make.Return(make.TypeCast(tree.sym.type,
2201 makeCall(make.Ident(syms.enumSym),
2202 names.valueOf,
2203 List.of(e_class, nameVal))));
2204 JCMethodDecl valueOf = make.MethodDef(valueOfSym,
2205 make.Block(0, List.of(enum_ValueOf)));
2206 nameVal.sym = valueOf.params.head.sym;
2207 if (debugLower)
2208 System.err.println(tree.sym + ".valueOf = " + valueOf);
2209 enumDefs.append(valueOf);
2210
2211 enumDefs.appendList(otherDefs.toList());
2212 tree.defs = enumDefs.toList();
2213
2214 // Add the necessary members for the EnumCompatibleMode
2215 if (target.compilerBootstrap(tree.sym)) {
2216 addEnumCompatibleMembers(tree);
2217 }
2218 }
2219 // where
2220 private MethodSymbol systemArraycopyMethod;
2221 private boolean useClone() {
2222 try {
2223 Scope.Entry e = syms.objectType.tsym.members().lookup(names.clone);
2224 return (e.sym != null);
2225 }
2226 catch (CompletionFailure e) {
2227 return false;
2228 }
2229 }
2230
2231 /** Translate an enumeration constant and its initializer. */
2232 private void visitEnumConstantDef(JCVariableDecl var, int ordinal) {
2233 JCNewClass varDef = (JCNewClass)var.init;
2234 varDef.args = varDef.args.
2235 prepend(makeLit(syms.intType, ordinal)).
2236 prepend(makeLit(syms.stringType, var.name.toString()));
2237 }
2238
2239 public void visitMethodDef(JCMethodDecl tree) {
2240 if (tree.name == names.init && (currentClass.flags_field&ENUM) != 0) {
2241 // Add "String $enum$name, int $enum$ordinal" to the beginning of the
2242 // argument list for each constructor of an enum.
2243 JCVariableDecl nameParam = make_at(tree.pos()).
2244 Param(names.fromString(target.syntheticNameChar() +
2245 "enum" + target.syntheticNameChar() + "name"),
2246 syms.stringType, tree.sym);
2247 nameParam.mods.flags |= SYNTHETIC; nameParam.sym.flags_field |= SYNTHETIC;
2248
2249 JCVariableDecl ordParam = make.
2250 Param(names.fromString(target.syntheticNameChar() +
2251 "enum" + target.syntheticNameChar() +
2252 "ordinal"),
2253 syms.intType, tree.sym);
2254 ordParam.mods.flags |= SYNTHETIC; ordParam.sym.flags_field |= SYNTHETIC;
2255
2256 tree.params = tree.params.prepend(ordParam).prepend(nameParam);
2257
2258 MethodSymbol m = tree.sym;
2259 Type olderasure = m.erasure(types);
2260 m.erasure_field = new MethodType(
2261 olderasure.getParameterTypes().prepend(syms.intType).prepend(syms.stringType),
2262 olderasure.getReturnType(),
2263 olderasure.getThrownTypes(),
2264 syms.methodClass);
2265
2266 if (target.compilerBootstrap(m.owner)) {
2267 // Initialize synthetic name field
2268 Symbol nameVarSym = lookupSynthetic(names.fromString("$name"),
2269 tree.sym.owner.members());
2270 JCIdent nameIdent = make.Ident(nameParam.sym);
2271 JCIdent id1 = make.Ident(nameVarSym);
2272 JCAssign newAssign = make.Assign(id1, nameIdent);
2273 newAssign.type = id1.type;
2274 JCExpressionStatement nameAssign = make.Exec(newAssign);
2275 nameAssign.type = id1.type;
2276 tree.body.stats = tree.body.stats.prepend(nameAssign);
2277
2278 // Initialize synthetic ordinal field
2279 Symbol ordinalVarSym = lookupSynthetic(names.fromString("$ordinal"),
2280 tree.sym.owner.members());
2281 JCIdent ordIdent = make.Ident(ordParam.sym);
2282 id1 = make.Ident(ordinalVarSym);
2283 newAssign = make.Assign(id1, ordIdent);
2284 newAssign.type = id1.type;
2285 JCExpressionStatement ordinalAssign = make.Exec(newAssign);
2286 ordinalAssign.type = id1.type;
2287 tree.body.stats = tree.body.stats.prepend(ordinalAssign);
2288 }
2289 }
2290
2291 JCMethodDecl prevMethodDef = currentMethodDef;
2292 MethodSymbol prevMethodSym = currentMethodSym;
2293 try {
2294 currentMethodDef = tree;
2295 currentMethodSym = tree.sym;
2296 visitMethodDefInternal(tree);
2297 } finally {
2298 currentMethodDef = prevMethodDef;
2299 currentMethodSym = prevMethodSym;
2300 }
2301 }
2302 //where
2303 private void visitMethodDefInternal(JCMethodDecl tree) {
2304 if (tree.name == names.init &&
2305 (currentClass.isInner() ||
2306 (currentClass.owner.kind & (VAR | MTH)) != 0)) {
2307 // We are seeing a constructor of an inner class.
2308 MethodSymbol m = tree.sym;
2309
2310 // Push a new proxy scope for constructor parameters.
2311 // and create definitions for any this$n and proxy parameters.
2312 proxies = proxies.dup(m);
2313 List<VarSymbol> prevOuterThisStack = outerThisStack;
2314 List<VarSymbol> fvs = freevars(currentClass);
2315 JCVariableDecl otdef = null;
2316 if (currentClass.hasOuterInstance())
2317 otdef = outerThisDef(tree.pos, m);
2318 List<JCVariableDecl> fvdefs = freevarDefs(tree.pos, fvs, m);
2319
2320 // Recursively translate result type, parameters and thrown list.
2321 tree.restype = translate(tree.restype);
2322 tree.params = translateVarDefs(tree.params);
2323 tree.thrown = translate(tree.thrown);
2324
2325 // when compiling stubs, don't process body
2326 if (tree.body == null) {
2327 result = tree;
2328 return;
2329 }
2330
2331 // Add this$n (if needed) in front of and free variables behind
2332 // constructor parameter list.
2333 tree.params = tree.params.appendList(fvdefs);
2334 if (currentClass.hasOuterInstance())
2335 tree.params = tree.params.prepend(otdef);
2336
2337 // If this is an initial constructor, i.e., it does not start with
2338 // this(...), insert initializers for this$n and proxies
2339 // before (pre-1.4, after) the call to superclass constructor.
2340 JCStatement selfCall = translate(tree.body.stats.head);
2341
2342 List<JCStatement> added = List.nil();
2343 if (fvs.nonEmpty()) {
2344 List<Type> addedargtypes = List.nil();
2345 for (List<VarSymbol> l = fvs; l.nonEmpty(); l = l.tail) {
2346 if (TreeInfo.isInitialConstructor(tree))
2347 added = added.prepend(
2348 initField(tree.body.pos, proxyName(l.head.name)));
2349 addedargtypes = addedargtypes.prepend(l.head.erasure(types));
2350 }
2351 Type olderasure = m.erasure(types);
2352 m.erasure_field = new MethodType(
2353 olderasure.getParameterTypes().appendList(addedargtypes),
2354 olderasure.getReturnType(),
2355 olderasure.getThrownTypes(),
2356 syms.methodClass);
2357 }
2358 if (currentClass.hasOuterInstance() &&
2359 TreeInfo.isInitialConstructor(tree))
2360 {
2361 added = added.prepend(initOuterThis(tree.body.pos));
2362 }
2363
2364 // pop local variables from proxy stack
2365 proxies = proxies.leave();
2366
2367 // recursively translate following local statements and
2368 // combine with this- or super-call
2369 List<JCStatement> stats = translate(tree.body.stats.tail);
2370 if (target.initializeFieldsBeforeSuper())
2371 tree.body.stats = stats.prepend(selfCall).prependList(added);
2372 else
2373 tree.body.stats = stats.prependList(added).prepend(selfCall);
2374
2375 outerThisStack = prevOuterThisStack;
2376 } else {
2377 super.visitMethodDef(tree);
2378 }
2379 result = tree;
2380 }
2381
2382 public void visitTypeCast(JCTypeCast tree) {
2383 tree.clazz = translate(tree.clazz);
2384 if (tree.type.isPrimitive() != tree.expr.type.isPrimitive())
2385 tree.expr = translate(tree.expr, tree.type);
2386 else
2387 tree.expr = translate(tree.expr);
2388 result = tree;
2389 }
2390
2391 public void visitNewClass(JCNewClass tree) {
2392 ClassSymbol c = (ClassSymbol)tree.constructor.owner;
2393
2394 // Box arguments, if necessary
2395 boolean isEnum = (tree.constructor.owner.flags() & ENUM) != 0;
2396 List<Type> argTypes = tree.constructor.type.getParameterTypes();
2397 if (isEnum) argTypes = argTypes.prepend(syms.intType).prepend(syms.stringType);
2398 tree.args = boxArgs(argTypes, tree.args, tree.varargsElement);
2399 tree.varargsElement = null;
2400
2401 // If created class is local, add free variables after
2402 // explicit constructor arguments.
2403 if ((c.owner.kind & (VAR | MTH)) != 0) {
2404 tree.args = tree.args.appendList(loadFreevars(tree.pos(), freevars(c)));
2405 }
2406
2407 // If an access constructor is used, append null as a last argument.
2408 Symbol constructor = accessConstructor(tree.pos(), tree.constructor);
2409 if (constructor != tree.constructor) {
2410 tree.args = tree.args.append(makeNull());
2411 tree.constructor = constructor;
2412 }
2413
2414 // If created class has an outer instance, and new is qualified, pass
2415 // qualifier as first argument. If new is not qualified, pass the
2416 // correct outer instance as first argument.
2417 if (c.hasOuterInstance()) {
2418 // System.out.println("\n\nlower newclass; tree="+tree);
2419 // System.out.println("\ttree.encl="+tree.encl+
2420 // " c.owner.kind MTH? "+((c.owner.kind & MTH)!=0)+
2421 // " c.owner.kind VAR? "+((c.owner.kind & VAR)!=0)+
2422 // " c.type="+c.type+" c.type.getEnclosingType="+c.type.getEnclosingType());
2423 JCExpression thisArg;
2424 if (tree.encl != null) {
2425 // System.out.println("\tmakeNullCheck");
2426 thisArg = attr.makeNullCheck(translate(tree.encl));
2427 thisArg.type = tree.encl.type;
2428 } else if ((c.owner.kind & (MTH | VAR)) != 0) {
2429 // local class
2430 // System.out.println("\tlocal class, makeThis");
2431 thisArg = makeThis(tree.pos(), c.type.getEnclosingType().tsym);
2432 } else {
2433 // nested class
2434 // System.out.println("\tnested class, makeOwnerThis");
2435 thisArg = makeOwnerThis(tree.pos(), c, false);
2436 }
2437 tree.args = tree.args.prepend(thisArg);
2438 }
2439 tree.encl = null;
2440
2441 // If we have an anonymous class, create its flat version, rather
2442 // than the class or interface following new.
2443 if (tree.def != null) {
2444 translate(tree.def);
2445 tree.clazz = access(make_at(tree.clazz.pos()).Ident(tree.def.sym));
2446 tree.def = null;
2447 } else {
2448 tree.clazz = access(c, tree.clazz, enclOp, false);
2449 }
2450 result = tree;
2451 }
2452
2453 // Simplify conditionals with known constant controlling expressions.
2454 // This allows us to avoid generating supporting declarations for
2455 // the dead code, which will not be eliminated during code generation.
2456 // Note that Flow.isFalse and Flow.isTrue only return true
2457 // for constant expressions in the sense of JLS 15.27, which
2458 // are guaranteed to have no side-effects. More agressive
2459 // constant propagation would require that we take care to
2460 // preserve possible side-effects in the condition expression.
2461
2462 /** Visitor method for conditional expressions.
2463 */
2464 public void visitConditional(JCConditional tree) {
2465 JCTree cond = tree.cond = translate(tree.cond, syms.booleanType);
2466 if (cond.type.isTrue()) {
2467 result = convert(translate(tree.truepart, tree.type), tree.type);
2468 } else if (cond.type.isFalse()) {
2469 result = convert(translate(tree.falsepart, tree.type), tree.type);
2470 } else {
2471 // Condition is not a compile-time constant.
2472 tree.truepart = translate(tree.truepart, tree.type);
2473 tree.falsepart = translate(tree.falsepart, tree.type);
2474 result = tree;
2475 }
2476 }
2477 //where
2478 private JCTree convert(JCTree tree, Type pt) {
2479 if (tree.type == pt) return tree;
2480 JCTree result = make_at(tree.pos()).TypeCast(make.Type(pt), (JCExpression)tree);
2481 result.type = (tree.type.constValue() != null) ? cfolder.coerce(tree.type, pt)
2482 : pt;
2483 return result;
2484 }
2485
2486 /** Visitor method for if statements.
2487 */
2488 public void visitIf(JCIf tree) {
2489 JCTree cond = tree.cond = translate(tree.cond, syms.booleanType);
2490 if (cond.type.isTrue()) {
2491 result = translate(tree.thenpart);
2492 } else if (cond.type.isFalse()) {
2493 if (tree.elsepart != null) {
2494 result = translate(tree.elsepart);
2495 } else {
2496 result = make.Skip();
2497 }
2498 } else {
2499 // Condition is not a compile-time constant.
2500 tree.thenpart = translate(tree.thenpart);
2501 tree.elsepart = translate(tree.elsepart);
2502 result = tree;
2503 }
2504 }
2505
2506 /** Visitor method for assert statements. Translate them away.
2507 */
2508 public void visitAssert(JCAssert tree) {
2509 DiagnosticPosition detailPos = (tree.detail == null) ? tree.pos() : tree.detail.pos();
2510 tree.cond = translate(tree.cond, syms.booleanType);
2511 if (!tree.cond.type.isTrue()) {
2512 JCExpression cond = assertFlagTest(tree.pos());
2513 List<JCExpression> exnArgs = (tree.detail == null) ?
2514 List.<JCExpression>nil() : List.of(translate(tree.detail));
2515 if (!tree.cond.type.isFalse()) {
2516 cond = makeBinary
2517 (JCTree.AND,
2518 cond,
2519 makeUnary(JCTree.NOT, tree.cond));
2520 }
2521 result =
2522 make.If(cond,
2523 make_at(detailPos).
2524 Throw(makeNewClass(syms.assertionErrorType, exnArgs)),
2525 null);
2526 } else {
2527 result = make.Skip();
2528 }
2529 }
2530
2531 public void visitApply(JCMethodInvocation tree) {
2532 Symbol meth = TreeInfo.symbol(tree.meth);
2533 List<Type> argtypes = meth.type.getParameterTypes();
2534 if (allowEnums &&
2535 meth.name==names.init &&
2536 meth.owner == syms.enumSym)
2537 argtypes = argtypes.tail.tail;
2538 tree.args = boxArgs(argtypes, tree.args, tree.varargsElement);
2539 tree.varargsElement = null;
2540 Name methName = TreeInfo.name(tree.meth);
2541 if (meth.name==names.init) {
2542 // We are seeing a this(...) or super(...) constructor call.
2543 // If an access constructor is used, append null as a last argument.
2544 Symbol constructor = accessConstructor(tree.pos(), meth);
2545 if (constructor != meth) {
2546 tree.args = tree.args.append(makeNull());
2547 TreeInfo.setSymbol(tree.meth, constructor);
2548 }
2549
2550 // If we are calling a constructor of a local class, add
2551 // free variables after explicit constructor arguments.
2552 ClassSymbol c = (ClassSymbol)constructor.owner;
2553 if ((c.owner.kind & (VAR | MTH)) != 0) {
2554 tree.args = tree.args.appendList(loadFreevars(tree.pos(), freevars(c)));
2555 }
2556
2557 // If we are calling a constructor of an enum class, pass
2558 // along the name and ordinal arguments
2559 if ((c.flags_field&ENUM) != 0 || c.getQualifiedName() == names.java_lang_Enum) {
2560 List<JCVariableDecl> params = currentMethodDef.params;
2561 if (currentMethodSym.owner.hasOuterInstance())
2562 params = params.tail; // drop this$n
2563 tree.args = tree.args
2564 .prepend(make_at(tree.pos()).Ident(params.tail.head.sym)) // ordinal
2565 .prepend(make.Ident(params.head.sym)); // name
2566 }
2567
2568 // If we are calling a constructor of a class with an outer
2569 // instance, and the call
2570 // is qualified, pass qualifier as first argument in front of
2571 // the explicit constructor arguments. If the call
2572 // is not qualified, pass the correct outer instance as
2573 // first argument.
2574 if (c.hasOuterInstance()) {
2575 JCExpression thisArg;
2576 if (tree.meth.getTag() == JCTree.SELECT) {
2577 thisArg = attr.
2578 makeNullCheck(translate(((JCFieldAccess) tree.meth).selected));
2579 tree.meth = make.Ident(constructor);
2580 ((JCIdent) tree.meth).name = methName;
2581 } else if ((c.owner.kind & (MTH | VAR)) != 0 || methName == names._this){
2582 // local class or this() call
2583 thisArg = makeThis(tree.meth.pos(), c.type.getEnclosingType().tsym);
2584 } else {
2585 // super() call of nested class
2586 thisArg = makeOwnerThis(tree.meth.pos(), c, false);
2587 }
2588 tree.args = tree.args.prepend(thisArg);
2589 }
2590 } else {
2591 // We are seeing a normal method invocation; translate this as usual.
2592 tree.meth = translate(tree.meth);
2593
2594 // If the translated method itself is an Apply tree, we are
2595 // seeing an access method invocation. In this case, append
2596 // the method arguments to the arguments of the access method.
2597 if (tree.meth.getTag() == JCTree.APPLY) {
2598 JCMethodInvocation app = (JCMethodInvocation)tree.meth;
2599 app.args = tree.args.prependList(app.args);
2600 result = app;
2601 return;
2602 }
2603 }
2604 result = tree;
2605 }
2606
2607 List<JCExpression> boxArgs(List<Type> parameters, List<JCExpression> _args, Type varargsElement) {
2608 List<JCExpression> args = _args;
2609 if (parameters.isEmpty()) return args;
2610 boolean anyChanges = false;
2611 ListBuffer<JCExpression> result = new ListBuffer<JCExpression>();
2612 while (parameters.tail.nonEmpty()) {
2613 JCExpression arg = translate(args.head, parameters.head);
2614 anyChanges |= (arg != args.head);
2615 result.append(arg);
2616 args = args.tail;
2617 parameters = parameters.tail;
2618 }
2619 Type parameter = parameters.head;
2620 if (varargsElement != null) {
2621 anyChanges = true;
2622 ListBuffer<JCExpression> elems = new ListBuffer<JCExpression>();
2623 while (args.nonEmpty()) {
2624 JCExpression arg = translate(args.head, varargsElement);
2625 elems.append(arg);
2626 args = args.tail;
2627 }
2628 JCNewArray boxedArgs = make.NewArray(make.Type(varargsElement),
2629 List.<JCExpression>nil(),
2630 elems.toList());
2631 boxedArgs.type = new ArrayType(varargsElement, syms.arrayClass);
2632 result.append(boxedArgs);
2633 } else {
2634 if (args.length() != 1) throw new AssertionError(args);
2635 JCExpression arg = translate(args.head, parameter);
2636 anyChanges |= (arg != args.head);
2637 result.append(arg);
2638 if (!anyChanges) return _args;
2639 }
2640 return result.toList();
2641 }
2642
2643 /** Expand a boxing or unboxing conversion if needed. */
2644 @SuppressWarnings("unchecked") // XXX unchecked
2645 <T extends JCTree> T boxIfNeeded(T tree, Type type) {
2646 boolean havePrimitive = tree.type.isPrimitive();
2647 if (havePrimitive == type.isPrimitive())
2648 return tree;
2649 if (havePrimitive) {
2650 Type unboxedTarget = types.unboxedType(type);
2651 if (unboxedTarget.tag != NONE) {
2652 if (!types.isSubtype(tree.type, unboxedTarget))
2653 tree.type = unboxedTarget; // e.g. Character c = 89;
2654 return (T)boxPrimitive((JCExpression)tree, type);
2655 } else {
2656 tree = (T)boxPrimitive((JCExpression)tree);
2657 }
2658 } else {
2659 tree = (T)unbox((JCExpression)tree, type);
2660 }
2661 return tree;
2662 }
2663
2664 /** Box up a single primitive expression. */
2665 JCExpression boxPrimitive(JCExpression tree) {
2666 return boxPrimitive(tree, types.boxedClass(tree.type).type);
2667 }
2668
2669 /** Box up a single primitive expression. */
2670 JCExpression boxPrimitive(JCExpression tree, Type box) {
2671 make_at(tree.pos());
2672 if (target.boxWithConstructors()) {
2673 Symbol ctor = lookupConstructor(tree.pos(),
2674 box,
2675 List.<Type>nil()
2676 .prepend(tree.type));
2677 return make.Create(ctor, List.of(tree));
2678 } else {
2679 Symbol valueOfSym = lookupMethod(tree.pos(),
2680 names.valueOf,
2681 box,
2682 List.<Type>nil()
2683 .prepend(tree.type));
2684 return make.App(make.QualIdent(valueOfSym), List.of(tree));
2685 }
2686 }
2687
2688 /** Unbox an object to a primitive value. */
2689 JCExpression unbox(JCExpression tree, Type primitive) {
2690 Type unboxedType = types.unboxedType(tree.type);
2691 // note: the "primitive" parameter is not used. There muse be
2692 // a conversion from unboxedType to primitive.
2693 make_at(tree.pos());
2694 Symbol valueSym = lookupMethod(tree.pos(),
2695 unboxedType.tsym.name.append(names.Value), // x.intValue()
2696 tree.type,
2697 List.<Type>nil());
2698 return make.App(make.Select(tree, valueSym));
2699 }
2700
2701 /** Visitor method for parenthesized expressions.
2702 * If the subexpression has changed, omit the parens.
2703 */
2704 public void visitParens(JCParens tree) {
2705 JCTree expr = translate(tree.expr);
2706 result = ((expr == tree.expr) ? tree : expr);
2707 }
2708
2709 public void visitIndexed(JCArrayAccess tree) {
2710 tree.indexed = translate(tree.indexed);
2711 tree.index = translate(tree.index, syms.intType);
2712 result = tree;
2713 }
2714
2715 public void visitAssign(JCAssign tree) {
2716 tree.lhs = translate(tree.lhs, tree);
2717 tree.rhs = translate(tree.rhs, tree.lhs.type);
2718
2719 // If translated left hand side is an Apply, we are
2720 // seeing an access method invocation. In this case, append
2721 // right hand side as last argument of the access method.
2722 if (tree.lhs.getTag() == JCTree.APPLY) {
2723 JCMethodInvocation app = (JCMethodInvocation)tree.lhs;
2724 app.args = List.of(tree.rhs).prependList(app.args);
2725 result = app;
2726 } else {
2727 result = tree;
2728 }
2729 }
2730
2731 public void visitAssignop(final JCAssignOp tree) {
2732 if (!tree.lhs.type.isPrimitive() &&
2733 tree.operator.type.getReturnType().isPrimitive()) {
2734 // boxing required; need to rewrite as x = (unbox typeof x)(x op y);
2735 // or if x == (typeof x)z then z = (unbox typeof x)((typeof x)z op y)
2736 // (but without recomputing x)
2737 JCTree newTree = abstractLval(tree.lhs, new TreeBuilder() {
2738 public JCTree build(final JCTree lhs) {
2739 int newTag = tree.getTag() - JCTree.ASGOffset;
2740 // Erasure (TransTypes) can change the type of
2741 // tree.lhs. However, we can still get the
2742 // unerased type of tree.lhs as it is stored
2743 // in tree.type in Attr.
2744 Symbol newOperator = rs.resolveBinaryOperator(tree.pos(),
2745 newTag,
2746 attrEnv,
2747 tree.type,
2748 tree.rhs.type);
2749 JCExpression expr = (JCExpression)lhs;
2750 if (expr.type != tree.type)
2751 expr = make.TypeCast(tree.type, expr);
2752 JCBinary opResult = make.Binary(newTag, expr, tree.rhs);
2753 opResult.operator = newOperator;
2754 opResult.type = newOperator.type.getReturnType();
2755 JCTypeCast newRhs = make.TypeCast(types.unboxedType(tree.type),
2756 opResult);
2757 return make.Assign((JCExpression)lhs, newRhs).setType(tree.type);
2758 }
2759 });
2760 result = translate(newTree);
2761 return;
2762 }
2763 tree.lhs = translate(tree.lhs, tree);
2764 tree.rhs = translate(tree.rhs, tree.operator.type.getParameterTypes().tail.head);
2765
2766 // If translated left hand side is an Apply, we are
2767 // seeing an access method invocation. In this case, append
2768 // right hand side as last argument of the access method.
2769 if (tree.lhs.getTag() == JCTree.APPLY) {
2770 JCMethodInvocation app = (JCMethodInvocation)tree.lhs;
2771 // if operation is a += on strings,
2772 // make sure to convert argument to string
2773 JCExpression rhs = (((OperatorSymbol)tree.operator).opcode == string_add)
2774 ? makeString(tree.rhs)
2775 : tree.rhs;
2776 app.args = List.of(rhs).prependList(app.args);
2777 result = app;
2778 } else {
2779 result = tree;
2780 }
2781 }
2782
2783 /** Lower a tree of the form e++ or e-- where e is an object type */
2784 JCTree lowerBoxedPostop(final JCUnary tree) {
2785 // translate to tmp1=lval(e); tmp2=tmp1; tmp1 OP 1; tmp2
2786 // or
2787 // translate to tmp1=lval(e); tmp2=tmp1; (typeof tree)tmp1 OP 1; tmp2
2788 // where OP is += or -=
2789 final boolean cast = TreeInfo.skipParens(tree.arg).getTag() == JCTree.TYPECAST;
2790 return abstractLval(tree.arg, new TreeBuilder() {
2791 public JCTree build(final JCTree tmp1) {
2792 return abstractRval(tmp1, tree.arg.type, new TreeBuilder() {
2793 public JCTree build(final JCTree tmp2) {
2794 int opcode = (tree.getTag() == JCTree.POSTINC)
2795 ? JCTree.PLUS_ASG : JCTree.MINUS_ASG;
2796 JCTree lhs = cast
2797 ? make.TypeCast(tree.arg.type, (JCExpression)tmp1)
2798 : tmp1;
2799 JCTree update = makeAssignop(opcode,
2800 lhs,
2801 make.Literal(1));
2802 return makeComma(update, tmp2);
2803 }
2804 });
2805 }
2806 });
2807 }
2808
2809 public void visitUnary(JCUnary tree) {
2810 boolean isUpdateOperator =
2811 JCTree.PREINC <= tree.getTag() && tree.getTag() <= JCTree.POSTDEC;
2812 if (isUpdateOperator && !tree.arg.type.isPrimitive()) {
2813 switch(tree.getTag()) {
2814 case JCTree.PREINC: // ++ e
2815 // translate to e += 1
2816 case JCTree.PREDEC: // -- e
2817 // translate to e -= 1
2818 {
2819 int opcode = (tree.getTag() == JCTree.PREINC)
2820 ? JCTree.PLUS_ASG : JCTree.MINUS_ASG;
2821 JCAssignOp newTree = makeAssignop(opcode,
2822 tree.arg,
2823 make.Literal(1));
2824 result = translate(newTree, tree.type);
2825 return;
2826 }
2827 case JCTree.POSTINC: // e ++
2828 case JCTree.POSTDEC: // e --
2829 {
2830 result = translate(lowerBoxedPostop(tree), tree.type);
2831 return;
2832 }
2833 }
2834 throw new AssertionError(tree);
2835 }
2836
2837 tree.arg = boxIfNeeded(translate(tree.arg, tree), tree.type);
2838
2839 if (tree.getTag() == JCTree.NOT && tree.arg.type.constValue() != null) {
2840 tree.type = cfolder.fold1(bool_not, tree.arg.type);
2841 }
2842
2843 // If translated left hand side is an Apply, we are
2844 // seeing an access method invocation. In this case, return
2845 // that access method invokation as result.
2846 if (isUpdateOperator && tree.arg.getTag() == JCTree.APPLY) {
2847 result = tree.arg;
2848 } else {
2849 result = tree;
2850 }
2851 }
2852
2853 public void visitBinary(JCBinary tree) {
2854 List<Type> formals = tree.operator.type.getParameterTypes();
2855 JCTree lhs = tree.lhs = translate(tree.lhs, formals.head);
2856 switch (tree.getTag()) {
2857 case JCTree.OR:
2858 if (lhs.type.isTrue()) {
2859 result = lhs;
2860 return;
2861 }
2862 if (lhs.type.isFalse()) {
2863 result = translate(tree.rhs, formals.tail.head);
2864 return;
2865 }
2866 break;
2867 case JCTree.AND:
2868 if (lhs.type.isFalse()) {
2869 result = lhs;
2870 return;
2871 }
2872 if (lhs.type.isTrue()) {
2873 result = translate(tree.rhs, formals.tail.head);
2874 return;
2875 }
2876 break;
2877 }
2878 tree.rhs = translate(tree.rhs, formals.tail.head);
2879 result = tree;
2880 }
2881
2882 public void visitIdent(JCIdent tree) {
2883 result = access(tree.sym, tree, enclOp, false);
2884 }
2885
2886 /** Translate away the foreach loop. */
2887 public void visitForeachLoop(JCEnhancedForLoop tree) {
2888 if (types.elemtype(tree.expr.type) == null)
2889 visitIterableForeachLoop(tree);
2890 else
2891 visitArrayForeachLoop(tree);
2892 }
2893 // where
2894 /**
2895 * A statment of the form
2896 *
2897 * <pre>
2898 * for ( T v : arrayexpr ) stmt;
2899 * </pre>
2900 *
2901 * (where arrayexpr is of an array type) gets translated to
2902 *
2903 * <pre>
2904 * for ( { arraytype #arr = arrayexpr;
2905 * int #len = array.length;
2906 * int #i = 0; };
2907 * #i < #len; i$++ ) {
2908 * T v = arr$[#i];
2909 * stmt;
2910 * }
2911 * </pre>
2912 *
2913 * where #arr, #len, and #i are freshly named synthetic local variables.
2914 */
2915 private void visitArrayForeachLoop(JCEnhancedForLoop tree) {
2916 make_at(tree.expr.pos());
2917 VarSymbol arraycache = new VarSymbol(0,
2918 names.fromString("arr" + target.syntheticNameChar()),
2919 tree.expr.type,
2920 currentMethodSym);
2921 JCStatement arraycachedef = make.VarDef(arraycache, tree.expr);
2922 VarSymbol lencache = new VarSymbol(0,
2923 names.fromString("len" + target.syntheticNameChar()),
2924 syms.intType,
2925 currentMethodSym);
2926 JCStatement lencachedef = make.
2927 VarDef(lencache, make.Select(make.Ident(arraycache), syms.lengthVar));
2928 VarSymbol index = new VarSymbol(0,
2929 names.fromString("i" + target.syntheticNameChar()),
2930 syms.intType,
2931 currentMethodSym);
2932
2933 JCVariableDecl indexdef = make.VarDef(index, make.Literal(INT, 0));
2934 indexdef.init.type = indexdef.type = syms.intType.constType(0);
2935
2936 List<JCStatement> loopinit = List.of(arraycachedef, lencachedef, indexdef);
2937 JCBinary cond = makeBinary(JCTree.LT, make.Ident(index), make.Ident(lencache));
2938
2939 JCExpressionStatement step = make.Exec(makeUnary(JCTree.PREINC, make.Ident(index)));
2940
2941 Type elemtype = types.elemtype(tree.expr.type);
2942 JCExpression loopvarinit = make.Indexed(make.Ident(arraycache),
2943 make.Ident(index)).setType(elemtype);
2944 JCVariableDecl loopvardef = (JCVariableDecl)make.VarDef(tree.var.mods,
2945 tree.var.name,
2946 tree.var.vartype,
2947 loopvarinit).setType(tree.var.type);
2948 loopvardef.sym = tree.var.sym;
2949 JCBlock body = make.
2950 Block(0, List.of(loopvardef, tree.body));
2951
2952 result = translate(make.
2953 ForLoop(loopinit,
2954 cond,
2955 List.of(step),
2956 body));
2957 patchTargets(body, tree, result);
2958 }
2959 /** Patch up break and continue targets. */
2960 private void patchTargets(JCTree body, final JCTree src, final JCTree dest) {
2961 class Patcher extends TreeScanner {
2962 public void visitBreak(JCBreak tree) {
2963 if (tree.target == src)
2964 tree.target = dest;
2965 }
2966 public void visitContinue(JCContinue tree) {
2967 if (tree.target == src)
2968 tree.target = dest;
2969 }
2970 public void visitClassDef(JCClassDecl tree) {}
2971 }
2972 new Patcher().scan(body);
2973 }
2974 /**
2975 * A statement of the form
2976 *
2977 * <pre>
2978 * for ( T v : coll ) stmt ;
2979 * </pre>
2980 *
2981 * (where coll implements Iterable<? extends T>) gets translated to
2982 *
2983 * <pre>
2984 * for ( Iterator<? extends T> #i = coll.iterator(); #i.hasNext(); ) {
2985 * T v = (T) #i.next();
2986 * stmt;
2987 * }
2988 * </pre>
2989 *
2990 * where #i is a freshly named synthetic local variable.
2991 */
2992 private void visitIterableForeachLoop(JCEnhancedForLoop tree) {
2993 make_at(tree.expr.pos());
2994 Type iteratorTarget = syms.objectType;
2995 Type iterableType = types.asSuper(types.upperBound(tree.expr.type),
2996 syms.iterableType.tsym);
2997 if (iterableType.getTypeArguments().nonEmpty())
2998 iteratorTarget = types.erasure(iterableType.getTypeArguments().head);
2999 Type eType = tree.expr.type;
3000 tree.expr.type = types.erasure(eType);
3001 if (eType.tag == TYPEVAR && eType.getUpperBound().isCompound())
3002 tree.expr = make.TypeCast(types.erasure(iterableType), tree.expr);
3003 Symbol iterator = lookupMethod(tree.expr.pos(),
3004 names.iterator,
3005 types.erasure(syms.iterableType),
3006 List.<Type>nil());
3007 VarSymbol itvar = new VarSymbol(0, names.fromString("i" + target.syntheticNameChar()),
3008 types.erasure(iterator.type.getReturnType()),
3009 currentMethodSym);
3010 JCStatement init = make.
3011 VarDef(itvar,
3012 make.App(make.Select(tree.expr, iterator)));
3013 Symbol hasNext = lookupMethod(tree.expr.pos(),
3014 names.hasNext,
3015 itvar.type,
3016 List.<Type>nil());
3017 JCMethodInvocation cond = make.App(make.Select(make.Ident(itvar), hasNext));
3018 Symbol next = lookupMethod(tree.expr.pos(),
3019 names.next,
3020 itvar.type,
3021 List.<Type>nil());
3022 JCExpression vardefinit = make.App(make.Select(make.Ident(itvar), next));
3023 if (tree.var.type.isPrimitive())
3024 vardefinit = make.TypeCast(types.upperBound(iteratorTarget), vardefinit);
3025 else
3026 vardefinit = make.TypeCast(tree.var.type, vardefinit);
3027 JCVariableDecl indexDef = (JCVariableDecl)make.VarDef(tree.var.mods,
3028 tree.var.name,
3029 tree.var.vartype,
3030 vardefinit).setType(tree.var.type);
3031 indexDef.sym = tree.var.sym;
3032 JCBlock body = make.Block(0, List.of(indexDef, tree.body));
3033 result = translate(make.
3034 ForLoop(List.of(init),
3035 cond,
3036 List.<JCExpressionStatement>nil(),
3037 body));
3038 patchTargets(body, tree, result);
3039 }
3040
3041 public void visitVarDef(JCVariableDecl tree) {
3042 MethodSymbol oldMethodSym = currentMethodSym;
3043 tree.mods = translate(tree.mods);
3044 tree.vartype = translate(tree.vartype);
3045 if (currentMethodSym == null) {
3046 // A class or instance field initializer.
3047 currentMethodSym =
3048 new MethodSymbol((tree.mods.flags&STATIC) | BLOCK,
3049 names.empty, null,
3050 currentClass);
3051 }
3052 if (tree.init != null) tree.init = translate(tree.init, tree.type);
3053 result = tree;
3054 currentMethodSym = oldMethodSym;
3055 }
3056
3057 public void visitBlock(JCBlock tree) {
3058 MethodSymbol oldMethodSym = currentMethodSym;
3059 if (currentMethodSym == null) {
3060 // Block is a static or instance initializer.
3061 currentMethodSym =
3062 new MethodSymbol(tree.flags | BLOCK,
3063 names.empty, null,
3064 currentClass);
3065 }
3066 super.visitBlock(tree);
3067 currentMethodSym = oldMethodSym;
3068 }
3069
3070 public void visitDoLoop(JCDoWhileLoop tree) {
3071 tree.body = translate(tree.body);
3072 tree.cond = translate(tree.cond, syms.booleanType);
3073 result = tree;
3074 }
3075
3076 public void visitWhileLoop(JCWhileLoop tree) {
3077 tree.cond = translate(tree.cond, syms.booleanType);
3078 tree.body = translate(tree.body);
3079 result = tree;
3080 }
3081
3082 public void visitForLoop(JCForLoop tree) {
3083 tree.init = translate(tree.init);
3084 if (tree.cond != null)
3085 tree.cond = translate(tree.cond, syms.booleanType);
3086 tree.step = translate(tree.step);
3087 tree.body = translate(tree.body);
3088 result = tree;
3089 }
3090
3091 public void visitReturn(JCReturn tree) {
3092 if (tree.expr != null)
3093 tree.expr = translate(tree.expr,
3094 types.erasure(currentMethodDef
3095 .restype.type));
3096 result = tree;
3097 }
3098
3099 public void visitSwitch(JCSwitch tree) {
3100 Type selsuper = types.supertype(tree.selector.type);
3101 boolean enumSwitch = selsuper != null &&
3102 (tree.selector.type.tsym.flags() & ENUM) != 0;
3103 Type target = enumSwitch ? tree.selector.type : syms.intType;
3104 tree.selector = translate(tree.selector, target);
3105 tree.cases = translateCases(tree.cases);
3106 if (enumSwitch) {
3107 result = visitEnumSwitch(tree);
3108 patchTargets(result, tree, result);
3109 } else {
3110 result = tree;
3111 }
3112 }
3113
3114 public JCTree visitEnumSwitch(JCSwitch tree) {
3115 TypeSymbol enumSym = tree.selector.type.tsym;
3116 EnumMapping map = mapForEnum(tree.pos(), enumSym);
3117 make_at(tree.pos());
3118 Symbol ordinalMethod = lookupMethod(tree.pos(),
3119 names.ordinal,
3120 tree.selector.type,
3121 List.<Type>nil());
3122 JCArrayAccess selector = make.Indexed(map.mapVar,
3123 make.App(make.Select(tree.selector,
3124 ordinalMethod)));
3125 ListBuffer<JCCase> cases = new ListBuffer<JCCase>();
3126 for (JCCase c : tree.cases) {
3127 if (c.pat != null) {
3128 VarSymbol label = (VarSymbol)TreeInfo.symbol(c.pat);
3129 JCLiteral pat = map.forConstant(label);
3130 cases.append(make.Case(pat, c.stats));
3131 } else {
3132 cases.append(c);
3133 }
3134 }
3135 return make.Switch(selector, cases.toList());
3136 }
3137
3138 public void visitNewArray(JCNewArray tree) {
3139 tree.elemtype = translate(tree.elemtype);
3140 for (List<JCExpression> t = tree.dims; t.tail != null; t = t.tail)
3141 if (t.head != null) t.head = translate(t.head, syms.intType);
3142 tree.elems = translate(tree.elems, types.elemtype(tree.type));
3143 result = tree;
3144 }
3145
3146 public void visitSelect(JCFieldAccess tree) {
3147 // need to special case-access of the form C.super.x
3148 // these will always need an access method.
3149 boolean qualifiedSuperAccess =
3150 tree.selected.getTag() == JCTree.SELECT &&
3151 TreeInfo.name(tree.selected) == names._super;
3152 tree.selected = translate(tree.selected);
3153 if (tree.name == names._class)
3154 result = classOf(tree.selected);
3155 else if (tree.name == names._this || tree.name == names._super)
3156 result = makeThis(tree.pos(), tree.selected.type.tsym);
3157 else
3158 result = access(tree.sym, tree, enclOp, qualifiedSuperAccess);
3159 }
3160
3161 public void visitLetExpr(LetExpr tree) {
3162 tree.defs = translateVarDefs(tree.defs);
3163 tree.expr = translate(tree.expr, tree.type);
3164 result = tree;
3165 }
3166
3167 // There ought to be nothing to rewrite here;
3168 // we don't generate code.
3169 public void visitAnnotation(JCAnnotation tree) {
3170 result = tree;
3171 }
3172
3173 /**************************************************************************
3174 * main method
3175 *************************************************************************/
3176
3177 /** Translate a toplevel class and return a list consisting of
3178 * the translated class and translated versions of all inner classes.
3179 * @param env The attribution environment current at the class definition.
3180 * We need this for resolving some additional symbols.
3181 * @param cdef The tree representing the class definition.
3182 */
3183 public List<JCTree> translateTopLevelClass(Env<AttrContext> env, JCTree cdef, TreeMaker make) {
3184 ListBuffer<JCTree> translated = null;
3185 try {
3186 attrEnv = env;
3187 this.make = make;
3188 endPositions = env.toplevel.endPositions;
3189 currentClass = null;
3190 currentMethodDef = null;
3191 outermostClassDef = (cdef.getTag() == JCTree.CLASSDEF) ? (JCClassDecl)cdef : null;
3192 outermostMemberDef = null;
3193 this.translated = new ListBuffer<JCTree>();
3194 classdefs = new HashMap<ClassSymbol,JCClassDecl>();
3195 actualSymbols = new HashMap<Symbol,Symbol>();
3196 freevarCache = new HashMap<ClassSymbol,List<VarSymbol>>();
3197 proxies = new Scope(syms.noSymbol);
3198 outerThisStack = List.nil();
3199 accessNums = new HashMap<Symbol,Integer>();
3200 accessSyms = new HashMap<Symbol,MethodSymbol[]>();
3201 accessConstrs = new HashMap<Symbol,MethodSymbol>();
3202 accessed = new ListBuffer<Symbol>();
3203 translate(cdef, (JCExpression)null);
3204 for (List<Symbol> l = accessed.toList(); l.nonEmpty(); l = l.tail)
3205 makeAccessible(l.head);
3206 for (EnumMapping map : enumSwitchMap.values())
3207 map.translate();
3208 translated = this.translated;
3209 } finally {
3210 // note that recursive invocations of this method fail hard
3211 attrEnv = null;
3212 this.make = null;
3213 endPositions = null;
3214 currentClass = null;
3215 currentMethodDef = null;
3216 outermostClassDef = null;
3217 outermostMemberDef = null;
3218 this.translated = null;
3219 classdefs = null;
3220 actualSymbols = null;
3221 freevarCache = null;
3222 proxies = null;
3223 outerThisStack = null;
3224 accessNums = null;
3225 accessSyms = null;
3226 accessConstrs = null;
3227 accessed = null;
3228 enumSwitchMap.clear();
3229 }
3230 return translated.toList();
3231 }
3232
3233 //////////////////////////////////////////////////////////////
3234 // The following contributed by Borland for bootstrapping purposes
3235 //////////////////////////////////////////////////////////////
3236 private void addEnumCompatibleMembers(JCClassDecl cdef) {
3237 make_at(null);
3238
3239 // Add the special enum fields
3240 VarSymbol ordinalFieldSym = addEnumOrdinalField(cdef);
3241 VarSymbol nameFieldSym = addEnumNameField(cdef);
3242
3243 // Add the accessor methods for name and ordinal
3244 MethodSymbol ordinalMethodSym = addEnumFieldOrdinalMethod(cdef, ordinalFieldSym);
3245 MethodSymbol nameMethodSym = addEnumFieldNameMethod(cdef, nameFieldSym);
3246
3247 // Add the toString method
3248 addEnumToString(cdef, nameFieldSym);
3249
3250 // Add the compareTo method
3251 addEnumCompareTo(cdef, ordinalFieldSym);
3252 }
3253
3254 private VarSymbol addEnumOrdinalField(JCClassDecl cdef) {
3255 VarSymbol ordinal = new VarSymbol(PRIVATE|FINAL|SYNTHETIC,
3256 names.fromString("$ordinal"),
3257 syms.intType,
3258 cdef.sym);
3259 cdef.sym.members().enter(ordinal);
3260 cdef.defs = cdef.defs.prepend(make.VarDef(ordinal, null));
3261 return ordinal;
3262 }
3263
3264 private VarSymbol addEnumNameField(JCClassDecl cdef) {
3265 VarSymbol name = new VarSymbol(PRIVATE|FINAL|SYNTHETIC,
3266 names.fromString("$name"),
3267 syms.stringType,
3268 cdef.sym);
3269 cdef.sym.members().enter(name);
3270 cdef.defs = cdef.defs.prepend(make.VarDef(name, null));
3271 return name;
3272 }
3273
3274 private MethodSymbol addEnumFieldOrdinalMethod(JCClassDecl cdef, VarSymbol ordinalSymbol) {
3275 // Add the accessor methods for ordinal
3276 Symbol ordinalSym = lookupMethod(cdef.pos(),
3277 names.ordinal,
3278 cdef.type,
3279 List.<Type>nil());
3280
3281 assert(ordinalSym != null);
3282 assert(ordinalSym instanceof MethodSymbol);
3283
3284 JCStatement ret = make.Return(make.Ident(ordinalSymbol));
3285 cdef.defs = cdef.defs.append(make.MethodDef((MethodSymbol)ordinalSym,
3286 make.Block(0L, List.of(ret))));
3287
3288 return (MethodSymbol)ordinalSym;
3289 }
3290
3291 private MethodSymbol addEnumFieldNameMethod(JCClassDecl cdef, VarSymbol nameSymbol) {
3292 // Add the accessor methods for name
3293 Symbol nameSym = lookupMethod(cdef.pos(),
3294 names._name,
3295 cdef.type,
3296 List.<Type>nil());
3297
3298 assert(nameSym != null);
3299 assert(nameSym instanceof MethodSymbol);
3300
3301 JCStatement ret = make.Return(make.Ident(nameSymbol));
3302
3303 cdef.defs = cdef.defs.append(make.MethodDef((MethodSymbol)nameSym,
3304 make.Block(0L, List.of(ret))));
3305
3306 return (MethodSymbol)nameSym;
3307 }
3308
3309 private MethodSymbol addEnumToString(JCClassDecl cdef,
3310 VarSymbol nameSymbol) {
3311 Symbol toStringSym = lookupMethod(cdef.pos(),
3312 names.toString,
3313 cdef.type,
3314 List.<Type>nil());
3315
3316 JCTree toStringDecl = null;
3317 if (toStringSym != null)
3318 toStringDecl = TreeInfo.declarationFor(toStringSym, cdef);
3319
3320 if (toStringDecl != null)
3321 return (MethodSymbol)toStringSym;
3322
3323 JCStatement ret = make.Return(make.Ident(nameSymbol));
3324
3325 JCTree resTypeTree = make.Type(syms.stringType);
3326
3327 MethodType toStringType = new MethodType(List.<Type>nil(),
3328 syms.stringType,
3329 List.<Type>nil(),
3330 cdef.sym);
3331 toStringSym = new MethodSymbol(PUBLIC,
3332 names.toString,
3333 toStringType,
3334 cdef.type.tsym);
3335 toStringDecl = make.MethodDef((MethodSymbol)toStringSym,
3336 make.Block(0L, List.of(ret)));
3337
3338 cdef.defs = cdef.defs.prepend(toStringDecl);
3339 cdef.sym.members().enter(toStringSym);
3340
3341 return (MethodSymbol)toStringSym;
3342 }
3343
3344 private MethodSymbol addEnumCompareTo(JCClassDecl cdef, VarSymbol ordinalSymbol) {
3345 Symbol compareToSym = lookupMethod(cdef.pos(),
3346 names.compareTo,
3347 cdef.type,
3348 List.of(cdef.sym.type));
3349
3350 assert(compareToSym != null);
3351 assert(compareToSym instanceof MethodSymbol);
3352
3353 JCMethodDecl compareToDecl = (JCMethodDecl) TreeInfo.declarationFor(compareToSym, cdef);
3354
3355 ListBuffer<JCStatement> blockStatements = new ListBuffer<JCStatement>();
3356
3357 JCModifiers mod1 = make.Modifiers(0L);
3358 Name oName = names.fromString("o");
3359 JCVariableDecl par1 = make.Param(oName, cdef.type, compareToSym);
3360
3361 JCIdent paramId1 = make.Ident(names.java_lang_Object);
3362 paramId1.type = cdef.type;
3363 paramId1.sym = par1.sym;
3364
3365 ((MethodSymbol)compareToSym).params = List.of(par1.sym);
3366
3367 JCIdent par1UsageId = make.Ident(par1.sym);
3368 JCIdent castTargetIdent = make.Ident(cdef.sym);
3369 JCTypeCast cast = make.TypeCast(castTargetIdent, par1UsageId);
3370 cast.setType(castTargetIdent.type);
3371
3372 Name otherName = names.fromString("other");
3373
3374 VarSymbol otherVarSym = new VarSymbol(mod1.flags,
3375 otherName,
3376 cdef.type,
3377 compareToSym);
3378 JCVariableDecl otherVar = make.VarDef(otherVarSym, cast);
3379 blockStatements.append(otherVar);
3380
3381 JCIdent id1 = make.Ident(ordinalSymbol);
3382
3383 JCIdent fLocUsageId = make.Ident(otherVarSym);
3384 JCExpression sel = make.Select(fLocUsageId, ordinalSymbol);
3385 JCBinary bin = makeBinary(JCTree.MINUS, id1, sel);
3386 JCReturn ret = make.Return(bin);
3387 blockStatements.append(ret);
3388 JCMethodDecl compareToMethod = make.MethodDef((MethodSymbol)compareToSym,
3389 make.Block(0L,
3390 blockStatements.toList()));
3391 compareToMethod.params = List.of(par1);
3392 cdef.defs = cdef.defs.append(compareToMethod);
3393
3394 return (MethodSymbol)compareToSym;
3395 }
3396 //////////////////////////////////////////////////////////////
3397 // The above contributed by Borland for bootstrapping purposes
3398 //////////////////////////////////////////////////////////////
3399 }