📄 classreader.java
字号:
/***
* ASM: a very small and fast Java bytecode manipulation framework
* Copyright (c) 2000-2005 INRIA, France Telecom
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the copyright holders nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
* THE POSSIBILITY OF SUCH DAMAGE.
*/
package org.drools.asm;
import java.io.IOException;
import java.io.InputStream;
/**
* A Java class parser to make a {@link ClassVisitor} visit an existing class.
* This class parses a byte array conforming to the Java class file format and
* calls the appropriate visit methods of a given class visitor for each field,
* method and bytecode instruction encountered.
*
* @author Eric Bruneton
* @author Eugene Kuleshov
*/
public class ClassReader {
/**
* The class to be parsed. <i>The content of this array must not be
* modified. This field is intended for {@link Attribute} sub classes, and
* is normally not needed by class generators or adapters.</i>
*/
public final byte[] b;
/**
* The start index of each constant pool item in {@link #b b}, plus one.
* The one byte offset skips the constant pool item tag that indicates its
* type.
*/
private int[] items;
/**
* The String objects corresponding to the CONSTANT_Utf8 items. This cache
* avoids multiple parsing of a given CONSTANT_Utf8 constant pool item,
* which GREATLY improves performances (by a factor 2 to 3). This caching
* strategy could be extended to all constant pool items, but its benefit
* would not be so great for these items (because they are much less
* expensive to parse than CONSTANT_Utf8 items).
*/
private String[] strings;
/**
* Maximum length of the strings contained in the constant pool of the
* class.
*/
private int maxStringLength;
/**
* Start index of the class header information (access, name...) in
* {@link #b b}.
*/
public final int header;
// ------------------------------------------------------------------------
// Constructors
// ------------------------------------------------------------------------
/**
* Constructs a new {@link ClassReader} object.
*
* @param b the bytecode of the class to be read.
*/
public ClassReader(final byte[] b) {
this( b,
0,
b.length );
}
/**
* Constructs a new {@link ClassReader} object.
*
* @param b the bytecode of the class to be read.
* @param off the start offset of the class data.
* @param len the length of the class data.
*/
public ClassReader(final byte[] b,
final int off,
final int len) {
this.b = b;
// parses the constant pool
this.items = new int[readUnsignedShort( off + 8 )];
final int ll = this.items.length;
this.strings = new String[ll];
int max = 0;
int index = off + 10;
for ( int i = 1; i < ll; ++i ) {
this.items[i] = index + 1;
final int tag = b[index];
int size;
switch ( tag ) {
case ClassWriter.FIELD :
case ClassWriter.METH :
case ClassWriter.IMETH :
case ClassWriter.INT :
case ClassWriter.FLOAT :
case ClassWriter.NAME_TYPE :
size = 5;
break;
case ClassWriter.LONG :
case ClassWriter.DOUBLE :
size = 9;
++i;
break;
case ClassWriter.UTF8 :
size = 3 + readUnsignedShort( index + 1 );
if ( size > max ) {
max = size;
}
break;
// case ClassWriter.CLASS:
// case ClassWriter.STR:
default :
size = 3;
break;
}
index += size;
}
this.maxStringLength = max;
// the class header information starts just after the constant pool
this.header = index;
}
/**
* Copies the constant pool data into the given {@link ClassWriter}. Should
* be called before the {@link #accept(ClassVisitor,boolean)} method.
*
* @param classWriter the {@link ClassWriter} to copy constant pool into.
*/
void copyPool(final ClassWriter classWriter) {
final char[] buf = new char[this.maxStringLength];
final int ll = this.items.length;
final Item[] items2 = new Item[ll];
for ( int i = 1; i < ll; i++ ) {
int index = this.items[i];
final int tag = this.b[index - 1];
final Item item = new Item( i );
int nameType;
switch ( tag ) {
case ClassWriter.FIELD :
case ClassWriter.METH :
case ClassWriter.IMETH :
nameType = this.items[readUnsignedShort( index + 2 )];
item.set( tag,
readClass( index,
buf ),
readUTF8( nameType,
buf ),
readUTF8( nameType + 2,
buf ) );
break;
case ClassWriter.INT :
item.set( readInt( index ) );
break;
case ClassWriter.FLOAT :
item.set( Float.intBitsToFloat( readInt( index ) ) );
break;
case ClassWriter.NAME_TYPE :
item.set( tag,
readUTF8( index,
buf ),
readUTF8( index + 2,
buf ),
null );
break;
case ClassWriter.LONG :
item.set( readLong( index ) );
++i;
break;
case ClassWriter.DOUBLE :
item.set( Double.longBitsToDouble( readLong( index ) ) );
++i;
break;
case ClassWriter.UTF8 : {
String s = this.strings[i];
if ( s == null ) {
index = this.items[i];
s = this.strings[i] = readUTF( index + 2,
readUnsignedShort( index ),
buf );
}
item.set( tag,
s,
null,
null );
}
break;
// case ClassWriter.STR:
// case ClassWriter.CLASS:
default :
item.set( tag,
readUTF8( index,
buf ),
null,
null );
break;
}
final int index2 = item.hashCode % items2.length;
item.next = items2[index2];
items2[index2] = item;
}
final int off = this.items[1] - 1;
classWriter.pool.putByteArray( this.b,
off,
this.header - off );
classWriter.items = items2;
classWriter.threshold = (int) (0.75d * ll);
classWriter.index = ll;
}
/**
* Constructs a new {@link ClassReader} object.
*
* @param is an input stream from which to read the class.
* @throws IOException if a problem occurs during reading.
*/
public ClassReader(final InputStream is) throws IOException {
this( readClass( is ) );
}
/**
* Constructs a new {@link ClassReader} object.
*
* @param name the fully qualified name of the class to be read.
* @throws IOException if an exception occurs during reading.
*/
public ClassReader(final String name) throws IOException {
this( ClassLoader.getSystemResourceAsStream( name.replace( '.',
'/' ) + ".class" ) );
}
/**
* Reads the bytecode of a class.
*
* @param is an input stream from which to read the class.
* @return the bytecode read from the given input stream.
* @throws IOException if a problem occurs during reading.
*/
private static byte[] readClass(final InputStream is) throws IOException {
if ( is == null ) {
throw new IOException( "Class not found" );
}
byte[] b = new byte[is.available()];
int len = 0;
while ( true ) {
final int n = is.read( b,
len,
b.length - len );
if ( n == -1 ) {
if ( len < b.length ) {
final byte[] c = new byte[len];
System.arraycopy( b,
0,
c,
0,
len );
b = c;
}
return b;
}
len += n;
if ( len == b.length ) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -