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.JAbsentArrayDimension; 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.JClassLiteral; 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.JField; 27 import com.google.gwt.dev.jjs.ast.JFieldRef; 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.JLocalRef; 31 import com.google.gwt.dev.jjs.ast.JMethod; 32 import com.google.gwt.dev.jjs.ast.JMethodCall; 33 import com.google.gwt.dev.jjs.ast.JModVisitor; 34 import com.google.gwt.dev.jjs.ast.JNewArray; 35 import com.google.gwt.dev.jjs.ast.JNewInstance; 36 import com.google.gwt.dev.jjs.ast.JParameter; 37 import com.google.gwt.dev.jjs.ast.JParameterRef; 38 import com.google.gwt.dev.jjs.ast.JPrimitiveType; 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.JStringLiteral; 42 import com.google.gwt.dev.jjs.ast.JThisRef; 43 import com.google.gwt.dev.jjs.ast.JType; 44 import com.google.gwt.dev.jjs.ast.JVariable; 45 import com.google.gwt.dev.jjs.ast.JVariableRef; 46 import com.google.gwt.dev.jjs.ast.JVisitor; 47 import com.google.gwt.dev.jjs.ast.js.JsniFieldRef; 48 import com.google.gwt.dev.jjs.ast.js.JsniMethod; 49 import com.google.gwt.dev.jjs.ast.js.JsniMethodRef; 50 51 import java.util.ArrayList ; 52 import java.util.HashSet ; 53 import java.util.Iterator ; 54 import java.util.List ; 55 import java.util.Set ; 56 57 73 public class Pruner { 74 75 80 private class CleanupRefsVisitor extends JModVisitor { 81 82 public void endVisit(JBinaryOperation x, Context ctx) { 83 if (x.getOp() == JBinaryOperator.ASG) { 85 JExpression lhs = x.getLhs(); 86 if (lhs.hasSideEffects()) { 87 return; 88 } 89 if (lhs instanceof JFieldRef || lhs instanceof JLocalRef) { 90 JVariable var = ((JVariableRef) lhs).getTarget(); 91 if (!referencedNonTypes.contains(var)) { 92 ctx.replaceMe(x.getRhs()); 94 } 95 } 96 } 97 } 98 } 99 100 104 private class PruneVisitor extends JVisitor { 105 106 private boolean didChange = false; 107 108 public boolean didChange() { 109 return didChange; 110 } 111 112 public boolean visit(JClassType type, Context ctx) { 114 115 assert (referencedTypes.contains(type)); 116 boolean isInstantiated = program.typeOracle.isInstantiatedType(type); 117 118 for (Iterator it = type.fields.iterator(); it.hasNext();) { 119 JField field = (JField) it.next(); 120 if (!referencedNonTypes.contains(field) 121 || pruneViaNoninstantiability(isInstantiated, field)) { 122 it.remove(); 123 didChange = true; 124 } 125 } 126 127 for (Iterator it = type.methods.iterator(); it.hasNext();) { 128 JMethod method = (JMethod) it.next(); 129 if (!methodIsReferenced(method) 130 || pruneViaNoninstantiability(isInstantiated, method)) { 131 it.remove(); 132 didChange = true; 133 } else { 134 accept(method); 135 } 136 } 137 138 return false; 139 } 140 141 public boolean visit(JInterfaceType type, Context ctx) { 143 boolean isReferenced = referencedTypes.contains(type); 144 boolean isInstantiated = program.typeOracle.isInstantiatedType(type); 145 146 for (Iterator it = type.fields.iterator(); it.hasNext();) { 147 JField field = (JField) it.next(); 148 if (!isReferenced || !referencedNonTypes.contains(field)) { 150 it.remove(); 151 didChange = true; 152 } 153 } 154 155 Iterator it = type.methods.iterator(); 156 if (it.hasNext()) { 157 it.next(); 159 } 160 while (it.hasNext()) { 161 JMethod method = (JMethod) it.next(); 162 if (!isInstantiated || !methodIsReferenced(method)) { 164 it.remove(); 165 didChange = true; 166 } 167 } 168 169 return false; 170 } 171 172 public boolean visit(JMethod method, Context ctx) { 173 for (Iterator it = method.locals.iterator(); it.hasNext();) { 174 JLocal local = (JLocal) it.next(); 175 if (!referencedNonTypes.contains(local)) { 176 it.remove(); 177 didChange = true; 178 } 179 } 180 return false; 181 } 182 183 public boolean visit(JProgram program, Context ctx) { 185 for (Iterator it = program.getDeclaredTypes().iterator(); it.hasNext(); ) { 186 JReferenceType type = (JReferenceType) it.next(); 187 if (referencedTypes.contains(type) 188 || program.typeOracle.isInstantiatedType(type)) { 189 accept(type); 190 } else { 191 it.remove(); 192 didChange = true; 193 } 194 } 195 return false; 196 } 197 198 201 private boolean methodIsReferenced(JMethod method) { 202 if (referencedNonTypes.contains(method)) { 204 return true; 205 } 206 207 214 JMethod staticImplFor = program.staticImplFor(method); 215 if (staticImplFor != null && referencedNonTypes.contains(staticImplFor)) { 216 if (noSpecialTypes) { 217 return true; 218 } 219 } 220 return false; 221 } 222 223 private boolean pruneViaNoninstantiability(boolean isInstantiated, JField it) { 224 return (!isInstantiated && !it.isStatic()); 225 } 226 227 private boolean pruneViaNoninstantiability(boolean isInstantiated, 228 JMethod it) { 229 return (!isInstantiated && (!it.isStatic() || program.isStaticImpl(it))); 230 } 231 } 232 233 240 private class RescueVisitor extends JVisitor { 241 242 private final Set instantiatedTypes = new HashSet (); 243 244 public void commitInstantiatedTypes() { 245 program.typeOracle.setInstantiatedTypes(instantiatedTypes); 246 } 247 248 public boolean visit(JArrayType type, Context ctx) { 250 assert (referencedTypes.contains(type)); 251 boolean isInstantiated = instantiatedTypes.contains(type); 252 253 JType leafType = type.getLeafType(); 254 int dims = type.getDims(); 255 256 if (leafType instanceof JReferenceType) { 258 JReferenceType rLeafType = (JReferenceType) leafType; 259 if (rLeafType.extnds != null) { 260 JArrayType superArray = program.getTypeArray(rLeafType.extnds, dims); 261 rescue(superArray, true, isInstantiated); 262 } 263 264 for (int i = 0; i < rLeafType.implments.size(); ++i) { 265 JInterfaceType intfType = (JInterfaceType) rLeafType.implments.get(i); 266 JArrayType intfArray = program.getTypeArray(intfType, dims); 267 rescue(intfArray, true, isInstantiated); 268 } 269 } 270 271 return false; 272 } 273 274 public boolean visit(JBinaryOperation x, Context ctx) { 275 if (x.getOp() == JBinaryOperator.ADD 277 && x.getType() == program.getTypeJavaLangString()) { 278 rescueByConcat(x.getLhs().getType()); 279 rescueByConcat(x.getRhs().getType()); 280 } else if (x.getOp() == JBinaryOperator.ASG) { 281 boolean doSkip = false; 283 JExpression lhs = x.getLhs(); 284 if (lhs.hasSideEffects()) { 285 } else if (lhs instanceof JLocalRef) { 287 doSkip = true; 289 } else if (lhs instanceof JFieldRef) { 290 JFieldRef fieldRef = (JFieldRef) lhs; 291 298 JExpression instance = fieldRef.getInstance(); 299 if (fieldRef.getField().isStatic()) { 300 doSkip = true; 302 } else if (instance instanceof JThisRef) { 303 doSkip = true; 305 } else if (instance instanceof JParameterRef) { 306 JParameter param = ((JParameterRef) instance).getParameter(); 307 JMethod enclosingMethod = param.getEnclosingMethod(); 308 if (program.isStaticImpl(enclosingMethod) 309 && enclosingMethod.params.get(0) == param) { 310 doSkip = true; 311 } 312 } 313 } 314 315 if (doSkip) { 316 accept(x.getRhs()); 317 return false; 318 } 319 } 320 return true; 321 } 322 323 public boolean visit(JClassLiteral literal, Context ctx) { 325 rescue(program.getTypeJavaLangClass(), true, true); 328 return true; 329 } 330 331 public boolean visit(JClassType type, Context ctx) { 333 assert (referencedTypes.contains(type)); 334 boolean isInstantiated = instantiatedTypes.contains(type); 335 336 341 if (noSpecialTypes && program.specialTypes.contains(type)) { 342 for (int i = 0; i < type.methods.size(); ++i) { 343 JMethod it = (JMethod) type.methods.get(i); 344 rescue(it); 345 } 346 } 347 348 rescue(type.extnds, true, isInstantiated); 350 351 rescue((JMethod) type.methods.get(0)); 353 354 for (int i = 0; i < type.implments.size(); ++i) { 357 JInterfaceType intfType = (JInterfaceType) type.implments.get(i); 358 rescue(intfType, false, isInstantiated); 359 } 360 361 return false; 362 } 363 364 public boolean visit(JFieldRef ref, Context ctx) { 366 JField target = ref.getField(); 367 368 if (target.isStatic()) { 373 rescue(target.getEnclosingType(), true, false); 374 } 375 rescue(target); 376 return true; 377 } 378 379 public boolean visit(JInterfaceType type, Context ctx) { 381 boolean isReferenced = referencedTypes.contains(type); 382 boolean isInstantiated = instantiatedTypes.contains(type); 383 assert (isReferenced || isInstantiated); 384 385 rescue((JMethod) type.methods.get(0)); 387 388 if (isInstantiated) { 391 for (int i = 0; i < type.implments.size(); ++i) { 392 JInterfaceType intfType = (JInterfaceType) type.implments.get(i); 393 rescue(intfType, false, true); 394 } 395 } 396 397 for (int i = 0; i < type.fields.size(); ++i) { 399 JField it = (JField) type.fields.get(i); 400 accept(it); 401 } 402 403 return false; 404 } 405 406 public boolean visit(JLocalRef ref, Context ctx) { 408 JLocal target = ref.getLocal(); 409 rescue(target); 410 return true; 411 } 412 413 public boolean visit(JMethodCall call, Context ctx) { 415 JMethod target = call.getTarget(); 416 if (target.isStatic()) { 418 rescue(target.getEnclosingType(), true, false); 419 } 420 rescue(target); 421 return true; 422 } 423 424 public boolean visit(JNewArray newArray, Context ctx) { 426 JArrayType arrayType = newArray.getArrayType(); 428 if (newArray.dims != null) { 429 int nDims = arrayType.getDims(); 431 JType leafType = arrayType.getLeafType(); 432 assert (newArray.dims.size() == nDims); 433 for (int i = 0; i < nDims; ++i) { 434 if (newArray.dims.get(i) instanceof JAbsentArrayDimension) { 435 break; 436 } 437 rescue(program.getTypeArray(leafType, nDims - i), true, true); 438 } 439 } else { 440 rescue(arrayType, true, true); 442 } 443 444 rescue(program.getSpecialArray(), true, true); 446 return true; 447 } 448 449 public boolean visit(JNewInstance newInstance, Context ctx) { 451 rescue(newInstance.getClassType(), true, true); 453 return true; 454 } 455 456 public boolean visit(JsniFieldRef x, Context ctx) { 458 465 maybeRescueJavaScriptObjectPassingIntoJava(x.getField().getType()); 466 return visit((JFieldRef) x, ctx); 468 } 469 470 public boolean visit(JsniMethodRef x, Context ctx) { 472 476 ArrayList params = x.getTarget().params; 477 for (int i = 0, c = params.size(); i < c; ++i) { 478 JParameter param = (JParameter) params.get(i); 479 maybeRescueJavaScriptObjectPassingIntoJava(param.getType()); 480 } 481 return visit((JMethodCall) x, ctx); 483 } 484 485 public boolean visit(JStringLiteral literal, Context ctx) { 487 rescue(program.getTypeJavaLangString(), true, true); 489 return true; 490 } 491 492 502 private void maybeRescueJavaScriptObjectPassingIntoJava(JType type) { 503 if (type instanceof JReferenceType) { 504 JReferenceType refType = (JReferenceType) type; 505 if (program.typeOracle.canTriviallyCast(refType, 506 program.getSpecialJavaScriptObject())) { 507 rescue(refType, true, true); 508 } 509 } 510 } 511 512 private boolean rescue(JMethod method) { 513 if (method != null) { 514 if (!referencedNonTypes.contains(method)) { 515 referencedNonTypes.add(method); 516 accept(method); 517 if (method instanceof JsniMethod) { 518 522 maybeRescueJavaScriptObjectPassingIntoJava(method.getType()); 523 } 524 return true; 525 } 526 } 527 return false; 528 } 529 530 private void rescue(JReferenceType type, boolean isReferenced, 531 boolean isInstantiated) { 532 if (type != null) { 533 534 boolean doVisit = false; 535 if (isInstantiated && !instantiatedTypes.contains(type)) { 536 instantiatedTypes.add(type); 537 doVisit = true; 538 } 539 540 if (isReferenced && !referencedTypes.contains(type)) { 541 referencedTypes.add(type); 542 doVisit = true; 543 } 544 545 if (doVisit) { 546 accept(type); 547 } 548 } 549 } 550 551 private void rescue(JVariable var) { 552 if (var != null) { 553 if (!referencedNonTypes.contains(var)) { 554 referencedNonTypes.add(var); 555 } 556 } 557 } 558 559 562 private void rescueByConcat(JType type) { 563 JClassType stringType = program.getTypeJavaLangString(); 564 JPrimitiveType charType = program.getTypePrimitiveChar(); 565 if (type instanceof JReferenceType && type != stringType) { 566 570 JMethod toStringMethod = program.getSpecialMethod("Object.toString"); 571 rescue(toStringMethod); 572 } else if (type == charType) { 573 576 if (stringValueOfChar == null) { 577 for (int i = 0; i < stringType.methods.size(); ++i) { 578 JMethod meth = (JMethod) stringType.methods.get(i); 579 if (meth.getName().equals("valueOf")) { 580 List params = meth.getOriginalParamTypes(); 581 if (params.size() == 1) { 582 if (params.get(0) == charType) { 583 stringValueOfChar = meth; 584 break; 585 } 586 } 587 } 588 } 589 assert (stringValueOfChar != null); 590 } 591 rescue(stringValueOfChar); 592 } 593 } 594 } 595 596 600 private class UpRefVisitor extends JVisitor { 601 602 private boolean didRescue = false; 603 private final RescueVisitor rescuer; 604 605 public UpRefVisitor(RescueVisitor rescuer) { 606 this.rescuer = rescuer; 607 } 608 609 public boolean didRescue() { 610 return didRescue; 611 } 612 613 public boolean visit(JMethod x, Context ctx) { 615 if (referencedNonTypes.contains(x)) { 616 return false; 617 } 618 619 for (int i = 0; i < x.overrides.size(); ++i) { 620 JMethod ref = (JMethod) x.overrides.get(i); 621 if (referencedNonTypes.contains(ref)) { 622 rescuer.rescue(x); 623 didRescue = true; 624 return false; 625 } 626 } 627 JMethod[] virtualOverrides = program.typeOracle.getAllVirtualOverrides(x); 628 for (int i = 0; i < virtualOverrides.length; ++i) { 629 JMethod ref = virtualOverrides[i]; 630 if (referencedNonTypes.contains(ref)) { 631 rescuer.rescue(x); 632 didRescue = true; 633 return false; 634 } 635 } 636 return false; 637 } 638 639 public boolean visit(JProgram x, Context ctx) { 641 didRescue = false; 642 return true; 643 } 644 645 public boolean visit(JsniMethod x, Context ctx) { 647 return visit((JMethod) x, ctx); 648 } 649 } 650 651 public static boolean exec(JProgram program, boolean noSpecialTypes) { 652 return new Pruner(program, noSpecialTypes).execImpl(); 653 } 654 655 private final boolean noSpecialTypes; 656 private final JProgram program; 657 private final Set referencedNonTypes = new HashSet (); 658 private final Set referencedTypes = new HashSet (); 659 private JMethod stringValueOfChar = null; 660 661 private Pruner(JProgram program, boolean noSpecialTypes) { 662 this.program = program; 663 this.noSpecialTypes = noSpecialTypes; 664 } 665 666 private boolean execImpl() { 667 boolean madeChanges = false; 668 while (true) { 669 RescueVisitor rescuer = new RescueVisitor(); 670 for (int i = 0; i < program.specialTypes.size(); ++i) { 671 JReferenceType type = (JReferenceType) program.specialTypes.get(i); 672 rescuer.rescue(type, true, noSpecialTypes); 673 } 674 for (int i = 0; i < program.entryMethods.size(); ++i) { 675 JMethod method = (JMethod) program.entryMethods.get(i); 676 rescuer.rescue(method); 677 } 678 679 UpRefVisitor upRefer = new UpRefVisitor(rescuer); 680 do { 681 rescuer.commitInstantiatedTypes(); 682 upRefer.accept(program); 683 } while (upRefer.didRescue()); 684 685 PruneVisitor pruner = new PruneVisitor(); 686 pruner.accept(program); 687 if (!pruner.didChange()) { 688 break; 689 } 690 691 CleanupRefsVisitor cleaner = new CleanupRefsVisitor(); 692 cleaner.accept(program); 693 694 referencedTypes.clear(); 695 referencedNonTypes.clear(); 696 madeChanges = true; 697 } 698 return madeChanges; 699 } 700 701 } 702 | Popular Tags |