📄 classwriter.java
字号:
if (sourceFile != null) { newUTF8("SourceFile"); this.sourceFile = newUTF8(sourceFile); } if ((access & Constants.ACC_DEPRECATED) != 0) { newUTF8("Deprecated"); } } 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.put2(name == null ? 0 : newClass(name).index); innerClasses.put2(outerName == null ? 0 : newClass(outerName).index); innerClasses.put2(innerName == null ? 0 : newUTF8(innerName).index); innerClasses.put2(access); } public void visitField ( final int access, final String name, final String desc, final Object value) { ++fieldCount; if (fields == null) { fields = new ByteVector(); } fields.put2(access).put2(newUTF8(name).index).put2(newUTF8(desc).index); int attributeCount = 0; if (value != null) { ++attributeCount; } if ((access & Constants.ACC_SYNTHETIC) != 0) { ++attributeCount; } if ((access & Constants.ACC_DEPRECATED) != 0) { ++attributeCount; } fields.put2(attributeCount); if (value != null) { fields.put2(newUTF8("ConstantValue").index); fields.put4(2).put2(newCst(value).index); } if ((access & Constants.ACC_SYNTHETIC) != 0) { fields.put2(newUTF8("Synthetic").index).put4(0); } if ((access & Constants.ACC_DEPRECATED) != 0) { fields.put2(newUTF8("Deprecated").index).put4(0); } } public CodeVisitor visitMethod ( final int access, final String name, final String desc, final String[] exceptions) { CodeWriter cw = new CodeWriter(this, computeMaxs); cw.init(access, name, desc, exceptions); return cw; } 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; } size += pool.length; int attributeCount = 0; if (sourceFile != null) { ++attributeCount; size += 8; } if ((access & Constants.ACC_DEPRECATED) != 0) { ++attributeCount; size += 6; } if (innerClasses != null) { ++attributeCount; size += 8 + innerClasses.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.put4(0xCAFEBABE).put2(3).put2(45); out.put2(index).putByteArray(pool.data, 0, pool.length); out.put2(access).put2(name).put2(superName); out.put2(interfaceCount); for (int i = 0; i < interfaceCount; ++i) { out.put2(interfaces[i]); } out.put2(fieldCount); if (fields != null) { out.putByteArray(fields.data, 0, fields.length); } out.put2(nbMethods); cb = firstMethod; while (cb != null) { cb.put(out); cb = cb.next; } out.put2(attributeCount); if (sourceFile != null) { out.put2(newUTF8("SourceFile").index).put4(2).put2(sourceFile.index); } if ((access & Constants.ACC_DEPRECATED) != 0) { out.put2(newUTF8("Deprecated").index).put4(0); } if (innerClasses != null) { out.put2(newUTF8("InnerClasses").index); out.put4(innerClasses.length + 2).put2(innerClassesCount); out.putByteArray(innerClasses.data, 0, innerClasses.length); } 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} or a {@link String String}. * @return a new or already existing constant item with the given value. */ Item newCst (final Object cst) { if (cst instanceof Integer) { int val = ((Integer)cst).intValue(); return newInteger(val); } else if (cst instanceof Float) { float val = ((Float)cst).floatValue(); return newFloat(val); } else if (cst instanceof Long) { long val = ((Long)cst).longValue(); return newLong(val); } else if (cst instanceof Double) { double val = ((Double)cst).doubleValue(); return newDouble(val); } else if (cst instanceof String) { return newString((String)cst); } else { throw new IllegalArgumentException("value " + cst); } } /** * Adds an UTF string to the constant pool of the class being build. Does * nothing if the constant pool already contains a similar item. * * @param value the String value. * @return a new or already existing UTF8 item. */ Item newUTF8 (final String value) { key.set(UTF8, value, null, null); Item result = get(key); if (result == null) { pool.put1(UTF8).putUTF(value); result = new Item(index++, key); put(result); } return result; } /** * Adds a class reference to the constant pool of the class being build. Does * nothing if the constant pool already contains a similar item. * * @param value the internal name of the class. * @return a new or already existing class reference item. */ Item newClass (final String value) { key2.set(CLASS, value, null, null); Item result = get(key2); if (result == null) { pool.put12(CLASS, newUTF8(value).index); result = new Item(index++, key2); put(result); } return result; } /** * Adds a field reference to the constant pool of the class being build. Does * nothing if the constant pool already contains a similar item. * * @param owner the internal name of the field's owner class. * @param name the field's name. * @param desc the field's descriptor. * @return a new or already existing field reference item. */ Item newField ( final String owner, final String name, final String desc) { key3.set(FIELD, owner, name, desc); Item result = get(key3); if (result == null) { put122(FIELD, newClass(owner).index, newNameType(name, desc).index); result = new Item(index++, key3); put(result); } return result; } /** * Adds a method reference to the constant pool of the class being build. Does * nothing if the constant pool already contains a similar item. * * @param owner the internal name of the method's owner class. * @param name the method's name. * @param desc the method's descriptor. * @return a new or already existing method reference item. */ Item newMethod ( final String owner, final String name, final String desc) { key3.set(METH, owner, name, desc); Item result = get(key3); if (result == null) { put122(METH, newClass(owner).index, newNameType(name, desc).index); result = new Item(index++, key3); put(result); } return result; } /** * Adds an interface method reference to the constant pool of the class being * build. Does nothing if the constant pool already contains a similar item. * * @param ownerItf the internal name of the method's owner interface. * @param name the method's name. * @param desc the method's descriptor. * @return a new or already existing interface method reference item. */ Item newItfMethod ( final String ownerItf, final String name, final String desc) { key3.set(IMETH, ownerItf, name, desc); Item result = get(key3); if (result == null) { put122(IMETH, newClass(ownerItf).index, newNameType(name, desc).index); result = new Item(index++, key3); put(result); } return result; } /** * Adds an integer to the constant pool of the class being build. Does nothing * if the constant pool already contains a similar item. * * @param value the int value. * @return a new or already existing int item. */ private Item newInteger (final int value) { key.set(value); Item result = get(key); if (result == null) { pool.put1(INT).put4(value); result = new Item(index++, key); put(result); } return result; } /** * Adds a float to the constant pool of the class being build. Does nothing if * the constant pool already contains a similar item. * * @param value the float value. * @return a new or already existing float item. */ private Item newFloat (final float value) { key.set(value); Item result = get(key); if (result == null) { pool.put1(FLOAT).put4(Float.floatToIntBits(value)); result = new Item(index++, key); put(result); } return result; } /** * Adds a long to the constant pool of the class being build. Does nothing if * the constant pool already contains a similar item. * * @param value the long value. * @return a new or already existing long item. */ private Item newLong (final long value) { key.set(value); Item result = get(key); if (result == null) { pool.put1(LONG).put8(value); result = new Item(index, key); put(result); index += 2; } return result; } /** * Adds a double to the constant pool of the class being build. Does nothing * if the constant pool already contains a similar item. * * @param value the double value. * @return a new or already existing double item. */ private Item newDouble (final double value) { key.set(value); Item result = get(key); if (result == null) { pool.put1(DOUBLE).put8(Double.doubleToLongBits(value)); result = new Item(index, key); put(result); index += 2; } return result; } /** * Adds a string to the constant pool of the class being build. Does nothing * if the constant pool already contains a similar item. * * @param value the String value. * @return a new or already existing string item. */ private Item newString (final String value) { key2.set(STR, value, null, null); Item result = get(key2); if (result == null) { pool.put12(STR, newUTF8(value).index); result = new Item(index++, key2); put(result); } return result; } /** * Adds a name and type to the constant pool of the class being build. Does * nothing if the constant pool already contains a similar item. * * @param name a name. * @param desc a type descriptor. * @return a new or already existing name and type item. */ private Item newNameType (final String name, final String desc) { key2.set(NAME_TYPE, name, desc, null); Item result = get(key2); if (result == null) { put122(NAME_TYPE, newUTF8(name).index, newUTF8(desc).index); result = new Item(index++, key2); put(result); } return result; } /** * Returns the constant pool's hash table item which is equal to the given * item. * * @param key a constant pool item. * @return the constant pool's hash table item which is equal to the given * item, or <tt>null</tt> if there is no such item. */ private Item get (final Item key) { Item tab[] = table; int hashCode = key.hashCode; int index = (hashCode & 0x7FFFFFFF) % tab.length; for (Item i = tab[index]; i != null; i = i.next) { if (i.hashCode == hashCode && key.isEqualTo(i)) { return i; } } return null; } /** * Puts the given item in the constant pool's hash table. The hash table * <i>must</i> not already contains this item. * * @param i the item to be added to the constant pool's hash table. */ private void put (final Item i) { if (index > threshold) { int oldCapacity = table.length; Item oldMap[] = table; int newCapacity = oldCapacity * 2 + 1; Item newMap[] = new Item[newCapacity]; threshold = (int)(newCapacity * 0.75); table = newMap; for (int j = oldCapacity; j-- > 0; ) { for (Item old = oldMap[j]; old != null; ) { Item e = old; old = old.next; int index = (e.hashCode & 0x7FFFFFFF) % newCapacity; e.next = newMap[index]; newMap[index] = e; } } } int index = (i.hashCode & 0x7FFFFFFF) % table.length; i.next = table[index]; table[index] = i; } /** * Puts one byte and two shorts into the constant pool. * * @param b a byte. * @param s1 a short. * @param s2 another short. */ private void put122 (final int b, final int s1, final int s2) { pool.put12(b, s1).put2(s2); }}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -