1 16 package com.google.gwt.dev.jjs.ast; 17 18 import com.google.gwt.core.ext.TreeLogger; 19 import com.google.gwt.core.ext.UnableToCompleteException; 20 import com.google.gwt.dev.jdt.FindDeferredBindingSitesVisitor; 21 import com.google.gwt.dev.jdt.RebindOracle; 22 import com.google.gwt.dev.jjs.InternalCompilerException; 23 import com.google.gwt.dev.jjs.SourceInfo; 24 import com.google.gwt.dev.jjs.ast.js.JClassSeed; 25 import com.google.gwt.dev.jjs.ast.js.JsniMethod; 26 27 import java.util.ArrayList ; 28 import java.util.Collection ; 29 import java.util.HashMap ; 30 import java.util.IdentityHashMap ; 31 import java.util.Iterator ; 32 import java.util.List ; 33 import java.util.Map ; 34 35 38 public class JProgram extends JNode { 39 40 private static final int IS_ARRAY = 2; 41 private static final int IS_CLASS = 3; 42 private static final int IS_INTERFACE = 1; 43 private static final int IS_NULL = 0; 44 45 public static boolean methodsDoMatch(JMethod method1, JMethod method2) { 46 if (method1.isStatic() || method2.isStatic()) { 48 return false; 49 } 50 51 if (!method1.getName().equals(method2.getName())) { 53 return false; 54 } 55 56 List params1 = method1.getOriginalParamTypes(); 58 List params2 = method2.getOriginalParamTypes(); 59 int params1size = params1.size(); 60 if (params1size != params2.size()) { 61 return false; 62 } 63 64 for (int i = 0; i < params1size; ++i) { 65 if (params1.get(i) != params2.get(i)) { 66 return false; 67 } 68 } 69 return true; 70 } 71 72 private static String dotify(char[][] name) { 73 StringBuffer result = new StringBuffer (); 74 for (int i = 0; i < name.length; ++i) { 75 if (i > 0) { 76 result.append('.'); 77 } 78 79 result.append(name[i]); 80 } 81 return result.toString(); 82 } 83 84 public final List entryMethods = new ArrayList (); 85 86 public final Map jsniMap = new HashMap (); 90 91 public final List specialTypes = new ArrayList (); 92 93 public final JTypeOracle typeOracle = new JTypeOracle(this); 94 95 private final List allArrayTypes = new ArrayList (); 96 97 private final List allTypes = new ArrayList (); 98 99 104 private final ArrayList dimensions = new ArrayList (); 108 109 private final Map instanceToStaticMap = new IdentityHashMap (); 113 114 private List jsonTypeTable; 115 116 private final JAbsentArrayDimension literalAbsentArrayDim = new JAbsentArrayDimension( 117 this); 118 119 private final JBooleanLiteral literalFalse = new JBooleanLiteral(this, false); 120 121 private final JIntLiteral literalIntNegOne = new JIntLiteral(this, -1); 122 123 private final JIntLiteral literalIntOne = new JIntLiteral(this, 1); 124 125 private final JIntLiteral literalIntZero = new JIntLiteral(this, 0); 126 127 private final JNullLiteral literalNull = new JNullLiteral(this); 128 129 private final JBooleanLiteral literalTrue = new JBooleanLiteral(this, true); 130 131 private final TreeLogger logger; 132 133 private JField nullField; 134 135 private JMethod nullMethod; 136 137 private Map queryIds; 138 139 private JMethod rebindCreateMethod; 140 141 private final RebindOracle rebindOracle; 142 143 private final Map specialFields = new HashMap (); 147 148 private final Map specialMethods = new HashMap (); 152 153 private final Map staticToInstanceMap = new IdentityHashMap (); 157 158 private final JPrimitiveType typeBoolean = new JPrimitiveType(this, 159 "boolean", "Z", literalFalse); 160 161 private final JPrimitiveType typeByte = new JPrimitiveType(this, "byte", "B", 162 literalIntZero); 163 164 private final JPrimitiveType typeChar = new JPrimitiveType(this, "char", "C", 165 getLiteralChar((char) 0)); 166 167 private JClassType typeClass; 168 169 private final JPrimitiveType typeDouble = new JPrimitiveType(this, "double", 170 "D", getLiteralDouble(0)); 171 172 private final JPrimitiveType typeFloat = new JPrimitiveType(this, "float", 173 "F", getLiteralFloat(0)); 174 175 private Map typeIdMap = new HashMap (); 179 180 private final JPrimitiveType typeInt = new JPrimitiveType(this, "int", "I", 181 literalIntZero); 182 183 private JClassType typeJavaLangObject; 184 185 private final JPrimitiveType typeLong = new JPrimitiveType(this, "long", "J", 186 getLiteralLong(0)); 187 188 private final Map typeNameMap = new HashMap (); 192 193 private final JNullType typeNull = new JNullType(this); 194 195 private final JPrimitiveType typeShort = new JPrimitiveType(this, "short", 196 "S", literalIntZero); 197 198 private JClassType typeSpecialArray; 199 200 private JClassType typeSpecialCast; 201 202 private JClassType typeSpecialExceptions; 203 204 private JClassType typeSpecialJavaScriptObject; 205 206 private JClassType typeString; 207 208 private final JPrimitiveType typeVoid = new JPrimitiveType(this, "void", "V", 209 null); 210 211 public JProgram(TreeLogger logger, RebindOracle rebindOracle) { 212 super(null, null); 213 this.logger = logger; 214 this.rebindOracle = rebindOracle; 215 } 216 217 public void addEntryMethod(JMethod entryPoint) { 218 if (!entryMethods.contains(entryPoint)) { 219 entryMethods.add(entryPoint); 220 } 221 } 222 223 226 public JExpressionStatement createAssignmentStmt(SourceInfo info, 227 JExpression lhs, JExpression rhs) { 228 JBinaryOperation assign = new JBinaryOperation(this, info, lhs.getType(), 229 JBinaryOperator.ASG, lhs, rhs); 230 return assign.makeStatement(); 231 } 232 233 public JClassType createClass(SourceInfo info, char[][] name, 234 boolean isAbstract, boolean isFinal) { 235 String sname = dotify(name); 236 JClassType x = new JClassType(this, info, sname, isAbstract, isFinal); 237 238 allTypes.add(x); 239 putIntoTypeMap(sname, x); 240 241 if (sname.equals("java.lang.Object")) { 242 typeJavaLangObject = x; 243 specialTypes.add(x); 244 } else if (sname.equals("java.lang.String")) { 245 typeString = x; 246 } else if (sname.equals("java.lang.Class")) { 247 typeClass = x; 248 } else if (sname.equals("com.google.gwt.core.client.JavaScriptObject")) { 249 typeSpecialJavaScriptObject = x; 250 } else if (sname.equals("com.google.gwt.lang.Array")) { 251 typeSpecialArray = x; 252 specialTypes.add(x); 253 } else if (sname.equals("com.google.gwt.lang.Cast")) { 254 typeSpecialCast = x; 255 specialTypes.add(x); 256 } else if (sname.equals("com.google.gwt.lang.Exceptions")) { 257 typeSpecialExceptions = x; 258 specialTypes.add(x); 259 } 260 261 return x; 262 } 263 264 public JField createField(SourceInfo info, char[] name, 265 JReferenceType enclosingType, JType type, boolean isStatic, 266 boolean isFinal, boolean hasInitializer) { 267 assert (name != null); 268 assert (enclosingType != null); 269 assert (type != null); 270 271 275 boolean isSpecialField = specialTypes.contains(enclosingType); 276 277 if (isSpecialField) { 278 hasInitializer = true; 279 } 280 281 String sname = String.valueOf(name); 282 JField x = new JField(this, info, sname, enclosingType, type, isStatic, 283 isFinal, hasInitializer); 284 285 if (isSpecialField) { 286 specialFields.put(enclosingType.getShortName() + '.' + sname, x); 287 } 288 289 enclosingType.fields.add(x); 290 291 return x; 292 } 293 294 public JInterfaceType createInterface(SourceInfo info, char[][] name) { 295 String sname = dotify(name); 296 JInterfaceType x = new JInterfaceType(this, info, sname); 297 298 allTypes.add(x); 299 putIntoTypeMap(sname, x); 300 301 return x; 302 } 303 304 public JLocal createLocal(SourceInfo info, char[] name, JType type, 305 boolean isFinal, JMethod enclosingMethod) { 306 assert (name != null); 307 assert (type != null); 308 assert (enclosingMethod != null); 309 310 JLocal x = new JLocal(this, info, String.valueOf(name), type, isFinal, 311 enclosingMethod); 312 313 enclosingMethod.locals.add(x); 314 315 return x; 316 } 317 318 public JMethod createMethod(SourceInfo info, char[] name, 319 JReferenceType enclosingType, JType returnType, boolean isAbstract, 320 boolean isStatic, boolean isFinal, boolean isPrivate, boolean isNative) { 321 assert (name != null); 322 assert (returnType != null); 323 assert (!isAbstract || !isNative); 324 325 JMethod x; 326 String sname = String.valueOf(name); 327 if (isNative) { 328 x = new JsniMethod(this, info, sname, enclosingType, returnType, 329 isStatic, isFinal, isPrivate); 330 } else { 331 x = new JMethod(this, info, sname, enclosingType, returnType, isAbstract, 332 isStatic, isFinal, isPrivate); 333 } 334 335 if (sname.equals(FindDeferredBindingSitesVisitor.REBIND_MAGIC_METHOD) 336 && enclosingType.getName().equals( 337 FindDeferredBindingSitesVisitor.REBIND_MAGIC_CLASS)) { 338 rebindCreateMethod = x; 339 } else if (!isPrivate && specialTypes.contains(enclosingType)) { 340 specialMethods.put(enclosingType.getShortName() + '.' + sname, x); 341 } 342 343 if (enclosingType != null) { 344 enclosingType.methods.add(x); 345 } 346 347 return x; 348 } 349 350 public JParameter createParameter(SourceInfo info, char[] name, JType type, 351 boolean isFinal, JMethod enclosingMethod) { 352 assert (name != null); 353 assert (type != null); 354 assert (enclosingMethod != null); 355 356 JParameter x = new JParameter(this, info, String.valueOf(name), type, 357 isFinal, enclosingMethod); 358 359 enclosingMethod.params.add(x); 360 361 return x; 362 } 363 364 public JReferenceType generalizeTypes(Collection types) { 365 assert (types != null); 366 assert (!types.isEmpty()); 367 Iterator it = types.iterator(); 368 JReferenceType curType = (JReferenceType) it.next(); 369 while (it.hasNext()) { 370 curType = generalizeTypes(curType, (JReferenceType) it.next()); 371 } 372 return curType; 373 } 374 375 public List getAllArrayTypes() { 376 return allArrayTypes; 377 } 378 379 public List getDeclaredTypes() { 380 return allTypes; 381 } 382 383 public JThisRef getExprThisRef(SourceInfo info, JClassType enclosingType) { 384 return new JThisRef(this, info, enclosingType); 385 } 386 387 public JReferenceType getFromTypeMap(String qualifiedBinaryOrSourceName) { 388 String srcTypeName = qualifiedBinaryOrSourceName.replace('$', '.'); 389 return (JReferenceType) typeNameMap.get(srcTypeName); 390 } 391 392 public List getJsonTypeTable() { 393 return jsonTypeTable; 394 } 395 396 public JAbsentArrayDimension getLiteralAbsentArrayDimension() { 397 return literalAbsentArrayDim; 398 } 399 400 public JBooleanLiteral getLiteralBoolean(boolean z) { 401 return z ? literalTrue : literalFalse; 402 } 403 404 public JCharLiteral getLiteralChar(char c) { 405 return new JCharLiteral(this, c); 407 } 408 409 public JClassLiteral getLiteralClass(JType type) { 410 return new JClassLiteral(this, type); 412 } 413 414 public JClassSeed getLiteralClassSeed(JClassType type) { 415 return new JClassSeed(this, type); 417 } 418 419 public JDoubleLiteral getLiteralDouble(double d) { 420 return new JDoubleLiteral(this, d); 422 } 423 424 public JFloatLiteral getLiteralFloat(float f) { 425 return new JFloatLiteral(this, f); 427 } 428 429 public JIntLiteral getLiteralInt(int i) { 430 switch (i) { 431 case -1: 432 return literalIntNegOne; 433 case 0: 434 return literalIntZero; 435 case 1: 436 return literalIntOne; 437 default: 438 return new JIntLiteral(this, i); 440 } 441 } 442 443 public JLongLiteral getLiteralLong(long l) { 444 return new JLongLiteral(this, l); 445 } 446 447 public JNullLiteral getLiteralNull() { 448 return literalNull; 449 } 450 451 public JStringLiteral getLiteralString(char[] s) { 452 return new JStringLiteral(this, String.valueOf(s)); 454 } 455 456 public JStringLiteral getLiteralString(String s) { 457 return new JStringLiteral(this, s); 459 } 460 461 public JField getNullField() { 462 if (nullField == null) { 463 nullField = new JField(this, null, "nullField", null, typeNull, false, 464 true, true); 465 } 466 return nullField; 467 } 468 469 public JMethod getNullMethod() { 470 if (nullMethod == null) { 471 nullMethod = new JsniMethod(this, null, "nullMethod", null, typeNull, 472 false, true, true); 473 } 474 return nullMethod; 475 } 476 477 public int getQueryId(JReferenceType elementType) { 478 Integer integer = (Integer ) queryIds.get(elementType); 479 if (integer == null) { 480 return 0; 481 } 482 483 return integer.intValue(); 484 } 485 486 public JMethod getRebindCreateMethod() { 487 return rebindCreateMethod; 488 } 489 490 public JClassType getSpecialArray() { 491 return typeSpecialArray; 492 } 493 494 public JClassType getSpecialCast() { 495 return typeSpecialCast; 496 } 497 498 public JClassType getSpecialExceptions() { 499 return typeSpecialExceptions; 500 } 501 502 public JField getSpecialField(String string) { 503 return (JField) specialFields.get(string); 504 } 505 506 public JClassType getSpecialJavaScriptObject() { 507 return typeSpecialJavaScriptObject; 508 } 509 510 public JMethod getSpecialMethod(String string) { 511 return (JMethod) specialMethods.get(string); 512 } 513 514 public JMethod getStaticImpl(JMethod method) { 515 return (JMethod) instanceToStaticMap.get(method); 516 } 517 518 public JArrayType getTypeArray(JType leafType, int dimensions) { 519 HashMap typeToArrayType; 520 521 for (int i = this.dimensions.size(); i < dimensions; ++i) { 524 typeToArrayType = new HashMap (); 525 this.dimensions.add(typeToArrayType); 526 } 527 528 typeToArrayType = (HashMap ) this.dimensions.get(dimensions - 1); 532 533 JArrayType arrayType = (JArrayType) typeToArrayType.get(leafType); 534 if (arrayType == null) { 535 arrayType = new JArrayType(this, leafType, dimensions); 536 arrayType.extnds = typeJavaLangObject; 537 allArrayTypes.add(arrayType); 538 539 545 typeToArrayType.put(leafType, arrayType); 546 } 547 548 return arrayType; 549 } 550 551 public int getTypeId(JClassType classType) { 552 Integer integer = (Integer ) typeIdMap.get(classType); 553 if (integer == null) { 554 return 0; 555 } 556 557 return integer.intValue(); 558 } 559 560 public JClassType getTypeJavaLangClass() { 561 return typeClass; 562 } 563 564 public JClassType getTypeJavaLangObject() { 565 return typeJavaLangObject; 566 } 567 568 public JClassType getTypeJavaLangString() { 569 return typeString; 570 } 571 572 public JNullType getTypeNull() { 573 return typeNull; 574 } 575 576 public JPrimitiveType getTypePrimitiveBoolean() { 577 return typeBoolean; 578 } 579 580 public JPrimitiveType getTypePrimitiveByte() { 581 return typeByte; 582 } 583 584 public JPrimitiveType getTypePrimitiveChar() { 585 return typeChar; 586 } 587 588 public JPrimitiveType getTypePrimitiveDouble() { 589 return typeDouble; 590 } 591 592 public JPrimitiveType getTypePrimitiveFloat() { 593 return typeFloat; 594 } 595 596 public JPrimitiveType getTypePrimitiveInt() { 597 return typeInt; 598 } 599 600 public JPrimitiveType getTypePrimitiveLong() { 601 return typeLong; 602 } 603 604 public JPrimitiveType getTypePrimitiveShort() { 605 return typeShort; 606 } 607 608 public JType getTypeVoid() { 609 return typeVoid; 610 } 611 612 public void initTypeInfo(List classes, 613 List jsonObjects) { 614 for (int i = 0, c = classes.size(); i < c; ++i) { 615 typeIdMap.put(classes.get(i), new Integer (i)); 616 } 617 this.jsonTypeTable = jsonObjects; 618 } 619 620 public boolean isJavaScriptObject(JType type) { 621 if (type instanceof JClassType) { 622 return typeOracle.canTriviallyCast((JClassType) type, 623 typeSpecialJavaScriptObject); 624 } 625 return false; 626 } 627 628 public boolean isStaticImpl(JMethod method) { 629 return staticToInstanceMap.containsKey(method); 630 } 631 632 public void putIntoTypeMap(String qualifiedBinaryName, JReferenceType type) { 633 String srcTypeName = qualifiedBinaryName.replace('$', '.'); 636 typeNameMap.put(srcTypeName, type); 637 } 638 639 public void putStaticImpl(JMethod method, JMethod staticImpl) { 640 instanceToStaticMap.put(method, staticImpl); 641 staticToInstanceMap.put(staticImpl, method); 642 } 643 644 public JClassType rebind(JType type) { 645 JType result = type; 646 String reqType = type.getName().replace('$', '.'); 648 String reboundClassName; 649 try { 650 reboundClassName = rebindOracle.rebind(logger, reqType); 651 } catch (UnableToCompleteException e) { 652 throw new IllegalStateException ("Unexpected failure to rebind '" 656 + reqType + "'"); 657 } 658 if (reboundClassName != null) { 659 result = getFromTypeMap(reboundClassName); 660 } 661 assert (result != null); 662 assert (result instanceof JClassType); 663 return (JClassType) result; 664 } 665 666 public void recordQueryIds(Map queryIds) { 667 this.queryIds = queryIds; 668 } 669 670 675 public JMethod staticImplFor(JMethod method) { 676 return (JMethod) staticToInstanceMap.get(method); 677 } 678 679 public JReferenceType strongerType(JReferenceType type1, JReferenceType type2) { 680 if (type1 == type2) { 681 return type1; 682 } 683 684 if (typeOracle.canTriviallyCast(type1, type2)) { 685 return type1; 686 } 687 688 if (typeOracle.canTriviallyCast(type2, type1)) { 689 return type2; 690 } 691 692 return type1; 695 } 696 697 public void traverse(JVisitor visitor, Context ctx) { 698 if (visitor.visit(this, ctx)) { 699 visitor.accept(entryMethods); 700 visitor.accept(allTypes); 701 } 702 visitor.endVisit(this, ctx); 703 } 704 705 JReferenceType generalizeTypes(JReferenceType type1, JReferenceType type2) { 706 if (type1 == type2) { 707 return type1; 708 } 709 710 int classify1 = classifyType(type1); 711 int classify2 = classifyType(type2); 712 713 if (classify1 == IS_NULL) { 714 return type2; 715 } 716 717 if (classify2 == IS_NULL) { 718 return type1; 719 } 720 721 if (classify1 == classify2) { 722 723 if (classify1 == IS_INTERFACE) { 725 726 if (typeOracle.canTriviallyCast(type1, type2)) { 727 return type2; 728 } 729 730 if (typeOracle.canTriviallyCast(type2, type1)) { 731 return type1; 732 } 733 734 return typeJavaLangObject; 736 737 } else if (classify1 == IS_ARRAY) { 738 739 JArrayType aType1 = (JArrayType) type1; 740 JArrayType aType2 = (JArrayType) type2; 741 int dims1 = aType1.getDims(); 742 int dims2 = aType2.getDims(); 743 744 int minDims = Math.min(dims1, dims2); 745 751 JReferenceType minimalGeneralType; 752 if (minDims > 1) { 753 minimalGeneralType = getTypeArray(typeJavaLangObject, minDims - 1); 754 } else { 755 minimalGeneralType = typeJavaLangObject; 756 } 757 758 if (dims1 == dims2) { 759 760 JType leafType1 = aType1.getLeafType(); 762 JType leafType2 = aType2.getLeafType(); 763 764 if (!(leafType1 instanceof JReferenceType) 765 || !(leafType2 instanceof JReferenceType)) { 766 return minimalGeneralType; 767 } 768 769 775 JReferenceType leafRefType1 = (JReferenceType) leafType1; 776 JReferenceType leafRefType2 = (JReferenceType) leafType2; 777 JReferenceType leafGeneralization = generalizeTypes(leafRefType1, 778 leafRefType2); 779 return getTypeArray(leafGeneralization, dims1); 780 781 } else { 782 783 785 JArrayType lesser = dims1 < dims2 ? aType1 : aType2; 787 if (lesser.getLeafType() == typeJavaLangObject) { 788 return lesser; 789 } 790 791 return minimalGeneralType; 793 } 794 795 } else { 796 797 assert (classify1 == IS_CLASS); 798 799 804 int distance1 = countSuperTypes(type1); 805 int distance2 = countSuperTypes(type2); 806 for (; distance1 > distance2; --distance1) { 807 type1 = type1.extnds; 808 } 809 810 for (; distance1 < distance2; --distance2) { 811 type2 = type2.extnds; 812 } 813 814 while (type1 != type2) { 815 type1 = type1.extnds; 816 type2 = type2.extnds; 817 } 818 819 return type1; 820 } 821 } else { 822 823 int lesser = Math.min(classify1, classify2); 825 int greater = Math.max(classify1, classify2); 826 827 JReferenceType tLesser = classify1 > classify2 ? type1 : type2; 828 JReferenceType tGreater = classify1 < classify2 ? type1 : type2; 829 830 if (lesser == IS_INTERFACE && greater == IS_CLASS) { 831 832 if (typeOracle.canTriviallyCast(tGreater, tLesser)) { 834 return tLesser; 835 } 836 837 return typeJavaLangObject; 839 840 } else { 841 842 return typeJavaLangObject; 845 } 846 } 847 } 848 849 private int classifyType(JReferenceType type) { 850 if (type instanceof JNullType) { 851 return IS_NULL; 852 } else if (type instanceof JInterfaceType) { 853 return IS_INTERFACE; 854 } else if (type instanceof JArrayType) { 855 return IS_ARRAY; 856 } else if (type instanceof JClassType) { 857 return IS_CLASS; 858 } 859 throw new InternalCompilerException("Unknown reference type"); 860 } 861 862 private int countSuperTypes(JReferenceType type) { 863 if (type instanceof JArrayType) { 864 JType leafType = ((JArrayType) type).getLeafType(); 865 if (leafType instanceof JReferenceType) { 866 return countSuperTypes((JReferenceType) leafType) + 1; 868 } else { 869 return 1; 871 } 872 } 873 int count = 0; 874 while ((type = type.extnds) != null) { 875 ++count; 876 } 877 return count; 878 } 879 880 } 881 | Popular Tags |