annotate src/clojure/asm/ClassReader.java @ 10:ef7dbbd6452c

added clojure source goodness
author Robert McIntyre <rlm@mit.edu>
date Sat, 21 Aug 2010 06:25:44 -0400
parents
children
rev   line source
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 }