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.JBinaryOperation; 21 import com.google.gwt.dev.jjs.ast.JBinaryOperator; 22 import com.google.gwt.dev.jjs.ast.JCastOperation; 23 import com.google.gwt.dev.jjs.ast.JClassType; 24 import com.google.gwt.dev.jjs.ast.JExpression; 25 import com.google.gwt.dev.jjs.ast.JField; 26 import com.google.gwt.dev.jjs.ast.JFieldRef; 27 import com.google.gwt.dev.jjs.ast.JInstanceOf; 28 import com.google.gwt.dev.jjs.ast.JInterfaceType; 29 import com.google.gwt.dev.jjs.ast.JLocal; 30 import com.google.gwt.dev.jjs.ast.JLocalDeclarationStatement; 31 import com.google.gwt.dev.jjs.ast.JLocalRef; 32 import com.google.gwt.dev.jjs.ast.JMethod; 33 import com.google.gwt.dev.jjs.ast.JMethodCall; 34 import com.google.gwt.dev.jjs.ast.JModVisitor; 35 import com.google.gwt.dev.jjs.ast.JNullLiteral; 36 import com.google.gwt.dev.jjs.ast.JNullType; 37 import com.google.gwt.dev.jjs.ast.JParameter; 38 import com.google.gwt.dev.jjs.ast.JParameterRef; 39 import com.google.gwt.dev.jjs.ast.JProgram; 40 import com.google.gwt.dev.jjs.ast.JReferenceType; 41 import com.google.gwt.dev.jjs.ast.JReturnStatement; 42 import com.google.gwt.dev.jjs.ast.JTryStatement; 43 import com.google.gwt.dev.jjs.ast.JType; 44 import com.google.gwt.dev.jjs.ast.JTypeOracle; 45 import com.google.gwt.dev.jjs.ast.JVariable; 46 import com.google.gwt.dev.jjs.ast.JVariableRef; 47 import com.google.gwt.dev.jjs.ast.JVisitor; 48 import com.google.gwt.dev.jjs.ast.js.JsniFieldRef; 49 import com.google.gwt.dev.jjs.ast.js.JsniMethod; 50 import com.google.gwt.dev.jjs.ast.js.JsniMethodRef; 51 52 import java.util.ArrayList ; 53 import java.util.HashSet ; 54 import java.util.IdentityHashMap ; 55 import java.util.Iterator ; 56 import java.util.List ; 57 import java.util.Map ; 58 import java.util.Set ; 59 60 90 public class TypeTightener { 91 92 95 public class FixDanglingRefsVisitor extends JModVisitor { 96 97 public void endVisit(JArrayRef x, Context ctx) { 99 JExpression instance = x.getInstance(); 100 if (instance.getType() == typeNull) { 101 if (!instance.hasSideEffects()) { 102 instance = program.getLiteralNull(); 103 } 104 JArrayRef arrayRef = new JArrayRef(program, x.getSourceInfo(), 105 instance, program.getLiteralInt(0)); 106 ctx.replaceMe(arrayRef); 107 } 108 } 109 110 public void endVisit(JFieldRef x, Context ctx) { 112 JExpression instance = x.getInstance(); 113 boolean isStatic = x.getField().isStatic(); 114 if (isStatic && instance != null) { 115 if (!instance.hasSideEffects()) { 118 JFieldRef fieldRef = new JFieldRef(program, x.getSourceInfo(), null, 119 x.getField(), x.getEnclosingType()); 120 ctx.replaceMe(fieldRef); 121 } 122 } else if (!isStatic && instance.getType() == typeNull) { 123 if (!instance.hasSideEffects()) { 124 instance = program.getLiteralNull(); 125 } 126 JFieldRef fieldRef = new JFieldRef(program, x.getSourceInfo(), 127 instance, program.getNullField(), null); 128 ctx.replaceMe(fieldRef); 129 } 130 } 131 132 public void endVisit(JMethodCall x, Context ctx) { 134 JExpression instance = x.getInstance(); 135 JMethod method = x.getTarget(); 136 boolean isStatic = method.isStatic(); 137 boolean isStaticImpl = program.isStaticImpl(method); 138 if (isStatic && !isStaticImpl && instance != null) { 139 if (!instance.hasSideEffects()) { 142 JMethodCall newCall = new JMethodCall(program, x.getSourceInfo(), 143 null, x.getTarget()); 144 newCall.getArgs().addAll(x.getArgs()); 145 ctx.replaceMe(newCall); 146 } 147 } else if (!isStatic && instance.getType() == typeNull) { 148 if (!instance.hasSideEffects()) { 150 instance = program.getLiteralNull(); 151 } 152 JMethodCall newCall = new JMethodCall(program, x.getSourceInfo(), 153 instance, program.getNullMethod()); 154 ctx.replaceMe(newCall); 155 } else if (isStaticImpl && x.getArgs().size() > 0 156 && ((JExpression) x.getArgs().get(0)).getType() == typeNull) { 157 instance = (JExpression) x.getArgs().get(0); 159 if (!instance.hasSideEffects()) { 160 instance = program.getLiteralNull(); 161 } 162 JMethodCall newCall = new JMethodCall(program, x.getSourceInfo(), 163 instance, program.getNullMethod()); 164 ctx.replaceMe(newCall); 165 } 166 } 167 } 168 169 183 public class RecordVisitor extends JVisitor { 184 185 private JMethod currentMethod; 186 187 public void endVisit(JBinaryOperation x, Context ctx) { 189 if (x.isAssignment() && (x.getType() instanceof JReferenceType)) { 190 JExpression lhs = x.getLhs(); 191 if (lhs instanceof JVariableRef) { 192 addAssignment(((JVariableRef) lhs).getTarget(), x.getRhs()); 193 } 194 } 195 } 196 197 public void endVisit(JClassType x, Context ctx) { 199 for (JClassType cur = x; cur != null; cur = cur.extnds) { 200 addImplementor(cur, x); 201 for (Iterator it = cur.implments.iterator(); it.hasNext();) { 202 JInterfaceType implment = (JInterfaceType) it.next(); 203 addImplementor(implment, x); 204 } 205 } 206 } 207 208 public void endVisit(JField x, Context ctx) { 210 if (x.constInitializer != null) { 211 addAssignment(x, x.constInitializer); 212 } 213 currentMethod = null; 214 } 215 216 public void endVisit(JLocalDeclarationStatement x, Context ctx) { 218 JExpression initializer = x.getInitializer(); 219 if (initializer != null) { 220 addAssignment(x.getLocalRef().getTarget(), initializer); 221 } 222 } 223 224 public void endVisit(JMethod x, Context ctx) { 226 for (int i = 0; i < x.overrides.size(); ++i) { 227 JMethod method = (JMethod) x.overrides.get(i); 228 addOverrider(method, x); 229 } 230 JMethod[] allVirtualOverrides = program.typeOracle.getAllVirtualOverrides(x); 231 for (int i = 0; i < allVirtualOverrides.length; ++i) { 232 JMethod method = allVirtualOverrides[i]; 233 addOverrider(method, x); 234 } 235 currentMethod = null; 236 } 237 238 public void endVisit(JMethodCall x, Context ctx) { 240 Iterator argIt = x.getArgs().iterator(); 243 ArrayList params = x.getTarget().params; 244 for (int i = 0; i < params.size(); ++i) { 245 JParameter param = (JParameter) params.get(i); 246 JExpression arg = (JExpression) argIt.next(); 247 if (param.getType() instanceof JReferenceType) { 248 addAssignment(param, arg); 249 } 250 } 251 } 252 253 public void endVisit(JReturnStatement x, Context ctx) { 255 if (currentMethod.getType() instanceof JReferenceType) { 256 addReturn(currentMethod, x.getExpr()); 257 } 258 } 259 260 public void endVisit(JsniFieldRef x, Context ctx) { 262 addAssignment(x.getTarget(), x); 265 } 266 267 public void endVisit(JsniMethod x, Context ctx) { 269 endVisit((JMethod) x, ctx); 270 } 271 272 public void endVisit(JsniMethodRef x, Context ctx) { 274 277 JMethod method = x.getTarget(); 278 279 for (int i = 0; i < method.params.size(); ++i) { 280 JParameter param = (JParameter) method.params.get(i); 281 addAssignment(param, new JParameterRef(program, null, param)); 282 } 283 } 284 285 public void endVisit(JTryStatement x, Context ctx) { 287 for (int i = 0; i < x.getCatchArgs().size(); ++i) { 290 JLocalRef arg = (JLocalRef) x.getCatchArgs().get(i); 291 addAssignment(arg.getTarget(), arg); 292 } 293 } 294 295 299 public boolean visit(JMethod x, Context ctx) { 301 currentMethod = x; 302 303 List overrides = x.overrides; 304 JMethod[] virtualOverrides = program.typeOracle.getAllVirtualOverrides(x); 305 306 316 JMethod staticImplFor = program.staticImplFor(x); 317 if (staticImplFor != null 319 && !staticImplFor.getEnclosingType().methods.contains(staticImplFor)) { 320 staticImplFor = null; 321 } 322 323 if (overrides.isEmpty() && virtualOverrides.length == 0 324 && staticImplFor == null) { 325 return true; 326 } 327 328 for (int j = 0, c = x.params.size(); j < c; ++j) { 329 JParameter param = (JParameter) x.params.get(j); 330 Set set = (Set ) paramUpRefs.get(param); 331 if (set == null) { 332 set = new HashSet (); 333 paramUpRefs.put(param, set); 334 } 335 for (int i = 0; i < overrides.size(); ++i) { 336 JMethod baseMethod = (JMethod) overrides.get(i); 337 JParameter baseParam = (JParameter) baseMethod.params.get(j); 338 set.add(baseParam); 339 } 340 for (int i = 0; i < virtualOverrides.length; ++i) { 341 JMethod baseMethod = virtualOverrides[i]; 342 JParameter baseParam = (JParameter) baseMethod.params.get(j); 343 set.add(baseParam); 344 } 345 if (staticImplFor != null && j > 1) { 346 JParameter baseParam = (JParameter) staticImplFor.params.get(j - 1); 348 set.add(baseParam); 349 } 350 } 351 352 return true; 353 } 354 355 private void addAssignment(JVariable target, JExpression rhs) { 356 add(target, rhs, assignments); 357 } 358 359 private void addImplementor(JReferenceType target, JClassType implementor) { 360 add(target, implementor, implementors); 361 } 362 363 private void addOverrider(JMethod target, JMethod overrider) { 364 add(target, overrider, overriders); 365 } 366 367 private void addReturn(JMethod target, JExpression expr) { 368 add(target, expr, returns); 369 } 370 } 371 372 379 public class TightenTypesVisitor extends JModVisitor { 380 381 385 private boolean myDidChange = false; 386 387 public boolean didChange() { 388 return myDidChange || super.didChange(); 389 } 390 391 public void endVisit(JCastOperation x, Context ctx) { 392 JType argType = x.getExpr().getType(); 393 if (!(x.getCastType() instanceof JReferenceType) 394 || !(argType instanceof JReferenceType)) { 395 return; 396 } 397 398 JReferenceType toType = (JReferenceType) x.getCastType(); 399 JReferenceType fromType = (JReferenceType) argType; 400 401 boolean triviallyTrue = false; 402 boolean triviallyFalse = false; 403 404 JTypeOracle typeOracle = program.typeOracle; 405 if (typeOracle.canTriviallyCast(fromType, toType)) { 406 triviallyTrue = true; 407 } else if (!typeOracle.isInstantiatedType(toType)) { 408 triviallyFalse = true; 409 } else if (!typeOracle.canTheoreticallyCast(fromType, toType)) { 410 triviallyFalse = true; 411 } 412 413 if (triviallyTrue) { 414 ctx.replaceMe(x.getExpr()); 416 } else if (triviallyFalse) { 417 JCastOperation newOp = new JCastOperation(program, x.getSourceInfo(), 419 program.getTypeNull(), x.getExpr()); 420 ctx.replaceMe(newOp); 421 } 422 } 423 424 public void endVisit(JField x, Context ctx) { 426 tighten(x); 427 } 428 429 public void endVisit(JInstanceOf x, Context ctx) { 431 JType argType = x.getExpr().getType(); 432 if (!(argType instanceof JReferenceType)) { 433 return; 435 } 436 437 JReferenceType toType = x.getTestType(); 438 JReferenceType fromType = (JReferenceType) argType; 439 440 boolean triviallyTrue = false; 441 boolean triviallyFalse = false; 442 443 JTypeOracle typeOracle = program.typeOracle; 444 if (fromType == program.getTypeNull()) { 445 triviallyFalse = true; 447 } else if (typeOracle.canTriviallyCast(fromType, toType)) { 448 triviallyTrue = true; 449 } else if (!typeOracle.isInstantiatedType(toType)) { 450 triviallyFalse = true; 451 } else if (!typeOracle.canTheoreticallyCast(fromType, toType)) { 452 triviallyFalse = true; 453 } 454 455 if (triviallyTrue) { 456 JNullLiteral nullLit = program.getLiteralNull(); 458 JBinaryOperation neq = new JBinaryOperation(program, x.getSourceInfo(), 459 program.getTypePrimitiveBoolean(), JBinaryOperator.NEQ, 460 x.getExpr(), nullLit); 461 ctx.replaceMe(neq); 462 } else if (triviallyFalse) { 463 ctx.replaceMe(program.getLiteralBoolean(false)); 465 } 466 } 467 468 public void endVisit(JLocal x, Context ctx) { 470 tighten(x); 471 } 472 473 476 public void endVisit(JMethod x, Context ctx) { 478 479 if (!(x.getType() instanceof JReferenceType)) { 480 return; 481 } 482 JReferenceType refType = (JReferenceType) x.getType(); 483 484 if (refType == typeNull) { 485 return; 486 } 487 488 if (!program.typeOracle.isInstantiatedType(refType)) { 490 x.setType(typeNull); 491 myDidChange = true; 492 return; 493 } 494 495 List typeList = new ArrayList (); 497 498 503 typeList.add(typeNull); 504 505 Set myReturns = (Set ) returns.get(x); 506 if (myReturns != null) { 507 for (Iterator iter = myReturns.iterator(); iter.hasNext();) { 508 JExpression expr = (JExpression) iter.next(); 509 typeList.add(expr.getType()); 510 } 511 } 512 Set myOverriders = (Set ) overriders.get(x); 513 if (myOverriders != null) { 514 for (Iterator iter = myOverriders.iterator(); iter.hasNext();) { 515 JMethod method = (JMethod) iter.next(); 516 typeList.add(method.getType()); 517 } 518 } 519 520 JReferenceType resultType = program.generalizeTypes(typeList); 521 resultType = program.strongerType(refType, resultType); 522 if (refType != resultType) { 523 x.setType(resultType); 524 myDidChange = true; 525 } 526 } 527 528 public void endVisit(JParameter x, Context ctx) { 530 tighten(x); 531 } 532 533 public boolean visit(JClassType x, Context ctx) { 535 if (program.specialTypes.contains(x)) { 537 return false; 538 } 539 return true; 540 } 541 542 public boolean visit(JsniMethod x, Context ctx) { 543 549 return false; 550 } 551 552 555 private void tighten(JVariable x) { 556 if (!(x.getType() instanceof JReferenceType)) { 557 return; 558 } 559 JReferenceType refType = (JReferenceType) x.getType(); 560 561 if (refType == typeNull) { 562 return; 563 } 564 565 if (!program.typeOracle.isInstantiatedType(refType)) { 567 x.setType(typeNull); 568 myDidChange = true; 569 return; 570 } 571 572 List typeList = new ArrayList (); 574 575 584 if (!(x instanceof JParameter)) { 585 typeList.add(typeNull); 586 } 587 588 Set myAssignments = (Set ) assignments.get(x); 589 if (myAssignments != null) { 590 for (Iterator iter = myAssignments.iterator(); iter.hasNext();) { 591 JExpression expr = (JExpression) iter.next(); 592 JType type = expr.getType(); 593 if (!(type instanceof JReferenceType)) { 594 return; } 596 typeList.add(type); 597 } 598 } 599 600 if (x instanceof JParameter) { 601 Set myParams = (Set ) paramUpRefs.get(x); 602 if (myParams != null) { 603 for (Iterator iter = myParams.iterator(); iter.hasNext();) { 604 JParameter param = (JParameter) iter.next(); 605 typeList.add(param.getType()); 606 } 607 } 608 } 609 610 if (typeList.isEmpty()) { 611 return; 612 } 613 614 JReferenceType resultType = program.generalizeTypes(typeList); 615 resultType = program.strongerType(refType, resultType); 616 if (refType != resultType) { 617 x.setType(resultType); 618 myDidChange = true; 619 } 620 } 621 } 622 623 public static boolean exec(JProgram program) { 624 return new TypeTightener(program).execImpl(); 625 } 626 627 private staticvoid add(Object target, Object value, 628 Map map) { 629 Set set = (Set ) map.get(target); 630 if (set == null) { 631 set = new HashSet (); 632 map.put(target, set); 633 } 634 set.add(value); 635 } 636 637 private final Map assignments = new IdentityHashMap (); 638 private final Map implementors = new IdentityHashMap (); 639 private final Map overriders = new IdentityHashMap (); 640 private final Map paramUpRefs = new IdentityHashMap (); 641 private final JProgram program; 642 private final Map returns = new IdentityHashMap (); 643 private final JNullType typeNull; 644 645 private TypeTightener(JProgram program) { 646 this.program = program; 647 typeNull = program.getTypeNull(); 648 } 649 650 private boolean execImpl() { 651 RecordVisitor recorder = new RecordVisitor(); 652 recorder.accept(program); 653 654 659 boolean madeChanges = false; 660 while (true) { 661 TightenTypesVisitor tightener = new TightenTypesVisitor(); 662 tightener.accept(program); 663 if (!tightener.didChange()) { 664 break; 665 } 666 madeChanges = true; 667 668 FixDanglingRefsVisitor fixer = new FixDanglingRefsVisitor(); 669 fixer.accept(program); 670 } 671 return madeChanges; 672 } 673 674 } 675 | Popular Tags |