📄 classwriter.java
字号:
//
// // LABEL(W)_INSN instructions
// for (i = Constants.IFEQ; i <= Constants.JSR; ++i) {
// b[i] = LABEL_INSN;
// }
// b[Constants.IFNULL] = LABEL_INSN;
// b[Constants.IFNONNULL] = LABEL_INSN;
// b[200] = LABELW_INSN; // GOTO_W
// b[201] = LABELW_INSN; // JSR_W
// // temporary opcodes used internally by ASM - see Label and
// MethodWriter
// for (i = 202; i < 220; ++i) {
// b[i] = LABEL_INSN;
// }
//
// // LDC(_W) instructions
// b[Constants.LDC] = LDC_INSN;
// b[19] = LDCW_INSN; // LDC_W
// b[20] = LDCW_INSN; // LDC2_W
//
// // special instructions
// b[Constants.IINC] = IINC_INSN;
// b[Constants.TABLESWITCH] = TABL_INSN;
// b[Constants.LOOKUPSWITCH] = LOOK_INSN;
// b[Constants.MULTIANEWARRAY] = MANA_INSN;
// b[196] = WIDE_INSN; // WIDE
//
// for (i = 0; i < b.length; ++i) {
// System.err.print((char)('A' + b[i]));
// }
// System.err.println();
}
// ------------------------------------------------------------------------
// Constructor
// ------------------------------------------------------------------------
/**
* Constructs a new {@link ClassWriter ClassWriter} object.
*
* @param computeMaxs <tt>true</tt> if the maximum stack size and the
* maximum number of local variables must be automatically computed.
* If this flag is <tt>true</tt>, then the arguments of the
* {@link MethodVisitor#visitMaxs visitMaxs} method of the
* {@link MethodVisitor} returned by the
* {@link #visitMethod visitMethod} method will be ignored, and
* computed automatically from the signature and the bytecode of each
* method.
*/
public ClassWriter(final boolean computeMaxs) {
this( computeMaxs,
false );
}
/**
* Constructs a new {@link ClassWriter} object.
*
* @param computeMaxs <tt>true</tt> if the maximum stack size and the
* maximum number of local variables must be automatically computed.
* If this flag is <tt>true</tt>, then the arguments of the
* {@link MethodVisitor#visitMaxs visitMaxs} method of the
* {@link MethodVisitor} returned by the
* {@link #visitMethod visitMethod} method will be ignored, and
* computed automatically from the signature and the bytecode of each
* method.
* @param skipUnknownAttributes <b>Deprecated</b>. The value of this
* parameter is ignored.
*/
public ClassWriter(final boolean computeMaxs,
final boolean skipUnknownAttributes) {
this.index = 1;
this.pool = new ByteVector();
this.items = new Item[256];
this.threshold = (int) (0.75d * this.items.length);
this.key = new Item();
this.key2 = new Item();
this.key3 = new Item();
this.computeMaxs = computeMaxs;
}
/**
* Constructs a new {@link ClassWriter} object and enables optimizations for
* "mostly add" bytecode transformations. These optimizations are the
* following:
*
* <ul> <li>The constant pool from the original class is copied as is in
* the new class, which saves time. New constant pool entries will be added
* at the end if necessary, but unused constant pool entries <i>won't be
* removed</i>.</li> <li>Methods that are not transformed are copied as
* is in the new class, directly from the original class bytecode (i.e.
* without emitting visit events for all the method instructions), which
* saves a <i>lot</i> of time. Untransformed methods are detected by the
* fact that the {@link ClassReader} receives {@link MethodVisitor} objects
* that come from a {@link ClassWriter} (and not from a custom
* {@link ClassAdapter} or any other {@link ClassVisitor} instance).</li>
* </ul>
*
* @param classReader the {@link ClassReader} used to read the original
* class. It will be used to copy the entire constant pool from the
* original class and also to copy other fragments of original
* bytecode where applicable.
* @param computeMaxs <tt>true</tt> if the maximum stack size and the
* maximum number of local variables must be automatically computed.
* If this flag is <tt>true</tt>, then the arguments of the
* {@link MethodVisitor#visitMaxs visitMaxs} method of the
* {@link MethodVisitor} returned by the
* {@link #visitMethod visitMethod} method will be ignored, and
* computed automatically from the signature and the bytecode of each
* method.
*/
public ClassWriter(final ClassReader classReader,
final boolean computeMaxs) {
this( computeMaxs,
false );
classReader.copyPool( this );
this.cr = classReader;
}
// ------------------------------------------------------------------------
// Implementation of the ClassVisitor interface
// ------------------------------------------------------------------------
public void visit(final int version,
final int access,
final String name,
final String signature,
final String superName,
final String[] interfaces) {
this.version = version;
this.access = access;
this.name = newClass( name );
if ( signature != null ) {
this.signature = newUTF8( signature );
}
this.superName = superName == null ? 0 : newClass( superName );
if ( interfaces != null && interfaces.length > 0 ) {
this.interfaceCount = interfaces.length;
this.interfaces = new int[this.interfaceCount];
for ( int i = 0; i < this.interfaceCount; ++i ) {
this.interfaces[i] = newClass( interfaces[i] );
}
}
}
public void visitSource(final String file,
final String debug) {
if ( file != null ) {
this.sourceFile = newUTF8( file );
}
if ( debug != null ) {
this.sourceDebug = new ByteVector().putUTF8( debug );
}
}
public void visitOuterClass(final String owner,
final String name,
final String desc) {
this.enclosingMethodOwner = newClass( owner );
if ( name != null && desc != null ) {
this.enclosingMethod = newNameType( name,
desc );
}
}
public AnnotationVisitor visitAnnotation(final String desc,
final boolean visible) {
final ByteVector bv = new ByteVector();
// write type, and reserve space for values count
bv.putShort( newUTF8( desc ) ).putShort( 0 );
final AnnotationWriter aw = new AnnotationWriter( this,
true,
bv,
bv,
2 );
if ( visible ) {
aw.next = this.anns;
this.anns = aw;
} else {
aw.next = this.ianns;
this.ianns = aw;
}
return aw;
}
public void visitAttribute(final Attribute attr) {
attr.next = this.attrs;
this.attrs = attr;
}
public void visitInnerClass(final String name,
final String outerName,
final String innerName,
final int access) {
if ( this.innerClasses == null ) {
this.innerClasses = new ByteVector();
}
++this.innerClassesCount;
this.innerClasses.putShort( name == null ? 0 : newClass( name ) );
this.innerClasses.putShort( outerName == null ? 0 : newClass( outerName ) );
this.innerClasses.putShort( innerName == null ? 0 : newUTF8( innerName ) );
this.innerClasses.putShort( access );
}
public FieldVisitor visitField(final int access,
final String name,
final String desc,
final String signature,
final Object value) {
return new FieldWriter( this,
access,
name,
desc,
signature,
value );
}
public MethodVisitor visitMethod(final int access,
final String name,
final String desc,
final String signature,
final String[] exceptions) {
return new MethodWriter( this,
access,
name,
desc,
signature,
exceptions,
this.computeMaxs );
}
public void visitEnd() {
}
// ------------------------------------------------------------------------
// Other public methods
// ------------------------------------------------------------------------
/**
* Returns the bytecode of the class that was build with this class writer.
*
* @return the bytecode of the class that was build with this class writer.
*/
public byte[] toByteArray() {
// computes the real size of the bytecode of this class
int size = 24 + 2 * this.interfaceCount;
int nbFields = 0;
FieldWriter fb = this.firstField;
while ( fb != null ) {
++nbFields;
size += fb.getSize();
fb = fb.next;
}
int nbMethods = 0;
MethodWriter mb = this.firstMethod;
while ( mb != null ) {
++nbMethods;
size += mb.getSize();
mb = mb.next;
}
int attributeCount = 0;
if ( this.signature != 0 ) {
++attributeCount;
size += 8;
newUTF8( "Signature" );
}
if ( this.sourceFile != 0 ) {
++attributeCount;
size += 8;
newUTF8( "SourceFile" );
}
if ( this.sourceDebug != null ) {
++attributeCount;
size += this.sourceDebug.length + 4;
newUTF8( "SourceDebugExtension" );
}
if ( this.enclosingMethodOwner != 0 ) {
++attributeCount;
size += 10;
newUTF8( "EnclosingMethod" );
}
if ( (this.access & Opcodes.ACC_DEPRECATED) != 0 ) {
++attributeCount;
size += 6;
newUTF8( "Deprecated" );
}
if ( (this.access & Opcodes.ACC_SYNTHETIC) != 0 && (this.version & 0xffff) < Opcodes.V1_5 ) {
++attributeCount;
size += 6;
newUTF8( "Synthetic" );
}
if ( this.version == Opcodes.V1_4 ) {
if ( (this.access & Opcodes.ACC_ANNOTATION) != 0 ) {
++attributeCount;
size += 6;
newUTF8( "Annotation" );
}
if ( (this.access & Opcodes.ACC_ENUM) != 0 ) {
++attributeCount;
size += 6;
newUTF8( "Enum" );
}
}
if ( this.innerClasses != null ) {
++attributeCount;
size += 8 + this.innerClasses.length;
newUTF8( "InnerClasses" );
}
if ( this.anns != null ) {
++attributeCount;
size += 8 + this.anns.getSize();
newUTF8( "RuntimeVisibleAnnotations" );
}
if ( this.ianns != null ) {
++attributeCount;
size += 8 + this.ianns.getSize();
newUTF8( "RuntimeInvisibleAnnotations" );
}
if ( this.attrs != null ) {
attributeCount += this.attrs.getCount();
size += this.attrs.getSize( this,
null,
0,
-1,
-1 );
}
size += this.pool.length;
// allocates a byte vector of this size, in order to avoid unnecessary
// arraycopy operations in the ByteVector.enlarge() method
final ByteVector out = new ByteVector( size );
out.putInt( 0xCAFEBABE ).putInt( this.version );
out.putShort( this.index ).putByteArray( this.pool.data,
0,
this.pool.length );
out.putShort( this.access ).putShort( this.name ).putShort( this.superName );
out.putShort( this.interfaceCount );
for ( int i = 0; i < this.interfaceCount; ++i ) {
out.putShort( this.interfaces[i] );
}
out.putShort( nbFields );
fb = this.firstField;
while ( fb != null ) {
fb.put( out );
fb = fb.next;
}
out.putShort( nbMethods );
mb = this.firstMethod;
while ( mb != null ) {
mb.put( out );
mb = mb.next;
}
out.putShort( attributeCount );
if ( this.signature != 0 ) {
out.putShort( newUTF8( "Signature" ) ).putInt( 2 ).putShort( this.signature );
}
if ( this.sourceFile != 0 ) {
out.putShort( newUTF8( "SourceFile" ) ).putInt( 2 ).putShort( this.sourceFile );
}
if ( this.sourceDebug != null ) {
final int len = this.sourceDebug.length - 2;
out.putShort( newUTF8( "SourceDebugExtension" ) ).putInt( len );
out.putByteArray( this.sourceDebug.data,
2,
len );
}
if ( this.enclosingMethodOwner != 0 ) {
out.putShort( newUTF8( "EnclosingMethod" ) ).putInt( 4 );
out.putShort( this.enclosingMethodOwner ).putShort( this.enclosingMethod );
}
if ( (this.access & Opcodes.ACC_DEPRECATED) != 0 ) {
out.putShort( newUTF8( "Deprecated" ) ).putInt( 0 );
}
if ( (this.access & Opcodes.ACC_SYNTHETIC) != 0 && (this.version & 0xffff) < Opcodes.V1_5 ) {
out.putShort( newUTF8( "Synthetic" ) ).putInt( 0 );
}
if ( this.version == Opcodes.V1_4 ) {
if ( (this.access & Opcodes.ACC_ANNOTATION) != 0 ) {
out.putShort( newUTF8( "Annotation" ) ).putInt( 0 );
}
if ( (this.access & Opcodes.ACC_ENUM) != 0 ) {
out.putShort( newUTF8( "Enum" ) ).putInt( 0 );
}
}
if ( this.innerClasses != null ) {
out.putShort( newUTF8( "InnerClasses" ) );
out.putInt( this.innerClasses.length + 2 ).putShort( this.innerClassesCount );
out.putByteArray( this.innerClasses.data,
0,
this.innerClasses.length );
}
if ( this.anns != null ) {
out.putShort( newUTF8( "RuntimeVisibleAnnotations" ) );
this.anns.put( out );
}
if ( this.ianns != null ) {
out.putShort( newUTF8( "RuntimeInvisibleAnnotations" ) );
this.ianns.put( out );
}
if ( this.attrs != null ) {
this.attrs.put( this,
null,
0,
-1,
-1,
out );
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -