📄 classwriter.java
字号:
// --------------------------------------------------------------------------
/**
* Computes the instruction types of JVM opcodes.
*/
static {
int i;
byte[] b = new byte[220];
String s =
"AAAAAAAAAAAAAAAABCKLLDDDDDEEEEEEEEEEEEEEEEEEEEAAAAAAAADDDDDEEEEEEEEE" +
"EEEEEEEEEEEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMAAA" +
"AAAAAAAAAAAAAAAAAIIIIIIIIIIIIIIIIDNOAAAAAAGGGGGGGHAFBFAAFFAAQPIIJJII" +
"IIIIIIIIIIIIIIII";
for (i = 0; i < b.length; ++i) {
b[i] = (byte)(s.charAt(i) - 'A');
}
TYPE = b;
/* code to generate the above string
// SBYTE_INSN instructions
b[Constants.NEWARRAY] = SBYTE_INSN;
b[Constants.BIPUSH] = SBYTE_INSN;
// SHORT_INSN instructions
b[Constants.SIPUSH] = SHORT_INSN;
// (IMPL)VAR_INSN instructions
b[Constants.RET] = VAR_INSN;
for (i = Constants.ILOAD; i <= Constants.ALOAD; ++i) {
b[i] = VAR_INSN;
}
for (i = Constants.ISTORE; i <= Constants.ASTORE; ++i) {
b[i] = VAR_INSN;
}
for (i = 26; i <= 45; ++i) { // ILOAD_0 to ALOAD_3
b[i] = IMPLVAR_INSN;
}
for (i = 59; i <= 78; ++i) { // ISTORE_0 to ASTORE_3
b[i] = IMPLVAR_INSN;
}
// TYPE_INSN instructions
b[Constants.NEW] = TYPE_INSN;
b[Constants.ANEWARRAY] = TYPE_INSN;
b[Constants.CHECKCAST] = TYPE_INSN;
b[Constants.INSTANCEOF] = TYPE_INSN;
// (Set)FIELDORMETH_INSN instructions
for (i = Constants.GETSTATIC; i <= Constants.INVOKESTATIC; ++i) {
b[i] = FIELDORMETH_INSN;
}
b[Constants.INVOKEINTERFACE] = ITFMETH_INSN;
// 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 CodeWriter
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
* CodeVisitor#visitMaxs visitMaxs} method of the {@link CodeVisitor
* CodeVisitor} 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 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
* CodeVisitor#visitMaxs visitMaxs} method of the {@link CodeVisitor
* CodeVisitor} returned by the {@link #visitMethod visitMethod} method
* will be ignored, and computed automatically from the signature and
* the bytecode of each method.
* @param skipUnknownAttributes <tt>true</tt> to silently ignore unknown
* attributes, or <tt>false</tt> to throw an exception if an unknown
* attribute is found.
*/
public ClassWriter (
final boolean computeMaxs,
final boolean skipUnknownAttributes)
{
index = 1;
pool = new ByteVector();
items = new Item[64];
threshold = (int)(0.75d*items.length);
key = new Item();
key2 = new Item();
key3 = new Item();
this.computeMaxs = computeMaxs;
this.checkAttributes = !skipUnknownAttributes;
}
// --------------------------------------------------------------------------
// Implementation of the ClassVisitor interface
// --------------------------------------------------------------------------
public void visit (
final int version,
final int access,
final String name,
final String superName,
final String[] interfaces,
final String sourceFile)
{
this.version = version;
this.access = access;
this.name = newClass(name);
this.superName = superName == null ? 0 : newClass(superName);
if (interfaces != null && interfaces.length > 0) {
interfaceCount = interfaces.length;
this.interfaces = new int[interfaceCount];
for (int i = 0; i < interfaceCount; ++i) {
this.interfaces[i] = newClass(interfaces[i]);
}
}
if (sourceFile != null) {
newUTF8("SourceFile");
this.sourceFile = newUTF8(sourceFile);
}
if ((access & Constants.ACC_DEPRECATED) != 0) {
newUTF8("Deprecated");
}
if ((access & Constants.ACC_SYNTHETIC) != 0) {
newUTF8("Synthetic");
}
}
public void visitInnerClass (
final String name,
final String outerName,
final String innerName,
final int access)
{
if (innerClasses == null) {
newUTF8("InnerClasses");
innerClasses = new ByteVector();
}
++innerClassesCount;
innerClasses.putShort(name == null ? 0 : newClass(name));
innerClasses.putShort(outerName == null ? 0 : newClass(outerName));
innerClasses.putShort(innerName == null ? 0 : newUTF8(innerName));
innerClasses.putShort(access);
}
public void visitField (
final int access,
final String name,
final String desc,
final Object value,
final Attribute attrs)
{
++fieldCount;
if (fields == null) {
fields = new ByteVector();
}
fields.putShort(access).putShort(newUTF8(name)).putShort(newUTF8(desc));
int attributeCount = 0;
if (value != null) {
++attributeCount;
}
if ((access & Constants.ACC_SYNTHETIC) != 0) {
++attributeCount;
}
if ((access & Constants.ACC_DEPRECATED) != 0) {
++attributeCount;
}
if (attrs != null) {
attributeCount += attrs.getCount();
}
fields.putShort(attributeCount);
if (value != null) {
fields.putShort(newUTF8("ConstantValue"));
fields.putInt(2).putShort(newConstItem(value).index);
}
if ((access & Constants.ACC_SYNTHETIC) != 0) {
fields.putShort(newUTF8("Synthetic")).putInt(0);
}
if ((access & Constants.ACC_DEPRECATED) != 0) {
fields.putShort(newUTF8("Deprecated")).putInt(0);
}
if (attrs != null) {
attrs.put(this, null, 0, -1, -1, fields);
}
}
public CodeVisitor visitMethod (
final int access,
final String name,
final String desc,
final String[] exceptions,
final Attribute attrs)
{
CodeWriter cw = new CodeWriter(this, computeMaxs);
cw.init(access, name, desc, exceptions, attrs);
return cw;
}
public void visitAttribute (final Attribute attr) {
attr.next = attrs;
attrs = attr;
}
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*interfaceCount;
if (fields != null) {
size += fields.length;
}
int nbMethods = 0;
CodeWriter cb = firstMethod;
while (cb != null) {
++nbMethods;
size += cb.getSize();
cb = cb.next;
}
int attributeCount = 0;
if (sourceFile != 0) {
++attributeCount;
size += 8;
}
if ((access & Constants.ACC_DEPRECATED) != 0) {
++attributeCount;
size += 6;
}
if ((access & Constants.ACC_SYNTHETIC) != 0) {
++attributeCount;
size += 6;
}
if (innerClasses != null) {
++attributeCount;
size += 8 + innerClasses.length;
}
if (attrs != null) {
attributeCount += attrs.getCount();
size += attrs.getSize(this, null, 0, -1, -1);
}
size += pool.length;
// allocates a byte vector of this size, in order to avoid unnecessary
// arraycopy operations in the ByteVector.enlarge() method
ByteVector out = new ByteVector(size);
out.putInt(0xCAFEBABE).putInt(version);
out.putShort(index).putByteArray(pool.data, 0, pool.length);
out.putShort(access).putShort(name).putShort(superName);
out.putShort(interfaceCount);
for (int i = 0; i < interfaceCount; ++i) {
out.putShort(interfaces[i]);
}
out.putShort(fieldCount);
if (fields != null) {
out.putByteArray(fields.data, 0, fields.length);
}
out.putShort(nbMethods);
cb = firstMethod;
while (cb != null) {
cb.put(out);
cb = cb.next;
}
out.putShort(attributeCount);
if (sourceFile != 0) {
out.putShort(newUTF8("SourceFile")).putInt(2).putShort(sourceFile);
}
if ((access & Constants.ACC_DEPRECATED) != 0) {
out.putShort(newUTF8("Deprecated")).putInt(0);
}
if ((access & Constants.ACC_SYNTHETIC) != 0) {
out.putShort(newUTF8("Synthetic")).putInt(0);
}
if (innerClasses != null) {
out.putShort(newUTF8("InnerClasses"));
out.putInt(innerClasses.length + 2).putShort(innerClassesCount);
out.putByteArray(innerClasses.data, 0, innerClasses.length);
}
if (attrs != null) {
attrs.put(this, null, 0, -1, -1, out);
}
return out.data;
}
// --------------------------------------------------------------------------
// Utility methods: constant pool management
// --------------------------------------------------------------------------
/**
* Adds a number or string constant to the constant pool of the class being
* build. Does nothing if the constant pool already contains a similar item.
*
* @param cst the value of the constant to be added to the constant pool. This
* parameter must be an {@link java.lang.Integer Integer}, a {@link
* java.lang.Float Float}, a {@link java.lang.Long Long}, a {@link
* java.lang.Double Double}, a {@link String String} or a {@link Type}.
* @return a new or already existing constant item with the given value.
*/
Item newConstItem (final Object cst) {
if (cst instanceof Integer) {
int val = ((Integer)cst).intValue();
return newInteger(val);
} else if (cst instanceof Byte) {
int val = ((Byte)cst).intValue();
return newInteger(val);
} else if (cst instanceof Character) {
int val = ((Character)cst).charValue();
return newInteger(val);
} else if (cst instanceof Short) {
int val = ((Short)cst).intValue();
return newInteger(val);
} else if (cst instanceof Boolean) {
int val = ((Boolean)cst).booleanValue() ? 1 : 0;
return newInteger(val);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -