KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > oracle > toplink > libraries > asm > ClassReader


1 /***
2  * ASM: a very small and fast Java bytecode manipulation framework
3  * Copyright (c) 2000,2002,2003 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
31 package oracle.toplink.libraries.asm;
32
33 import java.io.InputStream JavaDoc;
34 import java.io.IOException JavaDoc;
35
36 /**
37  * A Java class parser to make a {@link ClassVisitor ClassVisitor} visit an
38  * existing class. This class parses a byte array conforming to the Java class
39  * file format and calls the appropriate visit methods of a given class visitor
40  * for each field, method and bytecode instruction encountered.
41  *
42  * @author Eric Bruneton
43  */

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

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

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

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

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

83
84   private int header;
85
86   // --------------------------------------------------------------------------
87
// Constructors
88
// --------------------------------------------------------------------------
89

90   /**
91    * Constructs a new {@link ClassReader ClassReader} object.
92    *
93    * @param b the bytecode of the class to be read.
94    */

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

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

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

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

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

210   /**
211    * Makes the given visitor visit the Java class of this {@link ClassReader
212    * ClassReader}. This class is the one specified in the constructor (see
213    * {@link #ClassReader(byte[]) ClassReader}).
214    *
215    * @param classVisitor the visitor that must visit this class.
216    * @param skipDebug <tt>true</tt> if the debug information of the class must
217    * not be visited. In this case the {@link CodeVisitor#visitLocalVariable
218    * visitLocalVariable} and {@link CodeVisitor#visitLineNumber
219    * visitLineNumber} methods will not be called.
220    */

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

