diff options
Diffstat (limited to 'src/main/javassist/bytecode/Bytecode.java')
-rw-r--r-- | src/main/javassist/bytecode/Bytecode.java | 1262 |
1 files changed, 1262 insertions, 0 deletions
diff --git a/src/main/javassist/bytecode/Bytecode.java b/src/main/javassist/bytecode/Bytecode.java new file mode 100644 index 00000000..f903e4be --- /dev/null +++ b/src/main/javassist/bytecode/Bytecode.java @@ -0,0 +1,1262 @@ +/* + * This file is part of the Javassist toolkit. + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * either http://www.mozilla.org/MPL/. + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + * the License for the specific language governing rights and limitations + * under the License. + * + * The Original Code is Javassist. + * + * The Initial Developer of the Original Code is Shigeru Chiba. Portions + * created by Shigeru Chiba are Copyright (C) 1999-2003 Shigeru Chiba. + * All Rights Reserved. + * + * Contributor(s): + * + * The development of this software is supported in part by the PRESTO + * program (Sakigake Kenkyu 21) of Japan Science and Technology Corporation. + */ + +package javassist.bytecode; + +import java.io.DataOutputStream; +import java.io.IOException; +import javassist.CannotCompileException; +import javassist.CtClass; +import javassist.CtPrimitiveType; + +/** + * A utility class for producing a bytecode sequence. + * + * <p>A <code>Bytecode</code> object is an unbounded array + * containing bytecode. For example, + * + * <ul><pre>ConstPool cp = ...; // constant pool table + * Bytecode b = new Bytecode(cp, 1, 0); + * b.addIconst(3); + * b.addReturn(CtClass.intType); + * CodeAttribute ca = b.toCodeAttribute();</ul></pre> + * + * <p>This program produces a Code attribute including a bytecode + * sequence: + * + * <ul><pre>iconst_3 + * ireturn</pre></ul> + * + * @see ConstPool + * @see CodeAttribute + */ +public class Bytecode implements Opcode { + /** + * Represents the <code>CtClass</code> file using the + * constant pool table given to this <code>Bytecode</code> object. + */ + public static final CtClass THIS = ConstPool.THIS; + + static final int bufsize = 64; + ConstPool constPool; + int maxStack, maxLocals; + ExceptionTable tryblocks; + Bytecode next; + byte[] buffer; + int num; + + private int stackDepth; + + /** + * Constructs a <code>Bytecode</code> object with an empty bytecode + * sequence. + * + * <p>The parameters <code>stacksize</code> and <code>localvars</code> + * specify initial values + * of <code>max_stack</code> and <code>max_locals</code>. + * They can be changed later. + * + * @param cp constant pool table. + * @param stacksize <code>max_stack</code>. + * @param localvars <code>max_locals</code>. + */ + public Bytecode(ConstPool cp, int stacksize, int localvars) { + this(); + constPool = cp; + maxStack = stacksize; + maxLocals = localvars; + tryblocks = new ExceptionTable(cp); + stackDepth = 0; + } + + /* used in add(). + */ + private Bytecode() { + buffer = new byte[bufsize]; + num = 0; + next = null; + } + + /** + * Gets a constant pool table. + */ + public ConstPool getConstPool() { return constPool; } + + /** + * Returns <code>exception_table</code>. + */ + public ExceptionTable getExceptionTable() { return tryblocks; } + + /** + * Converts to a <code>CodeAttribute</code>. + */ + public CodeAttribute toCodeAttribute() { + return new CodeAttribute(constPool, maxStack, maxLocals, + get(), tryblocks); + } + + /** + * Returns the length of the bytecode sequence. + */ + public int length() { + int len = 0; + Bytecode b = this; + while (b != null) { + len += b.num; + b = b.next; + } + + return len; + } + + private void copy(byte[] dest, int index) { + Bytecode b = this; + while (b != null) { + System.arraycopy(b.buffer, 0, dest, index, b.num); + index += b.num; + b = b.next; + } + } + + /** + * Returns the produced bytecode sequence. + */ + public byte[] get() { + byte[] b = new byte[length()]; + copy(b, 0); + return b; + } + + /** + * Gets <code>max_stack</code>. + */ + public int getMaxStack() { return maxStack; } + + /** + * Sets <code>max_stack</code>. + * + * <p>This value may be automatically updated when an instruction + * is appended. A <code>Bytecode</code> object maintains the current + * stack depth whenever an instruction is added + * by <code>addOpcode()</code>. For example, if DUP is appended, + * the current stack depth is increased by one. If the new stack + * depth is more than <code>max_stack</code>, then it is assigned + * to <code>max_stack</code>. However, if branch instructions are + * appended, the current stack depth may not be correctly maintained. + * + * @see #addOpcode(int) + */ + public void setMaxStack(int size) { + maxStack = size; + } + + /** + * Gets <code>max_locals</code>. + */ + public int getMaxLocals() { return maxLocals; } + + /** + * Sets <code>max_locals</code>. + */ + public void setMaxLocals(int size) { + maxLocals = size; + } + + /** + * Sets <code>max_locals</code>. + * + * <p>This computes the number of local variables + * used to pass method parameters and sets <code>max_locals</code> + * to that number plus <code>locals</code>. + * + * @param isStatic true if <code>params</code> must be + * interpreted as parameters to a static method. + * @param params parameter types. + * @param locals the number of local variables excluding + * ones used to pass parameters. + */ + public void setMaxLocals(boolean isStatic, CtClass[] params, + int locals) { + if (!isStatic) + ++locals; + + if (params != null) { + CtClass doubleType = CtClass.doubleType; + CtClass longType = CtClass.longType; + int n = params.length; + for (int i = 0; i < n; ++i) { + CtClass type = params[i]; + if (type == doubleType || type == longType) + locals += 2; + else + ++locals; + } + } + + maxLocals = locals; + } + + /** + * Increments <code>max_locals</code>. + */ + public void incMaxLocals(int diff) { + maxLocals += diff; + } + + /** + * Adds a new entry of <code>exception_table</code>. + */ + public void addExceptionHandler(int start, int end, + int handler, CtClass type) { + addExceptionHandler(start, end, handler, + constPool.addClassInfo(type)); + } + + /** + * Adds a new entry of <code>exception_table</code>. + */ + public void addExceptionHandler(int start, int end, + int handler, int type) { + tryblocks.add(start, end, handler, type); + } + + /** + * Returns the length of bytecode sequence + * that have been added so far. + */ + public int currentPc() { + int n = 0; + Bytecode b = this; + while (b != null) { + n += b.num; + b = b.next; + } + + return n; + } + + /** + * Reads a signed 8bit value at the offset from the beginning of the + * bytecode sequence. + * + * @throws ArrayIndexOutOfBoundsException if offset is invalid. + */ + public int read(int offset) { + if (offset < 0) + return Opcode.NOP; + else if (offset < num) + return buffer[offset]; + else + try { + return next.read(offset - num); + } + catch (NullPointerException e) { + throw new ArrayIndexOutOfBoundsException(offset); + } + } + + /** + * Reads a signed 16bit value at the offset from the beginning of the + * bytecode sequence. + */ + public int read16bit(int offset) { + int v1 = read(offset); + int v2 = read(offset + 1); + return (v1 << 8) + (v2 & 0xff); + } + + /** + * Writes an 8bit value at the offset from the beginning of the + * bytecode sequence. + * + * @throws ArrayIndexOutOfBoundsException if offset is invalid. + */ + public void write(int offset, int value) { + if (offset < num) + buffer[offset] = (byte)value; + else + try { + next.write(offset - num, value); + } + catch (NullPointerException e) { + throw new ArrayIndexOutOfBoundsException(offset); + } + } + + /** + * Writes an 16bit value at the offset from the beginning of the + * bytecode sequence. + */ + public void write16bit(int offset, int value) { + write(offset, value >>> 8); + write(offset + 1, value); + } + + /** + * Appends an 8bit value to the end of the bytecode sequence. + */ + public void add(int code) { + if (num < bufsize) + buffer[num++] = (byte)code; + else { + if (next == null) + next = new Bytecode(); + + next.add(code); + } + } + + /** + * Appends an 8bit opcode to the end of the bytecode sequence. + * The current stack depth is updated. + * <code>max_stack</code> is updated if the current stack depth + * is the deepest so far. + * + * <p>Note: some instructions such as INVOKEVIRTUAL does not + * update the current stack depth since the increment depends + * on the method signature. + * <code>growStack()</code> must be explicitly called. + */ + public void addOpcode(int code) { + add(code); + growStack(STACK_GROW[code]); + } + + /** + * Increases the current stack depth. + * It also updates <code>max_stack</code> if the current stack depth + * is the deepest so far. + * + * @param diff the number added to the current stack depth. + */ + public void growStack(int diff) { + setStackDepth(stackDepth + diff); + } + + /** + * Returns the current stack depth. + */ + public int getStackDepth() { return stackDepth; } + + /** + * Sets the current stack depth. + * It also updates <code>max_stack</code> if the current stack depth + * is the deepest so far. + * + * @param depth new value. + */ + public void setStackDepth(int depth) { + stackDepth = depth; + if (stackDepth > maxStack) + maxStack = stackDepth; + } + + /** + * Appends a 16bit value to the end of the bytecode sequence. + * It never changes the current stack depth. + */ + public void addIndex(int index) { + add(index >> 8); + add(index); + } + + /** + * Appends ALOAD or (WIDE) ALOAD_<n> + * + * @param n an index into the local variable array. + */ + public void addAload(int n) { + if (n < 4) + addOpcode(42 + n); // aload_<n> + else if (n < 0x100) { + addOpcode(ALOAD); // aload + add(n); + } + else { + addOpcode(WIDE); + addOpcode(ALOAD); + addIndex(n); + } + } + + /** + * Appends ASTORE or (WIDE) ASTORE_<n> + * + * @param n an index into the local variable array. + */ + public void addAstore(int n) { + if (n < 4) + addOpcode(75 + n); // astore_<n> + else if (n < 0x100) { + addOpcode(ASTORE); // astore + add(n); + } + else { + addOpcode(WIDE); + addOpcode(ASTORE); + addIndex(n); + } + } + + /** + * Appends ICONST or ICONST_<n> + * + * @param n the pushed integer constant. + */ + public void addIconst(int n) { + if (n < 6 && -2 < n) + addOpcode(3 + n); // iconst_<i> -1..5 + else if (n <= 127 && -128 <= n) { + addOpcode(16); // bipush + add(n); + } + else if (n <= 32767 && -32768 <= n) { + addOpcode(17); // sipush + add(n >> 8); + add(n); + } + else + addLdc(constPool.addIntegerInfo(n)); + } + + /** + * Appends ILOAD or (WIDE) ILOAD_<n> + * + * @param n an index into the local variable array. + */ + public void addIload(int n) { + if (n < 4) + addOpcode(26 + n); // iload_<n> + else if (n < 0x100) { + addOpcode(ILOAD); // iload + add(n); + } + else { + addOpcode(WIDE); + addOpcode(ILOAD); + addIndex(n); + } + } + + /** + * Appends ISTORE or (WIDE) ISTORE_<n> + * + * @param n an index into the local variable array. + */ + public void addIstore(int n) { + if (n < 4) + addOpcode(59 + n); // istore_<n> + else if (n < 0x100) { + addOpcode(ISTORE); // istore + add(n); + } + else { + addOpcode(WIDE); + addOpcode(ISTORE); + addIndex(n); + } + } + + /** + * Appends LCONST or LCONST_<n> + * + * @param n the pushed long integer constant. + */ + public void addLconst(long n) { + if (n == 0 || n == 1) + addOpcode(9 + (int)n); // lconst_<n> + else + addLdc2w(n); + } + + /** + * Appends LLOAD or (WIDE) LLOAD_<n> + * + * @param n an index into the local variable array. + */ + public void addLload(int n) { + if (n < 4) + addOpcode(30 + n); // lload_<n> + else if (n < 0x100) { + addOpcode(LLOAD); // lload + add(n); + } + else { + addOpcode(WIDE); + addOpcode(LLOAD); + addIndex(n); + } + } + + /** + * Appends LSTORE or LSTORE_<n> + * + * @param n an index into the local variable array. + */ + public void addLstore(int n) { + if (n < 4) + addOpcode(63 + n); // lstore_<n> + else if (n < 0x100) { + addOpcode(LSTORE); // lstore + add(n); + } + else { + addOpcode(WIDE); + addOpcode(LSTORE); + addIndex(n); + } + } + + /** + * Appends DCONST or DCONST_<n> + * + * @param d the pushed double constant. + */ + public void addDconst(double d) { + if (d == 0.0 || d == 1.0) + addOpcode(14 + (int)d); // dconst_<n> + else + addLdc2w(d); + } + + /** + * Appends DLOAD or (WIDE) DLOAD_<n> + * + * @param n an index into the local variable array. + */ + public void addDload(int n) { + if (n < 4) + addOpcode(38 + n); // dload_<n> + else if (n < 0x100) { + addOpcode(DLOAD); // dload + add(n); + } + else { + addOpcode(WIDE); + addOpcode(DLOAD); + addIndex(n); + } + } + + /** + * Appends DSTORE or (WIDE) DSTORE_<n> + * + * @param n an index into the local variable array. + */ + public void addDstore(int n) { + if (n < 4) + addOpcode(71 + n); // dstore_<n> + else if (n < 0x100) { + addOpcode(DSTORE); // dstore + add(n); + } + else { + addOpcode(WIDE); + addOpcode(DSTORE); + addIndex(n); + } + } + + /** + * Appends FCONST or FCONST_<n> + * + * @param f the pushed float constant. + */ + public void addFconst(float f) { + if (f == 0.0f || f == 1.0f || f == 2.0f) + addOpcode(11 + (int)f); // fconst_<n> + else + addLdc(constPool.addFloatInfo(f)); + } + + /** + * Appends FLOAD or (WIDE) FLOAD_<n> + * + * @param n an index into the local variable array. + */ + public void addFload(int n) { + if (n < 4) + addOpcode(34 + n); // fload_<n> + else if (n < 0x100) { + addOpcode(FLOAD); // fload + add(n); + } + else { + addOpcode(WIDE); + addOpcode(FLOAD); + addIndex(n); + } + } + + /** + * Appends FSTORE or FSTORE_<n> + * + * @param n an index into the local variable array. + */ + public void addFstore(int n) { + if (n < 4) + addOpcode(67 + n); // fstore_<n> + else if (n < 0x100) { + addOpcode(FSTORE); // fstore + add(n); + } + else { + addOpcode(WIDE); + addOpcode(FSTORE); + addIndex(n); + } + } + + /** + * Appends an instruction for loading a value from the + * local variable at the index <code>n</code>. + * + * @param n the index. + * @param type the type of the loaded value. + * @return the size of the value (1 or 2 word). + */ + public int addLoad(int n, CtClass type) { + if (type.isPrimitive()) { + if (type == CtClass.booleanType || type == CtClass.charType + || type == CtClass.byteType || type == CtClass.shortType + || type == CtClass.intType) + addIload(n); + else if (type == CtClass.longType) { + addLload(n); + return 2; + } + else if(type == CtClass.floatType) + addFload(n); + else if(type == CtClass.doubleType) { + addDload(n); + return 2; + } + else + throw new RuntimeException("void type?"); + } + else + addAload(n); + + return 1; + } + + /** + * Appends an instruction for storing a value into the + * local variable at the index <code>n</code>. + * + * @param n the index. + * @param type the type of the stored value. + * @return 2 if the type is long or double. Otherwise 1. + */ + public int addStore(int n, CtClass type) { + if (type.isPrimitive()) { + if (type == CtClass.booleanType || type == CtClass.charType + || type == CtClass.byteType || type == CtClass.shortType + || type == CtClass.intType) + addIstore(n); + else if (type == CtClass.longType) { + addLstore(n); + return 2; + } + else if(type == CtClass.floatType) + addFstore(n); + else if(type == CtClass.doubleType) { + addDstore(n); + return 2; + } + else + throw new RuntimeException("void type?"); + } + else + addAstore(n); + + return 1; + } + + /** + * Appends instructions for loading all the parameters onto the + * operand stack. + */ + public int addLoadParameters(CtClass[] params) { + int stacksize = 0; + if (params != null) { + int n = params.length; + for (int i = 0; i < n; ++i) + stacksize += addLoad(stacksize + 1, params[i]); + } + + return stacksize; + } + + /** + * Appends CHECKCAST. + * + * @param c the type. + */ + public void addCheckcast(CtClass c) { + addOpcode(CHECKCAST); + addIndex(constPool.addClassInfo(c)); + } + + /** + * Appends CHECKCAST. + * + * @param classname a fully-qualified class name. + */ + public void addCheckcast(String classname) { + addOpcode(CHECKCAST); + addIndex(constPool.addClassInfo(classname)); + } + + /** + * Appends INSTANCEOF. + * + * @param classname the class name. + */ + public void addInstanceof(String classname) { + addOpcode(INSTANCEOF); + addIndex(constPool.addClassInfo(classname)); + } + + /** + * Appends GETFIELD. + * + * @param c the class + * @param name the field name + * @param type the descriptor of the field type. + * + * @see Descriptor#of(CtClass) + */ + public void addGetfield(CtClass c, String name, String type) { + add(GETFIELD); + int ci = constPool.addClassInfo(c); + addIndex(constPool.addFieldrefInfo(ci, name, type)); + growStack(Descriptor.dataSize(type) - 1); + } + + /** + * Appends GETSTATIC. + * + * @param c the class + * @param name the field name + * @param type the descriptor of the field type. + * + * @see Descriptor#of(CtClass) + */ + public void addGetstatic(CtClass c, String name, String type) { + add(GETSTATIC); + int ci = constPool.addClassInfo(c); + addIndex(constPool.addFieldrefInfo(ci, name, type)); + growStack(Descriptor.dataSize(type)); + } + + /** + * Appends GETSTATIC. + * + * @param c the fully-qualified class name + * @param name the field name + * @param type the descriptor of the field type. + * + * @see Descriptor#of(CtClass) + */ + public void addGetstatic(String c, String name, String type) { + add(GETSTATIC); + int ci = constPool.addClassInfo(c); + addIndex(constPool.addFieldrefInfo(ci, name, type)); + growStack(Descriptor.dataSize(type)); + } + + /** + * Appends INVOKESPECIAL. + * + * @param clazz the target class. + * @param name the method name. + * @param returnType the return type. + * @param paramTypes the parameter types. + */ + public void addInvokespecial(CtClass clazz, String name, + CtClass returnType, CtClass[] paramTypes) { + String desc = Descriptor.ofMethod(returnType, paramTypes); + addInvokespecial(clazz, name, desc); + } + + /** + * Appends INVOKESPECIAL. + * + * @param clazz the target class. + * @param name the method name + * @param desc the descriptor of the method signature. + * + * @see Descriptor#ofMethod(CtClass,CtClass[]) + * @see Descriptor#ofConstructor(CtClass[]) + */ + public void addInvokespecial(CtClass clazz, String name, String desc) { + addInvokespecial(constPool.addClassInfo(clazz), name, desc); + } + + /** + * Appends INVOKESPECIAL. + * + * @param clazz the fully-qualified class name. + * @param name the method name + * @param desc the descriptor of the method signature. + * + * @see Descriptor#ofMethod(CtClass,CtClass[]) + * @see Descriptor#ofConstructor(CtClass[]) + */ + public void addInvokespecial(String clazz, String name, String desc) { + addInvokespecial(constPool.addClassInfo(clazz), name, desc); + } + + /** + * Appends INVOKESPECIAL. + * + * @param clazz the index of <code>CONSTANT_Class_info</code> + * structure. + * @param name the method name + * @param desc the descriptor of the method signature. + * + * @see Descriptor#ofMethod(CtClass,CtClass[]) + * @see Descriptor#ofConstructor(CtClass[]) + */ + public void addInvokespecial(int clazz, String name, String desc) { + add(INVOKESPECIAL); + addIndex(constPool.addMethodrefInfo(clazz, name, desc)); + growStack(Descriptor.dataSize(desc) - 1); + } + + /** + * Appends INVOKESTATIC. + * + * @param clazz the target class. + * @param name the method name + * @param returnType the return type. + * @param paramTypes the parameter types. + */ + public void addInvokestatic(CtClass clazz, String name, + CtClass returnType, CtClass[] paramTypes) { + String desc = Descriptor.ofMethod(returnType, paramTypes); + addInvokestatic(clazz, name, desc); + } + + /** + * Appends INVOKESTATIC. + * + * @param clazz the target class. + * @param name the method name + * @param desc the descriptor of the method signature. + * + * @see Descriptor#ofMethod(CtClass,CtClass[]) + */ + public void addInvokestatic(CtClass clazz, String name, String desc) { + addInvokestatic(constPool.addClassInfo(clazz), name, desc); + } + + /** + * Appends INVOKESTATIC. + * + * @param classname the fully-qualified class name. + * @param name the method name + * @param desc the descriptor of the method signature. + * + * @see Descriptor#ofMethod(CtClass,CtClass[]) + */ + public void addInvokestatic(String classname, String name, String desc) { + addInvokestatic(constPool.addClassInfo(classname), name, desc); + } + + /** + * Appends INVOKESTATIC. + * + * @param clazz the index of <code>CONSTANT_Class_info</code> + * structure. + * @param name the method name + * @param desc the descriptor of the method signature. + * + * @see Descriptor#ofMethod(CtClass,CtClass[]) + */ + public void addInvokestatic(int clazz, String name, String desc) { + add(INVOKESTATIC); + addIndex(constPool.addMethodrefInfo(clazz, name, desc)); + growStack(Descriptor.dataSize(desc)); + } + + /** + * Appends INVOKEVIRTUAL. + * + * <p>The specified method must not be an inherited method. + * It must be directly declared in the class specified + * in <code>clazz</code>. + * + * @param clazz the target class. + * @param name the method name + * @param returnType the return type. + * @param paramTypes the parameter types. + */ + public void addInvokevirtual(CtClass clazz, String name, + CtClass returnType, CtClass[] paramTypes) { + String desc = Descriptor.ofMethod(returnType, paramTypes); + addInvokevirtual(clazz, name, desc); + } + + /** + * Appends INVOKEVIRTUAL. + * + * <p>The specified method must not be an inherited method. + * It must be directly declared in the class specified + * in <code>clazz</code>. + * + * @param clazz the target class. + * @param name the method name + * @param desc the descriptor of the method signature. + * + * @see Descriptor#ofMethod(CtClass,CtClass[]) + */ + public void addInvokevirtual(CtClass clazz, String name, String desc) { + addInvokevirtual(constPool.addClassInfo(clazz), name, desc); + } + + /** + * Appends INVOKEVIRTUAL. + * + * <p>The specified method must not be an inherited method. + * It must be directly declared in the class specified + * in <code>classname</code>. + * + * @param classname the fully-qualified class name. + * @param name the method name + * @param desc the descriptor of the method signature. + * + * @see Descriptor#ofMethod(CtClass,CtClass[]) + */ + public void addInvokevirtual(String classname, String name, String desc) { + addInvokevirtual(constPool.addClassInfo(classname), name, desc); + } + + /** + * Appends INVOKEVIRTUAL. + * + * <p>The specified method must not be an inherited method. + * It must be directly declared in the class specified + * by <code>clazz</code>. + * + * @param clazz the index of <code>CONSTANT_Class_info</code> + * structure. + * @param name the method name + * @param desc the descriptor of the method signature. + * + * @see Descriptor#ofMethod(CtClass,CtClass[]) + */ + public void addInvokevirtual(int clazz, String name, String desc) { + add(INVOKEVIRTUAL); + addIndex(constPool.addMethodrefInfo(clazz, name, desc)); + growStack(Descriptor.dataSize(desc) - 1); + } + + /** + * Appends INVOKEINTERFACE. + * + * @param clazz the target class. + * @param name the method name + * @param returnType the return type. + * @param paramTypes the parameter types. + * @param count the count operand of the instruction. + */ + public void addInvokeinterface(CtClass clazz, String name, + CtClass returnType, CtClass[] paramTypes, + int count) { + String desc = Descriptor.ofMethod(returnType, paramTypes); + addInvokeinterface(clazz, name, desc, count); + } + + /** + * Appends INVOKEINTERFACE. + * + * @param clazz the target class. + * @param name the method name + * @param desc the descriptor of the method signature. + * @param count the count operand of the instruction. + * + * @see Descriptor#ofMethod(CtClass,CtClass[]) + */ + public void addInvokeinterface(CtClass clazz, String name, + String desc, int count) { + addInvokeinterface(constPool.addClassInfo(clazz), name, desc, + count); + } + + /** + * Appends INVOKEINTERFACE. + * + * @param classname the fully-qualified class name. + * @param name the method name + * @param desc the descriptor of the method signature. + * @param count the count operand of the instruction. + * + * @see Descriptor#ofMethod(CtClass,CtClass[]) + */ + public void addInvokeinterface(String classname, String name, + String desc, int count) { + addInvokeinterface(constPool.addClassInfo(classname), name, desc, + count); + } + + /** + * Appends INVOKEINTERFACE. + * + * @param clazz the index of <code>CONSTANT_Class_info</code> + * structure. + * @param name the method name + * @param desc the descriptor of the method signature. + * @param count the count operand of the instruction. + * + * @see Descriptor#ofMethod(CtClass,CtClass[]) + */ + public void addInvokeinterface(int clazz, String name, + String desc, int count) { + add(INVOKEINTERFACE); + addIndex(constPool.addInterfaceMethodrefInfo(clazz, name, desc)); + add(count); + add(0); + growStack(Descriptor.dataSize(desc) - 1); + } + + /** + * Appends LDC or LDC_W. The pushed item is a <code>String</code> + * object. + * + * @param s the character string pushed by LDC or LDC_W. + */ + public void addLdc(String s) { + addLdc(constPool.addStringInfo(s)); + } + + /** + * Appends LDC or LDC_W. + * + * @param i index into the constant pool. + */ + public void addLdc(int i) { + if (i > 0xFF) { + addOpcode(LDC_W); + addIndex(i); + } + else { + addOpcode(LDC); + add(i); + } + } + + /** + * Appends LDC2_W. The pushed item is a long value. + */ + public void addLdc2w(long l) { + addOpcode(LDC2_W); + addIndex(constPool.addLongInfo(l)); + } + + /** + * Appends LDC2_W. The pushed item is a double value. + */ + public void addLdc2w(double d) { + addOpcode(LDC2_W); + addIndex(constPool.addDoubleInfo(d)); + } + + /** + * Appends NEW. + * + * @param clazz the class of the created instance. + */ + public void addNew(CtClass clazz) { + addOpcode(NEW); + addIndex(constPool.addClassInfo(clazz)); + } + + /** + * Appends NEW. + * + * @param classname the fully-qualified class name. + */ + public void addNew(String classname) { + addOpcode(NEW); + addIndex(constPool.addClassInfo(classname)); + } + + /** + * Appends ANEWARRAY. + * + * @param classname the qualified class name of the element type. + */ + public void addAnewarray(String classname) { + addOpcode(ANEWARRAY); + addIndex(constPool.addClassInfo(classname)); + } + + /** + * Appends ICONST and ANEWARRAY. + * + * @param clazz the elememnt type. + * @param length the array length. + */ + public void addAnewarray(CtClass clazz, int length) { + addIconst(length); + addOpcode(ANEWARRAY); + addIndex(constPool.addClassInfo(clazz)); + } + + /** + * Appends NEWARRAY for primitive types. + * + * @param atype <code>T_BOOLEAN</code>, <code>T_CHAR</code>, ... + * @see Opcode + */ + public void addNewarray(int atype, int length) { + addIconst(length); + addOpcode(NEWARRAY); + add(atype); + } + + /** + * Appends MULTINEWARRAY. + * + * @param clazz the array type. + * @param dimensions the sizes of all dimensions. + * @return the length of <code>dimensions</code>. + */ + public int addMultiNewarray(CtClass clazz, int[] dimensions) { + int len = dimensions.length; + for (int i = 0; i < len; ++i) + addIconst(dimensions[i]); + + growStack(len); + return addMultiNewarray(clazz, len); + } + + /** + * Appends MULTINEWARRAY. The size of every dimension must have been + * already pushed on the stack. + * + * @param clazz the array type. + * @param dim the number of the dimensions. + * @return the value of <code>dim</code>. + */ + public int addMultiNewarray(CtClass clazz, int dim) { + add(MULTIANEWARRAY); + addIndex(constPool.addClassInfo(clazz)); + add(dim); + growStack(1 - dim); + return dim; + } + + /** + * Appends MULTINEWARRAY. + * + * @param desc the type descriptor of the created array. + * @param dim dimensions. + * @return the value of <code>dim</code>. + */ + public int addMultiNewarray(String desc, int dim) { + add(MULTIANEWARRAY); + addIndex(constPool.addClassInfo(desc)); + add(dim); + growStack(1 - dim); + return dim; + } + + /** + * Appends PUTFIELD. + * + * @param c the target class. + * @param name the field name. + * @param desc the descriptor of the field type. + */ + public void addPutfield(CtClass c, String name, String desc) { + add(PUTFIELD); + int ci = constPool.addClassInfo(c); + addIndex(constPool.addFieldrefInfo(ci, name, desc)); + growStack(-1 - Descriptor.dataSize(desc)); + } + + /** + * Appends PUTSTATIC. + * + * @param c the target class. + * @param name the field name. + * @param desc the descriptor of the field type. + */ + public void addPutstatic(CtClass c, String name, String desc) { + add(PUTSTATIC); + int ci = constPool.addClassInfo(c); + addIndex(constPool.addFieldrefInfo(ci, name, desc)); + growStack(-Descriptor.dataSize(desc)); + } + + /** + * Appends ARETURN, IRETURN, .., or RETURN. + * + * @param type the return type. + */ + public void addReturn(CtClass type) { + if (type == null) + addOpcode(RETURN); + else if (type.isPrimitive()) { + CtPrimitiveType ptype = (CtPrimitiveType)type; + addOpcode(ptype.getReturnOp()); + } + else + addOpcode(ARETURN); + } + + /** + * Appends RET. + * + * @param var local variable + */ + public void addRet(int var) { + if (var < 0x100) { + addOpcode(RET); + add(var); + } + else { + addOpcode(WIDE); + addOpcode(RET); + addIndex(var); + } + } + + /** + * Appends instructions for executing + * <code>java.lang.System.println(<i>message</i>)</code>. + * + * @param message printed message. + */ + public void addPrintln(String message) { + addGetstatic("java.lang.System", "err", "Ljava/io/PrintStream;"); + addLdc(message); + addInvokevirtual("java.io.PrintStream", + "println", "(Ljava/lang/String;)V"); + } +} |