1 16 package com.google.gwt.dev.jjs.impl; 17 18 import com.google.gwt.dev.jjs.ast.Context; 19 import com.google.gwt.dev.jjs.ast.JArrayRef; 20 import com.google.gwt.dev.jjs.ast.JArrayType; 21 import com.google.gwt.dev.jjs.ast.JBinaryOperation; 22 import com.google.gwt.dev.jjs.ast.JBinaryOperator; 23 import com.google.gwt.dev.jjs.ast.JCastOperation; 24 import com.google.gwt.dev.jjs.ast.JClassType; 25 import com.google.gwt.dev.jjs.ast.JExpression; 26 import com.google.gwt.dev.jjs.ast.JInstanceOf; 27 import com.google.gwt.dev.jjs.ast.JIntLiteral; 28 import com.google.gwt.dev.jjs.ast.JMethod; 29 import com.google.gwt.dev.jjs.ast.JMethodCall; 30 import com.google.gwt.dev.jjs.ast.JModVisitor; 31 import com.google.gwt.dev.jjs.ast.JNullLiteral; 32 import com.google.gwt.dev.jjs.ast.JNullType; 33 import com.google.gwt.dev.jjs.ast.JPrimitiveType; 34 import com.google.gwt.dev.jjs.ast.JProgram; 35 import com.google.gwt.dev.jjs.ast.JReferenceType; 36 import com.google.gwt.dev.jjs.ast.JType; 37 import com.google.gwt.dev.jjs.ast.JTypeOracle; 38 import com.google.gwt.dev.jjs.ast.JVisitor; 39 import com.google.gwt.dev.jjs.ast.js.JClassSeed; 40 import com.google.gwt.dev.jjs.ast.js.JsonObject; 41 import com.google.gwt.dev.jjs.ast.js.JsonObject.JsonPropInit; 42 43 import java.util.ArrayList ; 44 import java.util.HashSet ; 45 import java.util.IdentityHashMap ; 46 import java.util.Iterator ; 47 import java.util.List ; 48 import java.util.Map ; 49 import java.util.Set ; 50 51 58 public class CastNormalizer { 59 60 private class AssignTypeIdsVisitor extends JVisitor { 61 62 Set alreadyRan = new HashSet (); 63 private Map queriedTypes = new IdentityHashMap (); 64 private int nextQueryId = 1; private final List instantiatedArrayTypes = new ArrayList (); 66 private List classes = new ArrayList (); 67 private List jsonObjects = new ArrayList (); 68 69 { 70 JTypeOracle typeOracle = program.typeOracle; 71 for (Iterator it = program.getAllArrayTypes().iterator(); it.hasNext();) { 72 JArrayType arrayType = (JArrayType) it.next(); 73 if (typeOracle.isInstantiatedType(arrayType)) { 74 instantiatedArrayTypes.add(arrayType); 75 } 76 } 77 } 78 79 public void computeTypeIds() { 80 81 classes.add(null); 83 jsonObjects.add(new JsonObject(program)); 84 85 90 for (Iterator it = program.getDeclaredTypes().iterator(); it.hasNext();) { 91 JReferenceType type = (JReferenceType) it.next(); 92 if (type instanceof JClassType) { 93 computeSourceClass((JClassType) type); 94 } 95 } 96 97 for (Iterator it = program.getAllArrayTypes().iterator(); it.hasNext();) { 98 JArrayType type = (JArrayType) it.next(); 99 computeSourceClass(type); 100 } 101 102 program.initTypeInfo(classes, jsonObjects); 104 program.recordQueryIds(queryIds); 105 } 106 107 111 public void endVisit(JBinaryOperation x, Context ctx) { 113 if (x.getOp() == JBinaryOperator.ASG && x.getLhs() instanceof JArrayRef) { 114 115 JExpression instance = ((JArrayRef) x.getLhs()).getInstance(); 118 if (instance.getType() instanceof JNullType) { 119 return; 121 } 122 JArrayType lhsArrayType = (JArrayType) instance.getType(); 123 JType elementType = lhsArrayType.getElementType(); 124 125 if (!(elementType instanceof JReferenceType)) { 127 return; 128 } 129 130 if (((JReferenceType) elementType).isFinal()) { 132 return; 133 } 134 135 140 JTypeOracle typeOracle = program.typeOracle; 141 JType rhsType = x.getRhs().getType(); 142 assert (rhsType instanceof JReferenceType); 143 JReferenceType refRhsType = (JReferenceType) rhsType; 144 for (Iterator it = instantiatedArrayTypes.iterator(); it.hasNext();) { 145 JArrayType arrayType = (JArrayType) it.next(); 146 if (typeOracle.canTheoreticallyCast(arrayType, lhsArrayType)) { 147 JType itElementType = arrayType.getElementType(); 148 if (itElementType instanceof JReferenceType) { 149 recordCastInternal((JReferenceType) itElementType, refRhsType); 150 } 151 } 152 } 153 } 154 } 155 156 public void endVisit(JCastOperation x, Context ctx) { 158 if (x.getCastType() != program.getTypeNull()) { 159 recordCast(x.getCastType(), x.getExpr()); 160 } 161 } 162 163 public void endVisit(JInstanceOf x, Context ctx) { 165 assert (x.getTestType() != program.getTypeNull()); 166 recordCast(x.getTestType(), x.getExpr()); 167 } 168 169 173 private void computeSourceClass(JClassType type) { 174 if (type == null || alreadyRan.contains(type)) { 175 return; 176 } 177 178 alreadyRan.add(type); 179 180 186 computeSourceClass(type.extnds); 187 188 if (!program.typeOracle.isInstantiatedType(type)) { 189 return; 190 } 191 192 Set yesSet = null; 194 for (Iterator iter = queriedTypes.keySet().iterator(); iter.hasNext();) { 195 JReferenceType qType = (JReferenceType) iter.next(); 196 Set querySet = (Set ) queriedTypes.get(qType); 197 if (program.typeOracle.canTriviallyCast(type, qType)) { 198 for (Iterator it = querySet.iterator(); it.hasNext();) { 199 JReferenceType argType = (JReferenceType) it.next(); 200 if (program.typeOracle.canTriviallyCast(type, argType)) { 201 if (yesSet == null) { 202 yesSet = new HashSet (); 203 } 204 yesSet.add(qType); 205 break; 206 } 207 } 208 } 209 } 210 211 215 if (yesSet == null && !program.isJavaScriptObject(type)) { 216 return; } 218 219 JReferenceType[] yesArray = new JReferenceType[nextQueryId]; 221 if (yesSet != null) { 222 for (Iterator it = yesSet.iterator(); it.hasNext();) { 223 JReferenceType yesType = (JReferenceType) it.next(); 224 Integer boxedInt = (Integer ) queryIds.get(yesType); 225 yesArray[boxedInt.intValue()] = yesType; 226 } 227 } 228 229 JsonObject jsonObject = new JsonObject(program); 231 for (int i = 0; i < nextQueryId; ++i) { 232 if (yesArray[i] != null) { 233 JIntLiteral labelExpr = program.getLiteralInt(i); 234 JIntLiteral valueExpr = program.getLiteralInt(1); 235 jsonObject.propInits.add(new JsonPropInit(program, labelExpr, 236 valueExpr)); 237 } 238 } 239 240 classes.add(type); 242 jsonObjects.add(jsonObject); 243 } 244 245 private void recordCast(JType targetType, JExpression rhs) { 246 if (targetType instanceof JReferenceType) { 247 JReferenceType rhsType = (JReferenceType) rhs.getType(); 249 if (rhsType instanceof JClassType) { 251 if (program.typeOracle.canTriviallyCast(rhsType, 252 (JReferenceType) targetType)) { 253 return; 254 } 255 } 256 257 recordCastInternal((JReferenceType) targetType, rhsType); 258 } 259 } 260 261 private void recordCastInternal(JReferenceType targetType, 262 JReferenceType rhsType) { 263 JReferenceType toType = targetType; 264 Set querySet = (Set ) queriedTypes.get(toType); 265 if (querySet == null) { 266 queryIds.put(toType, new Integer (nextQueryId++)); 267 querySet = new HashSet (); 268 queriedTypes.put(toType, querySet); 269 } 270 querySet.add(rhsType); 271 } 272 } 273 274 278 private class ConcatVisitor extends JModVisitor { 279 280 private JMethod stringValueOfChar = null; 281 282 public void endVisit(JBinaryOperation x, Context ctx) { 284 if (x.getType() != program.getTypeJavaLangString()) { 285 return; 286 } 287 288 if (x.getOp() == JBinaryOperator.ADD) { 289 JExpression newLhs = convertCharString(x.getLhs()); 290 JExpression newRhs = convertCharString(x.getRhs()); 291 if (newLhs != x.getLhs() || newRhs != x.getRhs()) { 292 JBinaryOperation newExpr = new JBinaryOperation(program, 293 x.getSourceInfo(), program.getTypeJavaLangString(), 294 JBinaryOperator.ADD, newLhs, newRhs); 295 ctx.replaceMe(newExpr); 296 } 297 } else if (x.getOp() == JBinaryOperator.ASG_ADD) { 298 JExpression newRhs = convertCharString(x.getRhs()); 299 if (newRhs != x.getRhs()) { 300 JBinaryOperation newExpr = new JBinaryOperation(program, 301 x.getSourceInfo(), program.getTypeJavaLangString(), 302 JBinaryOperator.ASG_ADD, x.getLhs(), newRhs); 303 ctx.replaceMe(newExpr); 304 } 305 } 306 } 307 308 private JExpression convertCharString(JExpression expr) { 309 JPrimitiveType charType = program.getTypePrimitiveChar(); 310 if (expr.getType() == charType) { 311 if (stringValueOfChar == null) { 313 stringValueOfChar = program.getSpecialMethod("Cast.charToString"); 314 assert (stringValueOfChar != null); 315 } 316 JMethodCall call = new JMethodCall(program, expr.getSourceInfo(), null, 317 stringValueOfChar); 318 call.getArgs().add(expr); 319 return call; 320 } 321 return expr; 322 } 323 } 324 325 329 private class DivVisitor extends JModVisitor { 330 331 public void endVisit(JBinaryOperation x, Context ctx) { 333 JType type = x.getType(); 334 if (x.getOp() == JBinaryOperator.DIV 335 && type != program.getTypePrimitiveFloat() 336 && type != program.getTypePrimitiveDouble()) { 337 x.setType(program.getTypePrimitiveDouble()); 338 JCastOperation cast = new JCastOperation(program, x.getSourceInfo(), 339 type, x); 340 ctx.replaceMe(cast); 341 } 342 } 343 } 344 345 349 private class ReplaceTypeChecksVisitor extends JModVisitor { 350 351 public void endVisit(JCastOperation x, Context ctx) { 353 JExpression replaceExpr; 354 JType toType = x.getCastType(); 355 if (toType instanceof JNullType) { 356 363 JMethod method = program.getSpecialMethod("Cast.throwClassCastExceptionUnlessNull"); 364 367 JMethodCall call = new JMethodCall(program, x.getSourceInfo(), null, 368 method, program.getTypeNull()); 369 call.getArgs().add(x.getExpr()); 370 replaceExpr = call; 371 } else if (toType instanceof JReferenceType) { 372 JExpression curExpr = x.getExpr(); 373 JReferenceType refType = (JReferenceType) toType; 374 JType argType = x.getExpr().getType(); 375 if (program.isJavaScriptObject(argType)) { 376 383 JMethod wrap = program.getSpecialMethod("Cast.wrapJSO"); 384 JMethodCall call = new JMethodCall(program, x.getSourceInfo(), null, 386 wrap, argType); 387 JClassSeed seed = program.getLiteralClassSeed((JClassType) argType); 388 call.getArgs().add(curExpr); 389 call.getArgs().add(seed); 390 curExpr = call; 391 } 392 if (argType instanceof JClassType 393 && program.typeOracle.canTriviallyCast((JClassType) argType, 394 refType)) { 395 replaceExpr = curExpr; 398 } else { 399 JMethod method = program.getSpecialMethod("Cast.dynamicCast"); 400 JMethodCall call = new JMethodCall(program, x.getSourceInfo(), null, 402 method, toType); 403 Integer boxedInt = (Integer ) queryIds.get(refType); 404 JIntLiteral qId = program.getLiteralInt(boxedInt.intValue()); 405 call.getArgs().add(curExpr); 406 call.getArgs().add(qId); 407 replaceExpr = call; 408 } 409 } else { 410 415 boolean narrow = false, round = false; 416 JPrimitiveType tByte = program.getTypePrimitiveByte(); 417 JPrimitiveType tChar = program.getTypePrimitiveChar(); 418 JPrimitiveType tShort = program.getTypePrimitiveShort(); 419 JPrimitiveType tInt = program.getTypePrimitiveInt(); 420 JPrimitiveType tLong = program.getTypePrimitiveLong(); 421 JPrimitiveType tFloat = program.getTypePrimitiveFloat(); 422 JPrimitiveType tDouble = program.getTypePrimitiveDouble(); 423 JType fromType = x.getExpr().getType(); 424 if (tByte == fromType) { 425 if (tChar == toType) { 426 narrow = true; 427 } 428 } else if (tShort == fromType) { 429 if (tByte == toType || tChar == toType) { 430 narrow = true; 431 } 432 } else if (tChar == fromType) { 433 if (tByte == toType || tShort == toType) { 434 narrow = true; 435 } 436 } else if (tInt == fromType) { 437 if (tByte == toType || tShort == toType || tChar == toType) { 438 narrow = true; 439 } 440 } else if (tLong == fromType) { 441 if (tByte == toType || tShort == toType || tChar == toType 442 || tInt == toType) { 443 narrow = true; 444 } 445 } else if (tFloat == fromType || tDouble == fromType) { 446 if (tByte == toType || tShort == toType || tChar == toType 447 || tInt == toType || tLong == toType) { 448 round = true; 449 } 450 } 451 452 if (narrow || round) { 453 String methodName = "Cast." + (narrow ? "narrow_" : "round_") 455 + toType.getName(); 456 JMethod castMethod = program.getSpecialMethod(methodName); 457 JMethodCall call = new JMethodCall(program, x.getSourceInfo(), null, 458 castMethod); 459 call.getArgs().add(x.getExpr()); 460 replaceExpr = call; 461 } else { 462 replaceExpr = x.getExpr(); 464 } 465 } 466 ctx.replaceMe(replaceExpr); 467 } 468 469 public void endVisit(JInstanceOf x, Context ctx) { 471 JType argType = x.getExpr().getType(); 472 if (argType instanceof JClassType 473 && program.typeOracle.canTriviallyCast((JClassType) argType, 474 x.getTestType())) { 475 JNullLiteral nullLit = program.getLiteralNull(); 477 JBinaryOperation eq = new JBinaryOperation(program, x.getSourceInfo(), 478 program.getTypePrimitiveBoolean(), JBinaryOperator.NEQ, 479 x.getExpr(), nullLit); 480 ctx.replaceMe(eq); 481 } else { 482 JMethod method = program.getSpecialMethod("Cast.instanceOf"); 483 JMethodCall call = new JMethodCall(program, x.getSourceInfo(), null, 484 method); 485 Integer boxedInt = (Integer ) queryIds.get(x.getTestType()); 486 JIntLiteral qId = program.getLiteralInt(boxedInt.intValue()); 487 call.getArgs().add(x.getExpr()); 488 call.getArgs().add(qId); 489 ctx.replaceMe(call); 490 } 491 } 492 } 493 494 public static void exec(JProgram program) { 495 new CastNormalizer(program).execImpl(); 496 } 497 498 private Map queryIds = new IdentityHashMap (); 499 500 private final JProgram program; 501 502 private CastNormalizer(JProgram program) { 503 this.program = program; 504 } 505 506 private void execImpl() { 507 { 508 ConcatVisitor visitor = new ConcatVisitor(); 509 visitor.accept(program); 510 } 511 { 512 DivVisitor visitor = new DivVisitor(); 513 visitor.accept(program); 514 } 515 { 516 AssignTypeIdsVisitor assigner = new AssignTypeIdsVisitor(); 517 assigner.accept(program); 518 assigner.computeTypeIds(); 519 } 520 { 521 ReplaceTypeChecksVisitor replacer = new ReplaceTypeChecksVisitor(); 522 replacer.accept(program); 523 } 524 } 525 526 } 527 | Popular Tags |