243
244   public void accept (
245     final ClassVisitor classVisitor,
246     final Attribute[] attrs,
247     final boolean skipDebug)
248   {
249     byte[] b = this.b; // the bytecode array
250
char[] c = new char[maxStringLength]; // buffer used to read strings
251
int i, j, k; // loop variables
252
int u, v, w; // indexes in b
253
Attribute attr;
254
255     // visits the header
256
u = header;
257     int version = readInt(4);
258     int access = readUnsignedShort(u);
259     String JavaDoc className = readClass(u + 2, c);
260     v = items[readUnsignedShort(u + 4)];
261     String JavaDoc superClassName = v == 0 ? null : readUTF8(v, c);
262     String JavaDoc[] implementedItfs = new String JavaDoc[readUnsignedShort(u + 6)];
263     String JavaDoc sourceFile = null;
264     Attribute clattrs = null;
265     w = 0;
266     u += 8;
267     for (i = 0; i < implementedItfs.length; ++i) {
268       implementedItfs[i] = readClass(u, c); u += 2;
269     }
270     // skips fields and methods
271
v = u;
272     i = readUnsignedShort(v); 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); v += 2;
281     for ( ; i > 0; --i) {
282       j = readUnsignedShort(v + 6);
283       v += 8;
284       for ( ; j > 0; --j) {
285         v += 6 + readInt(v + 2);
286       }
287     }
288     // reads the class's attributes
289
i = readUnsignedShort(v); v += 2;
290     for ( ; i > 0; --i) {
291       String JavaDoc attrName = readUTF8(v, c);
292       if (attrName.equals("SourceFile")) {
293         sourceFile = readUTF8(v + 6, c);
294       } else if (attrName.equals("Deprecated")) {
295         access |= Constants.ACC_DEPRECATED;
296       } else if (attrName.equals("Synthetic")) {
297         access |= Constants.ACC_SYNTHETIC;
298       } else if (attrName.equals("InnerClasses")) {
299         w = v + 6;
300       } else {
301         attr = readAttribute(
302             attrs, attrName, v + 6, readInt(v + 2), c, -1, null);
303         if (attr != null) {
304           attr.next = clattrs;
305           clattrs = attr;
306         }
307       }
308       v += 6 + readInt(v + 2);
309     }
310     // calls the visit method
311
classVisitor.visit(
312       version, access, className, superClassName, implementedItfs, sourceFile);
313
314     // visits the inner classes info
315
if (w != 0) {
316       i = readUnsignedShort(w); w += 2;
317       for ( ; i > 0; --i) {
318         classVisitor.visitInnerClass(
319           readUnsignedShort(w) == 0 ? null : readClass(w, c),
320           readUnsignedShort(w + 2) == 0 ? null : readClass(w + 2, c),
321           readUnsignedShort(w + 4) == 0 ? null : readUTF8(w + 4, c),
322           readUnsignedShort(w + 6));
323         w += 8;
324       }
325     }
326
327     // visits the fields
328
i = readUnsignedShort(u); u += 2;
329     for ( ; i > 0; --i) {
330       access = readUnsignedShort(u);
331       String JavaDoc fieldName = readUTF8(u + 2, c);
332       String JavaDoc fieldDesc = readUTF8(u + 4, c);
333       Attribute fattrs = null;
334       // visits the field's attributes and looks for a ConstantValue attribute
335
int fieldValueItem = 0;
336       j = readUnsignedShort(u + 6);
337       u += 8;
338       for ( ; j > 0; --j) {
339         String JavaDoc attrName = readUTF8(u, c);
340         if (attrName.equals("ConstantValue")) {
341           fieldValueItem = readUnsignedShort(u + 6);
342         } else if (attrName.equals("Synthetic")) {
343           access |= Constants.ACC_SYNTHETIC;
344         } else if (attrName.equals("Deprecated")) {
345           access |= Constants.ACC_DEPRECATED;
346         } else {
347           attr = readAttribute(
348             attrs, attrName, u + 6, readInt(u + 2), c, -1, null);
349           if (attr != null) {
350             attr.next = fattrs;
351             fattrs = attr;
352           }
353         }
354         u += 6 + readInt(u + 2);
355       }
356       // reads the field's value, if any
357
Object JavaDoc value = (fieldValueItem == 0 ? null : readConst(fieldValueItem, c));
358       // visits the field
359
classVisitor.visitField(access, fieldName, fieldDesc, value, fattrs);
360     }
361
362     // visits the methods
363
i = readUnsignedShort(u); u += 2;
364     for ( ; i > 0; --i) {
365       access = readUnsignedShort(u);
366       String JavaDoc methName = readUTF8(u + 2, c);
367       String JavaDoc methDesc = readUTF8(u + 4, c);
368       Attribute mattrs = null;
369       Attribute cattrs = null;
370       v = 0;
371       w = 0;
372       // looks for Code and Exceptions attributes
373
j = readUnsignedShort(u + 6);
374       u += 8;
375       for ( ; j > 0; --j) {
376         String JavaDoc attrName = readUTF8(u, c); u += 2;
377         int attrSize = readInt(u); u += 4;
378         if (attrName.equals("Code")) {
379           v = u;
380         } else if (attrName.equals("Exceptions")) {
381           w = u;
382         } else if (attrName.equals("Synthetic")) {
383           access |= Constants.ACC_SYNTHETIC;
384         } else if (attrName.equals("Deprecated")) {
385           access |= Constants.ACC_DEPRECATED;
386         } else {
387           attr = readAttribute(attrs, attrName, u, attrSize, c, -1, null);
388           if (attr != null) {
389             attr.next = mattrs;
390             mattrs = attr;
391           }
392         }
393         u += attrSize;
394       }
395       // reads declared exceptions
396
String JavaDoc[] exceptions;
397       if (w == 0) {
398         exceptions = null;
399       } else {
400         exceptions = new String JavaDoc[readUnsignedShort(w)]; w += 2;
401         for (j = 0; j < exceptions.length; ++j) {
402           exceptions[j] = readClass(w, c); w += 2;
403         }
404       }
405
406       // visits the method's code, if any
407
CodeVisitor cv;
408       cv = classVisitor.visitMethod(
409         access, methName, methDesc, exceptions, mattrs);
410       if (cv != null && v != 0) {
411         int maxStack = readUnsignedShort(v);
412         int maxLocals = readUnsignedShort(v + 2);
413         int codeLength = readInt(v + 4);
414         v += 8;
415
416         int codeStart = v;
417         int codeEnd = v + codeLength;
418
419         // 1st phase: finds the labels
420
int label;
421         Label[] labels = new Label[codeLength + 1];
422         while (v < codeEnd) {
423           int opcode = b[v] & 0xFF;
424           switch (ClassWriter.TYPE[opcode]) {
425             case ClassWriter.NOARG_INSN:
426             case ClassWriter.IMPLVAR_INSN:
427               v += 1;
428               break;
429             case ClassWriter.LABEL_INSN:
430               label = v - codeStart + readShort(v + 1);
431               if (labels[label] == null) {
432                 labels[label] = new Label();
433               }
434               v += 3;
435               break;
436             case ClassWriter.LABELW_INSN:
437               label = v - codeStart + readInt(v + 1);
438               if (labels[label] == null) {
439                 labels[label] = new Label();
440               }
441               v += 5;
442               break;
443             case ClassWriter.WIDE_INSN:
444               opcode = b[v + 1] & 0xFF;
445               if (opcode == Constants.IINC) {
446                 v += 6;
447               } else {
448                 v += 4;
449               }
450               break;
451             case ClassWriter.TABL_INSN:
452               // skips 0 to 3 padding bytes
453
w = v - codeStart;
454               v = v + 4 - (w & 3);
455               // reads instruction
456
label = w + readInt(v); v += 4;
457               if (labels[label] == null) {
458                 labels[label] = new Label();
459               }
460               j = readInt(v); v += 4;
461               j = readInt(v) - j + 1; v += 4;
462               for ( ; j > 0; --j) {
463                 label = w + readInt(v); v += 4;
464                 if (labels[label] == null) {
465                   labels[label] = new Label();
466                 }
467               }
468               break;
469             case ClassWriter.LOOK_INSN:
470               // skips 0 to 3 padding bytes
471
w = v - codeStart;
472               v = v + 4 - (w & 3);
473               // reads instruction
474
label = w + readInt(v); v += 4;
475               if (labels[label] == null) {
476                 labels[label] = new Label();
477               }
478               j = readInt(v); v += 4;
479               for ( ; j > 0; --j) {
480                 v += 4; // skips key
481
label = w + readInt(v); v += 4;
482                 if (labels[label] == null) {
483                   labels[label] = new Label();
484                 }
485               }
486               break;
487             case ClassWriter.VAR_INSN:
488             case ClassWriter.SBYTE_INSN:
489             case ClassWriter.LDC_INSN:
490               v += 2;
491               break;
492             case ClassWriter.SHORT_INSN:
493             case ClassWriter.LDCW_INSN:
494             case ClassWriter.FIELDORMETH_INSN:
495             case ClassWriter.TYPE_INSN:
496             case ClassWriter.IINC_INSN:
497               v += 3;
498               break;
499             case ClassWriter.ITFMETH_INSN:
500               v += 5;
501               break;
502             // case MANA_INSN:
503
default:
504               v += 4;
505               break;
506           }
507         }
508         // parses the try catch entries
509
j = readUnsignedShort(v); v += 2;
510         for ( ; j > 0; --j) {
511           label = readUnsignedShort(v);
512           if (labels[label] == null) {
513             labels[label] = new Label();
514           }
515           label = readUnsignedShort(v + 2);
516           if (labels[label] == null) {
517             labels[label] = new Label();
518           }
519           label = readUnsignedShort(v + 4);
520           if (labels[label] == null) {
521             labels[label] = new Label();
522           }
523           v += 8;
524         }
525         // parses the local variable, line number tables, and code attributes
526
j = readUnsignedShort(v); v += 2;
527         for ( ; j > 0; --j) {
528           String JavaDoc attrName = readUTF8(v, c);
529           if (attrName.equals("LocalVariableTable")) {
530             if (!skipDebug) {
531               k = readUnsignedShort(v + 6);
532               w = v + 8;
533               for ( ; k > 0; --k) {
534                 label = readUnsignedShort(w);
535                 if (labels[label] == null) {
536                   labels[label] = new Label();
537                 }
538                 label += readUnsignedShort(w + 2);
539                 if (labels[label] == null) {
540                   labels[label] = new Label();
541                 }
542                 w += 10;
543               }
544             }
545           } else if (attrName.equals("LineNumberTable")) {
546             if (!skipDebug) {
547               k = readUnsignedShort(v + 6);
548               w = v + 8;
549               for ( ; k > 0; --k) {
550                 label = readUnsignedShort(w);
551                 if (labels[label] == null) {
552                   labels[label] = new Label();
553                 }
554                 labels[label].line = readUnsignedShort(w + 2);
555                 w += 4;
556               }
557             }
558           } else {
559             for (k = 0; k < attrs.length; ++k) {
560               if (attrs[k].type.equals(attrName)) {
561                 attr = attrs[k].read(
562                   this, v + 6, readInt(v + 2), c, codeStart - 8, labels);
563                 if (attr != null) {
564                   attr.next = cattrs;
565                   cattrs = attr;
566                 }
567               }
568             }
569           }
570           v += 6 + readInt(v + 2);
571         }
572
573         // 2nd phase: visits each instruction
574
v = codeStart;
575         Label l;
576         while (v < codeEnd) {
577           w = v - codeStart;
578           l = labels[w];
579           if (l != null) {
580             cv.visitLabel(l);
581             if (!skipDebug && l.line > 0) {
582               cv.visitLineNumber(l.line, l);
583             }
584           }
585           int opcode = b[v] & 0xFF;
586           switch (ClassWriter.TYPE[opcode]) {
587             case ClassWriter.NOARG_INSN:
588               cv.visitInsn(opcode);
589               v += 1;
590               break;
591             case ClassWriter.IMPLVAR_INSN:
592               if (opcode > Constants.ISTORE) {
593                 opcode -= 59; //ISTORE_0
594
cv.visitVarInsn(Constants.ISTORE + (opcode >> 2), opcode & 0x3);
595               } else {
596                 opcode -= 26; //ILOAD_0
597
cv.visitVarInsn(Constants.ILOAD + (opcode >> 2), opcode & 0x3);
598               }
599               v += 1;
600               break;
601             case ClassWriter.LABEL_INSN:
602               cv.visitJumpInsn(opcode, labels[w + readShort(v + 1)]);
603               v += 3;
604               break;
605             case ClassWriter.LABELW_INSN:
606               cv.visitJumpInsn(opcode - 33, labels[w + readInt(v + 1)]);
607               v += 5;
608               break;
609             case ClassWriter.WIDE_INSN:
610               opcode = b[v + 1] & 0xFF;
611               if (opcode == Constants.IINC) {
612                 cv.visitIincInsn(readUnsignedShort(v + 2), readShort(v + 4));
613                 v += 6;
614               } else {
615                 cv.visitVarInsn(opcode, readUnsignedShort(v + 2));
616                 v += 4;
617               }
618               break;
619             case ClassWriter.TABL_INSN:
620               // skips 0 to 3 padding bytes
621
v = v + 4 - (w & 3);
622               // reads instruction
623
label = w + readInt(v); v += 4;
624               int min = readInt(v); v += 4;
625               int max = readInt(v); v += 4;
626               Label[] table = new Label[max - min + 1];
627               for (j = 0; j < table.length; ++j) {
628                 table[j] = labels[w + readInt(v)];
629                 v += 4;
630               }
631               cv.visitTableSwitchInsn(min, max, labels[label], table);
632               break;
633             case ClassWriter.LOOK_INSN:
634               // skips 0 to 3 padding bytes
635
v = v + 4 - (w & 3);
636               // reads instruction
637
label = w + readInt(v); v += 4;
638               j = readInt(v); v += 4;
639               int[] keys = new int[j];
640               Label[] values = new Label[j];
641               for (j = 0; j < keys.length; ++j) {
642                 keys[j] = readInt(v); v += 4;
643                 values[j] = labels[w + readInt(v)]; v += 4;
644               }
645               cv.visitLookupSwitchInsn(labels[label], keys, values);
646               break;
647             case ClassWriter.VAR_INSN:
648               cv.visitVarInsn(opcode, b[v + 1] & 0xFF);
649               v += 2;
650               break;
651             case ClassWriter.SBYTE_INSN:
652               cv.visitIntInsn(opcode, b[v + 1]);
653               v += 2;
654               break;
655             case ClassWriter.SHORT_INSN:
656               cv.visitIntInsn(opcode, readShort(v + 1));
657               v += 3;
658               break;
659             case ClassWriter.LDC_INSN:
660               cv.visitLdcInsn(readConst(b[v + 1] & 0xFF, c));
661               v += 2;
662               break;
663             case ClassWriter.LDCW_INSN:
664               cv.visitLdcInsn(readConst(readUnsignedShort(v + 1), c));
665               v += 3;
666               break;
667             case ClassWriter.FIELDORMETH_INSN:
668             case ClassWriter.ITFMETH_INSN:
669               int cpIndex = items[readUnsignedShort(v + 1)];
670               String JavaDoc iowner = readClass(cpIndex, c);
671               cpIndex = items[readUnsignedShort(cpIndex + 2)];
672               String JavaDoc iname = readUTF8(cpIndex, c);
673               String JavaDoc idesc = readUTF8(cpIndex + 2, c);
674               if (opcode < Constants.INVOKEVIRTUAL) {
675                 cv.visitFieldInsn(opcode, iowner, iname, idesc);
676               } else {
677                 cv.visitMethodInsn(opcode, iowner, iname, idesc);
678               }
679               if (opcode == Constants.INVOKEINTERFACE) {
680                 v += 5;
681               } else {
682                 v += 3;
683               }
684               break;
685             case ClassWriter.TYPE_INSN:
686               cv.visitTypeInsn(opcode, readClass(v + 1, c));
687               v += 3;
688               break;
689             case ClassWriter.IINC_INSN:
690               cv.visitIincInsn(b[v + 1] & 0xFF, b[v + 2]);
691               v += 3;
692               break;
693             // case MANA_INSN:
694
default:
695               cv.visitMultiANewArrayInsn(readClass(v + 1, c), b[v + 3] & 0xFF);
696               v += 4;
697               break;
698           }
699         }
700         l = labels[codeEnd - codeStart];
701         if (l != null) {
702           cv.visitLabel(l);
703         }
704         // visits the try catch entries
705
j = readUnsignedShort(v); v += 2;
706         for ( ; j > 0; --j) {
707           Label start = labels[readUnsignedShort(v)];
708           Label end = labels[readUnsignedShort(v + 2)];
709           Label handler = labels[readUnsignedShort(v + 4)];
710           int type = readUnsignedShort(v + 6);
711           if (type == 0) {
712             cv.visitTryCatchBlock(start, end, handler, null);
713           } else {
714             cv.visitTryCatchBlock(start, end, handler, readUTF8(items[type], c));
715           }
716           v += 8;
717         }
718         // visits the local variable table
719
j = readUnsignedShort(v); v += 2;
720         if (!skipDebug) {
721           for ( ; j > 0; --j) {
722             String JavaDoc attrName = readUTF8(v, c);
723             if (attrName.equals("LocalVariableTable")) {
724               k = readUnsignedShort(v + 6);
725               w = v + 8;
726               for ( ; k > 0; --k) {
727                 label = readUnsignedShort(w);
728                 Label start = labels[label];
729                 label += readUnsignedShort(w + 2);
730                 Label end = labels[label];
731                 cv.visitLocalVariable(
732                   readUTF8(w + 4, c),
733                   readUTF8(w + 6, c),
734                   start,
735                   end,
736                   readUnsignedShort(w + 8));
737                 w += 10;
738               }
739             }
740             v += 6 + readInt(v + 2);
741           }
742         }
743         // visits the other attributes
744
while (cattrs != null) {
745           attr = cattrs.next;
746           cattrs.next = null;
747           cv.visitAttribute(cattrs);
748           cattrs = attr;
749         }
750         // visits the max stack and max locals values
751
cv.visitMaxs(maxStack, maxLocals);
752       }
753     }
754     // visits the class attributes
755
Attribute last = null;
756     attr = clattrs;
757     while (attr != null) {
758       Attribute next = attr.next;
759       attr.next = last;
760       last = attr;
761       attr = next;
762     }
763     while (last != null) {
764       attr = last.next;
765       last.next = null;
766       classVisitor.visitAttribute(last);
767       last = attr;
768     }
769     // visits the end of the class
770
classVisitor.visitEnd();
771   }
772
773   // --------------------------------------------------------------------------
774
// Utility methods: low level parsing
775
// --------------------------------------------------------------------------
776

777   /**
778    * Returns the start index of the constant pool item in {@link #b b}, plus
779    * one. <i>This method is intended for {@link Attribute} sub classes, and is
780    * normally not needed by class generators or adapters.</i>
781    *
782    * @param item the index a constant pool item.
783    * @return the start index of the constant pool item in {@link #b b}, plus
784    * one.
785    */

786   
787   public int getItem (final int item) {
788     return items[item];
789   }
790   
791   /**
792    * Reads a byte value in {@link #b b}. <i>This method is intended
793    * for {@link Attribute} sub classes, and is normally not needed by class
794    * generators or adapters.</i>
795    *
796    * @param index the start index of the value to be read in {@link #b b}.
797    * @return the read value.
798    */

799
800   public int readByte (final int index) {
801     return b[index] & 0xFF;
802   }
803
804   /**
805    * Reads an unsigned short value in {@link #b b}. <i>This method is intended
806    * for {@link Attribute} sub classes, and is normally not needed by class
807    * generators or adapters.</i>
808    *
809    * @param index the start index of the value to be read in {@link #b b}.
810    * @return the read value.
811    */

812
813   public int readUnsignedShort (final int index) {
814     byte[] b = this.b;
815     return ((b[index] & 0xFF) << 8) | (b[index + 1] & 0xFF);
816   }
817
818   /**
819    * Reads a signed short value in {@link #b b}. <i>This method is intended
820    * for {@link Attribute} sub classes, and is normally not needed by class
821    * generators or adapters.</i>
822    *
823    * @param index the start index of the value to be read in {@link #b b}.
824    * @return the read value.
825    */

