1 package polyglot.types.reflect; 2 3 import polyglot.main.Report; 4 import polyglot.types.*; 5 import polyglot.util.*; 6 import java.io.*; 7 import java.util.*; 8 9 23 public class ClassFile implements LazyClassInitializer { 24 Constant[] constants; int modifiers; int thisClass; 27 int superClass; 28 int[] interfaces; 29 Field[] fields; 30 Method[] methods; 31 Attribute[] attrs; 32 InnerClasses innerClasses; 33 File classFileSource; 34 35 static Collection verbose = ClassFileLoader.verbose; 36 37 43 public ClassFile(File classFileSource, byte[] code) { 44 this.classFileSource = classFileSource; 45 46 try { 47 ByteArrayInputStream bin = new ByteArrayInputStream(code); 48 DataInputStream in = new DataInputStream(bin); 49 read(in); 50 in.close(); 51 bin.close(); 52 } 53 catch (IOException e) { 54 throw new InternalCompilerError("I/O exception on ByteArrayInputStream"); 55 } 56 } 57 58 public boolean fromClassFile() { 59 return true; 60 } 61 62 JLCInfo getJLCInfo(String ts) { 63 JLCInfo jlc = (JLCInfo) jlcInfo.get(ts); 65 66 if (jlc != null) { 67 return jlc; 68 } 69 70 jlc = new JLCInfo(); 71 jlcInfo.put(ts, jlc); 72 73 try { 74 int mask = 0; 75 76 for (int i = 0; i < fields.length; i++) { 77 if (fields[i].name().equals("jlc$SourceLastModified$" + ts)) { 78 jlc.sourceLastModified = fields[i].getLong(); 79 mask |= 1; 80 } 81 else if (fields[i].name().equals("jlc$CompilerVersion$" + ts)) { 82 jlc.compilerVersion = fields[i].getString(); 83 mask |= 2; 84 } 85 else if (fields[i].name().equals("jlc$ClassType$" + ts)) { 86 jlc.encodedClassType = fields[i].getString(); 87 mask |= 4; 88 } 89 } 90 91 if (mask != 7) { 92 jlc.sourceLastModified = 0; 94 jlc.compilerVersion = null; 95 jlc.encodedClassType = null; 96 } 97 } 98 catch (SemanticException e) { 99 jlc.sourceLastModified = 0; 100 jlc.compilerVersion = null; 101 jlc.encodedClassType = null; 102 } 103 104 return jlc; 105 } 106 107 110 public long sourceLastModified(String ts) { 111 JLCInfo jlc = getJLCInfo(ts); 112 return jlc.sourceLastModified; 113 } 114 115 public long rawSourceLastModified() { 116 return classFileSource.lastModified(); 117 } 118 119 122 public String compilerVersion(String ts) { 123 JLCInfo jlc = getJLCInfo(ts); 124 return jlc.compilerVersion; 125 } 126 127 130 public String encodedClassType(String ts) { 131 JLCInfo jlc = getJLCInfo(ts); 132 return jlc.encodedClassType; 133 } 134 135 Map jlcInfo = new HashMap(); 136 137 140 void read(DataInputStream in) throws IOException { 141 readHeader(in); 143 readConstantPool(in); 144 readAccessFlags(in); 145 readClassInfo(in); 146 readFields(in); 147 readMethods(in); 148 readAttributes(in); 149 } 150 151 154 public ParsedClassType type(TypeSystem ts) throws SemanticException { 155 ParsedClassType ct = createType(ts); 156 157 if (ts.equals(ct, ts.Object())) { 158 ct.superType(null); 159 } 160 else { 161 String superName = classNameCP(superClass); 162 163 if (superName != null) { 164 ct.superType(typeForName(ts, superName)); 165 } 166 else { 167 ct.superType(ts.Object()); 168 } 169 } 170 171 return ct; 172 } 173 174 177 public void initMemberClasses(ParsedClassType ct) { 178 if (innerClasses == null) { 179 return; 180 } 181 182 TypeSystem ts = ct.typeSystem(); 183 184 for (int i = 0; i < innerClasses.classes.length; i++) { 185 InnerClasses.Info c = innerClasses.classes[i]; 186 187 if (c.outerClassIndex == thisClass && c.classIndex != 0) { 188 String name = classNameCP(c.classIndex); 189 190 int index = name.lastIndexOf('$'); 191 192 if (index >= 0 && Character.isDigit(name.charAt(index+1))) { 194 continue; 195 } 196 197 ClassType t = quietTypeForName(ts, name); 199 200 if (t.isMember()) { 201 if (Report.should_report(verbose, 3)) 202 Report.report(3, "adding member " + t + " to " + ct); 203 204 ct.addMemberClass(t); 205 206 if (t instanceof ParsedClassType) { 209 ParsedClassType pt = (ParsedClassType) t; 210 pt.flags(ts.flagsForBits(c.modifiers)); 211 } 212 } 213 else { 214 throw new InternalCompilerError(name + " should be a member class."); 215 } 216 } 217 } 218 } 219 220 223 public void initInterfaces(ParsedClassType ct) { 224 TypeSystem ts = ct.typeSystem(); 225 226 for (int i = 0; i < interfaces.length; i++) { 227 String name = classNameCP(interfaces[i]); 228 ct.addInterface(quietTypeForName(ts, name)); 229 } 230 } 231 232 235 public void initFields(ParsedClassType ct) { 236 TypeSystem ts = ct.typeSystem(); 237 238 LazyClassInitializer init = ts.defaultClassInitializer(); 240 init.initFields(ct); 241 242 for (int i = 0; i < fields.length; i++) { 243 if (! fields[i].name().startsWith("jlc$") && 244 ! fields[i].isSynthetic()) { 245 FieldInstance fi = fields[i].fieldInstance(ts, ct); 246 if (Report.should_report(verbose, 3)) 247 Report.report(3, "adding " + fi + " to " + ct); 248 ct.addField(fi); 249 } 250 } 251 } 252 253 256 public void initMethods(ParsedClassType ct) { 257 TypeSystem ts = ct.typeSystem(); 258 259 for (int i = 0; i < methods.length; i++) { 260 if (! methods[i].name().equals("<init>") && 261 ! methods[i].name().equals("<clinit>") && 262 ! methods[i].isSynthetic()) { 263 MethodInstance mi = methods[i].methodInstance(ts, ct); 264 if (Report.should_report(verbose,3)) 265 Report.report(3, "adding " + mi + " to " + ct); 266 ct.addMethod(mi); 267 } 268 } 269 } 270 271 274 public void initConstructors(ParsedClassType ct) { 275 TypeSystem ts = ct.typeSystem(); 276 277 for (int i = 0; i < methods.length; i++) { 278 if (methods[i].name().equals("<init>") && 279 ! methods[i].isSynthetic()) { 280 ConstructorInstance ci = 281 methods[i].constructorInstance(ts, ct, fields); 282 if (Report.should_report(verbose,3)) 283 Report.report(3, "adding " + ci + " to " + ct); 284 ct.addConstructor(ci); 285 } 286 } 287 } 288 289 292 Type arrayOf(Type t, int dims) { 293 if (dims == 0) { 294 return t; 295 } 296 else { 297 return t.typeSystem().arrayOf(t, dims); 298 } 299 } 300 301 304 List typeListForString(TypeSystem ts, String str) { 305 List types = new ArrayList(); 306 307 for (int i = 0; i < str.length(); i++) { 308 int dims = 0; 309 310 while (str.charAt(i) == '[') { 311 dims++; 312 i++; 313 } 314 315 switch (str.charAt(i)) { 316 case 'Z': types.add(arrayOf(ts.Boolean(), dims)); 317 break; 318 case 'B': types.add(arrayOf(ts.Byte(), dims)); 319 break; 320 case 'S': types.add(arrayOf(ts.Short(), dims)); 321 break; 322 case 'C': types.add(arrayOf(ts.Char(), dims)); 323 break; 324 case 'I': types.add(arrayOf(ts.Int(), dims)); 325 break; 326 case 'J': types.add(arrayOf(ts.Long(), dims)); 327 break; 328 case 'F': types.add(arrayOf(ts.Float(), dims)); 329 break; 330 case 'D': types.add(arrayOf(ts.Double(), dims)); 331 break; 332 case 'V': types.add(arrayOf(ts.Void(), dims)); 333 break; 334 case 'L': { 335 int start = ++i; 336 while (i < str.length()) { 337 if (str.charAt(i) == ';') { 338 String s = str.substring(start, i); 339 s = s.replace('/', '.'); 340 types.add(arrayOf(quietTypeForName(ts, s), dims)); 341 break; 342 } 343 344 i++; 345 } 346 } 347 } 348 } 349 350 if (Report.should_report(verbose, 4)) 351 Report.report(4, "parsed \"" + str + "\" -> " + types); 352 353 return types; 354 } 355 356 359 Type typeForString(TypeSystem ts, String str) { 360 List l = typeListForString(ts, str); 361 362 if (l.size() == 1) { 363 return (Type) l.get(0); 364 } 365 366 throw new InternalCompilerError("Bad type string: \"" + str + "\""); 367 } 368 369 373 ClassType quietTypeForName(TypeSystem ts, String name) { 374 if (Report.should_report(verbose,2)) 375 Report.report(2, "resolving " + name); 376 377 try { 378 return (ClassType) ts.systemResolver().find(name); 379 } 380 catch (SemanticException e) { 381 throw new InternalCompilerError("could not load " + name); 382 } 383 } 384 385 389 ClassType typeForName(TypeSystem ts, String name) throws SemanticException { 390 if (Report.should_report(verbose,2)) 391 Report.report(2, "resolving " + name); 392 return (ClassType) ts.systemResolver().find(name); 393 } 394 395 398 ParsedClassType createType(TypeSystem ts) throws SemanticException { 399 String name = classNameCP(thisClass); 401 402 if (Report.should_report(verbose, 2)) 403 Report.report(2, "creating ClassType for " + name); 404 405 ParsedClassType ct = ts.createClassType(this); 407 408 ct.flags(ts.flagsForBits(modifiers)); 409 ct.position(position()); 410 411 ((CachingResolver) ts.systemResolver()).install(name, ct); 413 414 String packageName = StringUtil.getPackageComponent(name); 416 417 if (! packageName.equals("")) { 419 ct.package_(ts.packageForName(packageName)); 420 } 421 422 String className = StringUtil.getShortNameComponent(name); 424 425 String outerName; String innerName; 428 outerName = name; 429 innerName = null; 430 431 while (true) { 432 int dollar = outerName.lastIndexOf('$'); 433 434 if (dollar >= 0) { 435 outerName = name.substring(0, dollar); 436 innerName = name.substring(dollar+1); 437 } 438 else { 439 outerName = name; 440 innerName = null; 441 break; 442 } 443 444 try { 447 if (Report.should_report(verbose,2)) 448 Report.report(2, "resolving " + outerName + " for " + name); 449 ct.outer(typeForName(ts, outerName)); 450 break; 451 } 452 catch (SemanticException e) { 453 if (Report.should_report(verbose,3)) 455 Report.report(2, "error resolving " + outerName); 456 } 457 } 458 459 ClassType.Kind kind = ClassType.TOP_LEVEL; 460 461 if (innerName != null) { 462 StringTokenizer st = new StringTokenizer(className, "$"); 464 465 while (st.hasMoreTokens()) { 466 String s = st.nextToken(); 467 468 if (Character.isDigit(s.charAt(0))) { 469 kind = ClassType.ANONYMOUS; 471 } 472 else if (kind == ClassType.ANONYMOUS) { 473 kind = ClassType.LOCAL; 475 } 476 else { 477 kind = ClassType.MEMBER; 479 } 480 } 481 } 482 483 if (Report.should_report(verbose, 3)) 484 Report.report(3, name + " is " + kind); 485 486 ct.kind(kind); 487 488 if (ct.isTopLevel()) { 489 ct.name(className); 490 } 491 else if (ct.isMember() || ct.isLocal()) { 492 ct.name(innerName); 493 } 494 495 496 return ct; 497 } 498 499 502 public Position position() { 503 return new Position(name() + ".class"); 504 } 505 506 509 String classNameCP(int index) { 510 Constant c = constants[index]; 511 512 if (c != null && c.tag() == Constant.CLASS) { 513 Integer nameIndex = (Integer ) c.value(); 514 if (nameIndex != null) { 515 c = constants[nameIndex.intValue()]; 516 if (c.tag() == Constant.UTF8) { 517 String s = (String ) c.value(); 518 return s.replace('/', '.'); 519 } 520 } 521 } 522 523 return null; 524 } 525 526 532 public String name() { 533 Constant c = constants[thisClass]; 534 if (c.tag() == Constant.CLASS) { 535 Integer nameIndex = (Integer ) c.value(); 536 if (nameIndex != null) { 537 c = constants[nameIndex.intValue()]; 538 if (c.tag() == Constant.UTF8) { 539 return (String ) c.value(); 540 } 541 } 542 } 543 544 throw new ClassFormatError ("Couldn't find class name in file"); 545 } 546 547 557 Constant readConstant(DataInputStream in) 558 throws IOException 559 { 560 int tag = in.readUnsignedByte(); 561 Object value; 562 563 switch (tag) 564 { 565 case Constant.CLASS: 566 case Constant.STRING: 567 value = new Integer (in.readUnsignedShort()); 568 break; 569 case Constant.FIELD_REF: 570 case Constant.METHOD_REF: 571 case Constant.INTERFACE_METHOD_REF: 572 case Constant.NAME_AND_TYPE: 573 value = new int[2]; 574 575 ((int[]) value)[0] = in.readUnsignedShort(); 576 ((int[]) value)[1] = in.readUnsignedShort(); 577 break; 578 case Constant.INTEGER: 579 value = new Integer (in.readInt()); 580 break; 581 case Constant.FLOAT: 582 value = new Float (in.readFloat()); 583 break; 584 case Constant.LONG: 585 value = new Long (in.readLong()); 587 break; 588 case Constant.DOUBLE: 589 value = new Double (in.readDouble()); 591 break; 592 case Constant.UTF8: 593 value = in.readUTF(); 594 break; 595 default: 596 throw new ClassFormatError ("Invalid constant tag: " + tag); 597 } 598 599 return new Constant(tag, value); 600 } 601 602 610 void readHeader(DataInputStream in) 611 throws IOException 612 { 613 int magic = in.readInt(); 614 615 if (magic != 0xCAFEBABE) { 616 throw new ClassFormatError ("Bad magic number."); 617 } 618 619 int major = in.readUnsignedShort(); 620 int minor = in.readUnsignedShort(); 621 } 622 623 635 void readConstantPool(DataInputStream in) 636 throws IOException 637 { 638 int count = in.readUnsignedShort(); 639 640 constants = new Constant[count]; 641 642 constants[0] = null; 644 645 for (int i = 1; i < count; i++) { 647 constants[i] = readConstant(in); 648 649 switch (constants[i].tag()) { 650 case Constant.LONG: 651 case Constant.DOUBLE: 652 constants[++i] = null; 654 break; 655 } 656 } 657 } 658 659 667 void readAccessFlags(DataInputStream in) 668 throws IOException 669 { 670 modifiers = in.readUnsignedShort(); 671 } 672 673 681 void readClassInfo(DataInputStream in) 682 throws IOException 683 { 684 int index; 685 686 thisClass = in.readUnsignedShort(); 687 superClass = in.readUnsignedShort(); 688 689 int numInterfaces = in.readUnsignedShort(); 690 691 interfaces = new int[numInterfaces]; 692 693 for (int i = 0; i < numInterfaces; i++) { 694 interfaces[i] = in.readUnsignedShort(); 695 } 696 } 697 698 706 void readFields(DataInputStream in) 707 throws IOException 708 { 709 int numFields = in.readUnsignedShort(); 710 711 fields = new Field[numFields]; 712 713 for (int i = 0; i < numFields; i++) { 714 fields[i] = new Field(in, this); 715 } 716 } 717 718 726 void readMethods(DataInputStream in) 727 throws IOException 728 { 729 int numMethods = in.readUnsignedShort(); 730 731 methods = new Method[numMethods]; 732 733 for (int i = 0; i < numMethods; i++) { 734 methods[i] = new Method(in, this); 735 } 736 } 737 738 748 void readAttributes(DataInputStream in) 749 throws IOException 750 { 751 int numAttributes = in.readUnsignedShort(); 752 753 attrs = new Attribute[numAttributes]; 754 755 for (int i = 0; i < numAttributes; i++) { 756 int nameIndex = in.readUnsignedShort(); 757 int length = in.readInt(); 758 if ("InnerClasses".equals(constants[nameIndex].value())) { 759 innerClasses = new InnerClasses(in, nameIndex, length); 760 attrs[i] = innerClasses; 761 } 762 else { 763 long n = in.skip(length); 764 if (n != length) { 765 throw new EOFException(); 766 } 767 } 768 } 769 } 770 } 771 | Popular Tags |