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 +}