All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.feilong.lib.javassist.bytecode.Bytecode Maven / Gradle / Ivy

Go to download

feilong is a suite of core and expanded libraries that include utility classes, http, excel,cvs, io classes, and much much more.

There is a newer version: 4.0.8
Show newest version
/*
 * Javassist, a Java-bytecode translator toolkit.
 * Copyright (C) 1999- Shigeru Chiba. All Rights Reserved.
 *
 * 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.  Alternatively, the contents of this file may be used under
 * the terms of the GNU Lesser General Public License Version 2.1 or later,
 * or the Apache License Version 2.0.
 *
 * 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.
 */

package com.feilong.lib.javassist.bytecode;

import com.feilong.lib.javassist.CtClass;
import com.feilong.lib.javassist.CtPrimitiveType;

class ByteVector implements Cloneable{

    private byte[] buffer;

    private int    size;

    public ByteVector(){
        buffer = new byte[64];
        size = 0;
    }

    @Override
    public Object clone() throws CloneNotSupportedException{
        ByteVector bv = (ByteVector) super.clone();
        bv.buffer = buffer.clone();
        return bv;
    }

    public final int getSize(){
        return size;
    }

    public final byte[] copy(){
        byte[] b = new byte[size];
        System.arraycopy(buffer, 0, b, 0, size);
        return b;
    }

    public int read(int offset){
        if (offset < 0 || size <= offset){
            throw new ArrayIndexOutOfBoundsException(offset);
        }

        return buffer[offset];
    }

    public void write(int offset,int value){
        if (offset < 0 || size <= offset){
            throw new ArrayIndexOutOfBoundsException(offset);
        }

        buffer[offset] = (byte) value;
    }

    public void add(int code){
        addGap(1);
        buffer[size - 1] = (byte) code;
    }

    public void add(int b1,int b2){
        addGap(2);
        buffer[size - 2] = (byte) b1;
        buffer[size - 1] = (byte) b2;
    }

    public void add(int b1,int b2,int b3,int b4){
        addGap(4);
        buffer[size - 4] = (byte) b1;
        buffer[size - 3] = (byte) b2;
        buffer[size - 2] = (byte) b3;
        buffer[size - 1] = (byte) b4;
    }

    public void addGap(int length){
        if (size + length > buffer.length){
            int newSize = size << 1;
            if (newSize < size + length){
                newSize = size + length;
            }

            byte[] newBuf = new byte[newSize];
            System.arraycopy(buffer, 0, newBuf, 0, size);
            buffer = newBuf;
        }

        size += length;
    }
}