826
827   public short readShort (final int index) {
828     byte[] b = this.b;
829     return (short)(((b[index] & 0xFF) << 8) | (b[index + 1] & 0xFF));
830   }
831
832   /**
833    * Reads a signed int value in {@link #b b}. <i>This method is intended
834    * for {@link Attribute} sub classes, and is normally not needed by class
835    * generators or adapters.</i>
836    *
837    * @param index the start index of the value to be read in {@link #b b}.
838    * @return the read value.
839    */

840
841   public int readInt (final int index) {
842     byte[] b = this.b;
843     return ((b[index] & 0xFF) << 24) |
844            ((b[index + 1] & 0xFF) << 16) |
845            ((b[index + 2] & 0xFF) << 8) |
846            (b[index + 3] & 0xFF);
847   }
848
849   /**
850    * Reads a signed long value in {@link #b b}. <i>This method is intended
851    * for {@link Attribute} sub classes, and is normally not needed by class
852    * generators or adapters.</i>
853    *
854    * @param index the start index of the value to be read in {@link #b b}.
855    * @return the read value.
856    */

857
858   public long readLong (final int index) {
859     long l1 = readInt(index);
860     long l0 = readInt(index + 4) & 0xFFFFFFFFL;
861     return (l1 << 32) | l0;
862   }
863
864   /**
865    * Reads an UTF8 string constant pool item in {@link #b b}. <i>This method is
866    * intended for {@link Attribute} sub classes, and is normally not needed by
867    * class generators or adapters.</i>
868    *
869    * @param index the start index of an unsigned short value in {@link #b b},
870    * whose value is the index of an UTF8 constant pool item.
871    * @param buf buffer to be used to read the item. This buffer must be
872    * sufficiently large. It is not automatically resized.
873    * @return the String corresponding to the specified UTF8 item.
874    */

