340 * switches.
341 *
342 * <p>For each enum that appears as the type of a switch
343 * expression, we maintain an EnumMapping to assist in the
344 * translation, as exemplified by the following example:
345 *
346 * <p>we translate
347 * <pre>
348 * switch(colorExpression) {
349 * case red: stmt1;
350 * case green: stmt2;
351 * }
352 * </pre>
353 * into
354 * <pre>
355 * switch(Outer$0.$EnumMap$Color[colorExpression.ordinal()]) {
356 * case 1: stmt1;
357 * case 2: stmt2
358 * }
359 * </pre>
360 * with the auxilliary table intialized as follows:
361 * <pre>
362 * class Outer$0 {
363 * synthetic final int[] $EnumMap$Color = new int[Color.values().length];
364 * static {
365 * try { $EnumMap$Color[red.ordinal()] = 1; } catch (NoSuchFieldError ex) {}
366 * try { $EnumMap$Color[green.ordinal()] = 2; } catch (NoSuchFieldError ex) {}
367 * }
368 * }
369 * </pre>
370 * class EnumMapping provides mapping data and support methods for this translation.
371 */
372 class EnumMapping {
373 EnumMapping(DiagnosticPosition pos, TypeSymbol forEnum) {
374 this.forEnum = forEnum;
375 this.values = new LinkedHashMap<VarSymbol,Integer>();
376 this.pos = pos;
377 Name varName = names
378 .fromString(target.syntheticNameChar() +
379 "SwitchMap" +
380 target.syntheticNameChar() +
841
842 Symbol vsym = sym;
843 if (sym.owner != accOwner) {
844 vsym = sym.clone(accOwner);
845 actualSymbols.put(vsym, sym);
846 }
847
848 Integer anum // The access number of the access method.
849 = accessNums.get(vsym);
850 if (anum == null) {
851 anum = accessed.length();
852 accessNums.put(vsym, anum);
853 accessSyms.put(vsym, new MethodSymbol[NCODES]);
854 accessed.append(vsym);
855 // System.out.println("accessing " + vsym + " in " + vsym.location());
856 }
857
858 int acode; // The access code of the access method.
859 List<Type> argtypes; // The argument types of the access method.
860 Type restype; // The result type of the access method.
861 List<Type> thrown; // The thrown execeptions of the access method.
862 switch (vsym.kind) {
863 case VAR:
864 acode = accessCode(tree, enclOp);
865 if (acode >= FIRSTASGOPcode) {
866 OperatorSymbol operator = binaryAccessOperator(acode);
867 if (operator.opcode == string_add)
868 argtypes = List.of(syms.objectType);
869 else
870 argtypes = operator.type.getParameterTypes().tail;
871 } else if (acode == ASSIGNcode)
872 argtypes = List.of(vsym.erasure(types));
873 else
874 argtypes = List.nil();
875 restype = vsym.erasure(types);
876 thrown = List.nil();
877 break;
878 case MTH:
879 acode = DEREFcode;
880 argtypes = vsym.erasure(types).getParameterTypes();
881 restype = vsym.erasure(types).getReturnType();
2446 }
2447 tree.encl = null;
2448
2449 // If we have an anonymous class, create its flat version, rather
2450 // than the class or interface following new.
2451 if (tree.def != null) {
2452 translate(tree.def);
2453 tree.clazz = access(make_at(tree.clazz.pos()).Ident(tree.def.sym));
2454 tree.def = null;
2455 } else {
2456 tree.clazz = access(c, tree.clazz, enclOp, false);
2457 }
2458 result = tree;
2459 }
2460
2461 // Simplify conditionals with known constant controlling expressions.
2462 // This allows us to avoid generating supporting declarations for
2463 // the dead code, which will not be eliminated during code generation.
2464 // Note that Flow.isFalse and Flow.isTrue only return true
2465 // for constant expressions in the sense of JLS 15.27, which
2466 // are guaranteed to have no side-effects. More agressive
2467 // constant propagation would require that we take care to
2468 // preserve possible side-effects in the condition expression.
2469
2470 /** Visitor method for conditional expressions.
2471 */
2472 public void visitConditional(JCConditional tree) {
2473 JCTree cond = tree.cond = translate(tree.cond, syms.booleanType);
2474 if (cond.type.isTrue()) {
2475 result = convert(translate(tree.truepart, tree.type), tree.type);
2476 } else if (cond.type.isFalse()) {
2477 result = convert(translate(tree.falsepart, tree.type), tree.type);
2478 } else {
2479 // Condition is not a compile-time constant.
2480 tree.truepart = translate(tree.truepart, tree.type);
2481 tree.falsepart = translate(tree.falsepart, tree.type);
2482 result = tree;
2483 }
2484 }
2485 //where
2486 private JCTree convert(JCTree tree, Type pt) {
2833 return;
2834 }
2835 case JCTree.POSTINC: // e ++
2836 case JCTree.POSTDEC: // e --
2837 {
2838 result = translate(lowerBoxedPostop(tree), tree.type);
2839 return;
2840 }
2841 }
2842 throw new AssertionError(tree);
2843 }
2844
2845 tree.arg = boxIfNeeded(translate(tree.arg, tree), tree.type);
2846
2847 if (tree.getTag() == JCTree.NOT && tree.arg.type.constValue() != null) {
2848 tree.type = cfolder.fold1(bool_not, tree.arg.type);
2849 }
2850
2851 // If translated left hand side is an Apply, we are
2852 // seeing an access method invocation. In this case, return
2853 // that access method invokation as result.
2854 if (isUpdateOperator && tree.arg.getTag() == JCTree.APPLY) {
2855 result = tree.arg;
2856 } else {
2857 result = tree;
2858 }
2859 }
2860
2861 public void visitBinary(JCBinary tree) {
2862 List<Type> formals = tree.operator.type.getParameterTypes();
2863 JCTree lhs = tree.lhs = translate(tree.lhs, formals.head);
2864 switch (tree.getTag()) {
2865 case JCTree.OR:
2866 if (lhs.type.isTrue()) {
2867 result = lhs;
2868 return;
2869 }
2870 if (lhs.type.isFalse()) {
2871 result = translate(tree.rhs, formals.tail.head);
2872 return;
2873 }
2883 }
2884 break;
2885 }
2886 tree.rhs = translate(tree.rhs, formals.tail.head);
2887 result = tree;
2888 }
2889
2890 public void visitIdent(JCIdent tree) {
2891 result = access(tree.sym, tree, enclOp, false);
2892 }
2893
2894 /** Translate away the foreach loop. */
2895 public void visitForeachLoop(JCEnhancedForLoop tree) {
2896 if (types.elemtype(tree.expr.type) == null)
2897 visitIterableForeachLoop(tree);
2898 else
2899 visitArrayForeachLoop(tree);
2900 }
2901 // where
2902 /**
2903 * A statment of the form
2904 *
2905 * <pre>
2906 * for ( T v : arrayexpr ) stmt;
2907 * </pre>
2908 *
2909 * (where arrayexpr is of an array type) gets translated to
2910 *
2911 * <pre>
2912 * for ( { arraytype #arr = arrayexpr;
2913 * int #len = array.length;
2914 * int #i = 0; };
2915 * #i < #len; i$++ ) {
2916 * T v = arr$[#i];
2917 * stmt;
2918 * }
2919 * </pre>
2920 *
2921 * where #arr, #len, and #i are freshly named synthetic local variables.
2922 */
2923 private void visitArrayForeachLoop(JCEnhancedForLoop tree) {
3092 tree.init = translate(tree.init);
3093 if (tree.cond != null)
3094 tree.cond = translate(tree.cond, syms.booleanType);
3095 tree.step = translate(tree.step);
3096 tree.body = translate(tree.body);
3097 result = tree;
3098 }
3099
3100 public void visitReturn(JCReturn tree) {
3101 if (tree.expr != null)
3102 tree.expr = translate(tree.expr,
3103 types.erasure(currentMethodDef
3104 .restype.type));
3105 result = tree;
3106 }
3107
3108 public void visitSwitch(JCSwitch tree) {
3109 Type selsuper = types.supertype(tree.selector.type);
3110 boolean enumSwitch = selsuper != null &&
3111 (tree.selector.type.tsym.flags() & ENUM) != 0;
3112 Type target = enumSwitch ? tree.selector.type : syms.intType;
3113 tree.selector = translate(tree.selector, target);
3114 tree.cases = translateCases(tree.cases);
3115 if (enumSwitch) {
3116 result = visitEnumSwitch(tree);
3117 patchTargets(result, tree, result);
3118 } else {
3119 result = tree;
3120 }
3121 }
3122
3123 public JCTree visitEnumSwitch(JCSwitch tree) {
3124 TypeSymbol enumSym = tree.selector.type.tsym;
3125 EnumMapping map = mapForEnum(tree.pos(), enumSym);
3126 make_at(tree.pos());
3127 Symbol ordinalMethod = lookupMethod(tree.pos(),
3128 names.ordinal,
3129 tree.selector.type,
3130 List.<Type>nil());
3131 JCArrayAccess selector = make.Indexed(map.mapVar,
3132 make.App(make.Select(tree.selector,
3133 ordinalMethod)));
3134 ListBuffer<JCCase> cases = new ListBuffer<JCCase>();
3135 for (JCCase c : tree.cases) {
3136 if (c.pat != null) {
3137 VarSymbol label = (VarSymbol)TreeInfo.symbol(c.pat);
3138 JCLiteral pat = map.forConstant(label);
3139 cases.append(make.Case(pat, c.stats));
3140 } else {
3141 cases.append(c);
3142 }
3143 }
3144 return make.Switch(selector, cases.toList());
3145 }
3146
3147 public void visitNewArray(JCNewArray tree) {
3148 tree.elemtype = translate(tree.elemtype);
3149 for (List<JCExpression> t = tree.dims; t.tail != null; t = t.tail)
3150 if (t.head != null) t.head = translate(t.head, syms.intType);
3151 tree.elems = translate(tree.elems, types.elemtype(tree.type));
3152 result = tree;
3153 }
3154
3155 public void visitSelect(JCFieldAccess tree) {
3156 // need to special case-access of the form C.super.x
3157 // these will always need an access method.
3158 boolean qualifiedSuperAccess =
3159 tree.selected.getTag() == JCTree.SELECT &&
3160 TreeInfo.name(tree.selected) == names._super;
3161 tree.selected = translate(tree.selected);
3162 if (tree.name == names._class)
3163 result = classOf(tree.selected);
3164 else if (tree.name == names._this || tree.name == names._super)
3165 result = makeThis(tree.pos(), tree.selected.type.tsym);
3166 else
|
340 * switches.
341 *
342 * <p>For each enum that appears as the type of a switch
343 * expression, we maintain an EnumMapping to assist in the
344 * translation, as exemplified by the following example:
345 *
346 * <p>we translate
347 * <pre>
348 * switch(colorExpression) {
349 * case red: stmt1;
350 * case green: stmt2;
351 * }
352 * </pre>
353 * into
354 * <pre>
355 * switch(Outer$0.$EnumMap$Color[colorExpression.ordinal()]) {
356 * case 1: stmt1;
357 * case 2: stmt2
358 * }
359 * </pre>
360 * with the auxiliary table initialized as follows:
361 * <pre>
362 * class Outer$0 {
363 * synthetic final int[] $EnumMap$Color = new int[Color.values().length];
364 * static {
365 * try { $EnumMap$Color[red.ordinal()] = 1; } catch (NoSuchFieldError ex) {}
366 * try { $EnumMap$Color[green.ordinal()] = 2; } catch (NoSuchFieldError ex) {}
367 * }
368 * }
369 * </pre>
370 * class EnumMapping provides mapping data and support methods for this translation.
371 */
372 class EnumMapping {
373 EnumMapping(DiagnosticPosition pos, TypeSymbol forEnum) {
374 this.forEnum = forEnum;
375 this.values = new LinkedHashMap<VarSymbol,Integer>();
376 this.pos = pos;
377 Name varName = names
378 .fromString(target.syntheticNameChar() +
379 "SwitchMap" +
380 target.syntheticNameChar() +
841
842 Symbol vsym = sym;
843 if (sym.owner != accOwner) {
844 vsym = sym.clone(accOwner);
845 actualSymbols.put(vsym, sym);
846 }
847
848 Integer anum // The access number of the access method.
849 = accessNums.get(vsym);
850 if (anum == null) {
851 anum = accessed.length();
852 accessNums.put(vsym, anum);
853 accessSyms.put(vsym, new MethodSymbol[NCODES]);
854 accessed.append(vsym);
855 // System.out.println("accessing " + vsym + " in " + vsym.location());
856 }
857
858 int acode; // The access code of the access method.
859 List<Type> argtypes; // The argument types of the access method.
860 Type restype; // The result type of the access method.
861 List<Type> thrown; // The thrown exceptions of the access method.
862 switch (vsym.kind) {
863 case VAR:
864 acode = accessCode(tree, enclOp);
865 if (acode >= FIRSTASGOPcode) {
866 OperatorSymbol operator = binaryAccessOperator(acode);
867 if (operator.opcode == string_add)
868 argtypes = List.of(syms.objectType);
869 else
870 argtypes = operator.type.getParameterTypes().tail;
871 } else if (acode == ASSIGNcode)
872 argtypes = List.of(vsym.erasure(types));
873 else
874 argtypes = List.nil();
875 restype = vsym.erasure(types);
876 thrown = List.nil();
877 break;
878 case MTH:
879 acode = DEREFcode;
880 argtypes = vsym.erasure(types).getParameterTypes();
881 restype = vsym.erasure(types).getReturnType();
2446 }
2447 tree.encl = null;
2448
2449 // If we have an anonymous class, create its flat version, rather
2450 // than the class or interface following new.
2451 if (tree.def != null) {
2452 translate(tree.def);
2453 tree.clazz = access(make_at(tree.clazz.pos()).Ident(tree.def.sym));
2454 tree.def = null;
2455 } else {
2456 tree.clazz = access(c, tree.clazz, enclOp, false);
2457 }
2458 result = tree;
2459 }
2460
2461 // Simplify conditionals with known constant controlling expressions.
2462 // This allows us to avoid generating supporting declarations for
2463 // the dead code, which will not be eliminated during code generation.
2464 // Note that Flow.isFalse and Flow.isTrue only return true
2465 // for constant expressions in the sense of JLS 15.27, which
2466 // are guaranteed to have no side-effects. More aggressive
2467 // constant propagation would require that we take care to
2468 // preserve possible side-effects in the condition expression.
2469
2470 /** Visitor method for conditional expressions.
2471 */
2472 public void visitConditional(JCConditional tree) {
2473 JCTree cond = tree.cond = translate(tree.cond, syms.booleanType);
2474 if (cond.type.isTrue()) {
2475 result = convert(translate(tree.truepart, tree.type), tree.type);
2476 } else if (cond.type.isFalse()) {
2477 result = convert(translate(tree.falsepart, tree.type), tree.type);
2478 } else {
2479 // Condition is not a compile-time constant.
2480 tree.truepart = translate(tree.truepart, tree.type);
2481 tree.falsepart = translate(tree.falsepart, tree.type);
2482 result = tree;
2483 }
2484 }
2485 //where
2486 private JCTree convert(JCTree tree, Type pt) {
2833 return;
2834 }
2835 case JCTree.POSTINC: // e ++
2836 case JCTree.POSTDEC: // e --
2837 {
2838 result = translate(lowerBoxedPostop(tree), tree.type);
2839 return;
2840 }
2841 }
2842 throw new AssertionError(tree);
2843 }
2844
2845 tree.arg = boxIfNeeded(translate(tree.arg, tree), tree.type);
2846
2847 if (tree.getTag() == JCTree.NOT && tree.arg.type.constValue() != null) {
2848 tree.type = cfolder.fold1(bool_not, tree.arg.type);
2849 }
2850
2851 // If translated left hand side is an Apply, we are
2852 // seeing an access method invocation. In this case, return
2853 // that access method invocation as result.
2854 if (isUpdateOperator && tree.arg.getTag() == JCTree.APPLY) {
2855 result = tree.arg;
2856 } else {
2857 result = tree;
2858 }
2859 }
2860
2861 public void visitBinary(JCBinary tree) {
2862 List<Type> formals = tree.operator.type.getParameterTypes();
2863 JCTree lhs = tree.lhs = translate(tree.lhs, formals.head);
2864 switch (tree.getTag()) {
2865 case JCTree.OR:
2866 if (lhs.type.isTrue()) {
2867 result = lhs;
2868 return;
2869 }
2870 if (lhs.type.isFalse()) {
2871 result = translate(tree.rhs, formals.tail.head);
2872 return;
2873 }
2883 }
2884 break;
2885 }
2886 tree.rhs = translate(tree.rhs, formals.tail.head);
2887 result = tree;
2888 }
2889
2890 public void visitIdent(JCIdent tree) {
2891 result = access(tree.sym, tree, enclOp, false);
2892 }
2893
2894 /** Translate away the foreach loop. */
2895 public void visitForeachLoop(JCEnhancedForLoop tree) {
2896 if (types.elemtype(tree.expr.type) == null)
2897 visitIterableForeachLoop(tree);
2898 else
2899 visitArrayForeachLoop(tree);
2900 }
2901 // where
2902 /**
2903 * A statement of the form
2904 *
2905 * <pre>
2906 * for ( T v : arrayexpr ) stmt;
2907 * </pre>
2908 *
2909 * (where arrayexpr is of an array type) gets translated to
2910 *
2911 * <pre>
2912 * for ( { arraytype #arr = arrayexpr;
2913 * int #len = array.length;
2914 * int #i = 0; };
2915 * #i < #len; i$++ ) {
2916 * T v = arr$[#i];
2917 * stmt;
2918 * }
2919 * </pre>
2920 *
2921 * where #arr, #len, and #i are freshly named synthetic local variables.
2922 */
2923 private void visitArrayForeachLoop(JCEnhancedForLoop tree) {
3092 tree.init = translate(tree.init);
3093 if (tree.cond != null)
3094 tree.cond = translate(tree.cond, syms.booleanType);
3095 tree.step = translate(tree.step);
3096 tree.body = translate(tree.body);
3097 result = tree;
3098 }
3099
3100 public void visitReturn(JCReturn tree) {
3101 if (tree.expr != null)
3102 tree.expr = translate(tree.expr,
3103 types.erasure(currentMethodDef
3104 .restype.type));
3105 result = tree;
3106 }
3107
3108 public void visitSwitch(JCSwitch tree) {
3109 Type selsuper = types.supertype(tree.selector.type);
3110 boolean enumSwitch = selsuper != null &&
3111 (tree.selector.type.tsym.flags() & ENUM) != 0;
3112 boolean stringSwitch = selsuper != null &&
3113 types.isSameType(tree.selector.type, syms.stringType);
3114 Type target = enumSwitch ? tree.selector.type :
3115 (stringSwitch? syms.stringType : syms.intType);
3116 tree.selector = translate(tree.selector, target);
3117 tree.cases = translateCases(tree.cases);
3118 if (enumSwitch) {
3119 result = visitEnumSwitch(tree);
3120 patchTargets(result, tree, result);
3121 } else if (stringSwitch) {
3122 result = visitStringSwitch(tree);
3123 } else {
3124 result = tree;
3125 }
3126 }
3127
3128 public JCTree visitEnumSwitch(JCSwitch tree) {
3129 TypeSymbol enumSym = tree.selector.type.tsym;
3130 EnumMapping map = mapForEnum(tree.pos(), enumSym);
3131 make_at(tree.pos());
3132 Symbol ordinalMethod = lookupMethod(tree.pos(),
3133 names.ordinal,
3134 tree.selector.type,
3135 List.<Type>nil());
3136 JCArrayAccess selector = make.Indexed(map.mapVar,
3137 make.App(make.Select(tree.selector,
3138 ordinalMethod)));
3139 ListBuffer<JCCase> cases = new ListBuffer<JCCase>();
3140 for (JCCase c : tree.cases) {
3141 if (c.pat != null) {
3142 VarSymbol label = (VarSymbol)TreeInfo.symbol(c.pat);
3143 JCLiteral pat = map.forConstant(label);
3144 cases.append(make.Case(pat, c.stats));
3145 } else {
3146 cases.append(c);
3147 }
3148 }
3149 return make.Switch(selector, cases.toList());
3150 }
3151
3152 public JCTree visitStringSwitch(JCSwitch tree) {
3153 List<JCCase> caseList = tree.getCases();
3154 int alternatives = caseList.size();
3155
3156 if (alternatives == 0) { // Strange but legal possibility
3157 return make.at(tree.pos()).Exec(attr.makeNullCheck(tree.getExpression()));
3158 } else {
3159 /*
3160 * The general approach used is to translate a single
3161 * string switch statement into a series of two chained
3162 * switch statements: the first a synthesized statement
3163 * switching on the argument string's hash value and
3164 * computing a string's position in the list of original
3165 * case labels, if any, followed by a second switch on the
3166 * computed integer value. The second switch has the same
3167 * code structure as the original string switch statement
3168 * except that the string case labels are replaced with
3169 * positional integer constants starting at 0.
3170 *
3171 * The first switch statement can be thought of as an
3172 * inlined map from strings to their position in the case
3173 * label list. An alternate implementation would use an
3174 * actual Map for this purpose, as done for enum switches.
3175 *
3176 * With some additional effort, it would be possible to
3177 * use a single switch statement on the hash code of the
3178 * argument, but care would need to be taken to preserve
3179 * the proper control flow in the presence of hash
3180 * collisions and other complications, such as
3181 * fallthroughs. Switch statements with one or two
3182 * alternatives could also be specially translated into
3183 * if-then statements to omit the computation of the hash
3184 * code.
3185 *
3186 * The generated code assumes that the hashing algorithm
3187 * of String is the same in the compilation environment as
3188 * in the environment the code will run in. The string
3189 * hashing algorithm in the SE JDK has been unchanged
3190 * since at least JDK 1.2.
3191 */
3192
3193 ListBuffer<JCStatement> stmtList = new ListBuffer<JCStatement>();
3194
3195 // Map from String case labels to their original position in
3196 // the list of case labels.
3197 Map<String, Integer> caseLabelToPosition =
3198 new LinkedHashMap<String, Integer>(alternatives + 1, 1.0f);
3199
3200 // Map of hash codes to the string case labels having that hashCode.
3201 Map<Integer, Set<String>> hashToString =
3202 new LinkedHashMap<Integer, Set<String>>(alternatives + 1, 1.0f);
3203
3204 int casePosition = 0;
3205 for(JCCase oneCase : caseList) {
3206 JCExpression expression = oneCase.getExpression();
3207
3208 if (expression != null) { // expression for a "default" case is null
3209 String labelExpr = (String) expression.type.constValue();
3210 Integer mapping = caseLabelToPosition.put(labelExpr, casePosition);
3211 assert mapping == null;
3212 int hashCode = labelExpr.hashCode();
3213
3214 Set<String> stringSet = hashToString.get(hashCode);
3215 if (stringSet == null) {
3216 stringSet = new LinkedHashSet<String>(1, 1.0f);
3217 stringSet.add(labelExpr);
3218 hashToString.put(hashCode, stringSet);
3219 } else {
3220 boolean added = stringSet.add(labelExpr);
3221 assert added;
3222 }
3223 }
3224 casePosition++;
3225 }
3226
3227 // Synthesize a switch statement that has the effect of
3228 // mapping from a string to the integer position of that
3229 // string in the list of case labels. This is done by
3230 // switching on the hashCode of the string followed by an
3231 // if-then-else chain comparing the input for equality
3232 // with all the case labels having that hash value.
3233
3234 /*
3235 * s$ = top of stack;
3236 * tmp$ = -1;
3237 * switch($s.hashCode()) {
3238 * case caseLabel.hashCode:
3239 * if (s$.equals("caseLabel_1")
3240 * tmp$ = caseLabelToPosition("caseLabel_1");
3241 * else if (s$.equals("caseLabel_2"))
3242 * tmp$ = caseLabelToPosition("caseLabel_2");
3243 * ...
3244 * break;
3245 * ...
3246 * }
3247 */
3248
3249 VarSymbol dollar_s = new VarSymbol(FINAL|SYNTHETIC,
3250 names.fromString("s" + tree.pos + target.syntheticNameChar()),
3251 syms.stringType,
3252 currentMethodSym);
3253 stmtList.append(make.at(tree.pos()).VarDef(dollar_s, tree.getExpression()).setType(dollar_s.type));
3254
3255 VarSymbol dollar_tmp = new VarSymbol(SYNTHETIC,
3256 names.fromString("tmp" + tree.pos + target.syntheticNameChar()),
3257 syms.intType,
3258 currentMethodSym);
3259 JCVariableDecl dollar_tmp_def =
3260 (JCVariableDecl)make.VarDef(dollar_tmp, make.Literal(INT, -1)).setType(dollar_tmp.type);
3261 dollar_tmp_def.init.type = dollar_tmp.type = syms.intType;
3262 stmtList.append(dollar_tmp_def);
3263 ListBuffer<JCCase> caseBuffer = ListBuffer.lb();
3264 // hashCode will trigger nullcheck on original switch expression
3265 JCMethodInvocation hashCodeCall = makeCall(make.Ident(dollar_s),
3266 names.hashCode,
3267 List.<JCExpression>nil()).setType(syms.intType);
3268 JCSwitch switch1 = make.Switch(hashCodeCall,
3269 caseBuffer.toList());
3270 for(Map.Entry<Integer, Set<String>> entry : hashToString.entrySet()) {
3271 int hashCode = entry.getKey();
3272 Set<String> stringsWithHashCode = entry.getValue();
3273 assert stringsWithHashCode.size() >= 1;
3274
3275 JCStatement elsepart = null;
3276 for(String caseLabel : stringsWithHashCode ) {
3277 JCMethodInvocation stringEqualsCall = makeCall(make.Ident(dollar_s),
3278 names.equals,
3279 List.<JCExpression>of(make.Literal(caseLabel)));
3280 elsepart = make.If(stringEqualsCall,
3281 make.Exec(make.Assign(make.Ident(dollar_tmp),
3282 make.Literal(caseLabelToPosition.get(caseLabel))).
3283 setType(dollar_tmp.type)),
3284 elsepart);
3285 }
3286
3287 ListBuffer<JCStatement> lb = ListBuffer.lb();
3288 JCBreak breakStmt = make.Break(null);
3289 breakStmt.target = switch1;
3290 lb.append(elsepart).append(breakStmt);
3291
3292 caseBuffer.append(make.Case(make.Literal(hashCode), lb.toList()));
3293 }
3294
3295 switch1.cases = caseBuffer.toList();
3296 stmtList.append(switch1);
3297
3298 // Make isomorphic switch tree replacing string labels
3299 // with corresponding integer ones from the label to
3300 // position map.
3301
3302 ListBuffer<JCCase> lb = ListBuffer.lb();
3303 JCSwitch switch2 = make.Switch(make.Ident(dollar_tmp), lb.toList());
3304 for(JCCase oneCase : caseList ) {
3305 // Rewire up old unlabeled break statements to the
3306 // replacement switch being created.
3307 patchTargets(oneCase, tree, switch2);
3308
3309 boolean isDefault = (oneCase.getExpression() == null);
3310 JCExpression caseExpr;
3311 if (isDefault)
3312 caseExpr = null;
3313 else {
3314 caseExpr = make.Literal(caseLabelToPosition.get((String)oneCase.
3315 getExpression().
3316 type.constValue()));
3317 }
3318
3319 lb.append(make.Case(caseExpr,
3320 oneCase.getStatements()));
3321 }
3322
3323 switch2.cases = lb.toList();
3324 stmtList.append(switch2);
3325
3326 return make.Block(0L, stmtList.toList());
3327 }
3328 }
3329
3330 public void visitNewArray(JCNewArray tree) {
3331 tree.elemtype = translate(tree.elemtype);
3332 for (List<JCExpression> t = tree.dims; t.tail != null; t = t.tail)
3333 if (t.head != null) t.head = translate(t.head, syms.intType);
3334 tree.elems = translate(tree.elems, types.elemtype(tree.type));
3335 result = tree;
3336 }
3337
3338 public void visitSelect(JCFieldAccess tree) {
3339 // need to special case-access of the form C.super.x
3340 // these will always need an access method.
3341 boolean qualifiedSuperAccess =
3342 tree.selected.getTag() == JCTree.SELECT &&
3343 TreeInfo.name(tree.selected) == names._super;
3344 tree.selected = translate(tree.selected);
3345 if (tree.name == names._class)
3346 result = classOf(tree.selected);
3347 else if (tree.name == names._this || tree.name == names._super)
3348 result = makeThis(tree.pos(), tree.selected.type.tsym);
3349 else
|