/**
 * A utility class for producing a bytecode sequence.
 *
 * 

* A Bytecode object is an unbounded array * containing bytecode. For example, * *

 * ConstPool cp = ...;    // constant pool table
 * Bytecode b = new Bytecode(cp, 1, 0);
 * b.addIconst(3);
 * b.addReturn(CtClass.intType);
 * CodeAttribute ca = b.toCodeAttribute();
 * 
* *

* This program produces a Code attribute including a bytecode * sequence: * *

 * iconst_3
 * ireturn
 * 
* * @see ConstPool * @see CodeAttribute */ public class Bytecode extends ByteVector implements Cloneable,Opcode{ /** * Represents the CtClass file using the * constant pool table given to this Bytecode object. */ public static final CtClass THIS = ConstPool.THIS; ConstPool constPool; int maxStack, maxLocals; ExceptionTable tryblocks; private int stackDepth; /** * Constructs a Bytecode object with an empty bytecode * sequence. * *

* The parameters stacksize and localvars * specify initial values * of max_stack and max_locals. * They can be changed later. * * @param cp * constant pool table. * @param stacksize * max_stack. * @param localvars * max_locals. */ public Bytecode(ConstPool cp, int stacksize, int localvars){ constPool = cp; maxStack = stacksize; maxLocals = localvars; tryblocks = new ExceptionTable(cp); stackDepth = 0; } /** * Constructs a Bytecode object with an empty bytecode * sequence. The initial values of max_stack and * max_locals are zero. * * @param cp * constant pool table. * @see Bytecode#setMaxStack(int) * @see Bytecode#setMaxLocals(int) */ public Bytecode(ConstPool cp){ this(cp, 0, 0); } /** * Creates and returns a copy of this object. * The constant pool object is shared between this object * and the cloned object. */ @Override public Object clone(){ try{ Bytecode bc = (Bytecode) super.clone(); bc.tryblocks = (ExceptionTable) tryblocks.clone(); return bc; }catch (CloneNotSupportedException cnse){ throw new RuntimeException(cnse); } } /** * Gets a constant pool table. */ public ConstPool getConstPool(){ return constPool; } /** * Returns exception_table. */ public ExceptionTable getExceptionTable(){ return tryblocks; } /** * Converts to a CodeAttribute. */ public CodeAttribute toCodeAttribute(){ return new CodeAttribute(constPool, maxStack, maxLocals, get(), tryblocks); } /** * Returns the length of the bytecode sequence. */ public int length(){ return getSize(); } /** * Returns the produced bytecode sequence. */ public byte[] get(){ return copy(); } /** * Gets max_stack. */ public int getMaxStack(){ return maxStack; } /** * Sets max_stack. * *

* This value may be automatically updated when an instruction * is appended. A Bytecode object maintains the current * stack depth whenever an instruction is added * by addOpcode(). For example, if DUP is appended, * the current stack depth is increased by one. If the new stack * depth is more than max_stack, then it is assigned * to max_stack. 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 max_locals. */ public int getMaxLocals(){ return maxLocals; } /** * Sets max_locals. */ public void setMaxLocals(int size){ maxLocals = size; } /** * Sets max_locals. * *

* This computes the number of local variables * used to pass method parameters and sets max_locals * to that number plus locals. * * @param isStatic * true if params 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 max_locals. */ public void incMaxLocals(int diff){ maxLocals += diff; } /** * Adds a new entry of exception_table. */ public void addExceptionHandler(int start,int end,int handler,CtClass type){ addExceptionHandler(start, end, handler, constPool.addClassInfo(type)); } /** * Adds a new entry of exception_table. * * @param type * the fully-qualified name of a throwable class. */ public void addExceptionHandler(int start,int end,int handler,String type){ addExceptionHandler(start, end, handler, constPool.addClassInfo(type)); } /** * Adds a new entry of exception_table. */ 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(){ return getSize(); } /** * Reads a signed 8bit value at the offset from the beginning of the * bytecode sequence. * * @throws ArrayIndexOutOfBoundsException * if offset is invalid. */ @Override public int read(int offset){ return super.read(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); } /** * Reads a signed 32bit value at the offset from the beginning of the * bytecode sequence. */ public int read32bit(int offset){ int v1 = read16bit(offset); int v2 = read16bit(offset + 2); return (v1 << 16) + (v2 & 0xffff); } /** * Writes an 8bit value at the offset from the beginning of the * bytecode sequence. * * @throws ArrayIndexOutOfBoundsException * if offset is invalid. */ @Override public void write(int offset,int value){ super.write(offset, value); } /** * 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); } /** * Writes an 32bit value at the offset from the beginning of the * bytecode sequence. */ public void write32bit(int offset,int value){ write16bit(offset, value >> 16); write16bit(offset + 2, value); } /** * Appends an 8bit value to the end of the bytecode sequence. */ @Override public void add(int code){ super.add(code); } /** * Appends a 32bit value to the end of the bytecode sequence. */ public void add32bit(int value){ add(value >> 24, value >> 16, value >> 8, value); } /** * Appends the length-byte gap to the end of the bytecode sequence. * * @param length * the gap length in byte. */ @Override public void addGap(int length){ super.addGap(length); } /** * Appends an 8bit opcode to the end of the bytecode sequence. * The current stack depth is updated. * max_stack is updated if the current stack depth * is the deepest so far. * *

* Note: some instructions such as INVOKEVIRTUAL does not * update the current stack depth since the increment depends * on the method signature. * growStack() must be explicitly called. */ public void addOpcode(int code){ add(code); growStack(STACK_GROW[code]); } /** * Increases the current stack depth. * It also updates max_stack 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 max_stack 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, 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_ }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_ }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_ -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 an instruction for pushing zero or null on the stack. * If the type is void, this method does not append any instruction. * * @param type * the type of the zero value (or null). */ public void addConstZero(CtClass type){ if (type.isPrimitive()){ if (type == CtClass.longType){ addOpcode(LCONST_0); }else if (type == CtClass.floatType){ addOpcode(FCONST_0); }else if (type == CtClass.doubleType){ addOpcode(DCONST_0); }else if (type == CtClass.voidType){ throw new RuntimeException("void type?"); }else{ addOpcode(ICONST_0); } }else{ addOpcode(ACONST_NULL); } } /** * 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_ }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_ }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_ }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_ }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_ }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_ }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_ }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_ }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_ }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_ }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_ }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 n. * * @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 n. * * @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. * * @param offset * the index of the first parameter. It is 0 * if the method is static. Otherwise, it is 1. */ public int addLoadParameters(CtClass[] params,int offset){ int stacksize = 0; if (params != null){ int n = params.length; for (int i = 0; i < n; ++i){ stacksize += addLoad(stacksize + offset, 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 GETFIELD. * * @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 addGetfield(String 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){ boolean isInterface = clazz == null ? false : clazz.isInterface(); addInvokespecial(isInterface, constPool.addClassInfo(clazz), name, desc); } /** * Appends INVOKESPECIAL. The invoked method must not be a default * method declared in an interface. * * @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(false, constPool.addClassInfo(clazz), name, desc); } /** * Appends INVOKESPECIAL. The invoked method must not be a default * method declared in an interface. * * @param clazz * the index of CONSTANT_Class_info * 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){ addInvokespecial(false, clazz, name, desc); } /** * Appends INVOKESPECIAL. * * @param isInterface * true if the invoked method is a default method * declared in an interface. * @param clazz * the index of CONSTANT_Class_info * 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(boolean isInterface,int clazz,String name,String desc){ int index; if (isInterface){ index = constPool.addInterfaceMethodrefInfo(clazz, name, desc); }else{ index = constPool.addMethodrefInfo(clazz, name, desc); } addInvokespecial(index, desc); } /** * Appends INVOKESPECIAL. * * @param index * the index of CONSTANT_Methodref_info * or CONSTANT_InterfaceMethodref_info * @param desc * the descriptor of the method signature. * * @see Descriptor#ofMethod(CtClass,CtClass[]) * @see Descriptor#ofConstructor(CtClass[]) */ public void addInvokespecial(int index,String desc){ add(INVOKESPECIAL); addIndex(index); 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){ boolean isInterface; if (clazz == THIS){ isInterface = false; }else{ isInterface = clazz.isInterface(); } addInvokestatic(constPool.addClassInfo(clazz), name, desc, isInterface); } /** * Appends INVOKESTATIC. * * @param classname * the fully-qualified class name. * It must not be an interface-type 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 CONSTANT_Class_info * structure. It must not be an interface type. * @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){ addInvokestatic(clazz, name, desc, false); } private void addInvokestatic(int clazz,String name,String desc,boolean isInterface){ add(INVOKESTATIC); int index; if (isInterface){ index = constPool.addInterfaceMethodrefInfo(clazz, name, desc); }else{ index = constPool.addMethodrefInfo(clazz, name, desc); } addIndex(index); growStack(Descriptor.dataSize(desc)); } /** * Appends INVOKEVIRTUAL. * *

* The specified method must not be an inherited method. * It must be directly declared in the class specified * in clazz. * * @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. * *

* The specified method must not be an inherited method. * It must be directly declared in the class specified * in clazz. * * @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. * *

* The specified method must not be an inherited method. * It must be directly declared in the class specified * in classname. * * @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. * *

* The specified method must not be an inherited method. * It must be directly declared in the class specified * by clazz. * * @param clazz * the index of CONSTANT_Class_info * 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 CONSTANT_Class_info * 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 INVOKEDYNAMIC. * * @param bootstrap * an index into the bootstrap_methods array * of the bootstrap method table. * @param name * the method name. * @param desc * the method descriptor. * @see Descriptor#ofMethod(CtClass,CtClass[]) * @since 3.17 */ public void addInvokedynamic(int bootstrap,String name,String desc){ int nt = constPool.addNameAndTypeInfo(name, desc); int dyn = constPool.addInvokeDynamicInfo(bootstrap, nt); add(INVOKEDYNAMIC); addIndex(dyn); add(0, 0); growStack(Descriptor.dataSize(desc)); // assume ConstPool#REF_invokeStatic } /** * Appends LDC or LDC_W. The pushed item is a String * 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 * T_BOOLEAN, T_CHAR, ... * @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 dimensions. */ 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 dim. */ 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 dim. */ 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){ addPutfield0(c, null, name, desc); } /** * Appends PUTFIELD. * * @param classname * the fully-qualified name of the target class. * @param name * the field name. * @param desc * the descriptor of the field type. */ public void addPutfield(String classname,String name,String desc){ // if classnaem is null, the target class is THIS. addPutfield0(null, classname, name, desc); } private void addPutfield0(CtClass target,String classname,String name,String desc){ add(PUTFIELD); // target is null if it represents THIS. int ci = classname == null ? constPool.addClassInfo(target) : constPool.addClassInfo(classname); 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){ addPutstatic0(c, null, name, desc); } /** * Appends PUTSTATIC. * * @param classname * the fully-qualified name of the target class. * @param fieldName * the field name. * @param desc * the descriptor of the field type. */ public void addPutstatic(String classname,String fieldName,String desc){ // if classname is null, the target class is THIS. addPutstatic0(null, classname, fieldName, desc); } private void addPutstatic0(CtClass target,String classname,String fieldName,String desc){ add(PUTSTATIC); // target is null if it represents THIS. int ci = classname == null ? constPool.addClassInfo(target) : constPool.addClassInfo(classname); addIndex(constPool.addFieldrefInfo(ci, fieldName, 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 * java.lang.System.println(message). * * @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"); } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy