Mercurial > lasercutter
diff 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 |
line wrap: on
line diff
1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/src/clojure/asm/ClassReader.java Sat Aug 21 06:25:44 2010 -0400 1.3 @@ -0,0 +1,2224 @@ 1.4 +/*** 1.5 + * ASM: a very small and fast Java bytecode manipulation framework 1.6 + * Copyright (c) 2000-2005 INRIA, France Telecom 1.7 + * All rights reserved. 1.8 + * 1.9 + * Redistribution and use in source and binary forms, with or without 1.10 + * modification, are permitted provided that the following conditions 1.11 + * are met: 1.12 + * 1. Redistributions of source code must retain the above copyright 1.13 + * notice, this list of conditions and the following disclaimer. 1.14 + * 2. Redistributions in binary form must reproduce the above copyright 1.15 + * notice, this list of conditions and the following disclaimer in the 1.16 + * documentation and/or other materials provided with the distribution. 1.17 + * 3. Neither the name of the copyright holders nor the names of its 1.18 + * contributors may be used to endorse or promote products derived from 1.19 + * this software without specific prior written permission. 1.20 + * 1.21 + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 1.22 + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 1.23 + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 1.24 + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 1.25 + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 1.26 + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 1.27 + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 1.28 + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 1.29 + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 1.30 + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 1.31 + * THE POSSIBILITY OF SUCH DAMAGE. 1.32 + */ 1.33 +package clojure.asm; 1.34 + 1.35 +import java.io.InputStream; 1.36 +import java.io.IOException; 1.37 + 1.38 +/** 1.39 + * A Java class parser to make a {@link ClassVisitor} visit an existing class. 1.40 + * This class parses a byte array conforming to the Java class file format and 1.41 + * calls the appropriate visit methods of a given class visitor for each field, 1.42 + * method and bytecode instruction encountered. 1.43 + * 1.44 + * @author Eric Bruneton 1.45 + * @author Eugene Kuleshov 1.46 + */ 1.47 +public class ClassReader{ 1.48 + 1.49 +/** 1.50 + * Flag to skip method code. If this class is set <code>CODE</code> 1.51 + * attribute won't be visited. This can be used, for example, to retrieve 1.52 + * annotations for methods and method parameters. 1.53 + */ 1.54 +public final static int SKIP_CODE = 1; 1.55 + 1.56 +/** 1.57 + * Flag to skip the debug information in the class. If this flag is set the 1.58 + * debug information of the class is not visited, i.e. the 1.59 + * {@link MethodVisitor#visitLocalVariable visitLocalVariable} and 1.60 + * {@link MethodVisitor#visitLineNumber visitLineNumber} methods will not be 1.61 + * called. 1.62 + */ 1.63 +public final static int SKIP_DEBUG = 2; 1.64 + 1.65 +/** 1.66 + * Flag to skip the stack map frames in the class. If this flag is set the 1.67 + * stack map frames of the class is not visited, i.e. the 1.68 + * {@link MethodVisitor#visitFrame visitFrame} method will not be called. 1.69 + * This flag is useful when the {@link ClassWriter#COMPUTE_FRAMES} option is 1.70 + * used: it avoids visiting frames that will be ignored and recomputed from 1.71 + * scratch in the class writer. 1.72 + */ 1.73 +public final static int SKIP_FRAMES = 4; 1.74 + 1.75 +/** 1.76 + * Flag to expand the stack map frames. By default stack map frames are 1.77 + * visited in their original format (i.e. "expanded" for classes whose 1.78 + * version is less than V1_6, and "compressed" for the other classes). If 1.79 + * this flag is set, stack map frames are always visited in expanded format 1.80 + * (this option adds a decompression/recompression step in ClassReader and 1.81 + * ClassWriter which degrades performances quite a lot). 1.82 + */ 1.83 +public final static int EXPAND_FRAMES = 8; 1.84 + 1.85 +/** 1.86 + * The class to be parsed. <i>The content of this array must not be 1.87 + * modified. This field is intended for {@link Attribute} sub classes, and 1.88 + * is normally not needed by class generators or adapters.</i> 1.89 + */ 1.90 +public final byte[] b; 1.91 + 1.92 +/** 1.93 + * The start index of each constant pool item in {@link #b b}, plus one. 1.94 + * The one byte offset skips the constant pool item tag that indicates its 1.95 + * type. 1.96 + */ 1.97 +private final int[] items; 1.98 + 1.99 +/** 1.100 + * The String objects corresponding to the CONSTANT_Utf8 items. This cache 1.101 + * avoids multiple parsing of a given CONSTANT_Utf8 constant pool item, 1.102 + * which GREATLY improves performances (by a factor 2 to 3). This caching 1.103 + * strategy could be extended to all constant pool items, but its benefit 1.104 + * would not be so great for these items (because they are much less 1.105 + * expensive to parse than CONSTANT_Utf8 items). 1.106 + */ 1.107 +private final String[] strings; 1.108 + 1.109 +/** 1.110 + * Maximum length of the strings contained in the constant pool of the 1.111 + * class. 1.112 + */ 1.113 +private final int maxStringLength; 1.114 + 1.115 +/** 1.116 + * Start index of the class header information (access, name...) in 1.117 + * {@link #b b}. 1.118 + */ 1.119 +public final int header; 1.120 + 1.121 +// ------------------------------------------------------------------------ 1.122 +// Constructors 1.123 +// ------------------------------------------------------------------------ 1.124 + 1.125 +/** 1.126 + * Constructs a new {@link ClassReader} object. 1.127 + * 1.128 + * @param b the bytecode of the class to be read. 1.129 + */ 1.130 +public ClassReader(final byte[] b){ 1.131 + this(b, 0, b.length); 1.132 +} 1.133 + 1.134 +/** 1.135 + * Constructs a new {@link ClassReader} object. 1.136 + * 1.137 + * @param b the bytecode of the class to be read. 1.138 + * @param off the start offset of the class data. 1.139 + * @param len the length of the class data. 1.140 + */ 1.141 +public ClassReader(final byte[] b, final int off, final int len){ 1.142 + this.b = b; 1.143 + // parses the constant pool 1.144 + items = new int[readUnsignedShort(off + 8)]; 1.145 + int n = items.length; 1.146 + strings = new String[n]; 1.147 + int max = 0; 1.148 + int index = off + 10; 1.149 + for(int i = 1; i < n; ++i) 1.150 + { 1.151 + items[i] = index + 1; 1.152 + int size; 1.153 + switch(b[index]) 1.154 + { 1.155 + case ClassWriter.FIELD: 1.156 + case ClassWriter.METH: 1.157 + case ClassWriter.IMETH: 1.158 + case ClassWriter.INT: 1.159 + case ClassWriter.FLOAT: 1.160 + case ClassWriter.NAME_TYPE: 1.161 + size = 5; 1.162 + break; 1.163 + case ClassWriter.LONG: 1.164 + case ClassWriter.DOUBLE: 1.165 + size = 9; 1.166 + ++i; 1.167 + break; 1.168 + case ClassWriter.UTF8: 1.169 + size = 3 + readUnsignedShort(index + 1); 1.170 + if(size > max) 1.171 + { 1.172 + max = size; 1.173 + } 1.174 + break; 1.175 + // case ClassWriter.CLASS: 1.176 + // case ClassWriter.STR: 1.177 + default: 1.178 + size = 3; 1.179 + break; 1.180 + } 1.181 + index += size; 1.182 + } 1.183 + maxStringLength = max; 1.184 + // the class header information starts just after the constant pool 1.185 + header = index; 1.186 +} 1.187 + 1.188 +/** 1.189 + * Returns the class's access flags (see {@link Opcodes}). This value may 1.190 + * not reflect Deprecated and Synthetic flags when bytecode is before 1.5 1.191 + * and those flags are represented by attributes. 1.192 + * 1.193 + * @return the class access flags 1.194 + * @see ClassVisitor#visit(int,int,String,String,String,String[]) 1.195 + */ 1.196 +public int getAccess(){ 1.197 + return readUnsignedShort(header); 1.198 +} 1.199 + 1.200 +/** 1.201 + * Returns the internal name of the class (see 1.202 + * {@link Type#getInternalName() getInternalName}). 1.203 + * 1.204 + * @return the internal class name 1.205 + * @see ClassVisitor#visit(int,int,String,String,String,String[]) 1.206 + */ 1.207 +public String getClassName(){ 1.208 + return readClass(header + 2, new char[maxStringLength]); 1.209 +} 1.210 + 1.211 +/** 1.212 + * Returns the internal of name of the super class (see 1.213 + * {@link Type#getInternalName() getInternalName}). For interfaces, the 1.214 + * super class is {@link Object}. 1.215 + * 1.216 + * @return the internal name of super class, or <tt>null</tt> for 1.217 + * {@link Object} class. 1.218 + * @see ClassVisitor#visit(int,int,String,String,String,String[]) 1.219 + */ 1.220 +public String getSuperName(){ 1.221 + int n = items[readUnsignedShort(header + 4)]; 1.222 + return n == 0 ? null : readUTF8(n, new char[maxStringLength]); 1.223 +} 1.224 + 1.225 +/** 1.226 + * Returns the internal names of the class's interfaces (see 1.227 + * {@link Type#getInternalName() getInternalName}). 1.228 + * 1.229 + * @return the array of internal names for all implemented interfaces or 1.230 + * <tt>null</tt>. 1.231 + * @see ClassVisitor#visit(int,int,String,String,String,String[]) 1.232 + */ 1.233 +public String[] getInterfaces(){ 1.234 + int index = header + 6; 1.235 + int n = readUnsignedShort(index); 1.236 + String[] interfaces = new String[n]; 1.237 + if(n > 0) 1.238 + { 1.239 + char[] buf = new char[maxStringLength]; 1.240 + for(int i = 0; i < n; ++i) 1.241 + { 1.242 + index += 2; 1.243 + interfaces[i] = readClass(index, buf); 1.244 + } 1.245 + } 1.246 + return interfaces; 1.247 +} 1.248 + 1.249 +/** 1.250 + * Copies the constant pool data into the given {@link ClassWriter}. Should 1.251 + * be called before the {@link #accept(ClassVisitor,int)} method. 1.252 + * 1.253 + * @param classWriter the {@link ClassWriter} to copy constant pool into. 1.254 + */ 1.255 +void copyPool(final ClassWriter classWriter){ 1.256 + char[] buf = new char[maxStringLength]; 1.257 + int ll = items.length; 1.258 + Item[] items2 = new Item[ll]; 1.259 + for(int i = 1; i < ll; i++) 1.260 + { 1.261 + int index = items[i]; 1.262 + int tag = b[index - 1]; 1.263 + Item item = new Item(i); 1.264 + int nameType; 1.265 + switch(tag) 1.266 + { 1.267 + case ClassWriter.FIELD: 1.268 + case ClassWriter.METH: 1.269 + case ClassWriter.IMETH: 1.270 + nameType = items[readUnsignedShort(index + 2)]; 1.271 + item.set(tag, 1.272 + readClass(index, buf), 1.273 + readUTF8(nameType, buf), 1.274 + readUTF8(nameType + 2, buf)); 1.275 + break; 1.276 + 1.277 + case ClassWriter.INT: 1.278 + item.set(readInt(index)); 1.279 + break; 1.280 + 1.281 + case ClassWriter.FLOAT: 1.282 + item.set(Float.intBitsToFloat(readInt(index))); 1.283 + break; 1.284 + 1.285 + case ClassWriter.NAME_TYPE: 1.286 + item.set(tag, 1.287 + readUTF8(index, buf), 1.288 + readUTF8(index + 2, buf), 1.289 + null); 1.290 + break; 1.291 + 1.292 + case ClassWriter.LONG: 1.293 + item.set(readLong(index)); 1.294 + ++i; 1.295 + break; 1.296 + 1.297 + case ClassWriter.DOUBLE: 1.298 + item.set(Double.longBitsToDouble(readLong(index))); 1.299 + ++i; 1.300 + break; 1.301 + 1.302 + case ClassWriter.UTF8: 1.303 + { 1.304 + String s = strings[i]; 1.305 + if(s == null) 1.306 + { 1.307 + index = items[i]; 1.308 + s = strings[i] = readUTF(index + 2, 1.309 + readUnsignedShort(index), 1.310 + buf); 1.311 + } 1.312 + item.set(tag, s, null, null); 1.313 + } 1.314 + break; 1.315 + 1.316 + // case ClassWriter.STR: 1.317 + // case ClassWriter.CLASS: 1.318 + default: 1.319 + item.set(tag, readUTF8(index, buf), null, null); 1.320 + break; 1.321 + } 1.322 + 1.323 + int index2 = item.hashCode % items2.length; 1.324 + item.next = items2[index2]; 1.325 + items2[index2] = item; 1.326 + } 1.327 + 1.328 + int off = items[1] - 1; 1.329 + classWriter.pool.putByteArray(b, off, header - off); 1.330 + classWriter.items = items2; 1.331 + classWriter.threshold = (int) (0.75d * ll); 1.332 + classWriter.index = ll; 1.333 +} 1.334 + 1.335 +/** 1.336 + * Constructs a new {@link ClassReader} object. 1.337 + * 1.338 + * @param is an input stream from which to read the class. 1.339 + * @throws IOException if a problem occurs during reading. 1.340 + */ 1.341 +public ClassReader(final InputStream is) throws IOException{ 1.342 + this(readClass(is)); 1.343 +} 1.344 + 1.345 +/** 1.346 + * Constructs a new {@link ClassReader} object. 1.347 + * 1.348 + * @param name the fully qualified name of the class to be read. 1.349 + * @throws IOException if an exception occurs during reading. 1.350 + */ 1.351 +public ClassReader(final String name) throws IOException{ 1.352 + this(ClassLoader.getSystemResourceAsStream(name.replace('.', '/') 1.353 + + ".class")); 1.354 +} 1.355 + 1.356 +/** 1.357 + * Reads the bytecode of a class. 1.358 + * 1.359 + * @param is an input stream from which to read the class. 1.360 + * @return the bytecode read from the given input stream. 1.361 + * @throws IOException if a problem occurs during reading. 1.362 + */ 1.363 +private static byte[] readClass(final InputStream is) throws IOException{ 1.364 + if(is == null) 1.365 + { 1.366 + throw new IOException("Class not found"); 1.367 + } 1.368 + byte[] b = new byte[is.available()]; 1.369 + int len = 0; 1.370 + while(true) 1.371 + { 1.372 + int n = is.read(b, len, b.length - len); 1.373 + if(n == -1) 1.374 + { 1.375 + if(len < b.length) 1.376 + { 1.377 + byte[] c = new byte[len]; 1.378 + System.arraycopy(b, 0, c, 0, len); 1.379 + b = c; 1.380 + } 1.381 + return b; 1.382 + } 1.383 + len += n; 1.384 + if(len == b.length) 1.385 + { 1.386 + byte[] c = new byte[b.length + 1000]; 1.387 + System.arraycopy(b, 0, c, 0, len); 1.388 + b = c; 1.389 + } 1.390 + } 1.391 +} 1.392 + 1.393 +// ------------------------------------------------------------------------ 1.394 +// Public methods 1.395 +// ------------------------------------------------------------------------ 1.396 + 1.397 +/** 1.398 + * Makes the given visitor visit the Java class of this {@link ClassReader}. 1.399 + * This class is the one specified in the constructor (see 1.400 + * {@link #ClassReader(byte[]) ClassReader}). 1.401 + * 1.402 + * @param classVisitor the visitor that must visit this class. 1.403 + * @param flags option flags that can be used to modify the default behavior 1.404 + * of this class. See {@link #SKIP_DEBUG}, {@link #EXPAND_FRAMES}. 1.405 + */ 1.406 +public void accept(final ClassVisitor classVisitor, final int flags){ 1.407 + accept(classVisitor, new Attribute[0], flags); 1.408 +} 1.409 + 1.410 +/** 1.411 + * Makes the given visitor visit the Java class of this {@link ClassReader}. 1.412 + * This class is the one specified in the constructor (see 1.413 + * {@link #ClassReader(byte[]) ClassReader}). 1.414 + * 1.415 + * @param classVisitor the visitor that must visit this class. 1.416 + * @param attrs prototypes of the attributes that must be parsed during the 1.417 + * visit of the class. Any attribute whose type is not equal to the 1.418 + * type of one the prototypes will not be parsed: its byte array 1.419 + * value will be passed unchanged to the ClassWriter. <i>This may 1.420 + * corrupt it if this value contains references to the constant pool, 1.421 + * or has syntactic or semantic links with a class element that has 1.422 + * been transformed by a class adapter between the reader and the 1.423 + * writer</i>. 1.424 + * @param flags option flags that can be used to modify the default behavior 1.425 + * of this class. See {@link #SKIP_DEBUG}, {@link #EXPAND_FRAMES}. 1.426 + */ 1.427 +public void accept( 1.428 + final ClassVisitor classVisitor, 1.429 + final Attribute[] attrs, 1.430 + final int flags){ 1.431 + byte[] b = this.b; // the bytecode array 1.432 + char[] c = new char[maxStringLength]; // buffer used to read strings 1.433 + int i, j, k; // loop variables 1.434 + int u, v, w; // indexes in b 1.435 + Attribute attr; 1.436 + 1.437 + int access; 1.438 + String name; 1.439 + String desc; 1.440 + String attrName; 1.441 + String signature; 1.442 + int anns = 0; 1.443 + int ianns = 0; 1.444 + Attribute cattrs = null; 1.445 + 1.446 + // visits the header 1.447 + u = header; 1.448 + access = readUnsignedShort(u); 1.449 + name = readClass(u + 2, c); 1.450 + v = items[readUnsignedShort(u + 4)]; 1.451 + String superClassName = v == 0 ? null : readUTF8(v, c); 1.452 + String[] implementedItfs = new String[readUnsignedShort(u + 6)]; 1.453 + w = 0; 1.454 + u += 8; 1.455 + for(i = 0; i < implementedItfs.length; ++i) 1.456 + { 1.457 + implementedItfs[i] = readClass(u, c); 1.458 + u += 2; 1.459 + } 1.460 + 1.461 + boolean skipCode = (flags & SKIP_CODE) != 0; 1.462 + boolean skipDebug = (flags & SKIP_DEBUG) != 0; 1.463 + boolean unzip = (flags & EXPAND_FRAMES) != 0; 1.464 + 1.465 + // skips fields and methods 1.466 + v = u; 1.467 + i = readUnsignedShort(v); 1.468 + v += 2; 1.469 + for(; i > 0; --i) 1.470 + { 1.471 + j = readUnsignedShort(v + 6); 1.472 + v += 8; 1.473 + for(; j > 0; --j) 1.474 + { 1.475 + v += 6 + readInt(v + 2); 1.476 + } 1.477 + } 1.478 + i = readUnsignedShort(v); 1.479 + v += 2; 1.480 + for(; i > 0; --i) 1.481 + { 1.482 + j = readUnsignedShort(v + 6); 1.483 + v += 8; 1.484 + for(; j > 0; --j) 1.485 + { 1.486 + v += 6 + readInt(v + 2); 1.487 + } 1.488 + } 1.489 + // reads the class's attributes 1.490 + signature = null; 1.491 + String sourceFile = null; 1.492 + String sourceDebug = null; 1.493 + String enclosingOwner = null; 1.494 + String enclosingName = null; 1.495 + String enclosingDesc = null; 1.496 + 1.497 + i = readUnsignedShort(v); 1.498 + v += 2; 1.499 + for(; i > 0; --i) 1.500 + { 1.501 + attrName = readUTF8(v, c); 1.502 + // tests are sorted in decreasing frequency order 1.503 + // (based on frequencies observed on typical classes) 1.504 + if(attrName.equals("SourceFile")) 1.505 + { 1.506 + sourceFile = readUTF8(v + 6, c); 1.507 + } 1.508 + else if(attrName.equals("InnerClasses")) 1.509 + { 1.510 + w = v + 6; 1.511 + } 1.512 + else if(attrName.equals("EnclosingMethod")) 1.513 + { 1.514 + enclosingOwner = readClass(v + 6, c); 1.515 + int item = readUnsignedShort(v + 8); 1.516 + if(item != 0) 1.517 + { 1.518 + enclosingName = readUTF8(items[item], c); 1.519 + enclosingDesc = readUTF8(items[item] + 2, c); 1.520 + } 1.521 + } 1.522 + else if(attrName.equals("Signature")) 1.523 + { 1.524 + signature = readUTF8(v + 6, c); 1.525 + } 1.526 + else if(attrName.equals("RuntimeVisibleAnnotations")) 1.527 + { 1.528 + anns = v + 6; 1.529 + } 1.530 + else if(attrName.equals("Deprecated")) 1.531 + { 1.532 + access |= Opcodes.ACC_DEPRECATED; 1.533 + } 1.534 + else if(attrName.equals("Synthetic")) 1.535 + { 1.536 + access |= Opcodes.ACC_SYNTHETIC; 1.537 + } 1.538 + else if(attrName.equals("SourceDebugExtension")) 1.539 + { 1.540 + int len = readInt(v + 2); 1.541 + sourceDebug = readUTF(v + 6, len, new char[len]); 1.542 + } 1.543 + else if(attrName.equals("RuntimeInvisibleAnnotations")) 1.544 + { 1.545 + ianns = v + 6; 1.546 + } 1.547 + else 1.548 + { 1.549 + attr = readAttribute(attrs, 1.550 + attrName, 1.551 + v + 6, 1.552 + readInt(v + 2), 1.553 + c, 1.554 + -1, 1.555 + null); 1.556 + if(attr != null) 1.557 + { 1.558 + attr.next = cattrs; 1.559 + cattrs = attr; 1.560 + } 1.561 + } 1.562 + v += 6 + readInt(v + 2); 1.563 + } 1.564 + // calls the visit method 1.565 + classVisitor.visit(readInt(4), 1.566 + access, 1.567 + name, 1.568 + signature, 1.569 + superClassName, 1.570 + implementedItfs); 1.571 + 1.572 + // calls the visitSource method 1.573 + if(!skipDebug && (sourceFile != null || sourceDebug != null)) 1.574 + { 1.575 + classVisitor.visitSource(sourceFile, sourceDebug); 1.576 + } 1.577 + 1.578 + // calls the visitOuterClass method 1.579 + if(enclosingOwner != null) 1.580 + { 1.581 + classVisitor.visitOuterClass(enclosingOwner, 1.582 + enclosingName, 1.583 + enclosingDesc); 1.584 + } 1.585 + 1.586 + // visits the class annotations 1.587 + for(i = 1; i >= 0; --i) 1.588 + { 1.589 + v = i == 0 ? ianns : anns; 1.590 + if(v != 0) 1.591 + { 1.592 + j = readUnsignedShort(v); 1.593 + v += 2; 1.594 + for(; j > 0; --j) 1.595 + { 1.596 + v = readAnnotationValues(v + 2, 1.597 + c, 1.598 + true, 1.599 + classVisitor.visitAnnotation(readUTF8(v, c), i != 0)); 1.600 + } 1.601 + } 1.602 + } 1.603 + 1.604 + // visits the class attributes 1.605 + while(cattrs != null) 1.606 + { 1.607 + attr = cattrs.next; 1.608 + cattrs.next = null; 1.609 + classVisitor.visitAttribute(cattrs); 1.610 + cattrs = attr; 1.611 + } 1.612 + 1.613 + // calls the visitInnerClass method 1.614 + if(w != 0) 1.615 + { 1.616 + i = readUnsignedShort(w); 1.617 + w += 2; 1.618 + for(; i > 0; --i) 1.619 + { 1.620 + classVisitor.visitInnerClass(readUnsignedShort(w) == 0 1.621 + ? null 1.622 + : readClass(w, c), readUnsignedShort(w + 2) == 0 1.623 + ? null 1.624 + : readClass(w + 2, c), readUnsignedShort(w + 4) == 0 1.625 + ? null 1.626 + : readUTF8(w + 4, c), 1.627 + readUnsignedShort(w + 6)); 1.628 + w += 8; 1.629 + } 1.630 + } 1.631 + 1.632 + // visits the fields 1.633 + i = readUnsignedShort(u); 1.634 + u += 2; 1.635 + for(; i > 0; --i) 1.636 + { 1.637 + access = readUnsignedShort(u); 1.638 + name = readUTF8(u + 2, c); 1.639 + desc = readUTF8(u + 4, c); 1.640 + // visits the field's attributes and looks for a ConstantValue 1.641 + // attribute 1.642 + int fieldValueItem = 0; 1.643 + signature = null; 1.644 + anns = 0; 1.645 + ianns = 0; 1.646 + cattrs = null; 1.647 + 1.648 + j = readUnsignedShort(u + 6); 1.649 + u += 8; 1.650 + for(; j > 0; --j) 1.651 + { 1.652 + attrName = readUTF8(u, c); 1.653 + // tests are sorted in decreasing frequency order 1.654 + // (based on frequencies observed on typical classes) 1.655 + if(attrName.equals("ConstantValue")) 1.656 + { 1.657 + fieldValueItem = readUnsignedShort(u + 6); 1.658 + } 1.659 + else if(attrName.equals("Signature")) 1.660 + { 1.661 + signature = readUTF8(u + 6, c); 1.662 + } 1.663 + else if(attrName.equals("Deprecated")) 1.664 + { 1.665 + access |= Opcodes.ACC_DEPRECATED; 1.666 + } 1.667 + else if(attrName.equals("Synthetic")) 1.668 + { 1.669 + access |= Opcodes.ACC_SYNTHETIC; 1.670 + } 1.671 + else if(attrName.equals("RuntimeVisibleAnnotations")) 1.672 + { 1.673 + anns = u + 6; 1.674 + } 1.675 + else if(attrName.equals("RuntimeInvisibleAnnotations")) 1.676 + { 1.677 + ianns = u + 6; 1.678 + } 1.679 + else 1.680 + { 1.681 + attr = readAttribute(attrs, 1.682 + attrName, 1.683 + u + 6, 1.684 + readInt(u + 2), 1.685 + c, 1.686 + -1, 1.687 + null); 1.688 + if(attr != null) 1.689 + { 1.690 + attr.next = cattrs; 1.691 + cattrs = attr; 1.692 + } 1.693 + } 1.694 + u += 6 + readInt(u + 2); 1.695 + } 1.696 + // visits the field 1.697 + FieldVisitor fv = classVisitor.visitField(access, 1.698 + name, 1.699 + desc, 1.700 + signature, 1.701 + fieldValueItem == 0 ? null : readConst(fieldValueItem, c)); 1.702 + // visits the field annotations and attributes 1.703 + if(fv != null) 1.704 + { 1.705 + for(j = 1; j >= 0; --j) 1.706 + { 1.707 + v = j == 0 ? ianns : anns; 1.708 + if(v != 0) 1.709 + { 1.710 + k = readUnsignedShort(v); 1.711 + v += 2; 1.712 + for(; k > 0; --k) 1.713 + { 1.714 + v = readAnnotationValues(v + 2, 1.715 + c, 1.716 + true, 1.717 + fv.visitAnnotation(readUTF8(v, c), j != 0)); 1.718 + } 1.719 + } 1.720 + } 1.721 + while(cattrs != null) 1.722 + { 1.723 + attr = cattrs.next; 1.724 + cattrs.next = null; 1.725 + fv.visitAttribute(cattrs); 1.726 + cattrs = attr; 1.727 + } 1.728 + fv.visitEnd(); 1.729 + } 1.730 + } 1.731 + 1.732 + // visits the methods 1.733 + i = readUnsignedShort(u); 1.734 + u += 2; 1.735 + for(; i > 0; --i) 1.736 + { 1.737 + int u0 = u + 6; 1.738 + access = readUnsignedShort(u); 1.739 + name = readUTF8(u + 2, c); 1.740 + desc = readUTF8(u + 4, c); 1.741 + signature = null; 1.742 + anns = 0; 1.743 + ianns = 0; 1.744 + int dann = 0; 1.745 + int mpanns = 0; 1.746 + int impanns = 0; 1.747 + cattrs = null; 1.748 + v = 0; 1.749 + w = 0; 1.750 + 1.751 + // looks for Code and Exceptions attributes 1.752 + j = readUnsignedShort(u + 6); 1.753 + u += 8; 1.754 + for(; j > 0; --j) 1.755 + { 1.756 + attrName = readUTF8(u, c); 1.757 + int attrSize = readInt(u + 2); 1.758 + u += 6; 1.759 + // tests are sorted in decreasing frequency order 1.760 + // (based on frequencies observed on typical classes) 1.761 + if(attrName.equals("Code")) 1.762 + { 1.763 + if(!skipCode) 1.764 + { 1.765 + v = u; 1.766 + } 1.767 + } 1.768 + else if(attrName.equals("Exceptions")) 1.769 + { 1.770 + w = u; 1.771 + } 1.772 + else if(attrName.equals("Signature")) 1.773 + { 1.774 + signature = readUTF8(u, c); 1.775 + } 1.776 + else if(attrName.equals("Deprecated")) 1.777 + { 1.778 + access |= Opcodes.ACC_DEPRECATED; 1.779 + } 1.780 + else if(attrName.equals("RuntimeVisibleAnnotations")) 1.781 + { 1.782 + anns = u; 1.783 + } 1.784 + else if(attrName.equals("AnnotationDefault")) 1.785 + { 1.786 + dann = u; 1.787 + } 1.788 + else if(attrName.equals("Synthetic")) 1.789 + { 1.790 + access |= Opcodes.ACC_SYNTHETIC; 1.791 + } 1.792 + else if(attrName.equals("RuntimeInvisibleAnnotations")) 1.793 + { 1.794 + ianns = u; 1.795 + } 1.796 + else if(attrName.equals("RuntimeVisibleParameterAnnotations")) 1.797 + { 1.798 + mpanns = u; 1.799 + } 1.800 + else if(attrName.equals("RuntimeInvisibleParameterAnnotations")) 1.801 + { 1.802 + impanns = u; 1.803 + } 1.804 + else 1.805 + { 1.806 + attr = readAttribute(attrs, 1.807 + attrName, 1.808 + u, 1.809 + attrSize, 1.810 + c, 1.811 + -1, 1.812 + null); 1.813 + if(attr != null) 1.814 + { 1.815 + attr.next = cattrs; 1.816 + cattrs = attr; 1.817 + } 1.818 + } 1.819 + u += attrSize; 1.820 + } 1.821 + // reads declared exceptions 1.822 + String[] exceptions; 1.823 + if(w == 0) 1.824 + { 1.825 + exceptions = null; 1.826 + } 1.827 + else 1.828 + { 1.829 + exceptions = new String[readUnsignedShort(w)]; 1.830 + w += 2; 1.831 + for(j = 0; j < exceptions.length; ++j) 1.832 + { 1.833 + exceptions[j] = readClass(w, c); 1.834 + w += 2; 1.835 + } 1.836 + } 1.837 + 1.838 + // visits the method's code, if any 1.839 + MethodVisitor mv = classVisitor.visitMethod(access, 1.840 + name, 1.841 + desc, 1.842 + signature, 1.843 + exceptions); 1.844 + 1.845 + if(mv != null) 1.846 + { 1.847 + /* 1.848 + * if the returned MethodVisitor is in fact a MethodWriter, it 1.849 + * means there is no method adapter between the reader and the 1.850 + * writer. If, in addition, the writer's constant pool was 1.851 + * copied from this reader (mw.cw.cr == this), and the signature 1.852 + * and exceptions of the method have not been changed, then it 1.853 + * is possible to skip all visit events and just copy the 1.854 + * original code of the method to the writer (the access, name 1.855 + * and descriptor can have been changed, this is not important 1.856 + * since they are not copied as is from the reader). 1.857 + */ 1.858 + if(mv instanceof MethodWriter) 1.859 + { 1.860 + MethodWriter mw = (MethodWriter) mv; 1.861 + if(mw.cw.cr == this) 1.862 + { 1.863 + if(signature == mw.signature) 1.864 + { 1.865 + boolean sameExceptions = false; 1.866 + if(exceptions == null) 1.867 + { 1.868 + sameExceptions = mw.exceptionCount == 0; 1.869 + } 1.870 + else 1.871 + { 1.872 + if(exceptions.length == mw.exceptionCount) 1.873 + { 1.874 + sameExceptions = true; 1.875 + for(j = exceptions.length - 1; j >= 0; --j) 1.876 + { 1.877 + w -= 2; 1.878 + if(mw.exceptions[j] != readUnsignedShort(w)) 1.879 + { 1.880 + sameExceptions = false; 1.881 + break; 1.882 + } 1.883 + } 1.884 + } 1.885 + } 1.886 + if(sameExceptions) 1.887 + { 1.888 + /* 1.889 + * we do not copy directly the code into 1.890 + * MethodWriter to save a byte array copy 1.891 + * operation. The real copy will be done in 1.892 + * ClassWriter.toByteArray(). 1.893 + */ 1.894 + mw.classReaderOffset = u0; 1.895 + mw.classReaderLength = u - u0; 1.896 + continue; 1.897 + } 1.898 + } 1.899 + } 1.900 + } 1.901 + 1.902 + if(dann != 0) 1.903 + { 1.904 + AnnotationVisitor dv = mv.visitAnnotationDefault(); 1.905 + readAnnotationValue(dann, c, null, dv); 1.906 + if(dv != null) 1.907 + { 1.908 + dv.visitEnd(); 1.909 + } 1.910 + } 1.911 + for(j = 1; j >= 0; --j) 1.912 + { 1.913 + w = j == 0 ? ianns : anns; 1.914 + if(w != 0) 1.915 + { 1.916 + k = readUnsignedShort(w); 1.917 + w += 2; 1.918 + for(; k > 0; --k) 1.919 + { 1.920 + w = readAnnotationValues(w + 2, 1.921 + c, 1.922 + true, 1.923 + mv.visitAnnotation(readUTF8(w, c), j != 0)); 1.924 + } 1.925 + } 1.926 + } 1.927 + if(mpanns != 0) 1.928 + { 1.929 + readParameterAnnotations(mpanns, c, true, mv); 1.930 + } 1.931 + if(impanns != 0) 1.932 + { 1.933 + readParameterAnnotations(impanns, c, false, mv); 1.934 + } 1.935 + while(cattrs != null) 1.936 + { 1.937 + attr = cattrs.next; 1.938 + cattrs.next = null; 1.939 + mv.visitAttribute(cattrs); 1.940 + cattrs = attr; 1.941 + } 1.942 + } 1.943 + 1.944 + if(mv != null && v != 0) 1.945 + { 1.946 + int maxStack = readUnsignedShort(v); 1.947 + int maxLocals = readUnsignedShort(v + 2); 1.948 + int codeLength = readInt(v + 4); 1.949 + v += 8; 1.950 + 1.951 + int codeStart = v; 1.952 + int codeEnd = v + codeLength; 1.953 + 1.954 + mv.visitCode(); 1.955 + 1.956 + // 1st phase: finds the labels 1.957 + int label; 1.958 + Label[] labels = new Label[codeLength + 1]; 1.959 + while(v < codeEnd) 1.960 + { 1.961 + int opcode = b[v] & 0xFF; 1.962 + switch(ClassWriter.TYPE[opcode]) 1.963 + { 1.964 + case ClassWriter.NOARG_INSN: 1.965 + case ClassWriter.IMPLVAR_INSN: 1.966 + v += 1; 1.967 + break; 1.968 + case ClassWriter.LABEL_INSN: 1.969 + label = v - codeStart + readShort(v + 1); 1.970 + if(labels[label] == null) 1.971 + { 1.972 + labels[label] = new Label(); 1.973 + } 1.974 + v += 3; 1.975 + break; 1.976 + case ClassWriter.LABELW_INSN: 1.977 + label = v - codeStart + readInt(v + 1); 1.978 + if(labels[label] == null) 1.979 + { 1.980 + labels[label] = new Label(); 1.981 + } 1.982 + v += 5; 1.983 + break; 1.984 + case ClassWriter.WIDE_INSN: 1.985 + opcode = b[v + 1] & 0xFF; 1.986 + if(opcode == Opcodes.IINC) 1.987 + { 1.988 + v += 6; 1.989 + } 1.990 + else 1.991 + { 1.992 + v += 4; 1.993 + } 1.994 + break; 1.995 + case ClassWriter.TABL_INSN: 1.996 + // skips 0 to 3 padding bytes 1.997 + w = v - codeStart; 1.998 + v = v + 4 - (w & 3); 1.999 + // reads instruction 1.1000 + label = w + readInt(v); 1.1001 + if(labels[label] == null) 1.1002 + { 1.1003 + labels[label] = new Label(); 1.1004 + } 1.1005 + j = readInt(v + 8) - readInt(v + 4) + 1; 1.1006 + v += 12; 1.1007 + for(; j > 0; --j) 1.1008 + { 1.1009 + label = w + readInt(v); 1.1010 + v += 4; 1.1011 + if(labels[label] == null) 1.1012 + { 1.1013 + labels[label] = new Label(); 1.1014 + } 1.1015 + } 1.1016 + break; 1.1017 + case ClassWriter.LOOK_INSN: 1.1018 + // skips 0 to 3 padding bytes 1.1019 + w = v - codeStart; 1.1020 + v = v + 4 - (w & 3); 1.1021 + // reads instruction 1.1022 + label = w + readInt(v); 1.1023 + if(labels[label] == null) 1.1024 + { 1.1025 + labels[label] = new Label(); 1.1026 + } 1.1027 + j = readInt(v + 4); 1.1028 + v += 8; 1.1029 + for(; j > 0; --j) 1.1030 + { 1.1031 + label = w + readInt(v + 4); 1.1032 + v += 8; 1.1033 + if(labels[label] == null) 1.1034 + { 1.1035 + labels[label] = new Label(); 1.1036 + } 1.1037 + } 1.1038 + break; 1.1039 + case ClassWriter.VAR_INSN: 1.1040 + case ClassWriter.SBYTE_INSN: 1.1041 + case ClassWriter.LDC_INSN: 1.1042 + v += 2; 1.1043 + break; 1.1044 + case ClassWriter.SHORT_INSN: 1.1045 + case ClassWriter.LDCW_INSN: 1.1046 + case ClassWriter.FIELDORMETH_INSN: 1.1047 + case ClassWriter.TYPE_INSN: 1.1048 + case ClassWriter.IINC_INSN: 1.1049 + v += 3; 1.1050 + break; 1.1051 + case ClassWriter.ITFMETH_INSN: 1.1052 + v += 5; 1.1053 + break; 1.1054 + // case MANA_INSN: 1.1055 + default: 1.1056 + v += 4; 1.1057 + break; 1.1058 + } 1.1059 + } 1.1060 + // parses the try catch entries 1.1061 + j = readUnsignedShort(v); 1.1062 + v += 2; 1.1063 + for(; j > 0; --j) 1.1064 + { 1.1065 + label = readUnsignedShort(v); 1.1066 + Label start = labels[label]; 1.1067 + if(start == null) 1.1068 + { 1.1069 + labels[label] = start = new Label(); 1.1070 + } 1.1071 + label = readUnsignedShort(v + 2); 1.1072 + Label end = labels[label]; 1.1073 + if(end == null) 1.1074 + { 1.1075 + labels[label] = end = new Label(); 1.1076 + } 1.1077 + label = readUnsignedShort(v + 4); 1.1078 + Label handler = labels[label]; 1.1079 + if(handler == null) 1.1080 + { 1.1081 + labels[label] = handler = new Label(); 1.1082 + } 1.1083 + int type = readUnsignedShort(v + 6); 1.1084 + if(type == 0) 1.1085 + { 1.1086 + mv.visitTryCatchBlock(start, end, handler, null); 1.1087 + } 1.1088 + else 1.1089 + { 1.1090 + mv.visitTryCatchBlock(start, 1.1091 + end, 1.1092 + handler, 1.1093 + readUTF8(items[type], c)); 1.1094 + } 1.1095 + v += 8; 1.1096 + } 1.1097 + // parses the local variable, line number tables, and code 1.1098 + // attributes 1.1099 + int varTable = 0; 1.1100 + int varTypeTable = 0; 1.1101 + int stackMap = 0; 1.1102 + int frameCount = 0; 1.1103 + int frameMode = 0; 1.1104 + int frameOffset = 0; 1.1105 + int frameLocalCount = 0; 1.1106 + int frameLocalDiff = 0; 1.1107 + int frameStackCount = 0; 1.1108 + Object[] frameLocal = null; 1.1109 + Object[] frameStack = null; 1.1110 + boolean zip = true; 1.1111 + cattrs = null; 1.1112 + j = readUnsignedShort(v); 1.1113 + v += 2; 1.1114 + for(; j > 0; --j) 1.1115 + { 1.1116 + attrName = readUTF8(v, c); 1.1117 + if(attrName.equals("LocalVariableTable")) 1.1118 + { 1.1119 + if(!skipDebug) 1.1120 + { 1.1121 + varTable = v + 6; 1.1122 + k = readUnsignedShort(v + 6); 1.1123 + w = v + 8; 1.1124 + for(; k > 0; --k) 1.1125 + { 1.1126 + label = readUnsignedShort(w); 1.1127 + if(labels[label] == null) 1.1128 + { 1.1129 + labels[label] = new Label(true); 1.1130 + } 1.1131 + label += readUnsignedShort(w + 2); 1.1132 + if(labels[label] == null) 1.1133 + { 1.1134 + labels[label] = new Label(true); 1.1135 + } 1.1136 + w += 10; 1.1137 + } 1.1138 + } 1.1139 + } 1.1140 + else if(attrName.equals("LocalVariableTypeTable")) 1.1141 + { 1.1142 + varTypeTable = v + 6; 1.1143 + } 1.1144 + else if(attrName.equals("LineNumberTable")) 1.1145 + { 1.1146 + if(!skipDebug) 1.1147 + { 1.1148 + k = readUnsignedShort(v + 6); 1.1149 + w = v + 8; 1.1150 + for(; k > 0; --k) 1.1151 + { 1.1152 + label = readUnsignedShort(w); 1.1153 + if(labels[label] == null) 1.1154 + { 1.1155 + labels[label] = new Label(true); 1.1156 + } 1.1157 + labels[label].line = readUnsignedShort(w + 2); 1.1158 + w += 4; 1.1159 + } 1.1160 + } 1.1161 + } 1.1162 + else if(attrName.equals("StackMapTable")) 1.1163 + { 1.1164 + if((flags & SKIP_FRAMES) == 0) 1.1165 + { 1.1166 + stackMap = v + 8; 1.1167 + frameCount = readUnsignedShort(v + 6); 1.1168 + } 1.1169 + /* 1.1170 + * here we do not extract the labels corresponding to 1.1171 + * the attribute content. This would require a full 1.1172 + * parsing of the attribute, which would need to be 1.1173 + * repeated in the second phase (see below). Instead the 1.1174 + * content of the attribute is read one frame at a time 1.1175 + * (i.e. after a frame has been visited, the next frame 1.1176 + * is read), and the labels it contains are also 1.1177 + * extracted one frame at a time. Thanks to the ordering 1.1178 + * of frames, having only a "one frame lookahead" is not 1.1179 + * a problem, i.e. it is not possible to see an offset 1.1180 + * smaller than the offset of the current insn and for 1.1181 + * which no Label exist. 1.1182 + */ 1.1183 + // TODO true for frame offsets, 1.1184 + // but for UNINITIALIZED type offsets? 1.1185 + } 1.1186 + else if(attrName.equals("StackMap")) 1.1187 + { 1.1188 + if((flags & SKIP_FRAMES) == 0) 1.1189 + { 1.1190 + stackMap = v + 8; 1.1191 + frameCount = readUnsignedShort(v + 6); 1.1192 + zip = false; 1.1193 + } 1.1194 + /* 1.1195 + * IMPORTANT! here we assume that the frames are 1.1196 + * ordered, as in the StackMapTable attribute, although 1.1197 + * this is not guaranteed by the attribute format. 1.1198 + */ 1.1199 + } 1.1200 + else 1.1201 + { 1.1202 + for(k = 0; k < attrs.length; ++k) 1.1203 + { 1.1204 + if(attrs[k].type.equals(attrName)) 1.1205 + { 1.1206 + attr = attrs[k].read(this, 1.1207 + v + 6, 1.1208 + readInt(v + 2), 1.1209 + c, 1.1210 + codeStart - 8, 1.1211 + labels); 1.1212 + if(attr != null) 1.1213 + { 1.1214 + attr.next = cattrs; 1.1215 + cattrs = attr; 1.1216 + } 1.1217 + } 1.1218 + } 1.1219 + } 1.1220 + v += 6 + readInt(v + 2); 1.1221 + } 1.1222 + 1.1223 + // 2nd phase: visits each instruction 1.1224 + if(stackMap != 0) 1.1225 + { 1.1226 + // creates the very first (implicit) frame from the method 1.1227 + // descriptor 1.1228 + frameLocal = new Object[maxLocals]; 1.1229 + frameStack = new Object[maxStack]; 1.1230 + if(unzip) 1.1231 + { 1.1232 + int local = 0; 1.1233 + if((access & Opcodes.ACC_STATIC) == 0) 1.1234 + { 1.1235 + if(name.equals("<init>")) 1.1236 + { 1.1237 + frameLocal[local++] = Opcodes.UNINITIALIZED_THIS; 1.1238 + } 1.1239 + else 1.1240 + { 1.1241 + frameLocal[local++] = readClass(header + 2, c); 1.1242 + } 1.1243 + } 1.1244 + j = 1; 1.1245 + loop: 1.1246 + while(true) 1.1247 + { 1.1248 + k = j; 1.1249 + switch(desc.charAt(j++)) 1.1250 + { 1.1251 + case'Z': 1.1252 + case'C': 1.1253 + case'B': 1.1254 + case'S': 1.1255 + case'I': 1.1256 + frameLocal[local++] = Opcodes.INTEGER; 1.1257 + break; 1.1258 + case'F': 1.1259 + frameLocal[local++] = Opcodes.FLOAT; 1.1260 + break; 1.1261 + case'J': 1.1262 + frameLocal[local++] = Opcodes.LONG; 1.1263 + break; 1.1264 + case'D': 1.1265 + frameLocal[local++] = Opcodes.DOUBLE; 1.1266 + break; 1.1267 + case'[': 1.1268 + while(desc.charAt(j) == '[') 1.1269 + { 1.1270 + ++j; 1.1271 + } 1.1272 + if(desc.charAt(j) == 'L') 1.1273 + { 1.1274 + ++j; 1.1275 + while(desc.charAt(j) != ';') 1.1276 + { 1.1277 + ++j; 1.1278 + } 1.1279 + } 1.1280 + frameLocal[local++] = desc.substring(k, ++j); 1.1281 + break; 1.1282 + case'L': 1.1283 + while(desc.charAt(j) != ';') 1.1284 + { 1.1285 + ++j; 1.1286 + } 1.1287 + frameLocal[local++] = desc.substring(k + 1, 1.1288 + j++); 1.1289 + break; 1.1290 + default: 1.1291 + break loop; 1.1292 + } 1.1293 + } 1.1294 + frameLocalCount = local; 1.1295 + } 1.1296 + /* 1.1297 + * for the first explicit frame the offset is not 1.1298 + * offset_delta + 1 but only offset_delta; setting the 1.1299 + * implicit frame offset to -1 allow the use of the 1.1300 + * "offset_delta + 1" rule in all cases 1.1301 + */ 1.1302 + frameOffset = -1; 1.1303 + } 1.1304 + v = codeStart; 1.1305 + Label l; 1.1306 + while(v < codeEnd) 1.1307 + { 1.1308 + w = v - codeStart; 1.1309 + 1.1310 + l = labels[w]; 1.1311 + if(l != null) 1.1312 + { 1.1313 + mv.visitLabel(l); 1.1314 + if(!skipDebug && l.line > 0) 1.1315 + { 1.1316 + mv.visitLineNumber(l.line, l); 1.1317 + } 1.1318 + } 1.1319 + 1.1320 + while(frameLocal != null 1.1321 + && (frameOffset == w || frameOffset == -1)) 1.1322 + { 1.1323 + // if there is a frame for this offset, 1.1324 + // makes the visitor visit it, 1.1325 + // and reads the next frame if there is one. 1.1326 + if(!zip || unzip) 1.1327 + { 1.1328 + mv.visitFrame(Opcodes.F_NEW, 1.1329 + frameLocalCount, 1.1330 + frameLocal, 1.1331 + frameStackCount, 1.1332 + frameStack); 1.1333 + } 1.1334 + else if(frameOffset != -1) 1.1335 + { 1.1336 + mv.visitFrame(frameMode, 1.1337 + frameLocalDiff, 1.1338 + frameLocal, 1.1339 + frameStackCount, 1.1340 + frameStack); 1.1341 + } 1.1342 + 1.1343 + if(frameCount > 0) 1.1344 + { 1.1345 + int tag, delta, n; 1.1346 + if(zip) 1.1347 + { 1.1348 + tag = b[stackMap++] & 0xFF; 1.1349 + } 1.1350 + else 1.1351 + { 1.1352 + tag = MethodWriter.FULL_FRAME; 1.1353 + frameOffset = -1; 1.1354 + } 1.1355 + frameLocalDiff = 0; 1.1356 + if(tag < MethodWriter.SAME_LOCALS_1_STACK_ITEM_FRAME) 1.1357 + { 1.1358 + delta = tag; 1.1359 + frameMode = Opcodes.F_SAME; 1.1360 + frameStackCount = 0; 1.1361 + } 1.1362 + else if(tag < MethodWriter.RESERVED) 1.1363 + { 1.1364 + delta = tag 1.1365 + - MethodWriter.SAME_LOCALS_1_STACK_ITEM_FRAME; 1.1366 + stackMap = readFrameType(frameStack, 1.1367 + 0, 1.1368 + stackMap, 1.1369 + c, 1.1370 + labels); 1.1371 + frameMode = Opcodes.F_SAME1; 1.1372 + frameStackCount = 1; 1.1373 + } 1.1374 + else 1.1375 + { 1.1376 + delta = readUnsignedShort(stackMap); 1.1377 + stackMap += 2; 1.1378 + if(tag == MethodWriter.SAME_LOCALS_1_STACK_ITEM_FRAME_EXTENDED) 1.1379 + { 1.1380 + stackMap = readFrameType(frameStack, 1.1381 + 0, 1.1382 + stackMap, 1.1383 + c, 1.1384 + labels); 1.1385 + frameMode = Opcodes.F_SAME1; 1.1386 + frameStackCount = 1; 1.1387 + } 1.1388 + else if(tag >= MethodWriter.CHOP_FRAME 1.1389 + && tag < MethodWriter.SAME_FRAME_EXTENDED) 1.1390 + { 1.1391 + frameMode = Opcodes.F_CHOP; 1.1392 + frameLocalDiff = MethodWriter.SAME_FRAME_EXTENDED 1.1393 + - tag; 1.1394 + frameLocalCount -= frameLocalDiff; 1.1395 + frameStackCount = 0; 1.1396 + } 1.1397 + else if(tag == MethodWriter.SAME_FRAME_EXTENDED) 1.1398 + { 1.1399 + frameMode = Opcodes.F_SAME; 1.1400 + frameStackCount = 0; 1.1401 + } 1.1402 + else if(tag < MethodWriter.FULL_FRAME) 1.1403 + { 1.1404 + j = unzip ? frameLocalCount : 0; 1.1405 + for(k = tag 1.1406 + - MethodWriter.SAME_FRAME_EXTENDED; k > 0; k--) 1.1407 + { 1.1408 + stackMap = readFrameType(frameLocal, 1.1409 + j++, 1.1410 + stackMap, 1.1411 + c, 1.1412 + labels); 1.1413 + } 1.1414 + frameMode = Opcodes.F_APPEND; 1.1415 + frameLocalDiff = tag 1.1416 + - MethodWriter.SAME_FRAME_EXTENDED; 1.1417 + frameLocalCount += frameLocalDiff; 1.1418 + frameStackCount = 0; 1.1419 + } 1.1420 + else 1.1421 + { // if (tag == FULL_FRAME) { 1.1422 + frameMode = Opcodes.F_FULL; 1.1423 + n = frameLocalDiff = frameLocalCount = readUnsignedShort(stackMap); 1.1424 + stackMap += 2; 1.1425 + for(j = 0; n > 0; n--) 1.1426 + { 1.1427 + stackMap = readFrameType(frameLocal, 1.1428 + j++, 1.1429 + stackMap, 1.1430 + c, 1.1431 + labels); 1.1432 + } 1.1433 + n = frameStackCount = readUnsignedShort(stackMap); 1.1434 + stackMap += 2; 1.1435 + for(j = 0; n > 0; n--) 1.1436 + { 1.1437 + stackMap = readFrameType(frameStack, 1.1438 + j++, 1.1439 + stackMap, 1.1440 + c, 1.1441 + labels); 1.1442 + } 1.1443 + } 1.1444 + } 1.1445 + frameOffset += delta + 1; 1.1446 + if(labels[frameOffset] == null) 1.1447 + { 1.1448 + labels[frameOffset] = new Label(); 1.1449 + } 1.1450 + 1.1451 + --frameCount; 1.1452 + } 1.1453 + else 1.1454 + { 1.1455 + frameLocal = null; 1.1456 + } 1.1457 + } 1.1458 + 1.1459 + int opcode = b[v] & 0xFF; 1.1460 + switch(ClassWriter.TYPE[opcode]) 1.1461 + { 1.1462 + case ClassWriter.NOARG_INSN: 1.1463 + mv.visitInsn(opcode); 1.1464 + v += 1; 1.1465 + break; 1.1466 + case ClassWriter.IMPLVAR_INSN: 1.1467 + if(opcode > Opcodes.ISTORE) 1.1468 + { 1.1469 + opcode -= 59; // ISTORE_0 1.1470 + mv.visitVarInsn(Opcodes.ISTORE + (opcode >> 2), 1.1471 + opcode & 0x3); 1.1472 + } 1.1473 + else 1.1474 + { 1.1475 + opcode -= 26; // ILOAD_0 1.1476 + mv.visitVarInsn(Opcodes.ILOAD + (opcode >> 2), 1.1477 + opcode & 0x3); 1.1478 + } 1.1479 + v += 1; 1.1480 + break; 1.1481 + case ClassWriter.LABEL_INSN: 1.1482 + mv.visitJumpInsn(opcode, labels[w 1.1483 + + readShort(v + 1)]); 1.1484 + v += 3; 1.1485 + break; 1.1486 + case ClassWriter.LABELW_INSN: 1.1487 + mv.visitJumpInsn(opcode - 33, labels[w 1.1488 + + readInt(v + 1)]); 1.1489 + v += 5; 1.1490 + break; 1.1491 + case ClassWriter.WIDE_INSN: 1.1492 + opcode = b[v + 1] & 0xFF; 1.1493 + if(opcode == Opcodes.IINC) 1.1494 + { 1.1495 + mv.visitIincInsn(readUnsignedShort(v + 2), 1.1496 + readShort(v + 4)); 1.1497 + v += 6; 1.1498 + } 1.1499 + else 1.1500 + { 1.1501 + mv.visitVarInsn(opcode, 1.1502 + readUnsignedShort(v + 2)); 1.1503 + v += 4; 1.1504 + } 1.1505 + break; 1.1506 + case ClassWriter.TABL_INSN: 1.1507 + // skips 0 to 3 padding bytes 1.1508 + v = v + 4 - (w & 3); 1.1509 + // reads instruction 1.1510 + label = w + readInt(v); 1.1511 + int min = readInt(v + 4); 1.1512 + int max = readInt(v + 8); 1.1513 + v += 12; 1.1514 + Label[] table = new Label[max - min + 1]; 1.1515 + for(j = 0; j < table.length; ++j) 1.1516 + { 1.1517 + table[j] = labels[w + readInt(v)]; 1.1518 + v += 4; 1.1519 + } 1.1520 + mv.visitTableSwitchInsn(min, 1.1521 + max, 1.1522 + labels[label], 1.1523 + table); 1.1524 + break; 1.1525 + case ClassWriter.LOOK_INSN: 1.1526 + // skips 0 to 3 padding bytes 1.1527 + v = v + 4 - (w & 3); 1.1528 + // reads instruction 1.1529 + label = w + readInt(v); 1.1530 + j = readInt(v + 4); 1.1531 + v += 8; 1.1532 + int[] keys = new int[j]; 1.1533 + Label[] values = new Label[j]; 1.1534 + for(j = 0; j < keys.length; ++j) 1.1535 + { 1.1536 + keys[j] = readInt(v); 1.1537 + values[j] = labels[w + readInt(v + 4)]; 1.1538 + v += 8; 1.1539 + } 1.1540 + mv.visitLookupSwitchInsn(labels[label], 1.1541 + keys, 1.1542 + values); 1.1543 + break; 1.1544 + case ClassWriter.VAR_INSN: 1.1545 + mv.visitVarInsn(opcode, b[v + 1] & 0xFF); 1.1546 + v += 2; 1.1547 + break; 1.1548 + case ClassWriter.SBYTE_INSN: 1.1549 + mv.visitIntInsn(opcode, b[v + 1]); 1.1550 + v += 2; 1.1551 + break; 1.1552 + case ClassWriter.SHORT_INSN: 1.1553 + mv.visitIntInsn(opcode, readShort(v + 1)); 1.1554 + v += 3; 1.1555 + break; 1.1556 + case ClassWriter.LDC_INSN: 1.1557 + mv.visitLdcInsn(readConst(b[v + 1] & 0xFF, c)); 1.1558 + v += 2; 1.1559 + break; 1.1560 + case ClassWriter.LDCW_INSN: 1.1561 + mv.visitLdcInsn(readConst(readUnsignedShort(v + 1), 1.1562 + c)); 1.1563 + v += 3; 1.1564 + break; 1.1565 + case ClassWriter.FIELDORMETH_INSN: 1.1566 + case ClassWriter.ITFMETH_INSN: 1.1567 + int cpIndex = items[readUnsignedShort(v + 1)]; 1.1568 + String iowner = readClass(cpIndex, c); 1.1569 + cpIndex = items[readUnsignedShort(cpIndex + 2)]; 1.1570 + String iname = readUTF8(cpIndex, c); 1.1571 + String idesc = readUTF8(cpIndex + 2, c); 1.1572 + if(opcode < Opcodes.INVOKEVIRTUAL) 1.1573 + { 1.1574 + mv.visitFieldInsn(opcode, iowner, iname, idesc); 1.1575 + } 1.1576 + else 1.1577 + { 1.1578 + mv.visitMethodInsn(opcode, iowner, iname, idesc); 1.1579 + } 1.1580 + if(opcode == Opcodes.INVOKEINTERFACE) 1.1581 + { 1.1582 + v += 5; 1.1583 + } 1.1584 + else 1.1585 + { 1.1586 + v += 3; 1.1587 + } 1.1588 + break; 1.1589 + case ClassWriter.TYPE_INSN: 1.1590 + mv.visitTypeInsn(opcode, readClass(v + 1, c)); 1.1591 + v += 3; 1.1592 + break; 1.1593 + case ClassWriter.IINC_INSN: 1.1594 + mv.visitIincInsn(b[v + 1] & 0xFF, b[v + 2]); 1.1595 + v += 3; 1.1596 + break; 1.1597 + // case MANA_INSN: 1.1598 + default: 1.1599 + mv.visitMultiANewArrayInsn(readClass(v + 1, c), 1.1600 + b[v + 3] & 0xFF); 1.1601 + v += 4; 1.1602 + break; 1.1603 + } 1.1604 + } 1.1605 + l = labels[codeEnd - codeStart]; 1.1606 + if(l != null) 1.1607 + { 1.1608 + mv.visitLabel(l); 1.1609 + } 1.1610 + // visits the local variable tables 1.1611 + if(!skipDebug && varTable != 0) 1.1612 + { 1.1613 + int[] typeTable = null; 1.1614 + if(varTypeTable != 0) 1.1615 + { 1.1616 + k = readUnsignedShort(varTypeTable) * 3; 1.1617 + w = varTypeTable + 2; 1.1618 + typeTable = new int[k]; 1.1619 + while(k > 0) 1.1620 + { 1.1621 + typeTable[--k] = w + 6; // signature 1.1622 + typeTable[--k] = readUnsignedShort(w + 8); // index 1.1623 + typeTable[--k] = readUnsignedShort(w); // start 1.1624 + w += 10; 1.1625 + } 1.1626 + } 1.1627 + k = readUnsignedShort(varTable); 1.1628 + w = varTable + 2; 1.1629 + for(; k > 0; --k) 1.1630 + { 1.1631 + int start = readUnsignedShort(w); 1.1632 + int length = readUnsignedShort(w + 2); 1.1633 + int index = readUnsignedShort(w + 8); 1.1634 + String vsignature = null; 1.1635 + if(typeTable != null) 1.1636 + { 1.1637 + for(int a = 0; a < typeTable.length; a += 3) 1.1638 + { 1.1639 + if(typeTable[a] == start 1.1640 + && typeTable[a + 1] == index) 1.1641 + { 1.1642 + vsignature = readUTF8(typeTable[a + 2], c); 1.1643 + break; 1.1644 + } 1.1645 + } 1.1646 + } 1.1647 + mv.visitLocalVariable(readUTF8(w + 4, c), 1.1648 + readUTF8(w + 6, c), 1.1649 + vsignature, 1.1650 + labels[start], 1.1651 + labels[start + length], 1.1652 + index); 1.1653 + w += 10; 1.1654 + } 1.1655 + } 1.1656 + // visits the other attributes 1.1657 + while(cattrs != null) 1.1658 + { 1.1659 + attr = cattrs.next; 1.1660 + cattrs.next = null; 1.1661 + mv.visitAttribute(cattrs); 1.1662 + cattrs = attr; 1.1663 + } 1.1664 + // visits the max stack and max locals values 1.1665 + mv.visitMaxs(maxStack, maxLocals); 1.1666 + } 1.1667 + 1.1668 + if(mv != null) 1.1669 + { 1.1670 + mv.visitEnd(); 1.1671 + } 1.1672 + } 1.1673 + 1.1674 + // visits the end of the class 1.1675 + classVisitor.visitEnd(); 1.1676 +} 1.1677 + 1.1678 +/** 1.1679 + * Reads parameter annotations and makes the given visitor visit them. 1.1680 + * 1.1681 + * @param v start offset in {@link #b b} of the annotations to be read. 1.1682 + * @param buf buffer to be used to call {@link #readUTF8 readUTF8}, 1.1683 + * {@link #readClass(int,char[]) readClass} or 1.1684 + * {@link #readConst readConst}. 1.1685 + * @param visible <tt>true</tt> if the annotations to be read are visible 1.1686 + * at runtime. 1.1687 + * @param mv the visitor that must visit the annotations. 1.1688 + */ 1.1689 +private void readParameterAnnotations( 1.1690 + int v, 1.1691 + final char[] buf, 1.1692 + final boolean visible, 1.1693 + final MethodVisitor mv){ 1.1694 + int n = b[v++] & 0xFF; 1.1695 + for(int i = 0; i < n; ++i) 1.1696 + { 1.1697 + int j = readUnsignedShort(v); 1.1698 + v += 2; 1.1699 + for(; j > 0; --j) 1.1700 + { 1.1701 + v = readAnnotationValues(v + 2, 1.1702 + buf, 1.1703 + true, 1.1704 + mv.visitParameterAnnotation(i, 1.1705 + readUTF8(v, buf), 1.1706 + visible)); 1.1707 + } 1.1708 + } 1.1709 +} 1.1710 + 1.1711 +/** 1.1712 + * Reads the values of an annotation and makes the given visitor visit them. 1.1713 + * 1.1714 + * @param v the start offset in {@link #b b} of the values to be read 1.1715 + * (including the unsigned short that gives the number of values). 1.1716 + * @param buf buffer to be used to call {@link #readUTF8 readUTF8}, 1.1717 + * {@link #readClass(int,char[]) readClass} or 1.1718 + * {@link #readConst readConst}. 1.1719 + * @param named if the annotation values are named or not. 1.1720 + * @param av the visitor that must visit the values. 1.1721 + * @return the end offset of the annotation values. 1.1722 + */ 1.1723 +private int readAnnotationValues( 1.1724 + int v, 1.1725 + final char[] buf, 1.1726 + final boolean named, 1.1727 + final AnnotationVisitor av){ 1.1728 + int i = readUnsignedShort(v); 1.1729 + v += 2; 1.1730 + if(named) 1.1731 + { 1.1732 + for(; i > 0; --i) 1.1733 + { 1.1734 + v = readAnnotationValue(v + 2, buf, readUTF8(v, buf), av); 1.1735 + } 1.1736 + } 1.1737 + else 1.1738 + { 1.1739 + for(; i > 0; --i) 1.1740 + { 1.1741 + v = readAnnotationValue(v, buf, null, av); 1.1742 + } 1.1743 + } 1.1744 + if(av != null) 1.1745 + { 1.1746 + av.visitEnd(); 1.1747 + } 1.1748 + return v; 1.1749 +} 1.1750 + 1.1751 +/** 1.1752 + * Reads a value of an annotation and makes the given visitor visit it. 1.1753 + * 1.1754 + * @param v the start offset in {@link #b b} of the value to be read (<i>not 1.1755 + * including the value name constant pool index</i>). 1.1756 + * @param buf buffer to be used to call {@link #readUTF8 readUTF8}, 1.1757 + * {@link #readClass(int,char[]) readClass} or 1.1758 + * {@link #readConst readConst}. 1.1759 + * @param name the name of the value to be read. 1.1760 + * @param av the visitor that must visit the value. 1.1761 + * @return the end offset of the annotation value. 1.1762 + */ 1.1763 +private int readAnnotationValue( 1.1764 + int v, 1.1765 + final char[] buf, 1.1766 + final String name, 1.1767 + final AnnotationVisitor av){ 1.1768 + int i; 1.1769 + if(av == null) 1.1770 + { 1.1771 + switch(b[v] & 0xFF) 1.1772 + { 1.1773 + case'e': // enum_const_value 1.1774 + return v + 5; 1.1775 + case'@': // annotation_value 1.1776 + return readAnnotationValues(v + 3, buf, true, null); 1.1777 + case'[': // array_value 1.1778 + return readAnnotationValues(v + 1, buf, false, null); 1.1779 + default: 1.1780 + return v + 3; 1.1781 + } 1.1782 + } 1.1783 + switch(b[v++] & 0xFF) 1.1784 + { 1.1785 + case'I': // pointer to CONSTANT_Integer 1.1786 + case'J': // pointer to CONSTANT_Long 1.1787 + case'F': // pointer to CONSTANT_Float 1.1788 + case'D': // pointer to CONSTANT_Double 1.1789 + av.visit(name, readConst(readUnsignedShort(v), buf)); 1.1790 + v += 2; 1.1791 + break; 1.1792 + case'B': // pointer to CONSTANT_Byte 1.1793 + av.visit(name, 1.1794 + new Byte((byte) readInt(items[readUnsignedShort(v)]))); 1.1795 + v += 2; 1.1796 + break; 1.1797 + case'Z': // pointer to CONSTANT_Boolean 1.1798 + av.visit(name, readInt(items[readUnsignedShort(v)]) == 0 1.1799 + ? Boolean.FALSE 1.1800 + : Boolean.TRUE); 1.1801 + v += 2; 1.1802 + break; 1.1803 + case'S': // pointer to CONSTANT_Short 1.1804 + av.visit(name, 1.1805 + new Short((short) readInt(items[readUnsignedShort(v)]))); 1.1806 + v += 2; 1.1807 + break; 1.1808 + case'C': // pointer to CONSTANT_Char 1.1809 + av.visit(name, 1.1810 + new Character((char) readInt(items[readUnsignedShort(v)]))); 1.1811 + v += 2; 1.1812 + break; 1.1813 + case's': // pointer to CONSTANT_Utf8 1.1814 + av.visit(name, readUTF8(v, buf)); 1.1815 + v += 2; 1.1816 + break; 1.1817 + case'e': // enum_const_value 1.1818 + av.visitEnum(name, readUTF8(v, buf), readUTF8(v + 2, buf)); 1.1819 + v += 4; 1.1820 + break; 1.1821 + case'c': // class_info 1.1822 + av.visit(name, Type.getType(readUTF8(v, buf))); 1.1823 + v += 2; 1.1824 + break; 1.1825 + case'@': // annotation_value 1.1826 + v = readAnnotationValues(v + 2, 1.1827 + buf, 1.1828 + true, 1.1829 + av.visitAnnotation(name, readUTF8(v, buf))); 1.1830 + break; 1.1831 + case'[': // array_value 1.1832 + int size = readUnsignedShort(v); 1.1833 + v += 2; 1.1834 + if(size == 0) 1.1835 + { 1.1836 + return readAnnotationValues(v - 2, 1.1837 + buf, 1.1838 + false, 1.1839 + av.visitArray(name)); 1.1840 + } 1.1841 + switch(this.b[v++] & 0xFF) 1.1842 + { 1.1843 + case'B': 1.1844 + byte[] bv = new byte[size]; 1.1845 + for(i = 0; i < size; i++) 1.1846 + { 1.1847 + bv[i] = (byte) readInt(items[readUnsignedShort(v)]); 1.1848 + v += 3; 1.1849 + } 1.1850 + av.visit(name, bv); 1.1851 + --v; 1.1852 + break; 1.1853 + case'Z': 1.1854 + boolean[] zv = new boolean[size]; 1.1855 + for(i = 0; i < size; i++) 1.1856 + { 1.1857 + zv[i] = readInt(items[readUnsignedShort(v)]) != 0; 1.1858 + v += 3; 1.1859 + } 1.1860 + av.visit(name, zv); 1.1861 + --v; 1.1862 + break; 1.1863 + case'S': 1.1864 + short[] sv = new short[size]; 1.1865 + for(i = 0; i < size; i++) 1.1866 + { 1.1867 + sv[i] = (short) readInt(items[readUnsignedShort(v)]); 1.1868 + v += 3; 1.1869 + } 1.1870 + av.visit(name, sv); 1.1871 + --v; 1.1872 + break; 1.1873 + case'C': 1.1874 + char[] cv = new char[size]; 1.1875 + for(i = 0; i < size; i++) 1.1876 + { 1.1877 + cv[i] = (char) readInt(items[readUnsignedShort(v)]); 1.1878 + v += 3; 1.1879 + } 1.1880 + av.visit(name, cv); 1.1881 + --v; 1.1882 + break; 1.1883 + case'I': 1.1884 + int[] iv = new int[size]; 1.1885 + for(i = 0; i < size; i++) 1.1886 + { 1.1887 + iv[i] = readInt(items[readUnsignedShort(v)]); 1.1888 + v += 3; 1.1889 + } 1.1890 + av.visit(name, iv); 1.1891 + --v; 1.1892 + break; 1.1893 + case'J': 1.1894 + long[] lv = new long[size]; 1.1895 + for(i = 0; i < size; i++) 1.1896 + { 1.1897 + lv[i] = readLong(items[readUnsignedShort(v)]); 1.1898 + v += 3; 1.1899 + } 1.1900 + av.visit(name, lv); 1.1901 + --v; 1.1902 + break; 1.1903 + case'F': 1.1904 + float[] fv = new float[size]; 1.1905 + for(i = 0; i < size; i++) 1.1906 + { 1.1907 + fv[i] = Float.intBitsToFloat(readInt(items[readUnsignedShort(v)])); 1.1908 + v += 3; 1.1909 + } 1.1910 + av.visit(name, fv); 1.1911 + --v; 1.1912 + break; 1.1913 + case'D': 1.1914 + double[] dv = new double[size]; 1.1915 + for(i = 0; i < size; i++) 1.1916 + { 1.1917 + dv[i] = Double.longBitsToDouble(readLong(items[readUnsignedShort(v)])); 1.1918 + v += 3; 1.1919 + } 1.1920 + av.visit(name, dv); 1.1921 + --v; 1.1922 + break; 1.1923 + default: 1.1924 + v = readAnnotationValues(v - 3, 1.1925 + buf, 1.1926 + false, 1.1927 + av.visitArray(name)); 1.1928 + } 1.1929 + } 1.1930 + return v; 1.1931 +} 1.1932 + 1.1933 +private int readFrameType( 1.1934 + final Object[] frame, 1.1935 + final int index, 1.1936 + int v, 1.1937 + final char[] buf, 1.1938 + final Label[] labels){ 1.1939 + int type = b[v++] & 0xFF; 1.1940 + switch(type) 1.1941 + { 1.1942 + case 0: 1.1943 + frame[index] = Opcodes.TOP; 1.1944 + break; 1.1945 + case 1: 1.1946 + frame[index] = Opcodes.INTEGER; 1.1947 + break; 1.1948 + case 2: 1.1949 + frame[index] = Opcodes.FLOAT; 1.1950 + break; 1.1951 + case 3: 1.1952 + frame[index] = Opcodes.DOUBLE; 1.1953 + break; 1.1954 + case 4: 1.1955 + frame[index] = Opcodes.LONG; 1.1956 + break; 1.1957 + case 5: 1.1958 + frame[index] = Opcodes.NULL; 1.1959 + break; 1.1960 + case 6: 1.1961 + frame[index] = Opcodes.UNINITIALIZED_THIS; 1.1962 + break; 1.1963 + case 7: // Object 1.1964 + frame[index] = readClass(v, buf); 1.1965 + v += 2; 1.1966 + break; 1.1967 + default: // Uninitialized 1.1968 + int offset = readUnsignedShort(v); 1.1969 + if(labels[offset] == null) 1.1970 + { 1.1971 + labels[offset] = new Label(); 1.1972 + } 1.1973 + frame[index] = labels[offset]; 1.1974 + v += 2; 1.1975 + } 1.1976 + return v; 1.1977 +} 1.1978 + 1.1979 +/** 1.1980 + * Reads an attribute in {@link #b b}. 1.1981 + * 1.1982 + * @param attrs prototypes of the attributes that must be parsed during the 1.1983 + * visit of the class. Any attribute whose type is not equal to the 1.1984 + * type of one the prototypes is ignored (i.e. an empty 1.1985 + * {@link Attribute} instance is returned). 1.1986 + * @param type the type of the attribute. 1.1987 + * @param off index of the first byte of the attribute's content in 1.1988 + * {@link #b b}. The 6 attribute header bytes, containing the type 1.1989 + * and the length of the attribute, are not taken into account here 1.1990 + * (they have already been read). 1.1991 + * @param len the length of the attribute's content. 1.1992 + * @param buf buffer to be used to call {@link #readUTF8 readUTF8}, 1.1993 + * {@link #readClass(int,char[]) readClass} or 1.1994 + * {@link #readConst readConst}. 1.1995 + * @param codeOff index of the first byte of code's attribute content in 1.1996 + * {@link #b b}, or -1 if the attribute to be read is not a code 1.1997 + * attribute. The 6 attribute header bytes, containing the type and 1.1998 + * the length of the attribute, are not taken into account here. 1.1999 + * @param labels the labels of the method's code, or <tt>null</tt> if the 1.2000 + * attribute to be read is not a code attribute. 1.2001 + * @return the attribute that has been read, or <tt>null</tt> to skip this 1.2002 + * attribute. 1.2003 + */ 1.2004 +private Attribute readAttribute( 1.2005 + final Attribute[] attrs, 1.2006 + final String type, 1.2007 + final int off, 1.2008 + final int len, 1.2009 + final char[] buf, 1.2010 + final int codeOff, 1.2011 + final Label[] labels){ 1.2012 + for(int i = 0; i < attrs.length; ++i) 1.2013 + { 1.2014 + if(attrs[i].type.equals(type)) 1.2015 + { 1.2016 + return attrs[i].read(this, off, len, buf, codeOff, labels); 1.2017 + } 1.2018 + } 1.2019 + return new Attribute(type).read(this, off, len, null, -1, null); 1.2020 +} 1.2021 + 1.2022 +// ------------------------------------------------------------------------ 1.2023 +// Utility methods: low level parsing 1.2024 +// ------------------------------------------------------------------------ 1.2025 + 1.2026 +/** 1.2027 + * Returns the start index of the constant pool item in {@link #b b}, plus 1.2028 + * one. <i>This method is intended for {@link Attribute} sub classes, and is 1.2029 + * normally not needed by class generators or adapters.</i> 1.2030 + * 1.2031 + * @param item the index a constant pool item. 1.2032 + * @return the start index of the constant pool item in {@link #b b}, plus 1.2033 + * one. 1.2034 + */ 1.2035 +public int getItem(final int item){ 1.2036 + return items[item]; 1.2037 +} 1.2038 + 1.2039 +/** 1.2040 + * Reads a byte value in {@link #b b}. <i>This method is intended for 1.2041 + * {@link Attribute} sub classes, and is normally not needed by class 1.2042 + * generators or adapters.</i> 1.2043 + * 1.2044 + * @param index the start index of the value to be read in {@link #b b}. 1.2045 + * @return the read value. 1.2046 + */ 1.2047 +public int readByte(final int index){ 1.2048 + return b[index] & 0xFF; 1.2049 +} 1.2050 + 1.2051 +/** 1.2052 + * Reads an unsigned short value in {@link #b b}. <i>This method is 1.2053 + * intended for {@link Attribute} sub classes, and is normally not needed by 1.2054 + * class generators or adapters.</i> 1.2055 + * 1.2056 + * @param index the start index of the value to be read in {@link #b b}. 1.2057 + * @return the read value. 1.2058 + */ 1.2059 +public int readUnsignedShort(final int index){ 1.2060 + byte[] b = this.b; 1.2061 + return ((b[index] & 0xFF) << 8) | (b[index + 1] & 0xFF); 1.2062 +} 1.2063 + 1.2064 +/** 1.2065 + * Reads a signed short value in {@link #b b}. <i>This method is intended 1.2066 + * for {@link Attribute} sub classes, and is normally not needed by class 1.2067 + * generators or adapters.</i> 1.2068 + * 1.2069 + * @param index the start index of the value to be read in {@link #b b}. 1.2070 + * @return the read value. 1.2071 + */ 1.2072 +public short readShort(final int index){ 1.2073 + byte[] b = this.b; 1.2074 + return (short) (((b[index] & 0xFF) << 8) | (b[index + 1] & 0xFF)); 1.2075 +} 1.2076 + 1.2077 +/** 1.2078 + * Reads a signed int value in {@link #b b}. <i>This method is intended for 1.2079 + * {@link Attribute} sub classes, and is normally not needed by class 1.2080 + * generators or adapters.</i> 1.2081 + * 1.2082 + * @param index the start index of the value to be read in {@link #b b}. 1.2083 + * @return the read value. 1.2084 + */ 1.2085 +public int readInt(final int index){ 1.2086 + byte[] b = this.b; 1.2087 + return ((b[index] & 0xFF) << 24) | ((b[index + 1] & 0xFF) << 16) 1.2088 + | ((b[index + 2] & 0xFF) << 8) | (b[index + 3] & 0xFF); 1.2089 +} 1.2090 + 1.2091 +/** 1.2092 + * Reads a signed long value in {@link #b b}. <i>This method is intended 1.2093 + * for {@link Attribute} sub classes, and is normally not needed by class 1.2094 + * generators or adapters.</i> 1.2095 + * 1.2096 + * @param index the start index of the value to be read in {@link #b b}. 1.2097 + * @return the read value. 1.2098 + */ 1.2099 +public long readLong(final int index){ 1.2100 + long l1 = readInt(index); 1.2101 + long l0 = readInt(index + 4) & 0xFFFFFFFFL; 1.2102 + return (l1 << 32) | l0; 1.2103 +} 1.2104 + 1.2105 +/** 1.2106 + * Reads an UTF8 string constant pool item in {@link #b b}. <i>This method 1.2107 + * is intended for {@link Attribute} sub classes, and is normally not needed 1.2108 + * by class generators or adapters.</i> 1.2109 + * 1.2110 + * @param index the start index of an unsigned short value in {@link #b b}, 1.2111 + * whose value is the index of an UTF8 constant pool item. 1.2112 + * @param buf buffer to be used to read the item. This buffer must be 1.2113 + * sufficiently large. It is not automatically resized. 1.2114 + * @return the String corresponding to the specified UTF8 item. 1.2115 + */ 1.2116 +public String readUTF8(int index, final char[] buf){ 1.2117 + int item = readUnsignedShort(index); 1.2118 + String s = strings[item]; 1.2119 + if(s != null) 1.2120 + { 1.2121 + return s; 1.2122 + } 1.2123 + index = items[item]; 1.2124 + return strings[item] = readUTF(index + 2, readUnsignedShort(index), buf); 1.2125 +} 1.2126 + 1.2127 +/** 1.2128 + * Reads UTF8 string in {@link #b b}. 1.2129 + * 1.2130 + * @param index start offset of the UTF8 string to be read. 1.2131 + * @param utfLen length of the UTF8 string to be read. 1.2132 + * @param buf buffer to be used to read the string. This buffer must be 1.2133 + * sufficiently large. It is not automatically resized. 1.2134 + * @return the String corresponding to the specified UTF8 string. 1.2135 + */ 1.2136 +private String readUTF(int index, final int utfLen, final char[] buf){ 1.2137 + int endIndex = index + utfLen; 1.2138 + byte[] b = this.b; 1.2139 + int strLen = 0; 1.2140 + int c, d, e; 1.2141 + while(index < endIndex) 1.2142 + { 1.2143 + c = b[index++] & 0xFF; 1.2144 + switch(c >> 4) 1.2145 + { 1.2146 + case 0: 1.2147 + case 1: 1.2148 + case 2: 1.2149 + case 3: 1.2150 + case 4: 1.2151 + case 5: 1.2152 + case 6: 1.2153 + case 7: 1.2154 + // 0xxxxxxx 1.2155 + buf[strLen++] = (char) c; 1.2156 + break; 1.2157 + case 12: 1.2158 + case 13: 1.2159 + // 110x xxxx 10xx xxxx 1.2160 + d = b[index++]; 1.2161 + buf[strLen++] = (char) (((c & 0x1F) << 6) | (d & 0x3F)); 1.2162 + break; 1.2163 + default: 1.2164 + // 1110 xxxx 10xx xxxx 10xx xxxx 1.2165 + d = b[index++]; 1.2166 + e = b[index++]; 1.2167 + buf[strLen++] = (char) (((c & 0x0F) << 12) 1.2168 + | ((d & 0x3F) << 6) | (e & 0x3F)); 1.2169 + break; 1.2170 + } 1.2171 + } 1.2172 + return new String(buf, 0, strLen); 1.2173 +} 1.2174 + 1.2175 +/** 1.2176 + * Reads a class constant pool item in {@link #b b}. <i>This method is 1.2177 + * intended for {@link Attribute} sub classes, and is normally not needed by 1.2178 + * class generators or adapters.</i> 1.2179 + * 1.2180 + * @param index the start index of an unsigned short value in {@link #b b}, 1.2181 + * whose value is the index of a class constant pool item. 1.2182 + * @param buf buffer to be used to read the item. This buffer must be 1.2183 + * sufficiently large. It is not automatically resized. 1.2184 + * @return the String corresponding to the specified class item. 1.2185 + */ 1.2186 +public String readClass(final int index, final char[] buf){ 1.2187 + // computes the start index of the CONSTANT_Class item in b 1.2188 + // and reads the CONSTANT_Utf8 item designated by 1.2189 + // the first two bytes of this CONSTANT_Class item 1.2190 + return readUTF8(items[readUnsignedShort(index)], buf); 1.2191 +} 1.2192 + 1.2193 +/** 1.2194 + * Reads a numeric or string constant pool item in {@link #b b}. <i>This 1.2195 + * method is intended for {@link Attribute} sub classes, and is normally not 1.2196 + * needed by class generators or adapters.</i> 1.2197 + * 1.2198 + * @param item the index of a constant pool item. 1.2199 + * @param buf buffer to be used to read the item. This buffer must be 1.2200 + * sufficiently large. It is not automatically resized. 1.2201 + * @return the {@link Integer}, {@link Float}, {@link Long}, 1.2202 + * {@link Double}, {@link String} or {@link Type} corresponding to 1.2203 + * the given constant pool item. 1.2204 + */ 1.2205 +public Object readConst(final int item, final char[] buf){ 1.2206 + int index = items[item]; 1.2207 + switch(b[index - 1]) 1.2208 + { 1.2209 + case ClassWriter.INT: 1.2210 + return new Integer(readInt(index)); 1.2211 + case ClassWriter.FLOAT: 1.2212 + return new Float(Float.intBitsToFloat(readInt(index))); 1.2213 + case ClassWriter.LONG: 1.2214 + return new Long(readLong(index)); 1.2215 + case ClassWriter.DOUBLE: 1.2216 + return new Double(Double.longBitsToDouble(readLong(index))); 1.2217 + case ClassWriter.CLASS: 1.2218 + String s = readUTF8(index, buf); 1.2219 + return s.charAt(0) == '[' 1.2220 + ? Type.getType(s) 1.2221 + : Type.getObjectType(s); 1.2222 + // case ClassWriter.STR: 1.2223 + default: 1.2224 + return readUTF8(index, buf); 1.2225 + } 1.2226 +} 1.2227 +}