src/share/classes/com/sun/tools/javac/comp/Lower.java

changeset 430
8fb9b4be3cb1
parent 359
8227961c64d3
child 443
121e0ebf1658
equal deleted inserted replaced
429:c8083dc525b6 430:8fb9b4be3cb1
355 * switch(Outer$0.$EnumMap$Color[colorExpression.ordinal()]) { 355 * switch(Outer$0.$EnumMap$Color[colorExpression.ordinal()]) {
356 * case 1: stmt1; 356 * case 1: stmt1;
357 * case 2: stmt2 357 * case 2: stmt2
358 * } 358 * }
359 * </pre> 359 * </pre>
360 * with the auxilliary table intialized as follows: 360 * with the auxiliary table initialized as follows:
361 * <pre> 361 * <pre>
362 * class Outer$0 { 362 * class Outer$0 {
363 * synthetic final int[] $EnumMap$Color = new int[Color.values().length]; 363 * synthetic final int[] $EnumMap$Color = new int[Color.values().length];
364 * static { 364 * static {
365 * try { $EnumMap$Color[red.ordinal()] = 1; } catch (NoSuchFieldError ex) {} 365 * try { $EnumMap$Color[red.ordinal()] = 1; } catch (NoSuchFieldError ex) {}
856 } 856 }
857 857
858 int acode; // The access code of the access method. 858 int acode; // The access code of the access method.
859 List<Type> argtypes; // The argument types 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. 860 Type restype; // The result type of the access method.
861 List<Type> thrown; // The thrown execeptions of the access method. 861 List<Type> thrown; // The thrown exceptions of the access method.
862 switch (vsym.kind) { 862 switch (vsym.kind) {
863 case VAR: 863 case VAR:
864 acode = accessCode(tree, enclOp); 864 acode = accessCode(tree, enclOp);
865 if (acode >= FIRSTASGOPcode) { 865 if (acode >= FIRSTASGOPcode) {
866 OperatorSymbol operator = binaryAccessOperator(acode); 866 OperatorSymbol operator = binaryAccessOperator(acode);
2461 // Simplify conditionals with known constant controlling expressions. 2461 // Simplify conditionals with known constant controlling expressions.
2462 // This allows us to avoid generating supporting declarations for 2462 // This allows us to avoid generating supporting declarations for
2463 // the dead code, which will not be eliminated during code generation. 2463 // the dead code, which will not be eliminated during code generation.
2464 // Note that Flow.isFalse and Flow.isTrue only return true 2464 // Note that Flow.isFalse and Flow.isTrue only return true
2465 // for constant expressions in the sense of JLS 15.27, which 2465 // for constant expressions in the sense of JLS 15.27, which
2466 // are guaranteed to have no side-effects. More agressive 2466 // are guaranteed to have no side-effects. More aggressive
2467 // constant propagation would require that we take care to 2467 // constant propagation would require that we take care to
2468 // preserve possible side-effects in the condition expression. 2468 // preserve possible side-effects in the condition expression.
2469 2469
2470 /** Visitor method for conditional expressions. 2470 /** Visitor method for conditional expressions.
2471 */ 2471 */
2848 tree.type = cfolder.fold1(bool_not, tree.arg.type); 2848 tree.type = cfolder.fold1(bool_not, tree.arg.type);
2849 } 2849 }
2850 2850
2851 // If translated left hand side is an Apply, we are 2851 // If translated left hand side is an Apply, we are
2852 // seeing an access method invocation. In this case, return 2852 // seeing an access method invocation. In this case, return
2853 // that access method invokation as result. 2853 // that access method invocation as result.
2854 if (isUpdateOperator && tree.arg.getTag() == JCTree.APPLY) { 2854 if (isUpdateOperator && tree.arg.getTag() == JCTree.APPLY) {
2855 result = tree.arg; 2855 result = tree.arg;
2856 } else { 2856 } else {
2857 result = tree; 2857 result = tree;
2858 } 2858 }
2898 else 2898 else
2899 visitArrayForeachLoop(tree); 2899 visitArrayForeachLoop(tree);
2900 } 2900 }
2901 // where 2901 // where
2902 /** 2902 /**
2903 * A statment of the form 2903 * A statement of the form
2904 * 2904 *
2905 * <pre> 2905 * <pre>
2906 * for ( T v : arrayexpr ) stmt; 2906 * for ( T v : arrayexpr ) stmt;
2907 * </pre> 2907 * </pre>
2908 * 2908 *
3107 3107
3108 public void visitSwitch(JCSwitch tree) { 3108 public void visitSwitch(JCSwitch tree) {
3109 Type selsuper = types.supertype(tree.selector.type); 3109 Type selsuper = types.supertype(tree.selector.type);
3110 boolean enumSwitch = selsuper != null && 3110 boolean enumSwitch = selsuper != null &&
3111 (tree.selector.type.tsym.flags() & ENUM) != 0; 3111 (tree.selector.type.tsym.flags() & ENUM) != 0;
3112 Type target = enumSwitch ? tree.selector.type : syms.intType; 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);
3113 tree.selector = translate(tree.selector, target); 3116 tree.selector = translate(tree.selector, target);
3114 tree.cases = translateCases(tree.cases); 3117 tree.cases = translateCases(tree.cases);
3115 if (enumSwitch) { 3118 if (enumSwitch) {
3116 result = visitEnumSwitch(tree); 3119 result = visitEnumSwitch(tree);
3117 patchTargets(result, tree, result); 3120 patchTargets(result, tree, result);
3121 } else if (stringSwitch) {
3122 result = visitStringSwitch(tree);
3118 } else { 3123 } else {
3119 result = tree; 3124 result = tree;
3120 } 3125 }
3121 } 3126 }
3122 3127
3140 } else { 3145 } else {
3141 cases.append(c); 3146 cases.append(c);
3142 } 3147 }
3143 } 3148 }
3144 return make.Switch(selector, cases.toList()); 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 }
3145 } 3328 }
3146 3329
3147 public void visitNewArray(JCNewArray tree) { 3330 public void visitNewArray(JCNewArray tree) {
3148 tree.elemtype = translate(tree.elemtype); 3331 tree.elemtype = translate(tree.elemtype);
3149 for (List<JCExpression> t = tree.dims; t.tail != null; t = t.tail) 3332 for (List<JCExpression> t = tree.dims; t.tail != null; t = t.tail)

mercurial