rlm@10
|
1 /***
|
rlm@10
|
2 * ASM: a very small and fast Java bytecode manipulation framework
|
rlm@10
|
3 * Copyright (c) 2000-2005 INRIA, France Telecom
|
rlm@10
|
4 * All rights reserved.
|
rlm@10
|
5 *
|
rlm@10
|
6 * Redistribution and use in source and binary forms, with or without
|
rlm@10
|
7 * modification, are permitted provided that the following conditions
|
rlm@10
|
8 * are met:
|
rlm@10
|
9 * 1. Redistributions of source code must retain the above copyright
|
rlm@10
|
10 * notice, this list of conditions and the following disclaimer.
|
rlm@10
|
11 * 2. Redistributions in binary form must reproduce the above copyright
|
rlm@10
|
12 * notice, this list of conditions and the following disclaimer in the
|
rlm@10
|
13 * documentation and/or other materials provided with the distribution.
|
rlm@10
|
14 * 3. Neither the name of the copyright holders nor the names of its
|
rlm@10
|
15 * contributors may be used to endorse or promote products derived from
|
rlm@10
|
16 * this software without specific prior written permission.
|
rlm@10
|
17 *
|
rlm@10
|
18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
rlm@10
|
19 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
rlm@10
|
20 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
rlm@10
|
21 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
rlm@10
|
22 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
rlm@10
|
23 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
rlm@10
|
24 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
rlm@10
|
25 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
rlm@10
|
26 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
rlm@10
|
27 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
|
rlm@10
|
28 * THE POSSIBILITY OF SUCH DAMAGE.
|
rlm@10
|
29 */
|
rlm@10
|
30 package clojure.asm;
|
rlm@10
|
31
|
rlm@10
|
32 import java.io.InputStream;
|
rlm@10
|
33 import java.io.IOException;
|
rlm@10
|
34
|
rlm@10
|
35 /**
|
rlm@10
|
36 * A Java class parser to make a {@link ClassVisitor} visit an existing class.
|
rlm@10
|
37 * This class parses a byte array conforming to the Java class file format and
|
rlm@10
|
38 * calls the appropriate visit methods of a given class visitor for each field,
|
rlm@10
|
39 * method and bytecode instruction encountered.
|
rlm@10
|
40 *
|
rlm@10
|
41 * @author Eric Bruneton
|
rlm@10
|
42 * @author Eugene Kuleshov
|
rlm@10
|
43 */
|
rlm@10
|
44 public class ClassReader{
|
rlm@10
|
45
|
rlm@10
|
46 /**
|
rlm@10
|
47 * Flag to skip method code. If this class is set <code>CODE</code>
|
rlm@10
|
48 * attribute won't be visited. This can be used, for example, to retrieve
|
rlm@10
|
49 * annotations for methods and method parameters.
|
rlm@10
|
50 */
|
rlm@10
|
51 public final static int SKIP_CODE = 1;
|
rlm@10
|
52
|
rlm@10
|
53 /**
|
rlm@10
|
54 * Flag to skip the debug information in the class. If this flag is set the
|
rlm@10
|
55 * debug information of the class is not visited, i.e. the
|
rlm@10
|
56 * {@link MethodVisitor#visitLocalVariable visitLocalVariable} and
|
rlm@10
|
57 * {@link MethodVisitor#visitLineNumber visitLineNumber} methods will not be
|
rlm@10
|
58 * called.
|
rlm@10
|
59 */
|
rlm@10
|
60 public final static int SKIP_DEBUG = 2;
|
rlm@10
|
61
|
rlm@10
|
62 /**
|
rlm@10
|
63 * Flag to skip the stack map frames in the class. If this flag is set the
|
rlm@10
|
64 * stack map frames of the class is not visited, i.e. the
|
rlm@10
|
65 * {@link MethodVisitor#visitFrame visitFrame} method will not be called.
|
rlm@10
|
66 * This flag is useful when the {@link ClassWriter#COMPUTE_FRAMES} option is
|
rlm@10
|
67 * used: it avoids visiting frames that will be ignored and recomputed from
|
rlm@10
|
68 * scratch in the class writer.
|
rlm@10
|
69 */
|
rlm@10
|
70 public final static int SKIP_FRAMES = 4;
|
rlm@10
|
71
|
rlm@10
|
72 /**
|
rlm@10
|
73 * Flag to expand the stack map frames. By default stack map frames are
|
rlm@10
|
74 * visited in their original format (i.e. "expanded" for classes whose
|
rlm@10
|
75 * version is less than V1_6, and "compressed" for the other classes). If
|
rlm@10
|
76 * this flag is set, stack map frames are always visited in expanded format
|
rlm@10
|
77 * (this option adds a decompression/recompression step in ClassReader and
|
rlm@10
|
78 * ClassWriter which degrades performances quite a lot).
|
rlm@10
|
79 */
|
rlm@10
|
80 public final static int EXPAND_FRAMES = 8;
|
rlm@10
|
81
|
rlm@10
|
82 /**
|
rlm@10
|
83 * The class to be parsed. <i>The content of this array must not be
|
rlm@10
|
84 * modified. This field is intended for {@link Attribute} sub classes, and
|
rlm@10
|
85 * is normally not needed by class generators or adapters.</i>
|
rlm@10
|
86 */
|
rlm@10
|
87 public final byte[] b;
|
rlm@10
|
88
|
rlm@10
|
89 /**
|
rlm@10
|
90 * The start index of each constant pool item in {@link #b b}, plus one.
|
rlm@10
|
91 * The one byte offset skips the constant pool item tag that indicates its
|
rlm@10
|
92 * type.
|
rlm@10
|
93 */
|
rlm@10
|
94 private final int[] items;
|
rlm@10
|
95
|
rlm@10
|
96 /**
|
rlm@10
|
97 * The String objects corresponding to the CONSTANT_Utf8 items. This cache
|
rlm@10
|
98 * avoids multiple parsing of a given CONSTANT_Utf8 constant pool item,
|
rlm@10
|
99 * which GREATLY improves performances (by a factor 2 to 3). This caching
|
rlm@10
|
100 * strategy could be extended to all constant pool items, but its benefit
|
rlm@10
|
101 * would not be so great for these items (because they are much less
|
rlm@10
|
102 * expensive to parse than CONSTANT_Utf8 items).
|
rlm@10
|
103 */
|
rlm@10
|
104 private final String[] strings;
|
rlm@10
|
105
|
rlm@10
|
106 /**
|
rlm@10
|
107 * Maximum length of the strings contained in the constant pool of the
|
rlm@10
|
108 * class.
|
rlm@10
|
109 */
|
rlm@10
|
110 private final int maxStringLength;
|
rlm@10
|
111
|
rlm@10
|
112 /**
|
rlm@10
|
113 * Start index of the class header information (access, name...) in
|
rlm@10
|
114 * {@link #b b}.
|
rlm@10
|
115 */
|
rlm@10
|
116 public final int header;
|
rlm@10
|
117
|
rlm@10
|
118 // ------------------------------------------------------------------------
|
rlm@10
|
119 // Constructors
|
rlm@10
|
120 // ------------------------------------------------------------------------
|
rlm@10
|
121
|
rlm@10
|
122 /**
|
rlm@10
|
123 * Constructs a new {@link ClassReader} object.
|
rlm@10
|
124 *
|
rlm@10
|
125 * @param b the bytecode of the class to be read.
|
rlm@10
|
126 */
|
rlm@10
|
127 public ClassReader(final byte[] b){
|
rlm@10
|
128 this(b, 0, b.length);
|
rlm@10
|
129 }
|
rlm@10
|
130
|
rlm@10
|
131 /**
|
rlm@10
|
132 * Constructs a new {@link ClassReader} object.
|
rlm@10
|
133 *
|
rlm@10
|
134 * @param b the bytecode of the class to be read.
|
rlm@10
|
135 * @param off the start offset of the class data.
|
rlm@10
|
136 * @param len the length of the class data.
|
rlm@10
|
137 */
|
rlm@10
|
138 public ClassReader(final byte[] b, final int off, final int len){
|
rlm@10
|
139 this.b = b;
|
rlm@10
|
140 // parses the constant pool
|
rlm@10
|
141 items = new int[readUnsignedShort(off + 8)];
|
rlm@10
|
142 int n = items.length;
|
rlm@10
|
143 strings = new String[n];
|
rlm@10
|
144 int max = 0;
|
rlm@10
|
145 int index = off + 10;
|
rlm@10
|
146 for(int i = 1; i < n; ++i)
|
rlm@10
|
147 {
|
rlm@10
|
148 items[i] = index + 1;
|
rlm@10
|
149 int size;
|
rlm@10
|
150 switch(b[index])
|
rlm@10
|
151 {
|
rlm@10
|
152 case ClassWriter.FIELD:
|
rlm@10
|
153 case ClassWriter.METH:
|
rlm@10
|
154 case ClassWriter.IMETH:
|
rlm@10
|
155 case ClassWriter.INT:
|
rlm@10
|
156 case ClassWriter.FLOAT:
|
rlm@10
|
157 case ClassWriter.NAME_TYPE:
|
rlm@10
|
158 size = 5;
|
rlm@10
|
159 break;
|
rlm@10
|
160 case ClassWriter.LONG:
|
rlm@10
|
161 case ClassWriter.DOUBLE:
|
rlm@10
|
162 size = 9;
|
rlm@10
|
163 ++i;
|
rlm@10
|
164 break;
|
rlm@10
|
165 case ClassWriter.UTF8:
|
rlm@10
|
166 size = 3 + readUnsignedShort(index + 1);
|
rlm@10
|
167 if(size > max)
|
rlm@10
|
168 {
|
rlm@10
|
169 max = size;
|
rlm@10
|
170 }
|
rlm@10
|
171 break;
|
rlm@10
|
172 // case ClassWriter.CLASS:
|
rlm@10
|
173 // case ClassWriter.STR:
|
rlm@10
|
174 default:
|
rlm@10
|
175 size = 3;
|
rlm@10
|
176 break;
|
rlm@10
|
177 }
|
rlm@10
|
178 index += size;
|
rlm@10
|
179 }
|
rlm@10
|
180 maxStringLength = max;
|
rlm@10
|
181 // the class header information starts just after the constant pool
|
rlm@10
|
182 header = index;
|
rlm@10
|
183 }
|
rlm@10
|
184
|
rlm@10
|
185 /**
|
rlm@10
|
186 * Returns the class's access flags (see {@link Opcodes}). This value may
|
rlm@10
|
187 * not reflect Deprecated and Synthetic flags when bytecode is before 1.5
|
rlm@10
|
188 * and those flags are represented by attributes.
|
rlm@10
|
189 *
|
rlm@10
|
190 * @return the class access flags
|
rlm@10
|
191 * @see ClassVisitor#visit(int,int,String,String,String,String[])
|
rlm@10
|
192 */
|
rlm@10
|
193 public int getAccess(){
|
rlm@10
|
194 return readUnsignedShort(header);
|
rlm@10
|
195 }
|
rlm@10
|
196
|
rlm@10
|
197 /**
|
rlm@10
|
198 * Returns the internal name of the class (see
|
rlm@10
|
199 * {@link Type#getInternalName() getInternalName}).
|
rlm@10
|
200 *
|
rlm@10
|
201 * @return the internal class name
|
rlm@10
|
202 * @see ClassVisitor#visit(int,int,String,String,String,String[])
|
rlm@10
|
203 */
|
rlm@10
|
204 public String getClassName(){
|
rlm@10
|
205 return readClass(header + 2, new char[maxStringLength]);
|
rlm@10
|
206 }
|
rlm@10
|
207
|
rlm@10
|
208 /**
|
rlm@10
|
209 * Returns the internal of name of the super class (see
|
rlm@10
|
210 * {@link Type#getInternalName() getInternalName}). For interfaces, the
|
rlm@10
|
211 * super class is {@link Object}.
|
rlm@10
|
212 *
|
rlm@10
|
213 * @return the internal name of super class, or <tt>null</tt> for
|
rlm@10
|
214 * {@link Object} class.
|
rlm@10
|
215 * @see ClassVisitor#visit(int,int,String,String,String,String[])
|
rlm@10
|
216 */
|
rlm@10
|
217 public String getSuperName(){
|
rlm@10
|
218 int n = items[readUnsignedShort(header + 4)];
|
rlm@10
|
219 return n == 0 ? null : readUTF8(n, new char[maxStringLength]);
|
rlm@10
|
220 }
|
rlm@10
|
221
|
rlm@10
|
222 /**
|
rlm@10
|
223 * Returns the internal names of the class's interfaces (see
|
rlm@10
|
224 * {@link Type#getInternalName() getInternalName}).
|
rlm@10
|
225 *
|
rlm@10
|
226 * @return the array of internal names for all implemented interfaces or
|
rlm@10
|
227 * <tt>null</tt>.
|
rlm@10
|
228 * @see ClassVisitor#visit(int,int,String,String,String,String[])
|
rlm@10
|
229 */
|
rlm@10
|
230 public String[] getInterfaces(){
|
rlm@10
|
231 int index = header + 6;
|
rlm@10
|
232 int n = readUnsignedShort(index);
|
rlm@10
|
233 String[] interfaces = new String[n];
|
rlm@10
|
234 if(n > 0)
|
rlm@10
|
235 {
|
rlm@10
|
236 char[] buf = new char[maxStringLength];
|
rlm@10
|
237 for(int i = 0; i < n; ++i)
|
rlm@10
|
238 {
|
rlm@10
|
239 index += 2;
|
rlm@10
|
240 interfaces[i] = readClass(index, buf);
|
rlm@10
|
241 }
|
rlm@10
|
242 }
|
rlm@10
|
243 return interfaces;
|
rlm@10
|
244 }
|
rlm@10
|
245
|
rlm@10
|
246 /**
|
rlm@10
|
247 * Copies the constant pool data into the given {@link ClassWriter}. Should
|
rlm@10
|
248 * be called before the {@link #accept(ClassVisitor,int)} method.
|
rlm@10
|
249 *
|
rlm@10
|
250 * @param classWriter the {@link ClassWriter} to copy constant pool into.
|
rlm@10
|
251 */
|
rlm@10
|
252 void copyPool(final ClassWriter classWriter){
|
rlm@10
|
253 char[] buf = new char[maxStringLength];
|
rlm@10
|
254 int ll = items.length;
|
rlm@10
|
255 Item[] items2 = new Item[ll];
|
rlm@10
|
256 for(int i = 1; i < ll; i++)
|
rlm@10
|
257 {
|
rlm@10
|
258 int index = items[i];
|
rlm@10
|
259 int tag = b[index - 1];
|
rlm@10
|
260 Item item = new Item(i);
|
rlm@10
|
261 int nameType;
|
rlm@10
|
262 switch(tag)
|
rlm@10
|
263 {
|
rlm@10
|
264 case ClassWriter.FIELD:
|
rlm@10
|
265 case ClassWriter.METH:
|
rlm@10
|
266 case ClassWriter.IMETH:
|
rlm@10
|
267 nameType = items[readUnsignedShort(index + 2)];
|
rlm@10
|
268 item.set(tag,
|
rlm@10
|
269 readClass(index, buf),
|
rlm@10
|
270 readUTF8(nameType, buf),
|
rlm@10
|
271 readUTF8(nameType + 2, buf));
|
rlm@10
|
272 break;
|
rlm@10
|
273
|
rlm@10
|
274 case ClassWriter.INT:
|
rlm@10
|
275 item.set(readInt(index));
|
rlm@10
|
276 break;
|
rlm@10
|
277
|
rlm@10
|
278 case ClassWriter.FLOAT:
|
rlm@10
|
279 item.set(Float.intBitsToFloat(readInt(index)));
|
rlm@10
|
280 break;
|
rlm@10
|
281
|
rlm@10
|
282 case ClassWriter.NAME_TYPE:
|
rlm@10
|
283 item.set(tag,
|
rlm@10
|
284 readUTF8(index, buf),
|
rlm@10
|
285 readUTF8(index + 2, buf),
|
rlm@10
|
286 null);
|
rlm@10
|
287 break;
|
rlm@10
|
288
|
rlm@10
|
289 case ClassWriter.LONG:
|
rlm@10
|
290 item.set(readLong(index));
|
rlm@10
|
291 ++i;
|
rlm@10
|
292 break;
|
rlm@10
|
293
|
rlm@10
|
294 case ClassWriter.DOUBLE:
|
rlm@10
|
295 item.set(Double.longBitsToDouble(readLong(index)));
|
rlm@10
|
296 ++i;
|
rlm@10
|
297 break;
|
rlm@10
|
298
|
rlm@10
|
299 case ClassWriter.UTF8:
|
rlm@10
|
300 {
|
rlm@10
|
301 String s = strings[i];
|
rlm@10
|
302 if(s == null)
|
rlm@10
|
303 {
|
rlm@10
|
304 index = items[i];
|
rlm@10
|
305 s = strings[i] = readUTF(index + 2,
|
rlm@10
|
306 readUnsignedShort(index),
|
rlm@10
|
307 buf);
|
rlm@10
|
308 }
|
rlm@10
|
309 item.set(tag, s, null, null);
|
rlm@10
|
310 }
|
rlm@10
|
311 break;
|
rlm@10
|
312
|
rlm@10
|
313 // case ClassWriter.STR:
|
rlm@10
|
314 // case ClassWriter.CLASS:
|
rlm@10
|
315 default:
|
rlm@10
|
316 item.set(tag, readUTF8(index, buf), null, null);
|
rlm@10
|
317 break;
|
rlm@10
|
318 }
|
rlm@10
|
319
|
rlm@10
|
320 int index2 = item.hashCode % items2.length;
|
rlm@10
|
321 item.next = items2[index2];
|
rlm@10
|
322 items2[index2] = item;
|
rlm@10
|
323 }
|
rlm@10
|
324
|
rlm@10
|
325 int off = items[1] - 1;
|
rlm@10
|
326 classWriter.pool.putByteArray(b, off, header - off);
|
rlm@10
|
327 classWriter.items = items2;
|
rlm@10
|
328 classWriter.threshold = (int) (0.75d * ll);
|
rlm@10
|
329 classWriter.index = ll;
|
rlm@10
|
330 }
|
rlm@10
|
331
|
rlm@10
|
332 /**
|
rlm@10
|
333 * Constructs a new {@link ClassReader} object.
|
rlm@10
|
334 *
|
rlm@10
|
335 * @param is an input stream from which to read the class.
|
rlm@10
|
336 * @throws IOException if a problem occurs during reading.
|
rlm@10
|
337 */
|
rlm@10
|
338 public ClassReader(final InputStream is) throws IOException{
|
rlm@10
|
339 this(readClass(is));
|
rlm@10
|
340 }
|
rlm@10
|
341
|
rlm@10
|
342 /**
|
rlm@10
|
343 * Constructs a new {@link ClassReader} object.
|
rlm@10
|
344 *
|
rlm@10
|
345 * @param name the fully qualified name of the class to be read.
|
rlm@10
|
346 * @throws IOException if an exception occurs during reading.
|
rlm@10
|
347 */
|
rlm@10
|
348 public ClassReader(final String name) throws IOException{
|
rlm@10
|
349 this(ClassLoader.getSystemResourceAsStream(name.replace('.', '/')
|
rlm@10
|
350 + ".class"));
|
rlm@10
|
351 }
|
rlm@10
|
352
|
rlm@10
|
353 /**
|
rlm@10
|
354 * Reads the bytecode of a class.
|
rlm@10
|
355 *
|
rlm@10
|
356 * @param is an input stream from which to read the class.
|
rlm@10
|
357 * @return the bytecode read from the given input stream.
|
rlm@10
|
358 * @throws IOException if a problem occurs during reading.
|
rlm@10
|
359 */
|
rlm@10
|
360 private static byte[] readClass(final InputStream is) throws IOException{
|
rlm@10
|
361 if(is == null)
|
rlm@10
|
362 {
|
rlm@10
|
363 throw new IOException("Class not found");
|
rlm@10
|
364 }
|
rlm@10
|
365 byte[] b = new byte[is.available()];
|
rlm@10
|
366 int len = 0;
|
rlm@10
|
367 while(true)
|
rlm@10
|
368 {
|
rlm@10
|
369 int n = is.read(b, len, b.length - len);
|
rlm@10
|
370 if(n == -1)
|
rlm@10
|
371 {
|
rlm@10
|
372 if(len < b.length)
|
rlm@10
|
373 {
|
rlm@10
|
374 byte[] c = new byte[len];
|
rlm@10
|
375 System.arraycopy(b, 0, c, 0, len);
|
rlm@10
|
376 b = c;
|
rlm@10
|
377 }
|
rlm@10
|
378 return b;
|
rlm@10
|
379 }
|
rlm@10
|
380 len += n;
|
rlm@10
|
381 if(len == b.length)
|
rlm@10
|
382 {
|
rlm@10
|
383 byte[] c = new byte[b.length + 1000];
|
rlm@10
|
384 System.arraycopy(b, 0, c, 0, len);
|
rlm@10
|
385 b = c;
|
rlm@10
|
386 }
|
rlm@10
|
387 }
|
rlm@10
|
388 }
|
rlm@10
|
389
|
rlm@10
|
390 // ------------------------------------------------------------------------
|
rlm@10
|
391 // Public methods
|
rlm@10
|
392 // ------------------------------------------------------------------------
|
rlm@10
|
393
|
rlm@10
|
394 /**
|
rlm@10
|
395 * Makes the given visitor visit the Java class of this {@link ClassReader}.
|
rlm@10
|
396 * This class is the one specified in the constructor (see
|
rlm@10
|
397 * {@link #ClassReader(byte[]) ClassReader}).
|
rlm@10
|
398 *
|
rlm@10
|
399 * @param classVisitor the visitor that must visit this class.
|
rlm@10
|
400 * @param flags option flags that can be used to modify the default behavior
|
rlm@10
|
401 * of this class. See {@link #SKIP_DEBUG}, {@link #EXPAND_FRAMES}.
|
rlm@10
|
402 */
|
rlm@10
|
403 public void accept(final ClassVisitor classVisitor, final int flags){
|
rlm@10
|
404 accept(classVisitor, new Attribute[0], flags);
|
rlm@10
|
405 }
|
rlm@10
|
406
|
rlm@10
|
407 /**
|
rlm@10
|
408 * Makes the given visitor visit the Java class of this {@link ClassReader}.
|
rlm@10
|
409 * This class is the one specified in the constructor (see
|
rlm@10
|
410 * {@link #ClassReader(byte[]) ClassReader}).
|
rlm@10
|
411 *
|
rlm@10
|
412 * @param classVisitor the visitor that must visit this class.
|
rlm@10
|
413 * @param attrs prototypes of the attributes that must be parsed during the
|
rlm@10
|
414 * visit of the class. Any attribute whose type is not equal to the
|
rlm@10
|
415 * type of one the prototypes will not be parsed: its byte array
|
rlm@10
|
416 * value will be passed unchanged to the ClassWriter. <i>This may
|
rlm@10
|
417 * corrupt it if this value contains references to the constant pool,
|
rlm@10
|
418 * or has syntactic or semantic links with a class element that has
|
rlm@10
|
419 * been transformed by a class adapter between the reader and the
|
rlm@10
|
420 * writer</i>.
|
rlm@10
|
421 * @param flags option flags that can be used to modify the default behavior
|
rlm@10
|
422 * of this class. See {@link #SKIP_DEBUG}, {@link #EXPAND_FRAMES}.
|
rlm@10
|
423 */
|
rlm@10
|
424 public void accept(
|
rlm@10
|
425 final ClassVisitor classVisitor,
|
rlm@10
|
426 final Attribute[] attrs,
|
rlm@10
|
427 final int flags){
|
rlm@10
|
428 byte[] b = this.b; // the bytecode array
|
rlm@10
|
429 char[] c = new char[maxStringLength]; // buffer used to read strings
|
rlm@10
|
430 int i, j, k; // loop variables
|
rlm@10
|
431 int u, v, w; // indexes in b
|
rlm@10
|
432 Attribute attr;
|
rlm@10
|
433
|
rlm@10
|
434 int access;
|
rlm@10
|
435 String name;
|
rlm@10
|
436 String desc;
|
rlm@10
|
437 String attrName;
|
rlm@10
|
438 String signature;
|
rlm@10
|
439 int anns = 0;
|
rlm@10
|
440 int ianns = 0;
|
rlm@10
|
441 Attribute cattrs = null;
|
rlm@10
|
442
|
rlm@10
|
443 // visits the header
|
rlm@10
|
444 u = header;
|
rlm@10
|
445 access = readUnsignedShort(u);
|
rlm@10
|
446 name = readClass(u + 2, c);
|
rlm@10
|
447 v = items[readUnsignedShort(u + 4)];
|
rlm@10
|
448 String superClassName = v == 0 ? null : readUTF8(v, c);
|
rlm@10
|
449 String[] implementedItfs = new String[readUnsignedShort(u + 6)];
|
rlm@10
|
450 w = 0;
|
rlm@10
|
451 u += 8;
|
rlm@10
|
452 for(i = 0; i < implementedItfs.length; ++i)
|
rlm@10
|
453 {
|
rlm@10
|
454 implementedItfs[i] = readClass(u, c);
|
rlm@10
|
455 u += 2;
|
rlm@10
|
456 }
|
rlm@10
|
457
|
rlm@10
|
458 boolean skipCode = (flags & SKIP_CODE) != 0;
|
rlm@10
|
459 boolean skipDebug = (flags & SKIP_DEBUG) != 0;
|
rlm@10
|
460 boolean unzip = (flags & EXPAND_FRAMES) != 0;
|
rlm@10
|
461
|
rlm@10
|
462 // skips fields and methods
|
rlm@10
|
463 v = u;
|
rlm@10
|
464 i = readUnsignedShort(v);
|
rlm@10
|
465 v += 2;
|
rlm@10
|
466 for(; i > 0; --i)
|
rlm@10
|
467 {
|
rlm@10
|
468 j = readUnsignedShort(v + 6);
|
rlm@10
|
469 v += 8;
|
rlm@10
|
470 for(; j > 0; --j)
|
rlm@10
|
471 {
|
rlm@10
|
472 v += 6 + readInt(v + 2);
|
rlm@10
|
473 }
|
rlm@10
|
474 }
|
rlm@10
|
475 i = readUnsignedShort(v);
|
rlm@10
|
476 v += 2;
|
rlm@10
|
477 for(; i > 0; --i)
|
rlm@10
|
478 {
|
rlm@10
|
479 j = readUnsignedShort(v + 6);
|
rlm@10
|
480 v += 8;
|
rlm@10
|
481 for(; j > 0; --j)
|
rlm@10
|
482 {
|
rlm@10
|
483 v += 6 + readInt(v + 2);
|
rlm@10
|
484 }
|
rlm@10
|
485 }
|
rlm@10
|
486 // reads the class's attributes
|
rlm@10
|
487 signature = null;
|
rlm@10
|
488 String sourceFile = null;
|
rlm@10
|
489 String sourceDebug = null;
|
rlm@10
|
490 String enclosingOwner = null;
|
rlm@10
|
491 String enclosingName = null;
|
rlm@10
|
492 String enclosingDesc = null;
|
rlm@10
|
493
|
rlm@10
|
494 i = readUnsignedShort(v);
|
rlm@10
|
495 v += 2;
|
rlm@10
|
496 for(; i > 0; --i)
|
rlm@10
|
497 {
|
rlm@10
|
498 attrName = readUTF8(v, c);
|
rlm@10
|
499 // tests are sorted in decreasing frequency order
|
rlm@10
|
500 // (based on frequencies observed on typical classes)
|
rlm@10
|
501 if(attrName.equals("SourceFile"))
|
rlm@10
|
502 {
|
rlm@10
|
503 sourceFile = readUTF8(v + 6, c);
|
rlm@10
|
504 }
|
rlm@10
|
505 else if(attrName.equals("InnerClasses"))
|
rlm@10
|
506 {
|
rlm@10
|
507 w = v + 6;
|
rlm@10
|
508 }
|
rlm@10
|
509 else if(attrName.equals("EnclosingMethod"))
|
rlm@10
|
510 {
|
rlm@10
|
511 enclosingOwner = readClass(v + 6, c);
|
rlm@10
|
512 int item = readUnsignedShort(v + 8);
|
rlm@10
|
513 if(item != 0)
|
rlm@10
|
514 {
|
rlm@10
|
515 enclosingName = readUTF8(items[item], c);
|
rlm@10
|
516 enclosingDesc = readUTF8(items[item] + 2, c);
|
rlm@10
|
517 }
|
rlm@10
|
518 }
|
rlm@10
|
519 else if(attrName.equals("Signature"))
|
rlm@10
|
520 {
|
rlm@10
|
521 signature = readUTF8(v + 6, c);
|
rlm@10
|
522 }
|
rlm@10
|
523 else if(attrName.equals("RuntimeVisibleAnnotations"))
|
rlm@10
|
524 {
|
rlm@10
|
525 anns = v + 6;
|
rlm@10
|
526 }
|
rlm@10
|
527 else if(attrName.equals("Deprecated"))
|
rlm@10
|
528 {
|
rlm@10
|
529 access |= Opcodes.ACC_DEPRECATED;
|
rlm@10
|
530 }
|
rlm@10
|
531 else if(attrName.equals("Synthetic"))
|
rlm@10
|
532 {
|
rlm@10
|
533 access |= Opcodes.ACC_SYNTHETIC;
|
rlm@10
|
534 }
|
rlm@10
|
535 else if(attrName.equals("SourceDebugExtension"))
|
rlm@10
|
536 {
|
rlm@10
|
537 int len = readInt(v + 2);
|
rlm@10
|
538 sourceDebug = readUTF(v + 6, len, new char[len]);
|
rlm@10
|
539 }
|
rlm@10
|
540 else if(attrName.equals("RuntimeInvisibleAnnotations"))
|
rlm@10
|
541 {
|
rlm@10
|
542 ianns = v + 6;
|
rlm@10
|
543 }
|
rlm@10
|
544 else
|
rlm@10
|
545 {
|
rlm@10
|
546 attr = readAttribute(attrs,
|
rlm@10
|
547 attrName,
|
rlm@10
|
548 v + 6,
|
rlm@10
|
549 readInt(v + 2),
|
rlm@10
|
550 c,
|
rlm@10
|
551 -1,
|
rlm@10
|
552 null);
|
rlm@10
|
553 if(attr != null)
|
rlm@10
|
554 {
|
rlm@10
|
555 attr.next = cattrs;
|
rlm@10
|
556 cattrs = attr;
|
rlm@10
|
557 }
|
rlm@10
|
558 }
|
rlm@10
|
559 v += 6 + readInt(v + 2);
|
rlm@10
|
560 }
|
rlm@10
|
561 // calls the visit method
|
rlm@10
|
562 classVisitor.visit(readInt(4),
|
rlm@10
|
563 access,
|
rlm@10
|
564 name,
|
rlm@10
|
565 signature,
|
rlm@10
|
566 superClassName,
|
rlm@10
|
567 implementedItfs);
|
rlm@10
|
568
|
rlm@10
|
569 // calls the visitSource method
|
rlm@10
|
570 if(!skipDebug && (sourceFile != null || sourceDebug != null))
|
rlm@10
|
571 {
|
rlm@10
|
572 classVisitor.visitSource(sourceFile, sourceDebug);
|
rlm@10
|
573 }
|
rlm@10
|
574
|
rlm@10
|
575 // calls the visitOuterClass method
|
rlm@10
|
576 if(enclosingOwner != null)
|
rlm@10
|
577 {
|
rlm@10
|
578 classVisitor.visitOuterClass(enclosingOwner,
|
rlm@10
|
579 enclosingName,
|
rlm@10
|
580 enclosingDesc);
|
rlm@10
|
581 }
|
rlm@10
|
582
|
rlm@10
|
583 // visits the class annotations
|
rlm@10
|
584 for(i = 1; i >= 0; --i)
|
rlm@10
|
585 {
|
rlm@10
|
586 v = i == 0 ? ianns : anns;
|
rlm@10
|
587 if(v != 0)
|
rlm@10
|
588 {
|
rlm@10
|
589 j = readUnsignedShort(v);
|
rlm@10
|
590 v += 2;
|
rlm@10
|
591 for(; j > 0; --j)
|
rlm@10
|
592 {
|
rlm@10
|
593 v = readAnnotationValues(v + 2,
|
rlm@10
|
594 c,
|
rlm@10
|
595 true,
|
rlm@10
|
596 classVisitor.visitAnnotation(readUTF8(v, c), i != 0));
|
rlm@10
|
597 }
|
rlm@10
|
598 }
|
rlm@10
|
599 }
|
rlm@10
|
600
|
rlm@10
|
601 // visits the class attributes
|
rlm@10
|
602 while(cattrs != null)
|
rlm@10
|
603 {
|
rlm@10
|
604 attr = cattrs.next;
|
rlm@10
|
605 cattrs.next = null;
|
rlm@10
|
606 classVisitor.visitAttribute(cattrs);
|
rlm@10
|
607 cattrs = attr;
|
rlm@10
|
608 }
|
rlm@10
|
609
|
rlm@10
|
610 // calls the visitInnerClass method
|
rlm@10
|
611 if(w != 0)
|
rlm@10
|
612 {
|
rlm@10
|
613 i = readUnsignedShort(w);
|
rlm@10
|
614 w += 2;
|
rlm@10
|
615 for(; i > 0; --i)
|
rlm@10
|
616 {
|
rlm@10
|
617 classVisitor.visitInnerClass(readUnsignedShort(w) == 0
|
rlm@10
|
618 ? null
|
rlm@10
|
619 : readClass(w, c), readUnsignedShort(w + 2) == 0
|
rlm@10
|
620 ? null
|
rlm@10
|
621 : readClass(w + 2, c), readUnsignedShort(w + 4) == 0
|
rlm@10
|
622 ? null
|
rlm@10
|
623 : readUTF8(w + 4, c),
|
rlm@10
|
624 readUnsignedShort(w + 6));
|
rlm@10
|
625 w += 8;
|
rlm@10
|
626 }
|
rlm@10
|
627 }
|
rlm@10
|
628
|
rlm@10
|
629 // visits the fields
|
rlm@10
|
630 i = readUnsignedShort(u);
|
rlm@10
|
631 u += 2;
|
rlm@10
|
632 for(; i > 0; --i)
|
rlm@10
|
633 {
|
rlm@10
|
634 access = readUnsignedShort(u);
|
rlm@10
|
635 name = readUTF8(u + 2, c);
|
rlm@10
|
636 desc = readUTF8(u + 4, c);
|
rlm@10
|
637 // visits the field's attributes and looks for a ConstantValue
|
rlm@10
|
638 // attribute
|
rlm@10
|
639 int fieldValueItem = 0;
|
rlm@10
|
640 signature = null;
|
rlm@10
|
641 anns = 0;
|
rlm@10
|
642 ianns = 0;
|
rlm@10
|
643 cattrs = null;
|
rlm@10
|
644
|
rlm@10
|
645 j = readUnsignedShort(u + 6);
|
rlm@10
|
646 u += 8;
|
rlm@10
|
647 for(; j > 0; --j)
|
rlm@10
|
648 {
|
rlm@10
|
649 attrName = readUTF8(u, c);
|
rlm@10
|
650 // tests are sorted in decreasing frequency order
|
rlm@10
|
651 // (based on frequencies observed on typical classes)
|
rlm@10
|
652 if(attrName.equals("ConstantValue"))
|
rlm@10
|
653 {
|
rlm@10
|
654 fieldValueItem = readUnsignedShort(u + 6);
|
rlm@10
|
655 }
|
rlm@10
|
656 else if(attrName.equals("Signature"))
|
rlm@10
|
657 {
|
rlm@10
|
658 signature = readUTF8(u + 6, c);
|
rlm@10
|
659 }
|
rlm@10
|
660 else if(attrName.equals("Deprecated"))
|
rlm@10
|
661 {
|
rlm@10
|
662 access |= Opcodes.ACC_DEPRECATED;
|
rlm@10
|
663 }
|
rlm@10
|
664 else if(attrName.equals("Synthetic"))
|
rlm@10
|
665 {
|
rlm@10
|
666 access |= Opcodes.ACC_SYNTHETIC;
|
rlm@10
|
667 }
|
rlm@10
|
668 else if(attrName.equals("RuntimeVisibleAnnotations"))
|
rlm@10
|
669 {
|
rlm@10
|
670 anns = u + 6;
|
rlm@10
|
671 }
|
rlm@10
|
672 else if(attrName.equals("RuntimeInvisibleAnnotations"))
|
rlm@10
|
673 {
|
rlm@10
|
674 ianns = u + 6;
|
rlm@10
|
675 }
|
rlm@10
|
676 else
|
rlm@10
|
677 {
|
rlm@10
|
678 attr = readAttribute(attrs,
|
rlm@10
|
679 attrName,
|
rlm@10
|
680 u + 6,
|
rlm@10
|
681 readInt(u + 2),
|
rlm@10
|
682 c,
|
rlm@10
|
683 -1,
|
rlm@10
|
684 null);
|
rlm@10
|
685 if(attr != null)
|
rlm@10
|
686 {
|
rlm@10
|
687 attr.next = cattrs;
|
rlm@10
|
688 cattrs = attr;
|
rlm@10
|
689 }
|
rlm@10
|
690 }
|
rlm@10
|
691 u += 6 + readInt(u + 2);
|
rlm@10
|
692 }
|
rlm@10
|
693 // visits the field
|
rlm@10
|
694 FieldVisitor fv = classVisitor.visitField(access,
|
rlm@10
|
695 name,
|
rlm@10
|
696 desc,
|
rlm@10
|
697 signature,
|
rlm@10
|
698 fieldValueItem == 0 ? null : readConst(fieldValueItem, c));
|
rlm@10
|
699 // visits the field annotations and attributes
|
rlm@10
|
700 if(fv != null)
|
rlm@10
|
701 {
|
rlm@10
|
702 for(j = 1; j >= 0; --j)
|
rlm@10
|
703 {
|
rlm@10
|
704 v = j == 0 ? ianns : anns;
|
rlm@10
|
705 if(v != 0)
|
rlm@10
|
706 {
|
rlm@10
|
707 k = readUnsignedShort(v);
|
rlm@10
|
708 v += 2;
|
rlm@10
|
709 for(; k > 0; --k)
|
rlm@10
|
710 {
|
rlm@10
|
711 v = readAnnotationValues(v + 2,
|
rlm@10
|
712 c,
|
rlm@10
|
713 true,
|
rlm@10
|
714 fv.visitAnnotation(readUTF8(v, c), j != 0));
|
rlm@10
|
715 }
|
rlm@10
|
716 }
|
rlm@10
|
717 }
|
rlm@10
|
718 while(cattrs != null)
|
rlm@10
|
719 {
|
rlm@10
|
720 attr = cattrs.next;
|
rlm@10
|
721 cattrs.next = null;
|
rlm@10
|
722 fv.visitAttribute(cattrs);
|
rlm@10
|
723 cattrs = attr;
|
rlm@10
|
724 }
|
rlm@10
|
725 fv.visitEnd();
|
rlm@10
|
726 }
|
rlm@10
|
727 }
|
rlm@10
|
728
|
rlm@10
|
729 // visits the methods
|
rlm@10
|
730 i = readUnsignedShort(u);
|
rlm@10
|
731 u += 2;
|
rlm@10
|
732 for(; i > 0; --i)
|
rlm@10
|
733 {
|
rlm@10
|
734 int u0 = u + 6;
|
rlm@10
|
735 access = readUnsignedShort(u);
|
rlm@10
|
736 name = readUTF8(u + 2, c);
|
rlm@10
|
737 desc = readUTF8(u + 4, c);
|
rlm@10
|
738 signature = null;
|
rlm@10
|
739 anns = 0;
|
rlm@10
|
740 ianns = 0;
|
rlm@10
|
741 int dann = 0;
|
rlm@10
|
742 int mpanns = 0;
|
rlm@10
|
743 int impanns = 0;
|
rlm@10
|
744 cattrs = null;
|
rlm@10
|
745 v = 0;
|
rlm@10
|
746 w = 0;
|
rlm@10
|
747
|
rlm@10
|
748 // looks for Code and Exceptions attributes
|
rlm@10
|
749 j = readUnsignedShort(u + 6);
|
rlm@10
|
750 u += 8;
|
rlm@10
|
751 for(; j > 0; --j)
|
rlm@10
|
752 {
|
rlm@10
|
753 attrName = readUTF8(u, c);
|
rlm@10
|
754 int attrSize = readInt(u + 2);
|
rlm@10
|
755 u += 6;
|
rlm@10
|
756 // tests are sorted in decreasing frequency order
|
rlm@10
|
757 // (based on frequencies observed on typical classes)
|
rlm@10
|
758 if(attrName.equals("Code"))
|
rlm@10
|
759 {
|
rlm@10
|
760 if(!skipCode)
|
rlm@10
|
761 {
|
rlm@10
|
762 v = u;
|
rlm@10
|
763 }
|
rlm@10
|
764 }
|
rlm@10
|
765 else if(attrName.equals("Exceptions"))
|
rlm@10
|
766 {
|
rlm@10
|
767 w = u;
|
rlm@10
|
768 }
|
rlm@10
|
769 else if(attrName.equals("Signature"))
|
rlm@10
|
770 {
|
rlm@10
|
771 signature = readUTF8(u, c);
|
rlm@10
|
772 }
|
rlm@10
|
773 else if(attrName.equals("Deprecated"))
|
rlm@10
|
774 {
|
rlm@10
|
775 access |= Opcodes.ACC_DEPRECATED;
|
rlm@10
|
776 }
|
rlm@10
|
777 else if(attrName.equals("RuntimeVisibleAnnotations"))
|
rlm@10
|
778 {
|
rlm@10
|
779 anns = u;
|
rlm@10
|
780 }
|
rlm@10
|
781 else if(attrName.equals("AnnotationDefault"))
|
rlm@10
|
782 {
|
rlm@10
|
783 dann = u;
|
rlm@10
|
784 }
|
rlm@10
|
785 else if(attrName.equals("Synthetic"))
|
rlm@10
|
786 {
|
rlm@10
|
787 access |= Opcodes.ACC_SYNTHETIC;
|
rlm@10
|
788 }
|
rlm@10
|
789 else if(attrName.equals("RuntimeInvisibleAnnotations"))
|
rlm@10
|
790 {
|
rlm@10
|
791 ianns = u;
|
rlm@10
|
792 }
|
rlm@10
|
793 else if(attrName.equals("RuntimeVisibleParameterAnnotations"))
|
rlm@10
|
794 {
|
rlm@10
|
795 mpanns = u;
|
rlm@10
|
796 }
|
rlm@10
|
797 else if(attrName.equals("RuntimeInvisibleParameterAnnotations"))
|
rlm@10
|
798 {
|
rlm@10
|
799 impanns = u;
|
rlm@10
|
800 }
|
rlm@10
|
801 else
|
rlm@10
|
802 {
|
rlm@10
|
803 attr = readAttribute(attrs,
|
rlm@10
|
804 attrName,
|
rlm@10
|
805 u,
|
rlm@10
|
806 attrSize,
|
rlm@10
|
807 c,
|
rlm@10
|
808 -1,
|
rlm@10
|
809 null);
|
rlm@10
|
810 if(attr != null)
|
rlm@10
|
811 {
|
rlm@10
|
812 attr.next = cattrs;
|
rlm@10
|
813 cattrs = attr;
|
rlm@10
|
814 }
|
rlm@10
|
815 }
|
rlm@10
|
816 u += attrSize;
|
rlm@10
|
817 }
|
rlm@10
|
818 // reads declared exceptions
|
rlm@10
|
819 String[] exceptions;
|
rlm@10
|
820 if(w == 0)
|
rlm@10
|
821 {
|
rlm@10
|
822 exceptions = null;
|
rlm@10
|
823 }
|
rlm@10
|
824 else
|
rlm@10
|
825 {
|
rlm@10
|
826 exceptions = new String[readUnsignedShort(w)];
|
rlm@10
|
827 w += 2;
|
rlm@10
|
828 for(j = 0; j < exceptions.length; ++j)
|
rlm@10
|
829 {
|
rlm@10
|
830 exceptions[j] = readClass(w, c);
|
rlm@10
|
831 w += 2;
|
rlm@10
|
832 }
|
rlm@10
|
833 }
|
rlm@10
|
834
|
rlm@10
|
835 // visits the method's code, if any
|
rlm@10
|
836 MethodVisitor mv = classVisitor.visitMethod(access,
|
rlm@10
|
837 name,
|
rlm@10
|
838 desc,
|
rlm@10
|
839 signature,
|
rlm@10
|
840 exceptions);
|
rlm@10
|
841
|
rlm@10
|
842 if(mv != null)
|
rlm@10
|
843 {
|
rlm@10
|
844 /*
|
rlm@10
|
845 * if the returned MethodVisitor is in fact a MethodWriter, it
|
rlm@10
|
846 * means there is no method adapter between the reader and the
|
rlm@10
|
847 * writer. If, in addition, the writer's constant pool was
|
rlm@10
|
848 * copied from this reader (mw.cw.cr == this), and the signature
|
rlm@10
|
849 * and exceptions of the method have not been changed, then it
|
rlm@10
|
850 * is possible to skip all visit events and just copy the
|
rlm@10
|
851 * original code of the method to the writer (the access, name
|
rlm@10
|
852 * and descriptor can have been changed, this is not important
|
rlm@10
|
853 * since they are not copied as is from the reader).
|
rlm@10
|
854 */
|
rlm@10
|
855 if(mv instanceof MethodWriter)
|
rlm@10
|
856 {
|
rlm@10
|
857 MethodWriter mw = (MethodWriter) mv;
|
rlm@10
|
858 if(mw.cw.cr == this)
|
rlm@10
|
859 {
|
rlm@10
|
860 if(signature == mw.signature)
|
rlm@10
|
861 {
|
rlm@10
|
862 boolean sameExceptions = false;
|
rlm@10
|
863 if(exceptions == null)
|
rlm@10
|
864 {
|
rlm@10
|
865 sameExceptions = mw.exceptionCount == 0;
|
rlm@10
|
866 }
|
rlm@10
|
867 else
|
rlm@10
|
868 {
|
rlm@10
|
869 if(exceptions.length == mw.exceptionCount)
|
rlm@10
|
870 {
|
rlm@10
|
871 sameExceptions = true;
|
rlm@10
|
872 for(j = exceptions.length - 1; j >= 0; --j)
|
rlm@10
|
873 {
|
rlm@10
|
874 w -= 2;
|
rlm@10
|
875 if(mw.exceptions[j] != readUnsignedShort(w))
|
rlm@10
|
876 {
|
rlm@10
|
877 sameExceptions = false;
|
rlm@10
|
878 break;
|
rlm@10
|
879 }
|
rlm@10
|
880 }
|
rlm@10
|
881 }
|
rlm@10
|
882 }
|
rlm@10
|
883 if(sameExceptions)
|
rlm@10
|
884 {
|
rlm@10
|
885 /*
|
rlm@10
|
886 * we do not copy directly the code into
|
rlm@10
|
887 * MethodWriter to save a byte array copy
|
rlm@10
|
888 * operation. The real copy will be done in
|
rlm@10
|
889 * ClassWriter.toByteArray().
|
rlm@10
|
890 */
|
rlm@10
|
891 mw.classReaderOffset = u0;
|
rlm@10
|
892 mw.classReaderLength = u - u0;
|
rlm@10
|
893 continue;
|
rlm@10
|
894 }
|
rlm@10
|
895 }
|
rlm@10
|
896 }
|
rlm@10
|
897 }
|
rlm@10
|
898
|
rlm@10
|
899 if(dann != 0)
|
rlm@10
|
900 {
|
rlm@10
|
901 AnnotationVisitor dv = mv.visitAnnotationDefault();
|
rlm@10
|
902 readAnnotationValue(dann, c, null, dv);
|
rlm@10
|
903 if(dv != null)
|
rlm@10
|
904 {
|
rlm@10
|
905 dv.visitEnd();
|
rlm@10
|
906 }
|
rlm@10
|
907 }
|
rlm@10
|
908 for(j = 1; j >= 0; --j)
|
rlm@10
|
909 {
|
rlm@10
|
910 w = j == 0 ? ianns : anns;
|
rlm@10
|
911 if(w != 0)
|
rlm@10
|
912 {
|
rlm@10
|
913 k = readUnsignedShort(w);
|
rlm@10
|
914 w += 2;
|
rlm@10
|
915 for(; k > 0; --k)
|
rlm@10
|
916 {
|
rlm@10
|
917 w = readAnnotationValues(w + 2,
|
rlm@10
|
918 c,
|
rlm@10
|
919 true,
|
rlm@10
|
920 mv.visitAnnotation(readUTF8(w, c), j != 0));
|
rlm@10
|
921 }
|
rlm@10
|
922 }
|
rlm@10
|
923 }
|
rlm@10
|
924 if(mpanns != 0)
|
rlm@10
|
925 {
|
rlm@10
|
926 readParameterAnnotations(mpanns, c, true, mv);
|
rlm@10
|
927 }
|
rlm@10
|
928 if(impanns != 0)
|
rlm@10
|
929 {
|
rlm@10
|
930 readParameterAnnotations(impanns, c, false, mv);
|
rlm@10
|
931 }
|
rlm@10
|
932 while(cattrs != null)
|
rlm@10
|
933 {
|
rlm@10
|
934 attr = cattrs.next;
|
rlm@10
|
935 cattrs.next = null;
|
rlm@10
|
936 mv.visitAttribute(cattrs);
|
rlm@10
|
937 cattrs = attr;
|
rlm@10
|
938 }
|
rlm@10
|
939 }
|
rlm@10
|
940
|
rlm@10
|
941 if(mv != null && v != 0)
|
rlm@10
|
942 {
|
rlm@10
|
943 int maxStack = readUnsignedShort(v);
|
rlm@10
|
944 int maxLocals = readUnsignedShort(v + 2);
|
rlm@10
|
945 int codeLength = readInt(v + 4);
|
rlm@10
|
946 v += 8;
|
rlm@10
|
947
|
rlm@10
|
948 int codeStart = v;
|
rlm@10
|
949 int codeEnd = v + codeLength;
|
rlm@10
|
950
|
rlm@10
|
951 mv.visitCode();
|
rlm@10
|
952
|
rlm@10
|
953 // 1st phase: finds the labels
|
rlm@10
|
954 int label;
|
rlm@10
|
955 Label[] labels = new Label[codeLength + 1];
|
rlm@10
|
956 while(v < codeEnd)
|
rlm@10
|
957 {
|
rlm@10
|
958 int opcode = b[v] & 0xFF;
|
rlm@10
|
959 switch(ClassWriter.TYPE[opcode])
|
rlm@10
|
960 {
|
rlm@10
|
961 case ClassWriter.NOARG_INSN:
|
rlm@10
|
962 case ClassWriter.IMPLVAR_INSN:
|
rlm@10
|
963 v += 1;
|
rlm@10
|
964 break;
|
rlm@10
|
965 case ClassWriter.LABEL_INSN:
|
rlm@10
|
966 label = v - codeStart + readShort(v + 1);
|
rlm@10
|
967 if(labels[label] == null)
|
rlm@10
|
968 {
|
rlm@10
|
969 labels[label] = new Label();
|
rlm@10
|
970 }
|
rlm@10
|
971 v += 3;
|
rlm@10
|
972 break;
|
rlm@10
|
973 case ClassWriter.LABELW_INSN:
|
rlm@10
|
974 label = v - codeStart + readInt(v + 1);
|
rlm@10
|
975 if(labels[label] == null)
|
rlm@10
|
976 {
|
rlm@10
|
977 labels[label] = new Label();
|
rlm@10
|
978 }
|
rlm@10
|
979 v += 5;
|
rlm@10
|
980 break;
|
rlm@10
|
981 case ClassWriter.WIDE_INSN:
|
rlm@10
|
982 opcode = b[v + 1] & 0xFF;
|
rlm@10
|
983 if(opcode == Opcodes.IINC)
|
rlm@10
|
984 {
|
rlm@10
|
985 v += 6;
|
rlm@10
|
986 }
|
rlm@10
|
987 else
|
rlm@10
|
988 {
|
rlm@10
|
989 v += 4;
|
rlm@10
|
990 }
|
rlm@10
|
991 break;
|
rlm@10
|
992 case ClassWriter.TABL_INSN:
|
rlm@10
|
993 // skips 0 to 3 padding bytes
|
rlm@10
|
994 w = v - codeStart;
|
rlm@10
|
995 v = v + 4 - (w & 3);
|
rlm@10
|
996 // reads instruction
|
rlm@10
|
997 label = w + readInt(v);
|
rlm@10
|
998 if(labels[label] == null)
|
rlm@10
|
999 {
|
rlm@10
|
1000 labels[label] = new Label();
|
rlm@10
|
1001 }
|
rlm@10
|
1002 j = readInt(v + 8) - readInt(v + 4) + 1;
|
rlm@10
|
1003 v += 12;
|
rlm@10
|
1004 for(; j > 0; --j)
|
rlm@10
|
1005 {
|
rlm@10
|
1006 label = w + readInt(v);
|
rlm@10
|
1007 v += 4;
|
rlm@10
|
1008 if(labels[label] == null)
|
rlm@10
|
1009 {
|
rlm@10
|
1010 labels[label] = new Label();
|
rlm@10
|
1011 }
|
rlm@10
|
1012 }
|
rlm@10
|
1013 break;
|
rlm@10
|
1014 case ClassWriter.LOOK_INSN:
|
rlm@10
|
1015 // skips 0 to 3 padding bytes
|
rlm@10
|
1016 w = v - codeStart;
|
rlm@10
|
1017 v = v + 4 - (w & 3);
|
rlm@10
|
1018 // reads instruction
|
rlm@10
|
1019 label = w + readInt(v);
|
rlm@10
|
1020 if(labels[label] == null)
|
rlm@10
|
1021 {
|
rlm@10
|
1022 labels[label] = new Label();
|
rlm@10
|
1023 }
|
rlm@10
|
1024 j = readInt(v + 4);
|
rlm@10
|
1025 v += 8;
|
rlm@10
|
1026 for(; j > 0; --j)
|
rlm@10
|
1027 {
|
rlm@10
|
1028 label = w + readInt(v + 4);
|
rlm@10
|
1029 v += 8;
|
rlm@10
|
1030 if(labels[label] == null)
|
rlm@10
|
1031 {
|
rlm@10
|
1032 labels[label] = new Label();
|
rlm@10
|
1033 }
|
rlm@10
|
1034 }
|
rlm@10
|
1035 break;
|
rlm@10
|
1036 case ClassWriter.VAR_INSN:
|
rlm@10
|
1037 case ClassWriter.SBYTE_INSN:
|
rlm@10
|
1038 case ClassWriter.LDC_INSN:
|
rlm@10
|
1039 v += 2;
|
rlm@10
|
1040 break;
|
rlm@10
|
1041 case ClassWriter.SHORT_INSN:
|
rlm@10
|
1042 case ClassWriter.LDCW_INSN:
|
rlm@10
|
1043 case ClassWriter.FIELDORMETH_INSN:
|
rlm@10
|
1044 case ClassWriter.TYPE_INSN:
|
rlm@10
|
1045 case ClassWriter.IINC_INSN:
|
rlm@10
|
1046 v += 3;
|
rlm@10
|
1047 break;
|
rlm@10
|
1048 case ClassWriter.ITFMETH_INSN:
|
rlm@10
|
1049 v += 5;
|
rlm@10
|
1050 break;
|
rlm@10
|
1051 // case MANA_INSN:
|
rlm@10
|
1052 default:
|
rlm@10
|
1053 v += 4;
|
rlm@10
|
1054 break;
|
rlm@10
|
1055 }
|
rlm@10
|
1056 }
|
rlm@10
|
1057 // parses the try catch entries
|
rlm@10
|
1058 j = readUnsignedShort(v);
|
rlm@10
|
1059 v += 2;
|
rlm@10
|
1060 for(; j > 0; --j)
|
rlm@10
|
1061 {
|
rlm@10
|
1062 label = readUnsignedShort(v);
|
rlm@10
|
1063 Label start = labels[label];
|
rlm@10
|
1064 if(start == null)
|
rlm@10
|
1065 {
|
rlm@10
|
1066 labels[label] = start = new Label();
|
rlm@10
|
1067 }
|
rlm@10
|
1068 label = readUnsignedShort(v + 2);
|
rlm@10
|
1069 Label end = labels[label];
|
rlm@10
|
1070 if(end == null)
|
rlm@10
|
1071 {
|
rlm@10
|
1072 labels[label] = end = new Label();
|
rlm@10
|
1073 }
|
rlm@10
|
1074 label = readUnsignedShort(v + 4);
|
rlm@10
|
1075 Label handler = labels[label];
|
rlm@10
|
1076 if(handler == null)
|
rlm@10
|
1077 {
|
rlm@10
|
1078 labels[label] = handler = new Label();
|
rlm@10
|
1079 }
|
rlm@10
|
1080 int type = readUnsignedShort(v + 6);
|
rlm@10
|
1081 if(type == 0)
|
rlm@10
|
1082 {
|
rlm@10
|
1083 mv.visitTryCatchBlock(start, end, handler, null);
|
rlm@10
|
1084 }
|
rlm@10
|
1085 else
|
rlm@10
|
1086 {
|
rlm@10
|
1087 mv.visitTryCatchBlock(start,
|
rlm@10
|
1088 end,
|
rlm@10
|
1089 handler,
|
rlm@10
|
1090 readUTF8(items[type], c));
|
rlm@10
|
1091 }
|
rlm@10
|
1092 v += 8;
|
rlm@10
|
1093 }
|
rlm@10
|
1094 // parses the local variable, line number tables, and code
|
rlm@10
|
1095 // attributes
|
rlm@10
|
1096 int varTable = 0;
|
rlm@10
|
1097 int varTypeTable = 0;
|
rlm@10
|
1098 int stackMap = 0;
|
rlm@10
|
1099 int frameCount = 0;
|
rlm@10
|
1100 int frameMode = 0;
|
rlm@10
|
1101 int frameOffset = 0;
|
rlm@10
|
1102 int frameLocalCount = 0;
|
rlm@10
|
1103 int frameLocalDiff = 0;
|
rlm@10
|
1104 int frameStackCount = 0;
|
rlm@10
|
1105 Object[] frameLocal = null;
|
rlm@10
|
1106 Object[] frameStack = null;
|
rlm@10
|
1107 boolean zip = true;
|
rlm@10
|
1108 cattrs = null;
|
rlm@10
|
1109 j = readUnsignedShort(v);
|
rlm@10
|
1110 v += 2;
|
rlm@10
|
1111 for(; j > 0; --j)
|
rlm@10
|
1112 {
|
rlm@10
|
1113 attrName = readUTF8(v, c);
|
rlm@10
|
1114 if(attrName.equals("LocalVariableTable"))
|
rlm@10
|
1115 {
|
rlm@10
|
1116 if(!skipDebug)
|
rlm@10
|
1117 {
|
rlm@10
|
1118 varTable = v + 6;
|
rlm@10
|
1119 k = readUnsignedShort(v + 6);
|
rlm@10
|
1120 w = v + 8;
|
rlm@10
|
1121 for(; k > 0; --k)
|
rlm@10
|
1122 {
|
rlm@10
|
1123 label = readUnsignedShort(w);
|
rlm@10
|
1124 if(labels[label] == null)
|
rlm@10
|
1125 {
|
rlm@10
|
1126 labels[label] = new Label(true);
|
rlm@10
|
1127 }
|
rlm@10
|
1128 label += readUnsignedShort(w + 2);
|
rlm@10
|
1129 if(labels[label] == null)
|
rlm@10
|
1130 {
|
rlm@10
|
1131 labels[label] = new Label(true);
|
rlm@10
|
1132 }
|
rlm@10
|
1133 w += 10;
|
rlm@10
|
1134 }
|
rlm@10
|
1135 }
|
rlm@10
|
1136 }
|
rlm@10
|
1137 else if(attrName.equals("LocalVariableTypeTable"))
|
rlm@10
|
1138 {
|
rlm@10
|
1139 varTypeTable = v + 6;
|
rlm@10
|
1140 }
|
rlm@10
|
1141 else if(attrName.equals("LineNumberTable"))
|
rlm@10
|
1142 {
|
rlm@10
|
1143 if(!skipDebug)
|
rlm@10
|
1144 {
|
rlm@10
|
1145 k = readUnsignedShort(v + 6);
|
rlm@10
|
1146 w = v + 8;
|
rlm@10
|
1147 for(; k > 0; --k)
|
rlm@10
|
1148 {
|
rlm@10
|
1149 label = readUnsignedShort(w);
|
rlm@10
|
1150 if(labels[label] == null)
|
rlm@10
|
1151 {
|
rlm@10
|
1152 labels[label] = new Label(true);
|
rlm@10
|
1153 }
|
rlm@10
|
1154 labels[label].line = readUnsignedShort(w + 2);
|
rlm@10
|
1155 w += 4;
|
rlm@10
|
1156 }
|
rlm@10
|
1157 }
|
rlm@10
|
1158 }
|
rlm@10
|
1159 else if(attrName.equals("StackMapTable"))
|
rlm@10
|
1160 {
|
rlm@10
|
1161 if((flags & SKIP_FRAMES) == 0)
|
rlm@10
|
1162 {
|
rlm@10
|
1163 stackMap = v + 8;
|
rlm@10
|
1164 frameCount = readUnsignedShort(v + 6);
|
rlm@10
|
1165 }
|
rlm@10
|
1166 /*
|
rlm@10
|
1167 * here we do not extract the labels corresponding to
|
rlm@10
|
1168 * the attribute content. This would require a full
|
rlm@10
|
1169 * parsing of the attribute, which would need to be
|
rlm@10
|
1170 * repeated in the second phase (see below). Instead the
|
rlm@10
|
1171 * content of the attribute is read one frame at a time
|
rlm@10
|
1172 * (i.e. after a frame has been visited, the next frame
|
rlm@10
|
1173 * is read), and the labels it contains are also
|
rlm@10
|
1174 * extracted one frame at a time. Thanks to the ordering
|
rlm@10
|
1175 * of frames, having only a "one frame lookahead" is not
|
rlm@10
|
1176 * a problem, i.e. it is not possible to see an offset
|
rlm@10
|
1177 * smaller than the offset of the current insn and for
|
rlm@10
|
1178 * which no Label exist.
|
rlm@10
|
1179 */
|
rlm@10
|
1180 // TODO true for frame offsets,
|
rlm@10
|
1181 // but for UNINITIALIZED type offsets?
|
rlm@10
|
1182 }
|
rlm@10
|
1183 else if(attrName.equals("StackMap"))
|
rlm@10
|
1184 {
|
rlm@10
|
1185 if((flags & SKIP_FRAMES) == 0)
|
rlm@10
|
1186 {
|
rlm@10
|
1187 stackMap = v + 8;
|
rlm@10
|
1188 frameCount = readUnsignedShort(v + 6);
|
rlm@10
|
1189 zip = false;
|
rlm@10
|
1190 }
|
rlm@10
|
1191 /*
|
rlm@10
|
1192 * IMPORTANT! here we assume that the frames are
|
rlm@10
|
1193 * ordered, as in the StackMapTable attribute, although
|
rlm@10
|
1194 * this is not guaranteed by the attribute format.
|
rlm@10
|
1195 */
|
rlm@10
|
1196 }
|
rlm@10
|
1197 else
|
rlm@10
|
1198 {
|
rlm@10
|
1199 for(k = 0; k < attrs.length; ++k)
|
rlm@10
|
1200 {
|
rlm@10
|
1201 if(attrs[k].type.equals(attrName))
|
rlm@10
|
1202 {
|
rlm@10
|
1203 attr = attrs[k].read(this,
|
rlm@10
|
1204 v + 6,
|
rlm@10
|
1205 readInt(v + 2),
|
rlm@10
|
1206 c,
|
rlm@10
|
1207 codeStart - 8,
|
rlm@10
|
1208 labels);
|
rlm@10
|
1209 if(attr != null)
|
rlm@10
|
1210 {
|
rlm@10
|
1211 attr.next = cattrs;
|
rlm@10
|
1212 cattrs = attr;
|
rlm@10
|
1213 }
|
rlm@10
|
1214 }
|
rlm@10
|
1215 }
|
rlm@10
|
1216 }
|
rlm@10
|
1217 v += 6 + readInt(v + 2);
|
rlm@10
|
1218 }
|
rlm@10
|
1219
|
rlm@10
|
1220 // 2nd phase: visits each instruction
|
rlm@10
|
1221 if(stackMap != 0)
|
rlm@10
|
1222 {
|
rlm@10
|
1223 // creates the very first (implicit) frame from the method
|
rlm@10
|
1224 // descriptor
|
rlm@10
|
1225 frameLocal = new Object[maxLocals];
|
rlm@10
|
1226 frameStack = new Object[maxStack];
|
rlm@10
|
1227 if(unzip)
|
rlm@10
|
1228 {
|
rlm@10
|
1229 int local = 0;
|
rlm@10
|
1230 if((access & Opcodes.ACC_STATIC) == 0)
|
rlm@10
|
1231 {
|
rlm@10
|
1232 if(name.equals("<init>"))
|
rlm@10
|
1233 {
|
rlm@10
|
1234 frameLocal[local++] = Opcodes.UNINITIALIZED_THIS;
|
rlm@10
|
1235 }
|
rlm@10
|
1236 else
|
rlm@10
|
1237 {
|
rlm@10
|
1238 frameLocal[local++] = readClass(header + 2, c);
|
rlm@10
|
1239 }
|
rlm@10
|
1240 }
|
rlm@10
|
1241 j = 1;
|
rlm@10
|
1242 loop:
|
rlm@10
|
1243 while(true)
|
rlm@10
|
1244 {
|
rlm@10
|
1245 k = j;
|
rlm@10
|
1246 switch(desc.charAt(j++))
|
rlm@10
|
1247 {
|
rlm@10
|
1248 case'Z':
|
rlm@10
|
1249 case'C':
|
rlm@10
|
1250 case'B':
|
rlm@10
|
1251 case'S':
|
rlm@10
|
1252 case'I':
|
rlm@10
|
1253 frameLocal[local++] = Opcodes.INTEGER;
|
rlm@10
|
1254 break;
|
rlm@10
|
1255 case'F':
|
rlm@10
|
1256 frameLocal[local++] = Opcodes.FLOAT;
|
rlm@10
|
1257 break;
|
rlm@10
|
1258 case'J':
|
rlm@10
|
1259 frameLocal[local++] = Opcodes.LONG;
|
rlm@10
|
1260 break;
|
rlm@10
|
1261 case'D':
|
rlm@10
|
1262 frameLocal[local++] = Opcodes.DOUBLE;
|
rlm@10
|
1263 break;
|
rlm@10
|
1264 case'[':
|
rlm@10
|
1265 while(desc.charAt(j) == '[')
|
rlm@10
|
1266 {
|
rlm@10
|
1267 ++j;
|
rlm@10
|
1268 }
|
rlm@10
|
1269 if(desc.charAt(j) == 'L')
|
rlm@10
|
1270 {
|
rlm@10
|
1271 ++j;
|
rlm@10
|
1272 while(desc.charAt(j) != ';')
|
rlm@10
|
1273 {
|
rlm@10
|
1274 ++j;
|
rlm@10
|
1275 }
|
rlm@10
|
1276 }
|
rlm@10
|
1277 frameLocal[local++] = desc.substring(k, ++j);
|
rlm@10
|
1278 break;
|
rlm@10
|
1279 case'L':
|
rlm@10
|
1280 while(desc.charAt(j) != ';')
|
rlm@10
|
1281 {
|
rlm@10
|
1282 ++j;
|
rlm@10
|
1283 }
|
rlm@10
|
1284 frameLocal[local++] = desc.substring(k + 1,
|
rlm@10
|
1285 j++);
|
rlm@10
|
1286 break;
|
rlm@10
|
1287 default:
|
rlm@10
|
1288 break loop;
|
rlm@10
|
1289 }
|
rlm@10
|
1290 }
|
rlm@10
|
1291 frameLocalCount = local;
|
rlm@10
|
1292 }
|
rlm@10
|
1293 /*
|
rlm@10
|
1294 * for the first explicit frame the offset is not
|
rlm@10
|
1295 * offset_delta + 1 but only offset_delta; setting the
|
rlm@10
|
1296 * implicit frame offset to -1 allow the use of the
|
rlm@10
|
1297 * "offset_delta + 1" rule in all cases
|
rlm@10
|
1298 */
|
rlm@10
|
1299 frameOffset = -1;
|
rlm@10
|
1300 }
|
rlm@10
|
1301 v = codeStart;
|
rlm@10
|
1302 Label l;
|
rlm@10
|
1303 while(v < codeEnd)
|
rlm@10
|
1304 {
|
rlm@10
|
1305 w = v - codeStart;
|
rlm@10
|
1306
|
rlm@10
|
1307 l = labels[w];
|
rlm@10
|
1308 if(l != null)
|
rlm@10
|
1309 {
|
rlm@10
|
1310 mv.visitLabel(l);
|
rlm@10
|
1311 if(!skipDebug && l.line > 0)
|
rlm@10
|
1312 {
|
rlm@10
|
1313 mv.visitLineNumber(l.line, l);
|
rlm@10
|
1314 }
|
rlm@10
|
1315 }
|
rlm@10
|
1316
|
rlm@10
|
1317 while(frameLocal != null
|
rlm@10
|
1318 && (frameOffset == w || frameOffset == -1))
|
rlm@10
|
1319 {
|
rlm@10
|
1320 // if there is a frame for this offset,
|
rlm@10
|
1321 // makes the visitor visit it,
|
rlm@10
|
1322 // and reads the next frame if there is one.
|
rlm@10
|
1323 if(!zip || unzip)
|
rlm@10
|
1324 {
|
rlm@10
|
1325 mv.visitFrame(Opcodes.F_NEW,
|
rlm@10
|
1326 frameLocalCount,
|
rlm@10
|
1327 frameLocal,
|
rlm@10
|
1328 frameStackCount,
|
rlm@10
|
1329 frameStack);
|
rlm@10
|
1330 }
|
rlm@10
|
1331 else if(frameOffset != -1)
|
rlm@10
|
1332 {
|
rlm@10
|
1333 mv.visitFrame(frameMode,
|
rlm@10
|
1334 frameLocalDiff,
|
rlm@10
|
1335 frameLocal,
|
rlm@10
|
1336 frameStackCount,
|
rlm@10
|
1337 frameStack);
|
rlm@10
|
1338 }
|
rlm@10
|
1339
|
rlm@10
|
1340 if(frameCount > 0)
|
rlm@10
|
1341 {
|
rlm@10
|
1342 int tag, delta, n;
|
rlm@10
|
1343 if(zip)
|
rlm@10
|
1344 {
|
rlm@10
|
1345 tag = b[stackMap++] & 0xFF;
|
rlm@10
|
1346 }
|
rlm@10
|
1347 else
|
rlm@10
|
1348 {
|
rlm@10
|
1349 tag = MethodWriter.FULL_FRAME;
|
rlm@10
|
1350 frameOffset = -1;
|
rlm@10
|
1351 }
|
rlm@10
|
1352 frameLocalDiff = 0;
|
rlm@10
|
1353 if(tag < MethodWriter.SAME_LOCALS_1_STACK_ITEM_FRAME)
|
rlm@10
|
1354 {
|
rlm@10
|
1355 delta = tag;
|
rlm@10
|
1356 frameMode = Opcodes.F_SAME;
|
rlm@10
|
1357 frameStackCount = 0;
|
rlm@10
|
1358 }
|
rlm@10
|
1359 else if(tag < MethodWriter.RESERVED)
|
rlm@10
|
1360 {
|
rlm@10
|
1361 delta = tag
|
rlm@10
|
1362 - MethodWriter.SAME_LOCALS_1_STACK_ITEM_FRAME;
|
rlm@10
|
1363 stackMap = readFrameType(frameStack,
|
rlm@10
|
1364 0,
|
rlm@10
|
1365 stackMap,
|
rlm@10
|
1366 c,
|
rlm@10
|
1367 labels);
|
rlm@10
|
1368 frameMode = Opcodes.F_SAME1;
|
rlm@10
|
1369 frameStackCount = 1;
|
rlm@10
|
1370 }
|
rlm@10
|
1371 else
|
rlm@10
|
1372 {
|
rlm@10
|
1373 delta = readUnsignedShort(stackMap);
|
rlm@10
|
1374 stackMap += 2;
|
rlm@10
|
1375 if(tag == MethodWriter.SAME_LOCALS_1_STACK_ITEM_FRAME_EXTENDED)
|
rlm@10
|
1376 {
|
rlm@10
|
1377 stackMap = readFrameType(frameStack,
|
rlm@10
|
1378 0,
|
rlm@10
|
1379 stackMap,
|
rlm@10
|
1380 c,
|
rlm@10
|
1381 labels);
|
rlm@10
|
1382 frameMode = Opcodes.F_SAME1;
|
rlm@10
|
1383 frameStackCount = 1;
|
rlm@10
|
1384 }
|
rlm@10
|
1385 else if(tag >= MethodWriter.CHOP_FRAME
|
rlm@10
|
1386 && tag < MethodWriter.SAME_FRAME_EXTENDED)
|
rlm@10
|
1387 {
|
rlm@10
|
1388 frameMode = Opcodes.F_CHOP;
|
rlm@10
|
1389 frameLocalDiff = MethodWriter.SAME_FRAME_EXTENDED
|
rlm@10
|
1390 - tag;
|
rlm@10
|
1391 frameLocalCount -= frameLocalDiff;
|
rlm@10
|
1392 frameStackCount = 0;
|
rlm@10
|
1393 }
|
rlm@10
|
1394 else if(tag == MethodWriter.SAME_FRAME_EXTENDED)
|
rlm@10
|
1395 {
|
rlm@10
|
1396 frameMode = Opcodes.F_SAME;
|
rlm@10
|
1397 frameStackCount = 0;
|
rlm@10
|
1398 }
|
rlm@10
|
1399 else if(tag < MethodWriter.FULL_FRAME)
|
rlm@10
|
1400 {
|
rlm@10
|
1401 j = unzip ? frameLocalCount : 0;
|
rlm@10
|
1402 for(k = tag
|
rlm@10
|
1403 - MethodWriter.SAME_FRAME_EXTENDED; k > 0; k--)
|
rlm@10
|
1404 {
|
rlm@10
|
1405 stackMap = readFrameType(frameLocal,
|
rlm@10
|
1406 j++,
|
rlm@10
|
1407 stackMap,
|
rlm@10
|
1408 c,
|
rlm@10
|
1409 labels);
|
rlm@10
|
1410 }
|
rlm@10
|
1411 frameMode = Opcodes.F_APPEND;
|
rlm@10
|
1412 frameLocalDiff = tag
|
rlm@10
|
1413 - MethodWriter.SAME_FRAME_EXTENDED;
|
rlm@10
|
1414 frameLocalCount += frameLocalDiff;
|
rlm@10
|
1415 frameStackCount = 0;
|
rlm@10
|
1416 }
|
rlm@10
|
1417 else
|
rlm@10
|
1418 { // if (tag == FULL_FRAME) {
|
rlm@10
|
1419 frameMode = Opcodes.F_FULL;
|
rlm@10
|
1420 n = frameLocalDiff = frameLocalCount = readUnsignedShort(stackMap);
|
rlm@10
|
1421 stackMap += 2;
|
rlm@10
|
1422 for(j = 0; n > 0; n--)
|
rlm@10
|
1423 {
|
rlm@10
|
1424 stackMap = readFrameType(frameLocal,
|
rlm@10
|
1425 j++,
|
rlm@10
|
1426 stackMap,
|
rlm@10
|
1427 c,
|
rlm@10
|
1428 labels);
|
rlm@10
|
1429 }
|
rlm@10
|
1430 n = frameStackCount = readUnsignedShort(stackMap);
|
rlm@10
|
1431 stackMap += 2;
|
rlm@10
|
1432 for(j = 0; n > 0; n--)
|
rlm@10
|
1433 {
|
rlm@10
|
1434 stackMap = readFrameType(frameStack,
|
rlm@10
|
1435 j++,
|
rlm@10
|
1436 stackMap,
|
rlm@10
|
1437 c,
|
rlm@10
|
1438 labels);
|
rlm@10
|
1439 }
|
rlm@10
|
1440 }
|
rlm@10
|
1441 }
|
rlm@10
|
1442 frameOffset += delta + 1;
|
rlm@10
|
1443 if(labels[frameOffset] == null)
|
rlm@10
|
1444 {
|
rlm@10
|
1445 labels[frameOffset] = new Label();
|
rlm@10
|
1446 }
|
rlm@10
|
1447
|
rlm@10
|
1448 --frameCount;
|
rlm@10
|
1449 }
|
rlm@10
|
1450 else
|
rlm@10
|
1451 {
|
rlm@10
|
1452 frameLocal = null;
|
rlm@10
|
1453 }
|
rlm@10
|
1454 }
|
rlm@10
|
1455
|
rlm@10
|
1456 int opcode = b[v] & 0xFF;
|
rlm@10
|
1457 switch(ClassWriter.TYPE[opcode])
|
rlm@10
|
1458 {
|
rlm@10
|
1459 case ClassWriter.NOARG_INSN:
|
rlm@10
|
1460 mv.visitInsn(opcode);
|
rlm@10
|
1461 v += 1;
|
rlm@10
|
1462 break;
|
rlm@10
|
1463 case ClassWriter.IMPLVAR_INSN:
|
rlm@10
|
1464 if(opcode > Opcodes.ISTORE)
|
rlm@10
|
1465 {
|
rlm@10
|
1466 opcode -= 59; // ISTORE_0
|
rlm@10
|
1467 mv.visitVarInsn(Opcodes.ISTORE + (opcode >> 2),
|
rlm@10
|
1468 opcode & 0x3);
|
rlm@10
|
1469 }
|
rlm@10
|
1470 else
|
rlm@10
|
1471 {
|
rlm@10
|
1472 opcode -= 26; // ILOAD_0
|
rlm@10
|
1473 mv.visitVarInsn(Opcodes.ILOAD + (opcode >> 2),
|
rlm@10
|
1474 opcode & 0x3);
|
rlm@10
|
1475 }
|
rlm@10
|
1476 v += 1;
|
rlm@10
|
1477 break;
|
rlm@10
|
1478 case ClassWriter.LABEL_INSN:
|
rlm@10
|
1479 mv.visitJumpInsn(opcode, labels[w
|
rlm@10
|
1480 + readShort(v + 1)]);
|
rlm@10
|
1481 v += 3;
|
rlm@10
|
1482 break;
|
rlm@10
|
1483 case ClassWriter.LABELW_INSN:
|
rlm@10
|
1484 mv.visitJumpInsn(opcode - 33, labels[w
|
rlm@10
|
1485 + readInt(v + 1)]);
|
rlm@10
|
1486 v += 5;
|
rlm@10
|
1487 break;
|
rlm@10
|
1488 case ClassWriter.WIDE_INSN:
|
rlm@10
|
1489 opcode = b[v + 1] & 0xFF;
|
rlm@10
|
1490 if(opcode == Opcodes.IINC)
|
rlm@10
|
1491 {
|
rlm@10
|
1492 mv.visitIincInsn(readUnsignedShort(v + 2),
|
rlm@10
|
1493 readShort(v + 4));
|
rlm@10
|
1494 v += 6;
|
rlm@10
|
1495 }
|
rlm@10
|
1496 else
|
rlm@10
|
1497 {
|
rlm@10
|
1498 mv.visitVarInsn(opcode,
|
rlm@10
|
1499 readUnsignedShort(v + 2));
|
rlm@10
|
1500 v += 4;
|
rlm@10
|
1501 }
|
rlm@10
|
1502 break;
|
rlm@10
|
1503 case ClassWriter.TABL_INSN:
|
rlm@10
|
1504 // skips 0 to 3 padding bytes
|
rlm@10
|
1505 v = v + 4 - (w & 3);
|
rlm@10
|
1506 // reads instruction
|
rlm@10
|
1507 label = w + readInt(v);
|
rlm@10
|
1508 int min = readInt(v + 4);
|
rlm@10
|
1509 int max = readInt(v + 8);
|
rlm@10
|
1510 v += 12;
|
rlm@10
|
1511 Label[] table = new Label[max - min + 1];
|
rlm@10
|
1512 for(j = 0; j < table.length; ++j)
|
rlm@10
|
1513 {
|
rlm@10
|
1514 table[j] = labels[w + readInt(v)];
|
rlm@10
|
1515 v += 4;
|
rlm@10
|
1516 }
|
rlm@10
|
1517 mv.visitTableSwitchInsn(min,
|
rlm@10
|
1518 max,
|
rlm@10
|
1519 labels[label],
|
rlm@10
|
1520 table);
|
rlm@10
|
1521 break;
|
rlm@10
|
1522 case ClassWriter.LOOK_INSN:
|
rlm@10
|
1523 // skips 0 to 3 padding bytes
|
rlm@10
|
1524 v = v + 4 - (w & 3);
|
rlm@10
|
1525 // reads instruction
|
rlm@10
|
1526 label = w + readInt(v);
|
rlm@10
|
1527 j = readInt(v + 4);
|
rlm@10
|
1528 v += 8;
|
rlm@10
|
1529 int[] keys = new int[j];
|
rlm@10
|
1530 Label[] values = new Label[j];
|
rlm@10
|
1531 for(j = 0; j < keys.length; ++j)
|
rlm@10
|
1532 {
|
rlm@10
|
1533 keys[j] = readInt(v);
|
rlm@10
|
1534 values[j] = labels[w + readInt(v + 4)];
|
rlm@10
|
1535 v += 8;
|
rlm@10
|
1536 }
|
rlm@10
|
1537 mv.visitLookupSwitchInsn(labels[label],
|
rlm@10
|
1538 keys,
|
rlm@10
|
1539 values);
|
rlm@10
|
1540 break;
|
rlm@10
|
1541 case ClassWriter.VAR_INSN:
|
rlm@10
|
1542 mv.visitVarInsn(opcode, b[v + 1] & 0xFF);
|
rlm@10
|
1543 v += 2;
|
rlm@10
|
1544 break;
|
rlm@10
|
1545 case ClassWriter.SBYTE_INSN:
|
rlm@10
|
1546 mv.visitIntInsn(opcode, b[v + 1]);
|
rlm@10
|
1547 v += 2;
|
rlm@10
|
1548 break;
|
rlm@10
|
1549 case ClassWriter.SHORT_INSN:
|
rlm@10
|
1550 mv.visitIntInsn(opcode, readShort(v + 1));
|
rlm@10
|
1551 v += 3;
|
rlm@10
|
1552 break;
|
rlm@10
|
1553 case ClassWriter.LDC_INSN:
|
rlm@10
|
1554 mv.visitLdcInsn(readConst(b[v + 1] & 0xFF, c));
|
rlm@10
|
1555 v += 2;
|
rlm@10
|
1556 break;
|
rlm@10
|
1557 case ClassWriter.LDCW_INSN:
|
rlm@10
|
1558 mv.visitLdcInsn(readConst(readUnsignedShort(v + 1),
|
rlm@10
|
1559 c));
|
rlm@10
|
1560 v += 3;
|
rlm@10
|
1561 break;
|
rlm@10
|
1562 case ClassWriter.FIELDORMETH_INSN:
|
rlm@10
|
1563 case ClassWriter.ITFMETH_INSN:
|
rlm@10
|
1564 int cpIndex = items[readUnsignedShort(v + 1)];
|
rlm@10
|
1565 String iowner = readClass(cpIndex, c);
|
rlm@10
|
1566 cpIndex = items[readUnsignedShort(cpIndex + 2)];
|
rlm@10
|
1567 String iname = readUTF8(cpIndex, c);
|
rlm@10
|
1568 String idesc = readUTF8(cpIndex + 2, c);
|
rlm@10
|
1569 if(opcode < Opcodes.INVOKEVIRTUAL)
|
rlm@10
|
1570 {
|
rlm@10
|
1571 mv.visitFieldInsn(opcode, iowner, iname, idesc);
|
rlm@10
|
1572 }
|
rlm@10
|
1573 else
|
rlm@10
|
1574 {
|
rlm@10
|
1575 mv.visitMethodInsn(opcode, iowner, iname, idesc);
|
rlm@10
|
1576 }
|
rlm@10
|
1577 if(opcode == Opcodes.INVOKEINTERFACE)
|
rlm@10
|
1578 {
|
rlm@10
|
1579 v += 5;
|
rlm@10
|
1580 }
|
rlm@10
|
1581 else
|
rlm@10
|
1582 {
|
rlm@10
|
1583 v += 3;
|
rlm@10
|
1584 }
|
rlm@10
|
1585 break;
|
rlm@10
|
1586 case ClassWriter.TYPE_INSN:
|
rlm@10
|
1587 mv.visitTypeInsn(opcode, readClass(v + 1, c));
|
rlm@10
|
1588 v += 3;
|
rlm@10
|
1589 break;
|
rlm@10
|
1590 case ClassWriter.IINC_INSN:
|
rlm@10
|
1591 mv.visitIincInsn(b[v + 1] & 0xFF, b[v + 2]);
|
rlm@10
|
1592 v += 3;
|
rlm@10
|
1593 break;
|
rlm@10
|
1594 // case MANA_INSN:
|
rlm@10
|
1595 default:
|
rlm@10
|
1596 mv.visitMultiANewArrayInsn(readClass(v + 1, c),
|
rlm@10
|
1597 b[v + 3] & 0xFF);
|
rlm@10
|
1598 v += 4;
|
rlm@10
|
1599 break;
|
rlm@10
|
1600 }
|
rlm@10
|
1601 }
|
rlm@10
|
1602 l = labels[codeEnd - codeStart];
|
rlm@10
|
1603 if(l != null)
|
rlm@10
|
1604 {
|
rlm@10
|
1605 mv.visitLabel(l);
|
rlm@10
|
1606 }
|
rlm@10
|
1607 // visits the local variable tables
|
rlm@10
|
1608 if(!skipDebug && varTable != 0)
|
rlm@10
|
1609 {
|
rlm@10
|
1610 int[] typeTable = null;
|
rlm@10
|
1611 if(varTypeTable != 0)
|
rlm@10
|
1612 {
|
rlm@10
|
1613 k = readUnsignedShort(varTypeTable) * 3;
|
rlm@10
|
1614 w = varTypeTable + 2;
|
rlm@10
|
1615 typeTable = new int[k];
|
rlm@10
|
1616 while(k > 0)
|
rlm@10
|
1617 {
|
rlm@10
|
1618 typeTable[--k] = w + 6; // signature
|
rlm@10
|
1619 typeTable[--k] = readUnsignedShort(w + 8); // index
|
rlm@10
|
1620 typeTable[--k] = readUnsignedShort(w); // start
|
rlm@10
|
1621 w += 10;
|
rlm@10
|
1622 }
|
rlm@10
|
1623 }
|
rlm@10
|
1624 k = readUnsignedShort(varTable);
|
rlm@10
|
1625 w = varTable + 2;
|
rlm@10
|
1626 for(; k > 0; --k)
|
rlm@10
|
1627 {
|
rlm@10
|
1628 int start = readUnsignedShort(w);
|
rlm@10
|
1629 int length = readUnsignedShort(w + 2);
|
rlm@10
|
1630 int index = readUnsignedShort(w + 8);
|
rlm@10
|
1631 String vsignature = null;
|
rlm@10
|
1632 if(typeTable != null)
|
rlm@10
|
1633 {
|
rlm@10
|
1634 for(int a = 0; a < typeTable.length; a += 3)
|
rlm@10
|
1635 {
|
rlm@10
|
1636 if(typeTable[a] == start
|
rlm@10
|
1637 && typeTable[a + 1] == index)
|
rlm@10
|
1638 {
|
rlm@10
|
1639 vsignature = readUTF8(typeTable[a + 2], c);
|
rlm@10
|
1640 break;
|
rlm@10
|
1641 }
|
rlm@10
|
1642 }
|
rlm@10
|
1643 }
|
rlm@10
|
1644 mv.visitLocalVariable(readUTF8(w + 4, c),
|
rlm@10
|
1645 readUTF8(w + 6, c),
|
rlm@10
|
1646 vsignature,
|
rlm@10
|
1647 labels[start],
|
rlm@10
|
1648 labels[start + length],
|
rlm@10
|
1649 index);
|
rlm@10
|
1650 w += 10;
|
rlm@10
|
1651 }
|
rlm@10
|
1652 }
|
rlm@10
|
1653 // visits the other attributes
|
rlm@10
|
1654 while(cattrs != null)
|
rlm@10
|
1655 {
|
rlm@10
|
1656 attr = cattrs.next;
|
rlm@10
|
1657 cattrs.next = null;
|
rlm@10
|
1658 mv.visitAttribute(cattrs);
|
rlm@10
|
1659 cattrs = attr;
|
rlm@10
|
1660 }
|
rlm@10
|
1661 // visits the max stack and max locals values
|
rlm@10
|
1662 mv.visitMaxs(maxStack, maxLocals);
|
rlm@10
|
1663 }
|
rlm@10
|
1664
|
rlm@10
|
1665 if(mv != null)
|
rlm@10
|
1666 {
|
rlm@10
|
1667 mv.visitEnd();
|
rlm@10
|
1668 }
|
rlm@10
|
1669 }
|
rlm@10
|
1670
|
rlm@10
|
1671 // visits the end of the class
|
rlm@10
|
1672 classVisitor.visitEnd();
|
rlm@10
|
1673 }
|
rlm@10
|
1674
|
rlm@10
|
1675 /**
|
rlm@10
|
1676 * Reads parameter annotations and makes the given visitor visit them.
|
rlm@10
|
1677 *
|
rlm@10
|
1678 * @param v start offset in {@link #b b} of the annotations to be read.
|
rlm@10
|
1679 * @param buf buffer to be used to call {@link #readUTF8 readUTF8},
|
rlm@10
|
1680 * {@link #readClass(int,char[]) readClass} or
|
rlm@10
|
1681 * {@link #readConst readConst}.
|
rlm@10
|
1682 * @param visible <tt>true</tt> if the annotations to be read are visible
|
rlm@10
|
1683 * at runtime.
|
rlm@10
|
1684 * @param mv the visitor that must visit the annotations.
|
rlm@10
|
1685 */
|
rlm@10
|
1686 private void readParameterAnnotations(
|
rlm@10
|
1687 int v,
|
rlm@10
|
1688 final char[] buf,
|
rlm@10
|
1689 final boolean visible,
|
rlm@10
|
1690 final MethodVisitor mv){
|
rlm@10
|
1691 int n = b[v++] & 0xFF;
|
rlm@10
|
1692 for(int i = 0; i < n; ++i)
|
rlm@10
|
1693 {
|
rlm@10
|
1694 int j = readUnsignedShort(v);
|
rlm@10
|
1695 v += 2;
|
rlm@10
|
1696 for(; j > 0; --j)
|
rlm@10
|
1697 {
|
rlm@10
|
1698 v = readAnnotationValues(v + 2,
|
rlm@10
|
1699 buf,
|
rlm@10
|
1700 true,
|
rlm@10
|
1701 mv.visitParameterAnnotation(i,
|
rlm@10
|
1702 readUTF8(v, buf),
|
rlm@10
|
1703 visible));
|
rlm@10
|
1704 }
|
rlm@10
|
1705 }
|
rlm@10
|
1706 }
|
rlm@10
|
1707
|
rlm@10
|
1708 /**
|
rlm@10
|
1709 * Reads the values of an annotation and makes the given visitor visit them.
|
rlm@10
|
1710 *
|
rlm@10
|
1711 * @param v the start offset in {@link #b b} of the values to be read
|
rlm@10
|
1712 * (including the unsigned short that gives the number of values).
|
rlm@10
|
1713 * @param buf buffer to be used to call {@link #readUTF8 readUTF8},
|
rlm@10
|
1714 * {@link #readClass(int,char[]) readClass} or
|
rlm@10
|
1715 * {@link #readConst readConst}.
|
rlm@10
|
1716 * @param named if the annotation values are named or not.
|
rlm@10
|
1717 * @param av the visitor that must visit the values.
|
rlm@10
|
1718 * @return the end offset of the annotation values.
|
rlm@10
|
1719 */
|
rlm@10
|
1720 private int readAnnotationValues(
|
rlm@10
|
1721 int v,
|
rlm@10
|
1722 final char[] buf,
|
rlm@10
|
1723 final boolean named,
|
rlm@10
|
1724 final AnnotationVisitor av){
|
rlm@10
|
1725 int i = readUnsignedShort(v);
|
rlm@10
|
1726 v += 2;
|
rlm@10
|
1727 if(named)
|
rlm@10
|
1728 {
|
rlm@10
|
1729 for(; i > 0; --i)
|
rlm@10
|
1730 {
|
rlm@10
|
1731 v = readAnnotationValue(v + 2, buf, readUTF8(v, buf), av);
|
rlm@10
|
1732 }
|
rlm@10
|
1733 }
|
rlm@10
|
1734 else
|
rlm@10
|
1735 {
|
rlm@10
|
1736 for(; i > 0; --i)
|
rlm@10
|
1737 {
|
rlm@10
|
1738 v = readAnnotationValue(v, buf, null, av);
|
rlm@10
|
1739 }
|
rlm@10
|
1740 }
|
rlm@10
|
1741 if(av != null)
|
rlm@10
|
1742 {
|
rlm@10
|
1743 av.visitEnd();
|
rlm@10
|
1744 }
|
rlm@10
|
1745 return v;
|
rlm@10
|
1746 }
|
rlm@10
|
1747
|
rlm@10
|
1748 /**
|
rlm@10
|
1749 * Reads a value of an annotation and makes the given visitor visit it.
|
rlm@10
|
1750 *
|
rlm@10
|
1751 * @param v the start offset in {@link #b b} of the value to be read (<i>not
|
rlm@10
|
1752 * including the value name constant pool index</i>).
|
rlm@10
|
1753 * @param buf buffer to be used to call {@link #readUTF8 readUTF8},
|
rlm@10
|
1754 * {@link #readClass(int,char[]) readClass} or
|
rlm@10
|
1755 * {@link #readConst readConst}.
|
rlm@10
|
1756 * @param name the name of the value to be read.
|
rlm@10
|
1757 * @param av the visitor that must visit the value.
|
rlm@10
|
1758 * @return the end offset of the annotation value.
|
rlm@10
|
1759 */
|
rlm@10
|
1760 private int readAnnotationValue(
|
rlm@10
|
1761 int v,
|
rlm@10
|
1762 final char[] buf,
|
rlm@10
|
1763 final String name,
|
rlm@10
|
1764 final AnnotationVisitor av){
|
rlm@10
|
1765 int i;
|
rlm@10
|
1766 if(av == null)
|
rlm@10
|
1767 {
|
rlm@10
|
1768 switch(b[v] & 0xFF)
|
rlm@10
|
1769 {
|
rlm@10
|
1770 case'e': // enum_const_value
|
rlm@10
|
1771 return v + 5;
|
rlm@10
|
1772 case'@': // annotation_value
|
rlm@10
|
1773 return readAnnotationValues(v + 3, buf, true, null);
|
rlm@10
|
1774 case'[': // array_value
|
rlm@10
|
1775 return readAnnotationValues(v + 1, buf, false, null);
|
rlm@10
|
1776 default:
|
rlm@10
|
1777 return v + 3;
|
rlm@10
|
1778 }
|
rlm@10
|
1779 }
|
rlm@10
|
1780 switch(b[v++] & 0xFF)
|
rlm@10
|
1781 {
|
rlm@10
|
1782 case'I': // pointer to CONSTANT_Integer
|
rlm@10
|
1783 case'J': // pointer to CONSTANT_Long
|
rlm@10
|
1784 case'F': // pointer to CONSTANT_Float
|
rlm@10
|
1785 case'D': // pointer to CONSTANT_Double
|
rlm@10
|
1786 av.visit(name, readConst(readUnsignedShort(v), buf));
|
rlm@10
|
1787 v += 2;
|
rlm@10
|
1788 break;
|
rlm@10
|
1789 case'B': // pointer to CONSTANT_Byte
|
rlm@10
|
1790 av.visit(name,
|
rlm@10
|
1791 new Byte((byte) readInt(items[readUnsignedShort(v)])));
|
rlm@10
|
1792 v += 2;
|
rlm@10
|
1793 break;
|
rlm@10
|
1794 case'Z': // pointer to CONSTANT_Boolean
|
rlm@10
|
1795 av.visit(name, readInt(items[readUnsignedShort(v)]) == 0
|
rlm@10
|
1796 ? Boolean.FALSE
|
rlm@10
|
1797 : Boolean.TRUE);
|
rlm@10
|
1798 v += 2;
|
rlm@10
|
1799 break;
|
rlm@10
|
1800 case'S': // pointer to CONSTANT_Short
|
rlm@10
|
1801 av.visit(name,
|
rlm@10
|
1802 new Short((short) readInt(items[readUnsignedShort(v)])));
|
rlm@10
|
1803 v += 2;
|
rlm@10
|
1804 break;
|
rlm@10
|
1805 case'C': // pointer to CONSTANT_Char
|
rlm@10
|
1806 av.visit(name,
|
rlm@10
|
1807 new Character((char) readInt(items[readUnsignedShort(v)])));
|
rlm@10
|
1808 v += 2;
|
rlm@10
|
1809 break;
|
rlm@10
|
1810 case's': // pointer to CONSTANT_Utf8
|
rlm@10
|
1811 av.visit(name, readUTF8(v, buf));
|
rlm@10
|
1812 v += 2;
|
rlm@10
|
1813 break;
|
rlm@10
|
1814 case'e': // enum_const_value
|
rlm@10
|
1815 av.visitEnum(name, readUTF8(v, buf), readUTF8(v + 2, buf));
|
rlm@10
|
1816 v += 4;
|
rlm@10
|
1817 break;
|
rlm@10
|
1818 case'c': // class_info
|
rlm@10
|
1819 av.visit(name, Type.getType(readUTF8(v, buf)));
|
rlm@10
|
1820 v += 2;
|
rlm@10
|
1821 break;
|
rlm@10
|
1822 case'@': // annotation_value
|
rlm@10
|
1823 v = readAnnotationValues(v + 2,
|
rlm@10
|
1824 buf,
|
rlm@10
|
1825 true,
|
rlm@10
|
1826 av.visitAnnotation(name, readUTF8(v, buf)));
|
rlm@10
|
1827 break;
|
rlm@10
|
1828 case'[': // array_value
|
rlm@10
|
1829 int size = readUnsignedShort(v);
|
rlm@10
|
1830 v += 2;
|
rlm@10
|
1831 if(size == 0)
|
rlm@10
|
1832 {
|
rlm@10
|
1833 return readAnnotationValues(v - 2,
|
rlm@10
|
1834 buf,
|
rlm@10
|
1835 false,
|
rlm@10
|
1836 av.visitArray(name));
|
rlm@10
|
1837 }
|
rlm@10
|
1838 switch(this.b[v++] & 0xFF)
|
rlm@10
|
1839 {
|
rlm@10
|
1840 case'B':
|
rlm@10
|
1841 byte[] bv = new byte[size];
|
rlm@10
|
1842 for(i = 0; i < size; i++)
|
rlm@10
|
1843 {
|
rlm@10
|
1844 bv[i] = (byte) readInt(items[readUnsignedShort(v)]);
|
rlm@10
|
1845 v += 3;
|
rlm@10
|
1846 }
|
rlm@10
|
1847 av.visit(name, bv);
|
rlm@10
|
1848 --v;
|
rlm@10
|
1849 break;
|
rlm@10
|
1850 case'Z':
|
rlm@10
|
1851 boolean[] zv = new boolean[size];
|
rlm@10
|
1852 for(i = 0; i < size; i++)
|
rlm@10
|
1853 {
|
rlm@10
|
1854 zv[i] = readInt(items[readUnsignedShort(v)]) != 0;
|
rlm@10
|
1855 v += 3;
|
rlm@10
|
1856 }
|
rlm@10
|
1857 av.visit(name, zv);
|
rlm@10
|
1858 --v;
|
rlm@10
|
1859 break;
|
rlm@10
|
1860 case'S':
|
rlm@10
|
1861 short[] sv = new short[size];
|
rlm@10
|
1862 for(i = 0; i < size; i++)
|
rlm@10
|
1863 {
|
rlm@10
|
1864 sv[i] = (short) readInt(items[readUnsignedShort(v)]);
|
rlm@10
|
1865 v += 3;
|
rlm@10
|
1866 }
|
rlm@10
|
1867 av.visit(name, sv);
|
rlm@10
|
1868 --v;
|
rlm@10
|
1869 break;
|
rlm@10
|
1870 case'C':
|
rlm@10
|
1871 char[] cv = new char[size];
|
rlm@10
|
1872 for(i = 0; i < size; i++)
|
rlm@10
|
1873 {
|
rlm@10
|
1874 cv[i] = (char) readInt(items[readUnsignedShort(v)]);
|
rlm@10
|
1875 v += 3;
|
rlm@10
|
1876 }
|
rlm@10
|
1877 av.visit(name, cv);
|
rlm@10
|
1878 --v;
|
rlm@10
|
1879 break;
|
rlm@10
|
1880 case'I':
|
rlm@10
|
1881 int[] iv = new int[size];
|
rlm@10
|
1882 for(i = 0; i < size; i++)
|
rlm@10
|
1883 {
|
rlm@10
|
1884 iv[i] = readInt(items[readUnsignedShort(v)]);
|
rlm@10
|
1885 v += 3;
|
rlm@10
|
1886 }
|
rlm@10
|
1887 av.visit(name, iv);
|
rlm@10
|
1888 --v;
|
rlm@10
|
1889 break;
|
rlm@10
|
1890 case'J':
|
rlm@10
|
1891 long[] lv = new long[size];
|
rlm@10
|
1892 for(i = 0; i < size; i++)
|
rlm@10
|
1893 {
|
rlm@10
|
1894 lv[i] = readLong(items[readUnsignedShort(v)]);
|
rlm@10
|
1895 v += 3;
|
rlm@10
|
1896 }
|
rlm@10
|
1897 av.visit(name, lv);
|
rlm@10
|
1898 --v;
|
rlm@10
|
1899 break;
|
rlm@10
|
1900 case'F':
|
rlm@10
|
1901 float[] fv = new float[size];
|
rlm@10
|
1902 for(i = 0; i < size; i++)
|
rlm@10
|
1903 {
|
rlm@10
|
1904 fv[i] = Float.intBitsToFloat(readInt(items[readUnsignedShort(v)]));
|
rlm@10
|
1905 v += 3;
|
rlm@10
|
1906 }
|
rlm@10
|
1907 av.visit(name, fv);
|
rlm@10
|
1908 --v;
|
rlm@10
|
1909 break;
|
rlm@10
|
1910 case'D':
|
rlm@10
|
1911 double[] dv = new double[size];
|
rlm@10
|
1912 for(i = 0; i < size; i++)
|
rlm@10
|
1913 {
|
rlm@10
|
1914 dv[i] = Double.longBitsToDouble(readLong(items[readUnsignedShort(v)]));
|
rlm@10
|
1915 v += 3;
|
rlm@10
|
1916 }
|
rlm@10
|
1917 av.visit(name, dv);
|
rlm@10
|
1918 --v;
|
rlm@10
|
1919 break;
|
rlm@10
|
1920 default:
|
rlm@10
|
1921 v = readAnnotationValues(v - 3,
|
rlm@10
|
1922 buf,
|
rlm@10
|
1923 false,
|
rlm@10
|
1924 av.visitArray(name));
|
rlm@10
|
1925 }
|
rlm@10
|
1926 }
|
rlm@10
|
1927 return v;
|
rlm@10
|
1928 }
|
rlm@10
|
1929
|
rlm@10
|
1930 private int readFrameType(
|
rlm@10
|
1931 final Object[] frame,
|
rlm@10
|
1932 final int index,
|
rlm@10
|
1933 int v,
|
rlm@10
|
1934 final char[] buf,
|
rlm@10
|
1935 final Label[] labels){
|
rlm@10
|
1936 int type = b[v++] & 0xFF;
|
rlm@10
|
1937 switch(type)
|
rlm@10
|
1938 {
|
rlm@10
|
1939 case 0:
|
rlm@10
|
1940 frame[index] = Opcodes.TOP;
|
rlm@10
|
1941 break;
|
rlm@10
|
1942 case 1:
|
rlm@10
|
1943 frame[index] = Opcodes.INTEGER;
|
rlm@10
|
1944 break;
|
rlm@10
|
1945 case 2:
|
rlm@10
|
1946 frame[index] = Opcodes.FLOAT;
|
rlm@10
|
1947 break;
|
rlm@10
|
1948 case 3:
|
rlm@10
|
1949 frame[index] = Opcodes.DOUBLE;
|
rlm@10
|
1950 break;
|
rlm@10
|
1951 case 4:
|
rlm@10
|
1952 frame[index] = Opcodes.LONG;
|
rlm@10
|
1953 break;
|
rlm@10
|
1954 case 5:
|
rlm@10
|
1955 frame[index] = Opcodes.NULL;
|
rlm@10
|
1956 break;
|
rlm@10
|
1957 case 6:
|
rlm@10
|
1958 frame[index] = Opcodes.UNINITIALIZED_THIS;
|
rlm@10
|
1959 break;
|
rlm@10
|
1960 case 7: // Object
|
rlm@10
|
1961 frame[index] = readClass(v, buf);
|
rlm@10
|
1962 v += 2;
|
rlm@10
|
1963 break;
|
rlm@10
|
1964 default: // Uninitialized
|
rlm@10
|
1965 int offset = readUnsignedShort(v);
|
rlm@10
|
1966 if(labels[offset] == null)
|
rlm@10
|
1967 {
|
rlm@10
|
1968 labels[offset] = new Label();
|
rlm@10
|
1969 }
|
rlm@10
|
1970 frame[index] = labels[offset];
|
rlm@10
|
1971 v += 2;
|
rlm@10
|
1972 }
|
rlm@10
|
1973 return v;
|
rlm@10
|
1974 }
|
rlm@10
|
1975
|
rlm@10
|
1976 /**
|
rlm@10
|
1977 * Reads an attribute in {@link #b b}.
|
rlm@10
|
1978 *
|
rlm@10
|
1979 * @param attrs prototypes of the attributes that must be parsed during the
|
rlm@10
|
1980 * visit of the class. Any attribute whose type is not equal to the
|
rlm@10
|
1981 * type of one the prototypes is ignored (i.e. an empty
|
rlm@10
|
1982 * {@link Attribute} instance is returned).
|
rlm@10
|
1983 * @param type the type of the attribute.
|
rlm@10
|
1984 * @param off index of the first byte of the attribute's content in
|
rlm@10
|
1985 * {@link #b b}. The 6 attribute header bytes, containing the type
|
rlm@10
|
1986 * and the length of the attribute, are not taken into account here
|
rlm@10
|
1987 * (they have already been read).
|
rlm@10
|
1988 * @param len the length of the attribute's content.
|
rlm@10
|
1989 * @param buf buffer to be used to call {@link #readUTF8 readUTF8},
|
rlm@10
|
1990 * {@link #readClass(int,char[]) readClass} or
|
rlm@10
|
1991 * {@link #readConst readConst}.
|
rlm@10
|
1992 * @param codeOff index of the first byte of code's attribute content in
|
rlm@10
|
1993 * {@link #b b}, or -1 if the attribute to be read is not a code
|
rlm@10
|
1994 * attribute. The 6 attribute header bytes, containing the type and
|
rlm@10
|
1995 * the length of the attribute, are not taken into account here.
|
rlm@10
|
1996 * @param labels the labels of the method's code, or <tt>null</tt> if the
|
rlm@10
|
1997 * attribute to be read is not a code attribute.
|
rlm@10
|
1998 * @return the attribute that has been read, or <tt>null</tt> to skip this
|
rlm@10
|
1999 * attribute.
|
rlm@10
|
2000 */
|
rlm@10
|
2001 private Attribute readAttribute(
|
rlm@10
|
2002 final Attribute[] attrs,
|
rlm@10
|
2003 final String type,
|
rlm@10
|
2004 final int off,
|
rlm@10
|
2005 final int len,
|
rlm@10
|
2006 final char[] buf,
|
rlm@10
|
2007 final int codeOff,
|
rlm@10
|
2008 final Label[] labels){
|
rlm@10
|
2009 for(int i = 0; i < attrs.length; ++i)
|
rlm@10
|
2010 {
|
rlm@10
|
2011 if(attrs[i].type.equals(type))
|
rlm@10
|
2012 {
|
rlm@10
|
2013 return attrs[i].read(this, off, len, buf, codeOff, labels);
|
rlm@10
|
2014 }
|
rlm@10
|
2015 }
|
rlm@10
|
2016 return new Attribute(type).read(this, off, len, null, -1, null);
|
rlm@10
|
2017 }
|
rlm@10
|
2018
|
rlm@10
|
2019 // ------------------------------------------------------------------------
|
rlm@10
|
2020 // Utility methods: low level parsing
|
rlm@10
|
2021 // ------------------------------------------------------------------------
|
rlm@10
|
2022
|
rlm@10
|
2023 /**
|
rlm@10
|
2024 * Returns the start index of the constant pool item in {@link #b b}, plus
|
rlm@10
|
2025 * one. <i>This method is intended for {@link Attribute} sub classes, and is
|
rlm@10
|
2026 * normally not needed by class generators or adapters.</i>
|
rlm@10
|
2027 *
|
rlm@10
|
2028 * @param item the index a constant pool item.
|
rlm@10
|
2029 * @return the start index of the constant pool item in {@link #b b}, plus
|
rlm@10
|
2030 * one.
|
rlm@10
|
2031 */
|
rlm@10
|
2032 public int getItem(final int item){
|
rlm@10
|
2033 return items[item];
|
rlm@10
|
2034 }
|
rlm@10
|
2035
|
rlm@10
|
2036 /**
|
rlm@10
|
2037 * Reads a byte value in {@link #b b}. <i>This method is intended for
|
rlm@10
|
2038 * {@link Attribute} sub classes, and is normally not needed by class
|
rlm@10
|
2039 * generators or adapters.</i>
|
rlm@10
|
2040 *
|
rlm@10
|
2041 * @param index the start index of the value to be read in {@link #b b}.
|
rlm@10
|
2042 * @return the read value.
|
rlm@10
|
2043 */
|
rlm@10
|
2044 public int readByte(final int index){
|
rlm@10
|
2045 return b[index] & 0xFF;
|
rlm@10
|
2046 }
|
rlm@10
|
2047
|
rlm@10
|
2048 /**
|
rlm@10
|
2049 * Reads an unsigned short value in {@link #b b}. <i>This method is
|
rlm@10
|
2050 * intended for {@link Attribute} sub classes, and is normally not needed by
|
rlm@10
|
2051 * class generators or adapters.</i>
|
rlm@10
|
2052 *
|
rlm@10
|
2053 * @param index the start index of the value to be read in {@link #b b}.
|
rlm@10
|
2054 * @return the read value.
|
rlm@10
|
2055 */
|
rlm@10
|
2056 public int readUnsignedShort(final int index){
|
rlm@10
|
2057 byte[] b = this.b;
|
rlm@10
|
2058 return ((b[index] & 0xFF) << 8) | (b[index + 1] & 0xFF);
|
rlm@10
|
2059 }
|
rlm@10
|
2060
|
rlm@10
|
2061 /**
|
rlm@10
|
2062 * Reads a signed short value in {@link #b b}. <i>This method is intended
|
rlm@10
|
2063 * for {@link Attribute} sub classes, and is normally not needed by class
|
rlm@10
|
2064 * generators or adapters.</i>
|
rlm@10
|
2065 *
|
rlm@10
|
2066 * @param index the start index of the value to be read in {@link #b b}.
|
rlm@10
|
2067 * @return the read value.
|
rlm@10
|
2068 */
|
rlm@10
|
2069 public short readShort(final int index){
|
rlm@10
|
2070 byte[] b = this.b;
|
rlm@10
|
2071 return (short) (((b[index] & 0xFF) << 8) | (b[index + 1] & 0xFF));
|
rlm@10
|
2072 }
|
rlm@10
|
2073
|
rlm@10
|
2074 /**
|
rlm@10
|
2075 * Reads a signed int value in {@link #b b}. <i>This method is intended for
|
rlm@10
|
2076 * {@link Attribute} sub classes, and is normally not needed by class
|
rlm@10
|
2077 * generators or adapters.</i>
|
rlm@10
|
2078 *
|
rlm@10
|
2079 * @param index the start index of the value to be read in {@link #b b}.
|
rlm@10
|
2080 * @return the read value.
|
rlm@10
|
2081 */
|
rlm@10
|
2082 public int readInt(final int index){
|
rlm@10
|
2083 byte[] b = this.b;
|
rlm@10
|
2084 return ((b[index] & 0xFF) << 24) | ((b[index + 1] & 0xFF) << 16)
|
rlm@10
|
2085 | ((b[index + 2] & 0xFF) << 8) | (b[index + 3] & 0xFF);
|
rlm@10
|
2086 }
|
rlm@10
|
2087
|
rlm@10
|
2088 /**
|
rlm@10
|
2089 * Reads a signed long value in {@link #b b}. <i>This method is intended
|
rlm@10
|
2090 * for {@link Attribute} sub classes, and is normally not needed by class
|
rlm@10
|
2091 * generators or adapters.</i>
|
rlm@10
|
2092 *
|
rlm@10
|
2093 * @param index the start index of the value to be read in {@link #b b}.
|
rlm@10
|
2094 * @return the read value.
|
rlm@10
|
2095 */
|
rlm@10
|
2096 public long readLong(final int index){
|
rlm@10
|
2097 long l1 = readInt(index);
|
rlm@10
|
2098 long l0 = readInt(index + 4) & 0xFFFFFFFFL;
|
rlm@10
|
2099 return (l1 << 32) | l0;
|
rlm@10
|
2100 }
|
rlm@10
|
2101
|
rlm@10
|
2102 /**
|
rlm@10
|
2103 * Reads an UTF8 string constant pool item in {@link #b b}. <i>This method
|
rlm@10
|
2104 * is intended for {@link Attribute} sub classes, and is normally not needed
|
rlm@10
|
2105 * by class generators or adapters.</i>
|
rlm@10
|
2106 *
|
rlm@10
|
2107 * @param index the start index of an unsigned short value in {@link #b b},
|
rlm@10
|
2108 * whose value is the index of an UTF8 constant pool item.
|
rlm@10
|
2109 * @param buf buffer to be used to read the item. This buffer must be
|
rlm@10
|
2110 * sufficiently large. It is not automatically resized.
|
rlm@10
|
2111 * @return the String corresponding to the specified UTF8 item.
|
rlm@10
|
2112 */
|
rlm@10
|
2113 public String readUTF8(int index, final char[] buf){
|
rlm@10
|
2114 int item = readUnsignedShort(index);
|
rlm@10
|
2115 String s = strings[item];
|
rlm@10
|
2116 if(s != null)
|
rlm@10
|
2117 {
|
rlm@10
|
2118 return s;
|
rlm@10
|
2119 }
|
rlm@10
|
2120 index = items[item];
|
rlm@10
|
2121 return strings[item] = readUTF(index + 2, readUnsignedShort(index), buf);
|
rlm@10
|
2122 }
|
rlm@10
|
2123
|
rlm@10
|
2124 /**
|
rlm@10
|
2125 * Reads UTF8 string in {@link #b b}.
|
rlm@10
|
2126 *
|
rlm@10
|
2127 * @param index start offset of the UTF8 string to be read.
|
rlm@10
|
2128 * @param utfLen length of the UTF8 string to be read.
|
rlm@10
|
2129 * @param buf buffer to be used to read the string. This buffer must be
|
rlm@10
|
2130 * sufficiently large. It is not automatically resized.
|
rlm@10
|
2131 * @return the String corresponding to the specified UTF8 string.
|
rlm@10
|
2132 */
|
rlm@10
|
2133 private String readUTF(int index, final int utfLen, final char[] buf){
|
rlm@10
|
2134 int endIndex = index + utfLen;
|
rlm@10
|
2135 byte[] b = this.b;
|
rlm@10
|
2136 int strLen = 0;
|
rlm@10
|
2137 int c, d, e;
|
rlm@10
|
2138 while(index < endIndex)
|
rlm@10
|
2139 {
|
rlm@10
|
2140 c = b[index++] & 0xFF;
|
rlm@10
|
2141 switch(c >> 4)
|
rlm@10
|
2142 {
|
rlm@10
|
2143 case 0:
|
rlm@10
|
2144 case 1:
|
rlm@10
|
2145 case 2:
|
rlm@10
|
2146 case 3:
|
rlm@10
|
2147 case 4:
|
rlm@10
|
2148 case 5:
|
rlm@10
|
2149 case 6:
|
rlm@10
|
2150 case 7:
|
rlm@10
|
2151 // 0xxxxxxx
|
rlm@10
|
2152 buf[strLen++] = (char) c;
|
rlm@10
|
2153 break;
|
rlm@10
|
2154 case 12:
|
rlm@10
|
2155 case 13:
|
rlm@10
|
2156 // 110x xxxx 10xx xxxx
|
rlm@10
|
2157 d = b[index++];
|
rlm@10
|
2158 buf[strLen++] = (char) (((c & 0x1F) << 6) | (d & 0x3F));
|
rlm@10
|
2159 break;
|
rlm@10
|
2160 default:
|
rlm@10
|
2161 // 1110 xxxx 10xx xxxx 10xx xxxx
|
rlm@10
|
2162 d = b[index++];
|
rlm@10
|
2163 e = b[index++];
|
rlm@10
|
2164 buf[strLen++] = (char) (((c & 0x0F) << 12)
|
rlm@10
|
2165 | ((d & 0x3F) << 6) | (e & 0x3F));
|
rlm@10
|
2166 break;
|
rlm@10
|
2167 }
|
rlm@10
|
2168 }
|
rlm@10
|
2169 return new String(buf, 0, strLen);
|
rlm@10
|
2170 }
|
rlm@10
|
2171
|
rlm@10
|
2172 /**
|
rlm@10
|
2173 * Reads a class constant pool item in {@link #b b}. <i>This method is
|
rlm@10
|
2174 * intended for {@link Attribute} sub classes, and is normally not needed by
|
rlm@10
|
2175 * class generators or adapters.</i>
|
rlm@10
|
2176 *
|
rlm@10
|
2177 * @param index the start index of an unsigned short value in {@link #b b},
|
rlm@10
|
2178 * whose value is the index of a class constant pool item.
|
rlm@10
|
2179 * @param buf buffer to be used to read the item. This buffer must be
|
rlm@10
|
2180 * sufficiently large. It is not automatically resized.
|
rlm@10
|
2181 * @return the String corresponding to the specified class item.
|
rlm@10
|
2182 */
|
rlm@10
|
2183 public String readClass(final int index, final char[] buf){
|
rlm@10
|
2184 // computes the start index of the CONSTANT_Class item in b
|
rlm@10
|
2185 // and reads the CONSTANT_Utf8 item designated by
|
rlm@10
|
2186 // the first two bytes of this CONSTANT_Class item
|
rlm@10
|
2187 return readUTF8(items[readUnsignedShort(index)], buf);
|
rlm@10
|
2188 }
|
rlm@10
|
2189
|
rlm@10
|
2190 /**
|
rlm@10
|
2191 * Reads a numeric or string constant pool item in {@link #b b}. <i>This
|
rlm@10
|
2192 * method is intended for {@link Attribute} sub classes, and is normally not
|
rlm@10
|
2193 * needed by class generators or adapters.</i>
|
rlm@10
|
2194 *
|
rlm@10
|
2195 * @param item the index of a constant pool item.
|
rlm@10
|
2196 * @param buf buffer to be used to read the item. This buffer must be
|
rlm@10
|
2197 * sufficiently large. It is not automatically resized.
|
rlm@10
|
2198 * @return the {@link Integer}, {@link Float}, {@link Long},
|
rlm@10
|
2199 * {@link Double}, {@link String} or {@link Type} corresponding to
|
rlm@10
|
2200 * the given constant pool item.
|
rlm@10
|
2201 */
|
rlm@10
|
2202 public Object readConst(final int item, final char[] buf){
|
rlm@10
|
2203 int index = items[item];
|
rlm@10
|
2204 switch(b[index - 1])
|
rlm@10
|
2205 {
|
rlm@10
|
2206 case ClassWriter.INT:
|
rlm@10
|
2207 return new Integer(readInt(index));
|
rlm@10
|
2208 case ClassWriter.FLOAT:
|
rlm@10
|
2209 return new Float(Float.intBitsToFloat(readInt(index)));
|
rlm@10
|
2210 case ClassWriter.LONG:
|
rlm@10
|
2211 return new Long(readLong(index));
|
rlm@10
|
2212 case ClassWriter.DOUBLE:
|
rlm@10
|
2213 return new Double(Double.longBitsToDouble(readLong(index)));
|
rlm@10
|
2214 case ClassWriter.CLASS:
|
rlm@10
|
2215 String s = readUTF8(index, buf);
|
rlm@10
|
2216 return s.charAt(0) == '['
|
rlm@10
|
2217 ? Type.getType(s)
|
rlm@10
|
2218 : Type.getObjectType(s);
|
rlm@10
|
2219 // case ClassWriter.STR:
|
rlm@10
|
2220 default:
|
rlm@10
|
2221 return readUTF8(index, buf);
|
rlm@10
|
2222 }
|
rlm@10
|
2223 }
|
rlm@10
|
2224 }
|