KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > objectweb > asm > ClassReader


1 /***
2  * ASM: a very small and fast Java bytecode manipulation framework
3  * Copyright (c) 2000-2005 INRIA, France Telecom
4  * All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  * 1. Redistributions of source code must retain the above copyright
10  * notice, this list of conditions and the following disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  * notice, this list of conditions and the following disclaimer in the
13  * documentation and/or other materials provided with the distribution.
14  * 3. Neither the name of the copyright holders nor the names of its
15  * contributors may be used to endorse or promote products derived from
16  * this software without specific prior written permission.
17  *
18  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
19  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
22  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
23  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
24  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
25  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
26  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
27  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
28  * THE POSSIBILITY OF SUCH DAMAGE.
29  */

30 package org.objectweb.asm;
31
32 import java.io.InputStream JavaDoc;
33 import java.io.IOException JavaDoc;
34
35 /**
36  * A Java class parser to make a {@link ClassVisitor} visit an existing class.
37  * This class parses a byte array conforming to the Java class file format and
38  * calls the appropriate visit methods of a given class visitor for each field,
39  * method and bytecode instruction encountered.
40  *
41  * @author Eric Bruneton
42  * @author Eugene Kuleshov
43  */

44 public class ClassReader {
45
46     /**
47      * The class to be parsed. <i>The content of this array must not be
48      * modified. This field is intended for {@link Attribute} sub classes, and
49      * is normally not needed by class generators or adapters.</i>
50      */

51     public final byte[] b;
52
53     /**
54      * The start index of each constant pool item in {@link #b b}, plus one.
55      * The one byte offset skips the constant pool item tag that indicates its
56      * type.
57      */

58     private int[] items;
59
60     /**
61      * The String objects corresponding to the CONSTANT_Utf8 items. This cache
62      * avoids multiple parsing of a given CONSTANT_Utf8 constant pool item,
63      * which GREATLY improves performances (by a factor 2 to 3). This caching
64      * strategy could be extended to all constant pool items, but its benefit
65      * would not be so great for these items (because they are much less
66      * expensive to parse than CONSTANT_Utf8 items).
67      */

68     private String JavaDoc[] strings;
69
70     /**
71      * Maximum length of the strings contained in the constant pool of the
72      * class.
73      */

74     private int maxStringLength;
75
76     /**
77      * Start index of the class header information (access, name...) in
78      * {@link #b b}.
79      */

80     public final int header;
81
82     // ------------------------------------------------------------------------
83
// Constructors
84
// ------------------------------------------------------------------------
85

86     /**
87      * Constructs a new {@link ClassReader} object.
88      *
89      * @param b the bytecode of the class to be read.
90      */

91     public ClassReader(final byte[] b) {
92         this(b, 0, b.length);
93     }
94
95     /**
96      * Constructs a new {@link ClassReader} object.
97      *
98      * @param b the bytecode of the class to be read.
99      * @param off the start offset of the class data.
100      * @param len the length of the class data.
101      */

102     public ClassReader(final byte[] b, final int off, final int len) {
103         this.b = b;
104         // parses the constant pool
105
items = new int[readUnsignedShort(off + 8)];
106         strings = new String JavaDoc[items.length];
107         int max = 0;
108         int index = off + 10;
109         for (int i = 1; i < items.length; ++i) {
110             items[i] = index + 1;
111             int tag = b[index];
112             int size;
113             switch (tag) {
114                 case ClassWriter.FIELD:
115                 case ClassWriter.METH:
116                 case ClassWriter.IMETH:
117                 case ClassWriter.INT:
118                 case ClassWriter.FLOAT:
119                 case ClassWriter.NAME_TYPE:
120                     size = 5;
121                     break;
122                 case ClassWriter.LONG:
123                 case ClassWriter.DOUBLE:
124                     size = 9;
125                     ++i;
126                     break;
127                 case ClassWriter.UTF8:
128                     size = 3 + readUnsignedShort(index + 1);
129                     if (size > max) {
130                         max = size;
131                     }
132                     break;
133                 // case ClassWriter.CLASS:
134
// case ClassWriter.STR:
135
default:
136                     size = 3;
137                     break;
138             }
139             index += size;
140         }
141         maxStringLength = max;
142         // the class header information starts just after the constant pool
143
header = index;
144     }
145
146     /**
147      * Constructs a new {@link ClassReader} object.
148      *
149      * @param is an input stream from which to read the class.
150      * @throws IOException if a problem occurs during reading.
151      */

152     public ClassReader(final InputStream JavaDoc is) throws IOException JavaDoc {
153         this(readClass(is));
154     }
155
156     /**
157      * Constructs a new {@link ClassReader} object.
158      *
159      * @param name the fully qualified name of the class to be read.
160      * @throws IOException if an exception occurs during reading.
161      */

162     public ClassReader(final String JavaDoc name) throws IOException JavaDoc {
163         this(ClassLoader.getSystemResourceAsStream(name.replace('.', '/')
164                 + ".class"));
165     }
166
167     /**
168      * Reads the bytecode of a class.
169      *
170      * @param is an input stream from which to read the class.
171      * @return the bytecode read from the given input stream.
172      * @throws IOException if a problem occurs during reading.
173      */

174     private static byte[] readClass(final InputStream JavaDoc is) throws IOException JavaDoc {
175         if (is == null) {
176             throw new IOException JavaDoc("Class not found");
177         }
178         byte[] b = new byte[is.available()];
179         int len = 0;
180         while (true) {
181             int n = is.read(b, len, b.length - len);
182             if (n == -1) {
183                 if (len < b.length) {
184                     byte[] c = new byte[len];
185                     System.arraycopy(b, 0, c, 0, len);
186                     b = c;
187                 }
188                 return b;
189             }
190             len += n;
191             if (len == b.length) {
192                 byte[] c = new byte[b.length + 1000];
193                 System.arraycopy(b, 0, c, 0, len);
194                 b = c;
195             }
196         }
197     }
198
199     // ------------------------------------------------------------------------
200
// Public methods
201
// ------------------------------------------------------------------------
202

203     /**
204      * Makes the given visitor visit the Java class of this {@link ClassReader}.
205      * This class is the one specified in the constructor (see
206      * {@link #ClassReader(byte[]) ClassReader}).
207      *
208      * @param classVisitor the visitor that must visit this class.
209      * @param skipDebug <tt>true</tt> if the debug information of the class
210      * must not be visited. In this case the
211      * {@link MethodVisitor#visitLocalVariable visitLocalVariable} and
212      * {@link MethodVisitor#visitLineNumber visitLineNumber} methods will
213      * not be called.
214      */

215     public void accept(final ClassVisitor classVisitor, final boolean skipDebug)
216     {
217         accept(classVisitor, new Attribute[0], skipDebug);
218     }
219
220     /**
221      * Makes the given visitor visit the Java class of this {@link ClassReader}.
222      * This class is the one specified in the constructor (see
223      * {@link #ClassReader(byte[]) ClassReader}).
224      *
225      * @param classVisitor the visitor that must visit this class.
226      * @param attrs prototypes of the attributes that must be parsed during the
227      * visit of the class. Any attribute whose type is not equal to the
228      * type of one the prototypes will be ignored.
229      * @param skipDebug <tt>true</tt> if the debug information of the class
230      * must not be visited. In this case the
231      * {@link MethodVisitor#visitLocalVariable visitLocalVariable} and
232      * {@link MethodVisitor#visitLineNumber visitLineNumber} methods will
233      * not be called.
234      */

235     public void accept(
236         final ClassVisitor classVisitor,
237         final Attribute[] attrs,
238         final boolean skipDebug)
239     {
240         byte[] b = this.b; // the bytecode array
241
char[] c = new char[maxStringLength]; // buffer used to read strings
242
int i, j, k; // loop variables
243
int u, v, w; // indexes in b
244
Attribute attr;
245
246         int access;
247         String JavaDoc name;
248         String JavaDoc desc;
249         String JavaDoc attrName;
250         String JavaDoc signature;
251         int anns = 0;
252         int ianns = 0;
253         Attribute cattrs = null;
254
255         // visits the header
256
u = header;
257         access = readUnsignedShort(u);
258         name = readClass(u + 2, c);
259         v = items[readUnsignedShort(u + 4)];
260         String JavaDoc superClassName = v == 0 ? null : readUTF8(v, c);
261         String JavaDoc[] implementedItfs = new String JavaDoc[readUnsignedShort(u + 6)];
262         w = 0;
263         u += 8;
264         for (i = 0; i < implementedItfs.length; ++i) {
265             implementedItfs[i] = readClass(u, c);
266             u += 2;
267         }
268
269         // skips fields and methods
270
v = u;
271         i = readUnsignedShort(v);
272         v += 2;
273         for (; i > 0; --i) {
274             j = readUnsignedShort(v + 6);
275             v += 8;
276             for (; j > 0; --j) {
277                 v += 6 + readInt(v + 2);
278             }
279         }
280         i = readUnsignedShort(v);
281         v += 2;
282         for (; i > 0; --i) {
283             j = readUnsignedShort(v + 6);
284             v += 8;
285             for (; j > 0; --j) {
286                 v += 6 + readInt(v + 2);
287             }
288         }
289         // reads the class's attributes
290
signature = null;
291         String JavaDoc sourceFile = null;
292         String JavaDoc sourceDebug = null;
293         String JavaDoc enclosingOwner = null;
294         String JavaDoc enclosingName = null;
295         String JavaDoc enclosingDesc = null;
296
297         i = readUnsignedShort(v);
298         v += 2;
299         for (; i > 0; --i) {
300             attrName = readUTF8(v, c);
301             if (attrName.equals("SourceFile")) {
302                 sourceFile = readUTF8(v + 6, c);
303             } else if (attrName.equals("Deprecated")) {
304                 access |= Opcodes.ACC_DEPRECATED;
305             } else if (attrName.equals("Synthetic")) {
306                 access |= Opcodes.ACC_SYNTHETIC;
307             } else if (attrName.equals("Annotation")) {
308                 access |= Opcodes.ACC_ANNOTATION;
309             } else if (attrName.equals("Enum")) {
310                 access |= Opcodes.ACC_ENUM;
311             } else if (attrName.equals("InnerClasses")) {
312                 w = v + 6;
313             } else if (attrName.equals("Signature")) {
314                 signature = readUTF8(v + 6, c);
315             } else if (attrName.equals("SourceDebugExtension")) {
316                 int len = readInt(v + 2);
317                 sourceDebug = readUTF(v + 6, len, new char[len]);
318             } else if (attrName.equals("EnclosingMethod")) {
319                 enclosingOwner = readClass(v + 6, c);
320                 int item = readUnsignedShort(v + 8);
321                 if (item != 0) {
322                     enclosingName = readUTF8(items[item], c);
323                     enclosingDesc = readUTF8(items[item] + 2, c);
324                 }
325             } else if (attrName.equals("RuntimeVisibleAnnotations")) {
326                 anns = v + 6;
327             } else if (attrName.equals("RuntimeInvisibleAnnotations")) {
328                 ianns = v + 6;
329             } else {
330                 attr = readAttribute(attrs,
331                         attrName,
332                         v + 6,
333                         readInt(v + 2),
334                         c,
335                         -1,
336                         null);
337                 if (attr != null) {
338                     attr.next = cattrs;
339                     cattrs = attr;
340                 }
341             }
342             v += 6 + readInt(v + 2);
343         }
344         // calls the visit method
345
classVisitor.visit(readInt(4),
346                 access,
347                 name,
348                 signature,
349                 superClassName,
350                 implementedItfs);
351
352         // calls the visitSource method
353
if (sourceFile != null || sourceDebug != null) {
354             classVisitor.visitSource(sourceFile, sourceDebug);
355         }
356
357         // calls the visitOuterClass method
358
if (enclosingOwner != null) {
359             classVisitor.visitOuterClass(enclosingOwner,
360                     enclosingName,
361                     enclosingDesc);
362         }
363
364         // visits the class annotations
365
for (i = 1; i >= 0; --i) {
366             v = i == 0 ? ianns : anns;
367             if (v != 0) {
368                 j = readUnsignedShort(v);
369                 v += 2;
370                 for (; j > 0; --j) {
371                     desc = readUTF8(v, c);
372                     v += 2;
373                     v = readAnnotationValues(v,
374                             c,
375                             classVisitor.visitAnnotation(desc, i != 0));
376                 }
377             }
378         }
379
380         // visits the class attributes
381
while (cattrs != null) {
382             attr = cattrs.next;
383             cattrs.next = null;
384             classVisitor.visitAttribute(cattrs);
385             cattrs = attr;
386         }
387
388         // class the visitInnerClass method
389
if (w != 0) {
390             i = readUnsignedShort(w);
391             w += 2;
392             for (; i > 0; --i) {
393                 classVisitor.visitInnerClass(readUnsignedShort(w) == 0
394                         ? null
395                         : readClass(w, c), readUnsignedShort(w + 2) == 0
396                         ? null
397                         : readClass(w + 2, c), readUnsignedShort(w + 4) == 0
398                         ? null
399                         : readUTF8(w + 4, c), readUnsignedShort(w + 6));
400                 w += 8;
401             }
402         }
403
404         // visits the fields
405
i = readUnsignedShort(u);
406         u += 2;
407         for (; i > 0; --i) {
408             access = readUnsignedShort(u);
409             name = readUTF8(u + 2, c);
410             desc = readUTF8(u + 4, c);
411             // visits the field's attributes and looks for a ConstantValue
412
// attribute
413
int fieldValueItem = 0;
414             signature = null;
415             anns = 0;
416             ianns = 0;
417             cattrs = null;
418
419             j = readUnsignedShort(u + 6);
420             u += 8;
421             for (; j > 0; --j) {
422                 attrName = readUTF8(u, c);
423                 if (attrName.equals("ConstantValue")) {
424                     fieldValueItem = readUnsignedShort(u + 6);
425                 } else if (attrName.equals("Synthetic")) {
426                     access |= Opcodes.ACC_SYNTHETIC;
427                 } else if (attrName.equals("Deprecated")) {
428                     access |= Opcodes.ACC_DEPRECATED;
429                 } else if (attrName.equals("Enum")) {
430                     access |= Opcodes.ACC_ENUM;
431                 } else if (attrName.equals("Signature")) {
432                     signature = readUTF8(u + 6, c);
433                 } else if (attrName.equals("RuntimeVisibleAnnotations")) {
434                     anns = u + 6;
435                 } else if (attrName.equals("RuntimeInvisibleAnnotations")) {
436                     ianns = u + 6;
437                 } else {
438                     attr = readAttribute(attrs,
439                             attrName,
440                             u + 6,
441                             readInt(u + 2),
442                             c,
443                             -1,
444                             null);
445                     if (attr != null) {
446                         attr.next = cattrs;
447                         cattrs = attr;
448                     }
449                 }
450                 u += 6 + readInt(u + 2);
451             }
452             // reads the field's value, if any
453
Object JavaDoc value = (fieldValueItem == 0
454                     ? null
455                     : readConst(fieldValueItem, c));
456             // visits the field
457
FieldVisitor fv = classVisitor.visitField(access,
458                     name,
459                     desc,
460                     signature,
461                     value);
462             // visits the field annotations and attributes
463
if (fv != null) {
464                 for (j = 1; j >= 0; --j) {
465                     v = j == 0 ? ianns : anns;
466                     if (v != 0) {
467                         k = readUnsignedShort(v);
468                         v += 2;
469                         for (; k > 0; --k) {
470                             desc = readUTF8(v, c);
471                             v += 2;
472                             v = readAnnotationValues(v,
473                                     c,
474                                     fv.visitAnnotation(desc, j != 0));
475                         }
476                     }
477                 }
478                 while (cattrs != null) {
479                     attr = cattrs.next;
480                     cattrs.next = null;
481                     fv.visitAttribute(cattrs);
482                     cattrs = attr;
483                 }
484                 fv.visitEnd();
485             }
486         }
487
488         // visits the methods
489
i = readUnsignedShort(u);
490         u += 2;
491         for (; i > 0; --i) {
492             access = readUnsignedShort(u);
493             name = readUTF8(u + 2, c);
494             desc = readUTF8(u + 4, c);
495             signature = null;
496             anns = 0;
497             ianns = 0;
498             int dann = 0;
499             int mpanns = 0;
500             int impanns = 0;
501             cattrs = null;
502             v = 0;
503             w = 0;
504
505             // looks for Code and Exceptions attributes
506
j = readUnsignedShort(u + 6);
507             u += 8;
508             for (; j > 0; --j) {
509                 attrName = readUTF8(u, c);
510                 u += 2;
511                 int attrSize = readInt(u);
512                 u += 4;
513                 if (attrName.equals("Code")) {
514                     v = u;
515                 } else if (attrName.equals("Exceptions")) {
516                     w = u;
517                 } else if (attrName.equals("Synthetic")) {
518                     access |= Opcodes.ACC_SYNTHETIC;
519                 } else if (attrName.equals("Varargs")) {
520                     access |= Opcodes.ACC_VARARGS;
521                 } else if (attrName.equals("Bridge")) {
522                     access |= Opcodes.ACC_BRIDGE;
523                 } else if (attrName.equals("Deprecated")) {
524                     access |= Opcodes.ACC_DEPRECATED;
525                 } else if (attrName.equals("Signature")) {
526                     signature = readUTF8(u, c);
527                 } else if (attrName.equals("AnnotationDefault")) {
528                     dann = u;
529                 } else if (attrName.equals("RuntimeVisibleAnnotations")) {
530                     anns = u;
531                 } else if (attrName.equals("RuntimeInvisibleAnnotations")) {
532                     ianns = u;
533                 } else if (attrName.equals("RuntimeVisibleParameterAnnotations"))
534                 {
535                     mpanns = u;
536                 } else if (attrName.equals("RuntimeInvisibleParameterAnnotations"))
537                 {
538                     impanns = u;
539                 } else {
540                     attr = readAttribute(attrs,
541                             attrName,
542                             u,
543                             attrSize,
544                             c,
545                             -1,
546                             null);
547                     if (attr != null) {
548                         attr.next = cattrs;
549                         cattrs = attr;
550                     }
551                 }
552                 u += attrSize;
553             }
554             // reads declared exceptions
555
String JavaDoc[] exceptions;
556             if (w == 0) {
557                 exceptions = null;
558             } else {
559                 exceptions = new String JavaDoc[readUnsignedShort(w)];
560                 w += 2;
561                 for (j = 0; j < exceptions.length; ++j) {
562                     exceptions[j] = readClass(w, c);
563                     w += 2;
564                 }
565             }
566
567             // visits the method's code, if any
568
MethodVisitor mv = classVisitor.visitMethod(access,
569                     name,
570                     desc,
571                     signature,
572                     exceptions);
573
574             if (mv != null) {
575                 if (dann != 0) {
576                     AnnotationVisitor dv = mv.visitAnnotationDefault();
577                     readAnnotationValue(dann, c, null, dv);
578                     dv.visitEnd();
579                 }
580                 for (j = 1; j >= 0; --j) {
581                     w = j == 0 ? ianns : anns;
582                     if (w != 0) {
583                         k = readUnsignedShort(w);
584                         w += 2;
585                         for (; k > 0; --k) {
586                             desc = readUTF8(w, c);
587                             w += 2;
588                             w = readAnnotationValues(w,
589                                     c,
590                                     mv.visitAnnotation(desc, j != 0));
591                         }
592                     }
593                 }
594                 if (mpanns != 0) {
595                     readParameterAnnotations(mpanns, c, true, mv);
596                 }
597                 if (impanns != 0) {
598                     readParameterAnnotations(impanns, c, false, mv);
599                 }
600                 while (cattrs != null) {
601                     attr = cattrs.next;
602                     cattrs.next = null;
603                     mv.visitAttribute(cattrs);
604                     cattrs = attr;
605                 }
606             }
607
608             if (mv != null && v != 0) {
609                 int maxStack = readUnsignedShort(v);
610                 int maxLocals = readUnsignedShort(v + 2);
611                 int codeLength = readInt(v + 4);
612                 v += 8;
613
614                 int codeStart = v;
615                 int codeEnd = v + codeLength;
616
617                 // 1st phase: finds the labels
618
int label;
619                 Label[] labels = new Label[codeLength + 1];
620                 while (v < codeEnd) {
621                     int opcode = b[v] & 0xFF;
622                     switch (ClassWriter.TYPE[opcode]) {
623                         case ClassWriter.NOARG_INSN:
624                         case ClassWriter.IMPLVAR_INSN:
625                             v += 1;
626                             break;
627                         case ClassWriter.LABEL_INSN:
628                             label = v - codeStart + readShort(v + 1);
629                             if (labels[label] == null) {
630                                 labels[label] = new Label();
631                             }
632                             v += 3;
633                             break;
634                         case ClassWriter.LABELW_INSN:
635                             label = v - codeStart + readInt(v + 1);
636                             if (labels[label] == null) {
637                                 labels[label] = new Label();
638                             }
639                             v += 5;
640                             break;
641                         case ClassWriter.WIDE_INSN:
642                             opcode = b[v + 1] & 0xFF;
643                             if (opcode == Opcodes.IINC) {
644                                 v += 6;
645                             } else {
646                                 v += 4;
647                             }
648                             break;
649                         case ClassWriter.TABL_INSN:
650                             // skips 0 to 3 padding bytes
651
w = v - codeStart;
652                             v = v + 4 - (w & 3);
653                             // reads instruction
654
label = w + readInt(v);
655                             v += 4;
656                             if (labels[label] == null) {
657                                 labels[label] = new Label();
658                             }
659                             j = readInt(v);
660                             v += 4;
661                             j = readInt(v) - j + 1;
662                             v += 4;
663                             for (; j > 0; --j) {
664                                 label = w + readInt(v);
665                                 v += 4;
666                                 if (labels[label] == null) {
667                                     labels[label] = new Label();
668                                 }
669                             }
670                             break;
671                         case ClassWriter.LOOK_INSN:
672                             // skips 0 to 3 padding bytes
673
w = v - codeStart;
674                             v = v + 4 - (w & 3);
675                             // reads instruction
676
label = w + readInt(v);
677                             v += 4;
678                             if (labels[label] == null) {
679                                 labels[label] = new Label();
680                             }
681                             j = readInt(v);
682                             v += 4;
683                             for (; j > 0; --j) {
684                                 v += 4; // skips key
685
label = w + readInt(v);
686                                 v += 4;
687                                 if (labels[label] == null) {
688                                     labels[label] = new Label();
689                                 }
690                             }
691                             break;
692                         case ClassWriter.VAR_INSN:
693                         case ClassWriter.SBYTE_INSN:
694                         case ClassWriter.LDC_INSN:
695                             v += 2;
696                             break;
697                         case ClassWriter.SHORT_INSN:
698                         case ClassWriter.LDCW_INSN:
699                         case ClassWriter.FIELDORMETH_INSN:
700                         case ClassWriter.TYPE_INSN:
701                         case ClassWriter.IINC_INSN:
702                             v += 3;
703                             break;
704                         case ClassWriter.ITFMETH_INSN:
705                             v += 5;
706                             break;
707                         // case MANA_INSN:
708
default:
709                             v += 4;
710                             break;
711            &