875
876   public String JavaDoc readUTF8 (int index, final char[] buf) {
877     // consults cache
878
int item = readUnsignedShort(index);
879     String JavaDoc s = strings[item];
880     if (s != null) {
881       return s;
882     }
883     // computes the start index of the CONSTANT_Utf8 item in b
884
index = items[item];
885     // reads the length of the string (in bytes, not characters)
886
int utfLen = readUnsignedShort(index);
887     index += 2;
888     // parses the string bytes
889
int endIndex = index + utfLen;
890     byte[] b = this.b;
891     int strLen = 0;
892     int c, d, e;
893     while (index < endIndex) {
894       c = b[index++] & 0xFF;
895       switch (c >> 4) {
896         case 0:
897         case 1:
898         case 2:
899         case 3:
900         case 4:
901         case 5:
902         case 6:
903         case 7:
904           // 0xxxxxxx
905
buf[strLen++] = (char)c;
906           break;
907         case 12:
908         case 13:
909           // 110x xxxx 10xx xxxx
910
d = b[index++];
911           buf[strLen++] = (char)(((c & 0x1F) << 6) | (d & 0x3F));
912           break;
913         default:
914           // 1110 xxxx 10xx xxxx 10xx xxxx
915
d = b[index++];
916           e = b[index++];
917           buf[strLen++] =
918             (char)(((c & 0x0F) << 12) | ((d & 0x3F) << 6) | (e & 0x3F));
919           break;
920       }
921     }
922     s = new String JavaDoc(buf, 0, strLen);
923     strings[item] = s;
924     return s;
925   }
926
927   /**
928    * Reads a class constant pool item in {@link #b b}. <i>This method is
929    * intended for {@link Attribute} sub classes, and is normally not needed by
930    * class generators or adapters.</i>
931    *
932    * @param index the start index of an unsigned short value in {@link #b b},
933    * whose value is the index of a class constant pool item.
934    * @param buf buffer to be used to read the item. This buffer must be
935    * sufficiently large. It is not automatically resized.
936    * @return the String corresponding to the specified class item.
937    */

