1
2 package jrre.classloader;
3
4 import jrre.api.java.lang.reflect.*;
5
6 import jrre.classloader.classfile.pool_entries.*;
7 import jrre.classloader.classfile.attributes.*;
8 import jrre.classloader.classfile.access_flags.*;
9
10 import jrre.*;
11 import java.lang.reflect.*;
12 import java.util.*;
13 import java.util.jar.JarFile;
14 import java.util.jar.JarEntry;
15 import java.io.*;
16
17 /***
18 * file name : ClassLoader.java
19 * authors : Christopher Ellsworth (Chris@chrisellsworth.com)
20 * Clerance Alston (massclax@hotmail.com)
21 * created : 10/31/2002 05:19:12
22 *
23 * Loads a class file.
24 *
25 * @task Need to seperate jrre.api.java.lang from jrre.classloader.
26 *
27 * @task Need to perform Resolution phase to transform symbolic referances into
28 * direct references.
29 *
30 * @task Need to add ClassLoader.defineClass(String name, byte data[]) and
31 * resolveClass(Class c).
32 *
33 * @author Clarence Alston (massclax@hotmail.com)
34 * @author Christoher Ellsworth (chris@chrisellsworth.com)
35 */
36 public class ClassLoader {
37
38 // Put nameSpace in here.
39 public static boolean verboseOn = true;
40
41 private String currentClass;
42
43 private int magicNumber;
44 private int minorVersion,majorVersion,constantPoolCount;
45
46 private FileInputStream inStream;
47 private DataInputStream dataInStream;
48 //private BufferedReader reader;
49
50 private int u1;
51 private int u2;
52 private int u4;
53 private double u8;
54
55 private ClassProperties classProperties;
56
57 private static StringBuffer messages;
58
59 private jrre.api.java.lang.Class classToReturn = new jrre.api.java.lang.Class();
60 //private static MethodArea methodArea = new MethodArea();
61
62 private static int classesLoaded = 0;
63
64 private static String classPath;
65
66 /***
67 *
68 */
69 private ClassLoader(){
70
71 messages = new StringBuffer();
72 classProperties = new ClassProperties();
73 }
74
75 /***
76 * Gets the ClassPath.
77 */
78 public static String getClassPath(){
79 return classPath;
80 }
81
82 /***
83 * Sets the ClassPath.
84 * @param ClassPath The value to set it to.
85 */
86 public static void setClassPath(String classPath){
87 classPath = classPath;
88 }
89
90 /***
91 *
92 *
93 * @param className
94 * @return The loaded Class.
95 */
96 public static jrre.api.java.lang.Class loadClass(String className){
97
98 if(!MethodArea.containsClass(className)){
99
100 //System.out.println("Classes Loaded: "+classesLoaded++);
101
102 ClassLoader loader = new ClassLoader();
103 jrre.api.java.lang.Class loadedClass = loader.load(className);
104
105 /*
106 // Execute <cinit> method in class.
107 MethodEntry initMethod = loadedClass.getMethod("<clinit>()V");
108
109 if(initMethod != null){
110 StackFrame initMethodFrame = initMethod.getStackFrame();
111 jrre.Stack.push(initMethodFrame, "<clinit>()V::"+loadedClass.getFullyQualifiedName());
112 //jrre.JRRE.step();
113 //jrre.JRRE.run();
114 System.out.println("dont with <clinit>");
115 }
116 */
117 return loadedClass;
118 }
119 else{
120 //System.out.println("Class already loaded: "+className);
121 return MethodArea.getClass(className);
122 }
123 }
124
125 /***
126 * Loads and returns the class specified.
127 *
128 * @param className The fully qualified name of the class to load.
129 * @return The jrre internal representation of the class.
130 */
131 private jrre.api.java.lang.Class load(String className){
132
133 className = className.replace('.','/')+".class";
134
135 currentClass = className.substring(0, className.indexOf("."));
136 reportMessage("Class: "+currentClass+"\n");
137
138 classPath = System.getProperty("java.class.path");
139 classPath += ";.";
140
141 // First look in JDK classes.
142 byte [] classData = readClassFromJar("D:/j2sdk1.4.0_02/jre/lib/rt.jar", className);
143 if(classData != null){
144 try{
145 dataInStream = new DataInputStream(new ByteArrayInputStream(classData));
146 }
147 catch(Exception e){System.out.println("Exception loading class: "+e);}
148
149 }
150 // Search classpath for class.
151 else {
152
153 String fileName;
154 StringTokenizer classPathTokenizer = new StringTokenizer(classPath, ";");
155 while(classPathTokenizer.hasMoreElements()){
156
157 fileName = classPathTokenizer.nextElement() + "/" + className;
158
159 File fileToRead = new File(fileName);
160 if(fileToRead.canRead()){
161
162 try{
163 dataInStream = new DataInputStream(
164 new BufferedInputStream(inStream = new FileInputStream(fileToRead),
165 (int)fileToRead.length()));
166 }
167 catch(FileNotFoundException e){}
168
169 break;
170 }
171
172 }
173 }
174
175 // Bail out if class file not found on classpath.
176 if(dataInStream == null){
177 System.err.println("Im sorry, the requested class was not found on system classpath.");
178 System.exit(1);
179 }
180
181 // Begin loading the class.
182 verifyMagicNumber();
183 verifyVersions();
184 loadConstantPool();
185 loadAccessFlags();
186 loadThisClass();
187 loadSuperClass();
188
189 // Update this class referance in symbol table with its class properties.
190 // (magic number, minor version, major version, access flags, and super class)
191 classToReturn.setProperties(classProperties);
192
193 loadInterfaces();
194 loadFields();
195 loadMethods();
196 loadAttributes();
197
198 try{
199 dataInStream.close();
200 if(inStream != null)
201 inStream.close();
202 }catch(IOException e){ System.out.println(e);}
203
204 classToReturn.setLoadingMessages(messages);
205 messages = new StringBuffer();
206
207 //ClassLoader.methodArea.addClass(classToReturn);
208 MethodArea.addClass(classToReturn);
209
210 return classToReturn;
211 }
212
213 private boolean loadAttributes(){
214
215 int attributeCount = get2Bytes();
216
217 for(int i=0;i < attributeCount;i++){
218 int nameIndex = get2Bytes();
219 int attributeLength = get4Bytes();
220
221
222 CPInfo cpName = (CPInfo)classToReturn.getSymbol(nameIndex);
223
224 if(cpName instanceof CPUTF8){
225 if(((CPUTF8)cpName).getValue().equals("SourceFile")){
226 SourceFileAttribute sourceFileAttribute = new SourceFileAttribute(nameIndex,
227 attributeLength,
228 get2Bytes()); // sourceFileIndex
229 }
230 else if(((CPUTF8)cpName).getValue().equals("InnerClasses")){
231 eatBytes(attributeLength);
232 }
233 }
234
235 }
236 return true;
237 }
238
239 /***
240 * Loads the classes methods into the jrre.java.lang.Class object.
241 *
242 * @return
243 */
244 private boolean loadMethods(){
245
246 int methodCount = get2Bytes();
247 MethodEntry [] methods = new MethodEntry[methodCount+1];
248
249 for(int i=1;i <= methodCount;i++){
250 int methodAccessFlags = get2Bytes();
251
252 MethodAccessFlags accessFlags = new MethodAccessFlags(Modifier.isPublic(methodAccessFlags),
253 Modifier.isPrivate(methodAccessFlags),
254 Modifier.isProtected(methodAccessFlags),
255 Modifier.isStatic(methodAccessFlags),
256 Modifier.isFinal(methodAccessFlags),
257 Modifier.isSynchronized(methodAccessFlags),
258 Modifier.isNative(methodAccessFlags),
259 Modifier.isAbstract(methodAccessFlags));
260 int attributesCount;
261 Attributes attributes = new Attributes();
262 int methodNameIndex;
263 int descriptorIndex;
264
265 MethodEntry entry = new MethodEntry(accessFlags,
266 methodNameIndex = get2Bytes(), //name Index
267 descriptorIndex = get2Bytes(), //descriptor Index
268 attributesCount = get2Bytes(),
269 attributes);
270
271 //????????????????????????????????????????
272 //????????????????????????????????????????
273 // Must be Native if it crashes.
274 //if((CPUTF8)classToReturn.getSymbol(methodNameIndex) == null)return false;
275 //System.out.println(messages);
276 //if(Modifier.isNative(methodAccessFlags))
277 //System.out.println("\t\tNative Method: "+Modifier.isNative(methodAccessFlags));
278
279 CPUTF8 cpMethodName = (CPUTF8)classToReturn.getSymbol(methodNameIndex);
280 entry.setName(cpMethodName.getValue());
281 entry.setClassName(classToReturn.getFullyQualifiedName());
282
283 //System.out.println("Loading Method: "+cpMethodName.getValue());
284 //System.out.println("In Class: "+classToReturn.getFullyQualifiedName());
285
286 if(cpMethodName.getValue().equals("<init>")){
287 classProperties.setInitMethod(methodNameIndex);
288 }
289 else if(cpMethodName.getValue().equals("<cinit>")){
290 classProperties.setInitMethod(methodNameIndex);
291 }
292
293 CPUTF8 cpDescriptor = (CPUTF8)classToReturn.getSymbol(descriptorIndex);
294 entry.setDescriptor(cpDescriptor.getValue());
295
296 Attribute [] attributesArray = new Attribute[attributesCount];
297 attributes.setAttributes(attributesArray);
298
299 for(int k = 0;k < attributesCount;k++){
300 int nameIndex = get2Bytes();
301 int attributeLength = get4Bytes();
302
303
304 CPInfo cpEntry = classToReturn.getSymbol(nameIndex);
305 if(cpEntry instanceof CPUTF8){
306 if(((CPUTF8)cpEntry).getValue().equals("Code")){
307 int codeLength= 0;
308 CodeAttribute code = new CodeAttribute(nameIndex, //nameIndex
309 attributeLength, //attributesLength
310 get2Bytes(), //max Stack
311 get2Bytes(), //max Locals
312 codeLength = get4Bytes(), //code length
313 new Code(getCode(codeLength)),
314 get2Bytes()); //exception table length
315
316 ExceptionTableEntry [] exceptionTableEntry =
317 new ExceptionTableEntry[code.getExceptionTableLength()];
318
319 for(int j=0;j < code.getExceptionTableLength();j++){
320 exceptionTableEntry[j] = new ExceptionTableEntry(get2Bytes(), // Start PC
321 get2Bytes(), // End PC
322 get2Bytes(), // Handler PC
323 get2Bytes()); // Catch Type
324 }
325
326 code.setExceptionTable(new ExceptionTable(exceptionTableEntry));
327
328 // Create code attribute attributes.
329 int codeAttributeAttributesCount = get2Bytes();
330 for(int p=0;p < codeAttributeAttributesCount; p++){
331
332 nameIndex = get2Bytes();
333 attributeLength = get4Bytes();
334
335 cpEntry = classToReturn.getSymbol(nameIndex);
336 if(cpEntry instanceof CPUTF8){
337 // Local Variable Table
338 if(((CPUTF8)cpEntry).getValue().equals("LocalVariableTable")){
339
340
341 int localVariableTableLength;
342 LocalVariableAttributeTable localVariableTable =
343 new LocalVariableAttributeTable(nameIndex, // nameIndex
344 attributeLength, // length
345 localVariableTableLength = get2Bytes());
346
347 LocalVariableEntry [] localVariableEntry =
348 new LocalVariableEntry[localVariableTableLength];
349
350 for(int n=0;n < localVariableTableLength;n++){
351 localVariableEntry[n] =
352 new LocalVariableEntry(get2Bytes(), // startPC
353 get2Bytes(), // entryLength
354 get2Bytes(), // nameIndex
355 get2Bytes(), // descriptorIndex
356 get2Bytes()); // stackFrameIndex
357 }
358
359 localVariableTable.setLocalVariableEntries(localVariableEntry);
360
361 code.setLocalVariableAttributeTable(localVariableTable);
362 }
363 else {
364 // Line Number Table
365 eatBytes(attributeLength);
366 }
367 }
368 else{
369 eatBytes(attributeLength);
370 }
371
372 }
373 attributesArray[k] = code;
374 }
375 else if(((CPUTF8)cpEntry).getValue().equals("Exceptions")){
376
377 int exceptionNameIndex = nameIndex;//get2Bytes();
378 int exceptionLength = attributeLength;//get4Bytes();
379 int exceptionCount = get2Bytes();
380 int [] exceptionTable = new int[exceptionCount];
381 for(int q = 0;q < exceptionCount;q++){
382 exceptionTable[q] = get2Bytes();
383 }
384 ExceptionAttribute exceptionAttribute = new ExceptionAttribute(exceptionNameIndex,
385 exceptionLength,
386 exceptionCount,
387 exceptionTable);
388 attributesArray[k] = exceptionAttribute;
389 }
390 else{
391 eatBytes(attributeLength);
392 }
393 }
394 else{
395 eatBytes(attributeLength);
396 }
397 }
398
399 //reportMessage(entry.toString());
400 methods[i] = entry;
401 }
402
403 Methods methodsCollection = new Methods(methods);
404 classToReturn.setMethods(methodsCollection);
405 return true;
406
407 }
408 private boolean loadFields(){
409
410 int fieldCount = get2Bytes();
411
412 FieldEntry [] fieldArray = new FieldEntry[fieldCount];
413
414 for(int i=0;i < fieldCount; i++){
415
416
417 int fieldAccessFlags = get2Bytes();
418 FieldAccessFlags accessFlags = new FieldAccessFlags(Modifier.isPublic(fieldAccessFlags),
419 Modifier.isPrivate(fieldAccessFlags),
420 Modifier.isFinal(fieldAccessFlags),
421 Modifier.isProtected(fieldAccessFlags),
422 Modifier.isStatic(fieldAccessFlags),
423 Modifier.isVolatile(fieldAccessFlags),
424 Modifier.isTransient(fieldAccessFlags));
425
426 int attributesCount;
427 int nameFieldIndex;
428 ConstantValueAttribute attributes = new ConstantValueAttribute();
429 FieldEntry fieldEntry = new FieldEntry(accessFlags,
430 nameFieldIndex = get2Bytes(), // nameIndex
431 get2Bytes(), // descriptorIndex
432 attributesCount = get2Bytes(), // attributesCount
433 attributes);
434 fieldEntry.setName(((CPUTF8)classToReturn.getSymbol(nameFieldIndex)).getValue());
435
436
437 for(int k = 0;k < attributesCount;k++){ //loop to cycle through attributes, looking
438 int nameIndex = get2Bytes(); //for the String ConstantValue
439 int attributesLength = get4Bytes();
440
441 attributes.setNameIndex(nameIndex);
442 attributes.setAttributesLength(attributesLength);
443
444 CPInfo cpEntry = classToReturn.getSymbol(nameIndex);
445 if(cpEntry instanceof CPUTF8){
446 if(((CPUTF8)cpEntry).getValue().equals("ConstantValue")){
447 int constantValueIndex = get2Bytes();
448 attributes.setConstantValueIndex(constantValueIndex);
449 }
450 else{
451 eatBytes(attributesLength);
452 }
453 }
454
455 else{
456 eatBytes(attributesLength);
457 }
458
459
460 }
461
462 fieldArray[i] = fieldEntry;
463
464 reportMessage(fieldEntry.toString());
465
466 }
467
468
469 Fields fields = new Fields(fieldArray);
470 classToReturn.setFields(fields);
471 return true;
472 }
473
474 private boolean loadInterfaces(){
475
476 int interfaceCount = get2Bytes();
477 int [] interfaceArray = new int[interfaceCount];
478 for(int i=0;i < interfaceCount;i++){
479 interfaceArray[i] = get2Bytes();
480 }
481
482 Interfaces interfaces = new Interfaces(interfaceArray);
483 reportMessage(interfaces.toString());
484
485 classToReturn.setInterfaces(interfaces);
486
487 return true;
488 }
489
490 private boolean loadSuperClass(){
491
492 int superClass = get2Bytes();
493
494 classProperties.setSuperClass(superClass);
495
496 reportMessage("Super class: "+superClass);
497
498 return true;
499 }
500 private boolean loadThisClass(){
501
502 int thisClass = get2Bytes();
503
504 classProperties.setThisClass(thisClass);
505
506 reportMessage("This class: "+thisClass);
507 return true;
508 }
509
510 private boolean loadAccessFlags(){
511
512 int flags = get2Bytes();
513 int flags2 = flags;
514 int flags3 = flags2;
515
516 ClassAccessFlags accessFlags = new ClassAccessFlags(Modifier.isPublic(flags),
517 Modifier.isFinal(flags),
518 true,
519 Modifier.isInterface(flags2),
520 Modifier.isAbstract(flags3));
521 reportMessage(accessFlags.toString());
522
523 classProperties.setAccessFlags(accessFlags);
524
525 return true;
526 }
527
528 private boolean toBoolean(int i){
529 System.out.println("i = " + i);
530 return i == 1;
531 }
532
533 private boolean loadConstantPool(){
534
535 int constantPoolCount = get2Bytes()-1;
536 classToReturn.initTableSize(constantPoolCount);
537
538 reportMessage("Constant Pool Count: "+constantPoolCount);
539
540 int [] classesToLoad = new int[constantPoolCount];
541 int classesToLoadIndex = 0;
542
543 for(int cpIndex = 1;cpIndex <= constantPoolCount;){
544 u1 = getByte();
545 CPInfo info = createCPInfo(u1, cpIndex);
546
547 if(info instanceof CPClass){
548 classesToLoad[classesToLoadIndex++] = ((CPClass)info).getNameIndex();
549 }
550
551 classToReturn.addSymbol(cpIndex,info);
552 cpIndex += getIncrement(info);
553 }
554
555 //Thread thread = null;
556
557 // Load referanced classes.
558 //for(int i=0;i < classesToLoadIndex;i++){
559 if(false){
560 ///
561 int i=1;
562 ///
563 String classToLoad = ((CPUTF8)classToReturn.getSymbol(classesToLoad[i])).getValue();
564
565 // Figure out the ; [ problem.
566 if(classToLoad.endsWith(";") || classToLoad.startsWith("["))
567 reportMessage("Skipping bad class name: "+classToLoad);
568
569 else if(!classToLoad.equals(currentClass)){
570
571 ClassLoader.loadClass(classToLoad+".class");
572 /*
573 final String toLoad = classToLoad;
574 Runnable r = new Runnable() {
575 public void run() {
576 ClassLoader.loadClass(toLoad+".class");
577 }
578 };
579 thread = new Thread(r, "ClassLoader: "+toLoad);
580 thread.start();
581 //r.run();
582 */
583 }
584 }
585
586 /*
587 try {
588 if(thread !=null)
589 thread.join();
590 }
591 catch(Exception e){System.out.println("Join Exception!!!: "+e);}
592 */
593
594 return true;
595 }
596
597 private int getIncrement(CPInfo info){
598
599 int increment = 1;
600
601 if(info instanceof CPDouble) increment++;
602 else if(info instanceof CPLong) increment++;
603
604 return increment;
605 }
606
607 private CPInfo createCPInfo(int tag, final int cpIndex){
608 CPInfo toReturn = null;
609
610 switch(tag){
611
612 case CPInfo.C_MethodRef:
613 toReturn = new CPMethodRef(get2Bytes(),get2Bytes());
614 break;
615 case CPInfo.C_Class:
616 toReturn = new CPClass(get2Bytes());
617 break;
618 case CPInfo.C_UTF8:
619 toReturn = new CPUTF8(getUTF8());
620 break;
621 case CPInfo.C_NameType:
622 toReturn = new CPNameType(get2Bytes(), get2Bytes());
623 break;
624 case CPInfo.C_Integer:
625 toReturn = new CPInteger(get4Bytes());
626 break;
627 case CPInfo.C_FieldRef:
628 toReturn = new CPFieldRef(get2Bytes(),get2Bytes());
629 break;
630 case CPInfo.C_Float:
631 toReturn = new CPFloat(getFloat());
632 break;
633 case CPInfo.C_Double:
634 toReturn = new CPDouble(get8Bytes());
635 break;
636 case CPInfo.C_Long:
637 toReturn = new CPLong(getLong());
638 break;
639 case CPInfo.C_InterfaceMethodRef:
640 toReturn = new CPInterfaceMethodRef(get2Bytes(), get2Bytes());
641 break;
642 case CPInfo.C_String:
643 toReturn = new CPString(get2Bytes());
644 break;
645 }
646 reportMessage(cpIndex+": "+toReturn.toString());
647 return toReturn;
648 }
649
650 private void reportMessage(String message){
651 // slower
652 if(verboseOn){
653 messages.append(message+"\n");
654 }
655 }
656
657 /***
658 * Gets the contents of the buffer of runtime messages from the classloader.
659 *
660 * @return StringBuffer The messages.
661 */
662 public StringBuffer getMessages(){ return messages; }
663
664 private boolean verifyVersions(){
665
666 minorVersion = get2Bytes();
667 reportMessage("Minor Version: "+Integer.toHexString(minorVersion));
668
669 majorVersion = get2Bytes();
670 reportMessage("Major Version: "+Integer.toHexString(majorVersion));
671
672 classProperties.setMinorVersion(minorVersion);
673 classProperties.setMajorVersion(majorVersion);
674
675 return true;
676
677 }
678
679 private boolean verifyMagicNumber(){
680
681 magicNumber = get4Bytes();
682 reportMessage("Magic: "+Integer.toHexString(magicNumber));
683
684 classProperties.setMagicNumber(magicNumber);
685 return magicNumber == 0xcafebabe;
686 }
687
688 private int getByte(){
689 int inByte = 0;
690 try{
691 inByte = dataInStream.readUnsignedByte();
692 }catch(IOException e){System.out.println(e);}
693 return inByte;
694 }
695 private int get2Bytes(){
696 int inShort = 0;
697 try{
698 inShort = dataInStream.readUnsignedShort();
699 return inShort;
700 }catch(IOException e){System.out.println(e);}
701 return inShort;
702 }
703 private int get4Bytes(){
704 int inInt = 0;
705 try{
706 inInt = dataInStream.readInt();
707 return inInt;
708 }catch(IOException e){System.out.println(e);}
709 return inInt;
710 }
711 private float getFloat(){
712 float inFloat = 0.0f;
713 try{
714 inFloat = dataInStream.readFloat();
715 return inFloat;
716 }catch(IOException e){System.out.println(e);}
717 return inFloat;
718 }
719 private long getLong(){
720 long inLong = 0;
721 try{
722 inLong = dataInStream.readLong();
723 return inLong;
724 }catch(IOException e){System.out.println(e);}
725 return inLong;
726 }
727 private int getShort(){
728 int inShort = 0;
729 try{
730 inShort = dataInStream.readShort();
731 return inShort;
732 }catch(IOException e){System.out.println(e);}
733 return inShort;
734 }
735 private double get8Bytes(){
736 double inDouble = 0;
737 try{
738 inDouble = dataInStream.readDouble();
739 return inDouble;
740 }catch(IOException e){System.out.println(e);}
741 return inDouble;
742 }
743
744 private int [] getCode(int codeLength){
745 int [] toReturn = new int[codeLength];
746
747 for(int i = 0;i < codeLength;i++){
748 toReturn[i] = getByte();
749 }
750
751 return toReturn;
752 }
753
754
755 private void eatBytes(int bytesToEat){
756 try{
757 for(int i = 0;i < bytesToEat;i++){
758 dataInStream.readByte();
759 }
760 }catch(IOException e){System.out.println(e);}
761 }
762
763 private String getUTF8(){
764 String toReturn = null;
765 try{
766 toReturn = dataInStream.readUTF();
767 }
768 catch(IOException e){System.out.println(e);}
769
770 return toReturn;
771 }
772
773 public static byte [] readClassFromJar(String jarFileName, String fileToRead){
774
775 byte [] toReturn = null;
776 try{
777
778 JarFile jarFile = new JarFile(jarFileName);
779 JarEntry jarEntry = jarFile.getJarEntry(fileToRead);
780
781 if(jarEntry == null)
782 return null;
783
784 DataInputStream inStream = new DataInputStream(jarFile.getInputStream(jarEntry));
785 byte[] b = new byte[inStream.available()];
786
787 inStream.readFully(b);
788 inStream.close();
789
790 toReturn = b;
791 }
792 catch(IOException e){ e.printStackTrace(); }
793
794 return toReturn;
795 }
796 }
797
This page was automatically generated by Maven