001 /* 002 * This file is part of the Jikes RVM project (http://jikesrvm.org). 003 * 004 * This file is licensed to You under the Eclipse Public License (EPL); 005 * You may not use this file except in compliance with the License. You 006 * may obtain a copy of the License at 007 * 008 * http://www.opensource.org/licenses/eclipse-1.0.php 009 * 010 * See the COPYRIGHT.txt file distributed with this work for information 011 * regarding copyright ownership. 012 */ 013 014 package org.jikesrvm.classloader; 015 016 import java.io.DataInputStream; 017 import java.io.IOException; 018 019 import org.jikesrvm.Constants; 020 import org.jikesrvm.VM; 021 import org.jikesrvm.runtime.Statics; 022 import org.vmmagic.pragma.Uninterruptible; 023 import org.vmmagic.unboxed.Offset; 024 025 /** 026 * Support code to parse a DataInputStream in the Java classfile format 027 * and create the appropriate instance of an RVMClass or UnboxedType. 028 * Also low-level support for our internal constant pool format. 029 */ 030 public class ClassFileReader implements Constants, ClassLoaderConstants { 031 032 /** 033 * Parse and return the constant pool in a class file 034 * @param typeRef the canonical type reference for this type. 035 * @param input the data stream from which to read the class's description. 036 */ 037 static int[] readConstantPool(TypeReference typeRef, DataInputStream input) throws ClassFormatError, IOException { 038 039 int magic = input.readInt(); 040 if (magic != 0xCAFEBABE) { 041 throw new ClassFormatError("bad magic number " + Integer.toHexString(magic)); 042 } 043 044 // Get the class file version number and check to see if it is a version 045 // that we support. 046 int minor = input.readUnsignedShort(); 047 int major = input.readUnsignedShort(); 048 switch (major) { 049 case 45: 050 case 46: 051 case 47: 052 case 48: 053 case 49: // we support all variants of these major versions so the minor number doesn't matter. 054 break; 055 case 50: // we only support up to 50.0 (ie Java 1.6.0) 056 if (minor == 0) break; 057 default: 058 throw new UnsupportedClassVersionError("unsupported class file version " + major + "." + minor); 059 } 060 061 // 062 // pass 1: read constant pool 063 // 064 int[] constantPool = new int[input.readUnsignedShort()]; 065 byte[] tmpTags = new byte[constantPool.length]; 066 067 // note: slot 0 is unused 068 for (int i = 1; i < constantPool.length; i++) { 069 tmpTags[i] = input.readByte(); 070 switch (tmpTags[i]) { 071 case TAG_UTF: { 072 byte[] utf = new byte[input.readUnsignedShort()]; 073 input.readFully(utf); 074 int atomId = Atom.findOrCreateUtf8Atom(utf).getId(); 075 constantPool[i] = packCPEntry(CP_UTF, atomId); 076 break; 077 } 078 case TAG_UNUSED: 079 if (VM.VerifyAssertions) VM._assert(NOT_REACHED); 080 break; 081 082 case TAG_INT: { 083 int literal = input.readInt(); 084 int offset = Statics.findOrCreateIntSizeLiteral(literal); 085 constantPool[i] = packCPEntry(CP_INT, offset); 086 break; 087 } 088 case TAG_FLOAT: { 089 int literal = input.readInt(); 090 int offset = Statics.findOrCreateIntSizeLiteral(literal); 091 constantPool[i] = packCPEntry(CP_FLOAT, offset); 092 break; 093 } 094 case TAG_LONG: { 095 long literal = input.readLong(); 096 int offset = Statics.findOrCreateLongSizeLiteral(literal); 097 constantPool[i] = packCPEntry(CP_LONG, offset); 098 i++; 099 break; 100 } 101 case TAG_DOUBLE: { 102 long literal = input.readLong(); 103 int offset = Statics.findOrCreateLongSizeLiteral(literal); 104 constantPool[i] = packCPEntry(CP_DOUBLE, offset); 105 i++; 106 break; 107 } 108 case TAG_TYPEREF: 109 constantPool[i] = input.readUnsignedShort(); 110 break; 111 112 case TAG_STRING: 113 constantPool[i] = input.readUnsignedShort(); 114 break; 115 116 case TAG_FIELDREF: 117 case TAG_METHODREF: 118 case TAG_INTERFACE_METHODREF: { 119 int classDescriptorIndex = input.readUnsignedShort(); 120 int memberNameAndDescriptorIndex = input.readUnsignedShort(); 121 constantPool[i] = packTempCPEntry(classDescriptorIndex, memberNameAndDescriptorIndex); 122 break; 123 } 124 125 case TAG_MEMBERNAME_AND_DESCRIPTOR: { 126 int memberNameIndex = input.readUnsignedShort(); 127 int descriptorIndex = input.readUnsignedShort(); 128 constantPool[i] = packTempCPEntry(memberNameIndex, descriptorIndex); 129 break; 130 } 131 132 default: 133 throw new ClassFormatError("bad constant pool"); 134 } 135 } 136 137 // 138 // pass 2: post-process type and string constant pool entries 139 // (we must do this in a second pass because of forward references) 140 // 141 try { 142 for (int i = 1; i < constantPool.length; i++) { 143 switch (tmpTags[i]) { 144 case TAG_LONG: 145 case TAG_DOUBLE: 146 ++i; 147 break; 148 149 case TAG_TYPEREF: { // in: utf index 150 Atom typeName = getUtf(constantPool, constantPool[i]); 151 int typeRefId = 152 TypeReference.findOrCreate(typeRef.getClassLoader(), typeName.descriptorFromClassName()).getId(); 153 constantPool[i] = packCPEntry(CP_CLASS, typeRefId); 154 break; 155 } // out: type reference id 156 157 case TAG_STRING: { // in: utf index 158 Atom literal = getUtf(constantPool, constantPool[i]); 159 int offset = literal.getStringLiteralOffset(); 160 constantPool[i] = packCPEntry(CP_STRING, offset); 161 break; 162 } // out: jtoc slot number 163 } 164 } 165 } catch (java.io.UTFDataFormatException x) { 166 throw new ClassFormatError(x.toString()); 167 } 168 169 // 170 // pass 3: post-process type field and method constant pool entries 171 // 172 for (int i = 1; i < constantPool.length; i++) { 173 switch (tmpTags[i]) { 174 case TAG_LONG: 175 case TAG_DOUBLE: 176 ++i; 177 break; 178 179 case TAG_FIELDREF: 180 case TAG_METHODREF: 181 case TAG_INTERFACE_METHODREF: { // in: classname+membername+memberdescriptor indices 182 int bits = constantPool[i]; 183 int classNameIndex = unpackTempCPIndex1(bits); 184 int memberNameAndDescriptorIndex = unpackTempCPIndex2(bits); 185 int memberNameAndDescriptorBits = constantPool[memberNameAndDescriptorIndex]; 186 int memberNameIndex = unpackTempCPIndex1(memberNameAndDescriptorBits); 187 int memberDescriptorIndex = unpackTempCPIndex2(memberNameAndDescriptorBits); 188 189 TypeReference tref = getTypeRef(constantPool, classNameIndex); 190 Atom memberName = getUtf(constantPool, memberNameIndex); 191 Atom memberDescriptor = getUtf(constantPool, memberDescriptorIndex); 192 MemberReference mr = MemberReference.findOrCreate(tref, memberName, memberDescriptor); 193 int mrId = mr.getId(); 194 constantPool[i] = packCPEntry(CP_MEMBER, mrId); 195 break; 196 } // out: MemberReference id 197 } 198 } 199 return constantPool; 200 } 201 202 /** 203 * Read the class' TypeReference 204 * @param typeRef 205 * @param input 206 * @param constantPool 207 * @return the constantPool index of the typeRef of the class we are reading 208 */ 209 static int readTypeRef(TypeReference typeRef, DataInputStream input, int[] constantPool) throws IOException, ClassFormatError { 210 int myTypeIndex = input.readUnsignedShort(); 211 TypeReference myTypeRef = getTypeRef(constantPool, myTypeIndex); 212 if (myTypeRef != typeRef) { 213 // eg. file contains a different class than would be 214 // expected from its .class file name 215 if (!VM.VerifyAssertions) { 216 throw new ClassFormatError("expected class \"" + 217 typeRef.getName() + 218 "\" but found \"" + 219 myTypeRef.getName() + 220 "\""); 221 } else { 222 throw new ClassFormatError("expected class \"" + 223 typeRef.getName() + 224 "\" but found \"" + 225 myTypeRef.getName() + 226 "\"\n" + typeRef + " != " + myTypeRef); 227 } 228 } 229 return myTypeIndex; 230 } 231 232 /** 233 * Read the super class name, load and resolve the super class 234 * @param input 235 * @param constantPool 236 * @param modifiers 237 * @return the super class of the class being read 238 */ 239 static RVMClass readSuperClass(DataInputStream input, int[] constantPool, 240 short modifiers) throws IOException, NoClassDefFoundError { 241 TypeReference superType = getTypeRef(constantPool, input.readUnsignedShort()); // possibly null 242 RVMClass superClass = null; 243 if (((modifiers & ACC_INTERFACE) == 0) && (superType != null)) { 244 superClass = superType.resolve().asClass(); 245 } 246 return superClass; 247 } 248 249 /** 250 * Read the list of interfaces implemented by the class being read 251 * @param input 252 * @param constantPool 253 * @return the interfaces implemented by the class 254 */ 255 static RVMClass[] readDeclaredInterfaces(DataInputStream input, int[] constantPool) throws IOException, NoClassDefFoundError { 256 int numInterfaces = input.readUnsignedShort(); 257 RVMClass[] declaredInterfaces; 258 if (numInterfaces == 0) { 259 declaredInterfaces = RVMType.emptyVMClass; 260 } else { 261 declaredInterfaces = new RVMClass[numInterfaces]; 262 for (int i = 0; i < numInterfaces; ++i) { 263 TypeReference inTR = getTypeRef(constantPool, input.readUnsignedShort()); 264 declaredInterfaces[i] = inTR.resolve().asClass(); 265 } 266 } 267 return declaredInterfaces; 268 } 269 270 /** 271 * Read the declared fields of the class being read 272 * @param typeRef 273 * @param input 274 * @param constantPool 275 * @return the list of declared fields 276 */ 277 static RVMField[] readDeclaredFields(TypeReference typeRef, DataInputStream input, int[] constantPool) throws IOException { 278 int numFields = input.readUnsignedShort(); 279 RVMField[] declaredFields; 280 if (numFields == 0) { 281 declaredFields = RVMType.emptyVMField; 282 } else { 283 declaredFields = new RVMField[numFields]; 284 for (int i = 0; i < numFields; i++) { 285 short fmodifiers = input.readShort(); 286 Atom fieldName = getUtf(constantPool, input.readUnsignedShort()); 287 Atom fieldDescriptor = getUtf(constantPool, input.readUnsignedShort()); 288 if (typeRef == TypeReference.JavaLangSystem && 289 (fmodifiers & (ACC_STATIC | ACC_FINAL | ACC_PUBLIC)) == (ACC_STATIC | ACC_FINAL | ACC_PUBLIC)) { 290 /* We have to stop System.in .out and .err fields from being final! */ 291 fmodifiers -= ACC_FINAL; 292 } 293 MemberReference memRef = MemberReference.findOrCreate(typeRef, fieldName, fieldDescriptor); 294 declaredFields[i] = RVMField.readField(typeRef, constantPool, memRef, fmodifiers, input); 295 } 296 } 297 return declaredFields; 298 } 299 300 /** 301 * Read the declared methods of the class being read 302 * @param typeRef 303 * @param input 304 * @param constantPool 305 * @return the declared methods of the class 306 */ 307 static RVMMethod[] readDeclaredMethods(TypeReference typeRef, DataInputStream input, int[] constantPool) throws IOException { 308 int numMethods = input.readUnsignedShort(); 309 RVMMethod[] declaredMethods; 310 if (numMethods == 0) { 311 declaredMethods = RVMType.emptyVMMethod; 312 } else { 313 declaredMethods = new RVMMethod[numMethods]; 314 for (int i = 0; i < numMethods; i++) { 315 short mmodifiers = input.readShort(); 316 Atom methodName = getUtf(constantPool, input.readUnsignedShort()); 317 Atom methodDescriptor = getUtf(constantPool, input.readUnsignedShort()); 318 MemberReference memRef = MemberReference.findOrCreate(typeRef, methodName, methodDescriptor); 319 RVMMethod method = RVMMethod.readMethod(typeRef, constantPool, memRef, mmodifiers, input); 320 declaredMethods[i] = method; 321 } 322 } 323 return declaredMethods; 324 } 325 326 /** 327 * Return the class initializer method among the declared methods of the class 328 * @param declaredMethods 329 * @return the class initializer method <cinit> of the class 330 */ 331 static RVMMethod getClassInitializerMethod(RVMMethod[] declaredMethods) { 332 for (RVMMethod method : declaredMethods) { 333 if (method.isClassInitializer()) return method; 334 } 335 return null; 336 } 337 338 /** 339 * Create an instance of a RVMClass. 340 * @param typeRef the canonical type reference for this type. 341 * @param input the data stream from which to read the class's description. 342 */ 343 static RVMClass readClass(TypeReference typeRef, DataInputStream input) throws ClassFormatError, IOException { 344 345 if (RVMClass.classLoadingDisabled) { 346 throw new RuntimeException("ClassLoading Disabled : " + typeRef); 347 } 348 349 if (VM.TraceClassLoading && VM.runningVM) { 350 VM.sysWrite("RVMClass: (begin) load file " + typeRef.getName() + "\n"); 351 } 352 353 int[] constantPool = readConstantPool(typeRef, input); 354 short modifiers = input.readShort(); 355 int myTypeIndex = readTypeRef(typeRef, input, constantPool); 356 RVMClass superClass = readSuperClass(input, constantPool, modifiers); 357 RVMClass[] declaredInterfaces = readDeclaredInterfaces(input, constantPool); 358 RVMField[] declaredFields = readDeclaredFields(typeRef, input, constantPool); 359 RVMMethod[] declaredMethods = readDeclaredMethods(typeRef, input, constantPool); 360 RVMMethod classInitializerMethod = getClassInitializerMethod(declaredMethods); 361 362 TypeReference[] declaredClasses = null; 363 Atom sourceName = null; 364 TypeReference declaringClass = null; 365 Atom signature = null; 366 RVMAnnotation[] annotations = null; 367 TypeReference enclosingClass = null; 368 MethodReference enclosingMethod = null; 369 // Read attributes. 370 for (int i = 0, n = input.readUnsignedShort(); i < n; ++i) { 371 Atom attName = getUtf(constantPool, input.readUnsignedShort()); 372 int attLength = input.readInt(); 373 374 // Class attributes 375 if (attName == RVMClassLoader.sourceFileAttributeName && attLength == 2) { 376 sourceName = getUtf(constantPool, input.readUnsignedShort()); 377 } else if (attName == RVMClassLoader.innerClassesAttributeName) { 378 // Parse InnerClasses attribute, and use the information to populate 379 // the list of declared member classes. We do this so we can 380 // support the java.lang.Class.getDeclaredClasses() 381 // and java.lang.Class.getDeclaredClass methods. 382 383 int numberOfClasses = input.readUnsignedShort(); 384 declaredClasses = new TypeReference[numberOfClasses]; 385 386 for (int j = 0; j < numberOfClasses; ++j) { 387 int innerClassInfoIndex = input.readUnsignedShort(); 388 int outerClassInfoIndex = input.readUnsignedShort(); 389 int innerNameIndex = input.readUnsignedShort(); 390 int innerClassAccessFlags = input.readUnsignedShort(); 391 392 if (innerClassInfoIndex != 0 && outerClassInfoIndex == myTypeIndex && innerNameIndex != 0) { 393 // This looks like a declared inner class. 394 declaredClasses[j] = getTypeRef(constantPool, innerClassInfoIndex); 395 } 396 397 if (innerClassInfoIndex == myTypeIndex) { 398 if (outerClassInfoIndex != 0) { 399 declaringClass = getTypeRef(constantPool, outerClassInfoIndex); 400 if (enclosingClass == null) { 401 // TODO: is this the null test necessary? 402 enclosingClass = declaringClass; 403 } 404 } 405 if ((innerClassAccessFlags & (ACC_PRIVATE | ACC_PROTECTED)) != 0) { 406 modifiers &= ~(ACC_PUBLIC | ACC_PRIVATE | ACC_PROTECTED); 407 } 408 modifiers |= innerClassAccessFlags; 409 } 410 } 411 } else if (attName == RVMClassLoader.syntheticAttributeName) { 412 modifiers |= ACC_SYNTHETIC; 413 } else if (attName == RVMClassLoader.enclosingMethodAttributeName) { 414 int enclosingClassIndex = input.readUnsignedShort(); 415 enclosingClass = getTypeRef(constantPool, enclosingClassIndex); 416 417 int enclosingMethodIndex = input.readUnsignedShort(); 418 if (enclosingMethodIndex != 0) { 419 int memberNameIndex = constantPool[enclosingMethodIndex] >>> BITS_IN_SHORT; 420 int memberDescriptorIndex = constantPool[enclosingMethodIndex] & ((1 << BITS_IN_SHORT) - 1); 421 Atom memberName = getUtf(constantPool, memberNameIndex); 422 Atom memberDescriptor = getUtf(constantPool, memberDescriptorIndex); 423 enclosingMethod = 424 MemberReference.findOrCreate(enclosingClass, memberName, memberDescriptor).asMethodReference(); 425 } 426 } else if (attName == RVMClassLoader.signatureAttributeName) { 427 signature = getUtf(constantPool, input.readUnsignedShort()); 428 } else if (attName == RVMClassLoader.runtimeVisibleAnnotationsAttributeName) { 429 annotations = AnnotatedElement.readAnnotations(constantPool, input, typeRef.getClassLoader()); 430 } else { 431 int skippedAmount = input.skipBytes(attLength); 432 if (skippedAmount != attLength) { 433 throw new IOException("Unexpected short skip"); 434 } 435 } 436 } 437 438 return new RVMClass(typeRef, 439 constantPool, 440 modifiers, 441 superClass, 442 declaredInterfaces, 443 declaredFields, 444 declaredMethods, 445 declaredClasses, 446 declaringClass, 447 enclosingClass, 448 enclosingMethod, 449 sourceName, 450 classInitializerMethod, 451 signature, 452 annotations); 453 } 454 455 @Uninterruptible 456 static int packCPEntry(byte type, int value) { 457 return (type << 29) | (value & 0x1fffffff); 458 } 459 460 @Uninterruptible 461 static byte unpackCPType(int cpValue) { 462 return (byte) (cpValue >>> 29); 463 } 464 465 @Uninterruptible 466 static int unpackSignedCPValue(int cpValue) { 467 return (cpValue << 3) >> 3; 468 } 469 470 @Uninterruptible 471 static int unpackUnsignedCPValue(int cpValue) { 472 return cpValue & 0x1fffffff; 473 } 474 475 @Uninterruptible 476 static boolean packedCPTypeIsClassType(int cpValue) { 477 return (cpValue & (7 << 29)) == (CP_CLASS << 29); 478 } 479 480 @Uninterruptible 481 static int packTempCPEntry(int index1, int index2) { 482 return (index1 << 16) | (index2 & 0xffff); 483 } 484 485 @Uninterruptible 486 static int unpackTempCPIndex1(int cpValue) { 487 return cpValue >>> 16; 488 } 489 490 @Uninterruptible 491 static int unpackTempCPIndex2(int cpValue) { 492 return cpValue & 0xffff; 493 } 494 495 static int getLiteralSize(int[] constantPool, int constantPoolIndex) { 496 int cpValue = constantPool[constantPoolIndex]; 497 switch (unpackCPType(cpValue)) { 498 case CP_INT: 499 case CP_FLOAT: 500 return BYTES_IN_INT; 501 case CP_LONG: 502 case CP_DOUBLE: 503 return BYTES_IN_LONG; 504 case CP_CLASS: 505 case CP_STRING: 506 return BYTES_IN_ADDRESS; 507 default: 508 if (VM.VerifyAssertions) VM._assert(NOT_REACHED); 509 return 0; 510 } 511 } 512 513 /** 514 * Get offset of a literal constant, in bytes. 515 * Offset is with respect to virtual machine's "table of contents" (jtoc). 516 */ 517 static Offset getLiteralOffset(int[] constantPool, int constantPoolIndex) { 518 int cpValue = constantPool[constantPoolIndex]; 519 if (VM.VerifyAssertions) { 520 int value = unpackSignedCPValue(cpValue); 521 byte type = unpackCPType(cpValue); 522 switch (type) { 523 case CP_INT: 524 case CP_FLOAT: 525 case CP_LONG: 526 case CP_DOUBLE: 527 case CP_STRING: 528 return Offset.fromIntSignExtend(value); 529 case CP_CLASS: { 530 int typeId = unpackUnsignedCPValue(cpValue); 531 Class<?> literalAsClass = TypeReference.getTypeRef(typeId).resolve().getClassForType(); 532 return Offset.fromIntSignExtend(Statics.findOrCreateObjectLiteral(literalAsClass)); 533 } 534 default: 535 VM._assert(NOT_REACHED); 536 return Offset.fromIntSignExtend(0xebad0ff5); 537 } 538 } else { 539 if (packedCPTypeIsClassType(cpValue)) { 540 int typeId = unpackUnsignedCPValue(cpValue); 541 Class<?> literalAsClass = TypeReference.getTypeRef(typeId).resolve().getClassForType(); 542 return Offset.fromIntSignExtend(Statics.findOrCreateObjectLiteral(literalAsClass)); 543 } else { 544 int value = unpackSignedCPValue(cpValue); 545 return Offset.fromIntSignExtend(value); 546 } 547 } 548 } 549 550 /** 551 * Get description of a literal constant. 552 */ 553 static byte getLiteralDescription(int[] constantPool, int constantPoolIndex) { 554 int cpValue = constantPool[constantPoolIndex]; 555 byte type = unpackCPType(cpValue); 556 return type; 557 } 558 559 /** 560 * Get contents of a "typeRef" constant pool entry. 561 * @return type that was referenced 562 */ 563 @Uninterruptible 564 static TypeReference getTypeRef(int[] constantPool, int constantPoolIndex) { 565 if (constantPoolIndex != 0) { 566 int cpValue = constantPool[constantPoolIndex]; 567 if (VM.VerifyAssertions) VM._assert(unpackCPType(cpValue) == CP_CLASS); 568 return TypeReference.getTypeRef(unpackUnsignedCPValue(cpValue)); 569 } else { 570 return null; 571 } 572 } 573 574 /** 575 * Get contents of a "methodRef" constant pool entry. 576 */ 577 @Uninterruptible 578 static MethodReference getMethodRef(int[] constantPool, int constantPoolIndex) { 579 int cpValue = constantPool[constantPoolIndex]; 580 if (VM.VerifyAssertions) VM._assert(unpackCPType(cpValue) == CP_MEMBER); 581 return (MethodReference) MemberReference.getMemberRef(unpackUnsignedCPValue(cpValue)); 582 } 583 584 /** 585 * Get contents of a "methodRef" constant pool entry. 586 */ 587 @Uninterruptible 588 static FieldReference getFieldRef(int[] constantPool, int constantPoolIndex) { 589 int cpValue = constantPool[constantPoolIndex]; 590 if (VM.VerifyAssertions) VM._assert(unpackCPType(cpValue) == CP_MEMBER); 591 return (FieldReference) MemberReference.getMemberRef(unpackUnsignedCPValue(cpValue)); 592 } 593 594 /** 595 * Get contents of a "utf" from a constant pool entry. 596 */ 597 @Uninterruptible 598 static Atom getUtf(int[] constantPool, int constantPoolIndex) { 599 int cpValue = constantPool[constantPoolIndex]; 600 if (VM.VerifyAssertions) VM._assert(unpackCPType(cpValue) == CP_UTF); 601 return Atom.getAtom(unpackUnsignedCPValue(cpValue)); 602 } 603 }