938
939   public String JavaDoc readClass (final int index, final char[] buf) {
940     // computes the start index of the CONSTANT_Class item in b
941
// and reads the CONSTANT_Utf8 item designated by
942
// the first two bytes of this CONSTANT_Class item
943
return readUTF8(items[readUnsignedShort(index)], buf);
944   }
945
946   /**
947    * Reads a numeric or string constant pool item in {@link #b b}. <i>This
948    * method is intended for {@link Attribute} sub classes, and is normally not
949    * needed by class generators or adapters.</i>
950    *
951    * @param item the index of a constant pool item.
952    * @param buf buffer to be used to read the item. This buffer must be
953    * sufficiently large. It is not automatically resized.
954    * @return the {@link java.lang.Integer Integer}, {@link java.lang.Float
955    * Float}, {@link java.lang.Long Long}, {@link java.lang.Double Double},
956    * {@link String String} or {@link Type Type} corresponding to the given
957    * constant pool item.
958    */

959
960   public Object JavaDoc readConst (final int item, final char[] buf) {
961     int index = items[item];
962     switch (b[index - 1]) {
963       case ClassWriter.INT:
964         return new Integer JavaDoc(readInt(index));
965       case ClassWriter.FLOAT:
966         return new Float JavaDoc(Float.intBitsToFloat(readInt(index)));
967       case ClassWriter.LONG:
968         return new Long JavaDoc(readLong(index));
969       case ClassWriter.DOUBLE:
970         return new Double JavaDoc(Double.longBitsToDouble(readLong(index)));
971       case ClassWriter.CLASS:
972         String JavaDoc s = readUTF8(index, buf);
973         return Type.getType(s.charAt(0) == '[' ? s : "L" + s + ";");
974       //case ClassWriter.STR:
975
default:
976         return readUTF8(index, buf);
977     }
978   }
979
980   /**
981    * Reads an attribute in {@link #b b}.
982    *
983    * @param attrs prototypes of the attributes that must be parsed during the
984    * visit of the class. Any attribute whose type is not equal to the type
985    * of one the prototypes is ignored (i.e. an empty {@link Attribute}
986    * instance is returned).
987    * @param type the type of the attribute.
988    * @param off index of the first byte of the attribute's content in {@link #b
989    * b}. The 6 attribute header bytes, containing the type and the length
990    * of the attribute, are not taken into account here (they have already
991    * been read).
992    * @param len the length of the attribute's content.
993    * @param buf buffer to be used to call {@link #readUTF8 readUTF8}, {@link
994    * #readClass(int,char[]) readClass} or {@link #readConst readConst}.
995    * @param codeOff index of the first byte of code's attribute content in
996    * {@link #b b}, or -1 if the attribute to be read is not a code
997    * attribute. The 6 attribute header bytes, containing the type and the
998    * length of the attribute, are not taken into account here.
999    * @param labels the labels of the method's code, or <tt>null</tt> if the
1000   * attribute to be read is not a code attribute.
1001   * @return the attribute that has been read, or <tt>null</tt> to skip this
1002   * attribute.
1003   */

1004
1005  protected Attribute readAttribute (
1006    final Attribute[] attrs,
1007    final String JavaDoc type,
1008    final int off,
1009    final int len,
1010    final char[] buf,
1011    final int codeOff,
1012    final Label[] labels)
1013  {
1014    for (int i = 0; i < attrs.length; ++i) {
1015      if (attrs[i].type.equals(type)) {
1016        return attrs[i].read(this, off, len, buf, codeOff, labels);
1017      }
1018    }
1019    return new Attribute(type);
1020  }
1021}
1022
Popular Tags