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

proguard.classfile.editor.InstructionSequenceBuilder Maven / Gradle / Ivy

Go to download

ProGuardCORE is a free library to read, analyze, modify, and write Java class files.

There is a newer version: 9.1.6
Show newest version
/*
 * ProGuardCORE -- library to process Java bytecode.
 *
 * Copyright (c) 2002-2020 Guardsquare NV
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package proguard.classfile.editor;

import proguard.classfile.*;
import proguard.classfile.constant.Constant;
import proguard.classfile.instruction.*;
import proguard.classfile.util.ClassUtil;
import proguard.resources.file.ResourceFile;

import java.util.*;

/**
 * This utility class allows to construct sequences of instructions and
 * their constants.
 *
 * @author Eric Lafortune
 */
public class InstructionSequenceBuilder
{
    private final ConstantPoolEditor constantPoolEditor;

    private final List instructions = new ArrayList(256);


    /**
     * Creates a new InstructionSequenceBuilder.
     */
    public InstructionSequenceBuilder()
    {
        this(null, null);
    }


    /**
     * Creates a new InstructionSequenceBuilder that automatically initializes
     * class references and class member references in new constants.
     * @param programClassPool the program class pool from which new
     *                         constants can be initialized.
     * @param libraryClassPool the library class pool from which new
     *                         constants can be initialized.
     */
    public InstructionSequenceBuilder(ClassPool programClassPool,
                                      ClassPool libraryClassPool)
    {
        this(new MyDummyClass(),
             programClassPool,
             libraryClassPool);
    }


    /**
     * Creates a new InstructionSequenceBuilder.
     * @param targetClass the target class for the instruction
     *                    constants.
     */
    public InstructionSequenceBuilder(ProgramClass targetClass)
    {
        this(new ConstantPoolEditor(targetClass));
    }


    /**
     * Creates a new InstructionSequenceBuilder that automatically initializes
     * class references and class member references in new constants.
     * @param targetClass      the target class for the instruction
     *                         constants.
     * @param programClassPool the program class pool from which new
     *                         constants can be initialized.
     * @param libraryClassPool the library class pool from which new
     *                         constants can be initialized.
     */
    public InstructionSequenceBuilder(ProgramClass targetClass,
                                      ClassPool    programClassPool,
                                      ClassPool    libraryClassPool)
    {
        this(new ConstantPoolEditor(targetClass, programClassPool, libraryClassPool));
    }


    /**
     * Creates a new InstructionSequenceBuilder.
     * @param constantPoolEditor the editor to use for creating any constants
     *                           for the instructions.
     */
    public InstructionSequenceBuilder(ConstantPoolEditor constantPoolEditor)
    {
         this.constantPoolEditor = constantPoolEditor;
    }


    /**
     * Returns the ConstantPoolEditor used by this builder to
     * create constants.
     *
     * @return the ConstantPoolEditor used by this builder to
     * create constants.
     */
    public ConstantPoolEditor getConstantPoolEditor()
    {
        return constantPoolEditor;
    }


    /**
     * Short for {@link #appendInstruction(Instruction)}.
     *
     * @see InstructionSequenceReplacer#label()
     */
    public InstructionSequenceBuilder label(Instruction instruction)
    {
        return add(instruction);
    }


    /**
     * Short for {@link #appendInstruction(Instruction)}.
     *
     * @see InstructionSequenceReplacer#catch_(int,int,int)
     */
    public InstructionSequenceBuilder catch_(Instruction instruction)
    {
        return add(instruction);
    }


    /**
     * Appends the given instruction.
     * @param instruction the instruction to be appended.
     * @return the builder itself.
     */
    public InstructionSequenceBuilder appendInstruction(Instruction instruction)
    {
        return add(instruction);
    }


    /**
     * Appends the given instructions.
     * @param instructions the instructions to be appended.
     * @return the builder itself.
     */
    public InstructionSequenceBuilder appendInstructions(Instruction[] instructions)
    {
        for (Instruction instruction : instructions)
        {
            add(instruction);
        }

        return this;
    }


    /**
     * Short for {@link #instructions()}.
     */
    public Instruction[] __()
    {
        return instructions();
    }


    /**
     * Returns the accumulated sequence of instructions
     * and resets the sequence in the builder.
     */
    public Instruction[] instructions()
    {
        Instruction[] instructionsArray = new Instruction[instructions.size()];
        instructions.toArray(instructionsArray);

        instructions.clear();

        return instructionsArray;
    }


    /**
     * Returns the accumulated set of constants
     * and resets the set in the builder.
     */
    public Constant[] constants()
    {
        ProgramClass targetClass = constantPoolEditor.getTargetClass();

        Constant[] constantPool = new Constant[targetClass.u2constantPoolCount];
        System.arraycopy(targetClass.constantPool,
                         0,
                         constantPool,
                         0,
                         targetClass.u2constantPoolCount);

        targetClass.u2constantPoolCount = 0;

        return constantPool;
    }


    /**
     * Returns the number of instructions accumulated by this InstructionSequenceBuilder.
     */
    public int size()
    {
        return instructions.size();
    }


    // Methods corresponding to the bytecode opcodes.

    public InstructionSequenceBuilder nop()
    {
        return add(new SimpleInstruction(Instruction.OP_NOP));
    }

    public InstructionSequenceBuilder aconst_null()
    {
        return add(new SimpleInstruction(Instruction.OP_ACONST_NULL));
    }

    public InstructionSequenceBuilder iconst(int constant)
    {
        return add(new SimpleInstruction(Instruction.OP_ICONST_0, constant));
    }

    public InstructionSequenceBuilder iconst_m1()
    {
        return add(new SimpleInstruction(Instruction.OP_ICONST_M1));
    }

    public InstructionSequenceBuilder iconst_0()
    {
        return add(new SimpleInstruction(Instruction.OP_ICONST_0));
    }

    public InstructionSequenceBuilder iconst_1()
    {
        return add(new SimpleInstruction(Instruction.OP_ICONST_1));
    }

    public InstructionSequenceBuilder iconst_2()
    {
        return add(new SimpleInstruction(Instruction.OP_ICONST_2));
    }

    public InstructionSequenceBuilder iconst_3()
    {
        return add(new SimpleInstruction(Instruction.OP_ICONST_3));
    }

    public InstructionSequenceBuilder iconst_4()
    {
        return add(new SimpleInstruction(Instruction.OP_ICONST_4));
    }

    public InstructionSequenceBuilder iconst_5()
    {
        return add(new SimpleInstruction(Instruction.OP_ICONST_5));
    }

    public InstructionSequenceBuilder lconst(int constant)
    {
        return add(new SimpleInstruction(Instruction.OP_LCONST_0, constant));
    }

    public InstructionSequenceBuilder lconst_0()
    {
        return add(new SimpleInstruction(Instruction.OP_LCONST_0));
    }

    public InstructionSequenceBuilder lconst_1()
    {
        return add(new SimpleInstruction(Instruction.OP_LCONST_1));
    }

    public InstructionSequenceBuilder fconst(int constant)
    {
        return add(new SimpleInstruction(Instruction.OP_FCONST_0, constant));
    }

    public InstructionSequenceBuilder fconst_0()
    {
        return add(new SimpleInstruction(Instruction.OP_FCONST_0));
    }

    public InstructionSequenceBuilder fconst_1()
    {
        return add(new SimpleInstruction(Instruction.OP_FCONST_1));
    }

    public InstructionSequenceBuilder fconst_2()
    {
        return add(new SimpleInstruction(Instruction.OP_FCONST_2));
    }

    public InstructionSequenceBuilder dconst(int constant)
    {
        return add(new SimpleInstruction(Instruction.OP_DCONST_0, constant));
    }

    public InstructionSequenceBuilder dconst_0()
    {
        return add(new SimpleInstruction(Instruction.OP_DCONST_0));
    }

    public InstructionSequenceBuilder dconst_1()
    {
        return add(new SimpleInstruction(Instruction.OP_DCONST_1));
    }

    public InstructionSequenceBuilder bipush(int constant)
    {
        return add(new SimpleInstruction(Instruction.OP_BIPUSH, constant));
    }

    public InstructionSequenceBuilder sipush(int constant)
    {
        return add(new SimpleInstruction(Instruction.OP_SIPUSH, constant));
    }

    /**
     * Appends an ldc instruction that loads an integer constant with the given value.
     */
    public InstructionSequenceBuilder ldc(int value)
    {
        return ldc_(constantPoolEditor.addIntegerConstant(value));
    }

    /**
     * Appends an ldc instruction that loads a float constant with the given value.
     */
    public InstructionSequenceBuilder ldc(float value)
    {
        return ldc_(constantPoolEditor.addFloatConstant(value));
    }

    /**
     * Appends an ldc instruction that loads a string constant with the given value.
     */
    public InstructionSequenceBuilder ldc(String string)
    {
        return ldc(string, null, null);
    }

    /**
     * Appends an ldc instruction that loads an (internal) primitive array constant with the given value.
     */
    public InstructionSequenceBuilder ldc(Object primitiveArray)
    {
        return ldc_(constantPoolEditor.addPrimitiveArrayConstant(primitiveArray));
    }

    /**
     * Appends an ldc instruction that loads a string constant with the given class member name.
     */
    public InstructionSequenceBuilder ldc(Clazz  clazz,
                                          Member member)
    {
        return ldc(member.getName(clazz), clazz, member);
    }

    /**
     * Appends an ldc instruction that loads a string constant with the given value,
     * that references the given class member.
     */
    public InstructionSequenceBuilder ldc(String string,
                                          Clazz  referencedClass,
                                          Member referencedMember)
    {
        return ldc_(constantPoolEditor.addStringConstant(string, referencedClass, referencedMember));
    }

    /**
     * Appends an ldc instruction that loads a string constant with the given resource file name.
     */
    public InstructionSequenceBuilder ldc(ResourceFile resourceFile)
    {
        return ldc(resourceFile.getFileName(), resourceFile);
    }

    /**
     * Appends an ldc instruction that loads a string constant with the given value,
     * that references the given resource file.
     */
    public InstructionSequenceBuilder ldc(String       string,
                                          ResourceFile referencedResourceFile)
    {
        return ldc_(constantPoolEditor.addStringConstant(string, referencedResourceFile));
    }

    /**
     * Appends an ldc instruction that loads a class constant for the given class.
     */
    public InstructionSequenceBuilder ldc(Clazz clazz)
    {
        return ldc(clazz.getName(), clazz);
    }

    /**
     * Appends an ldc instruction that loads a class constant for the given type name,
     * that references the given class.
     */
    public InstructionSequenceBuilder ldc(String typeName,
                                          Clazz  referencedClass)
    {
        return ldc_(constantPoolEditor.addClassConstant(typeName, referencedClass));
    }

    /**
     * Appends an ldc instruction that loads the constant at the given index.
     */
    public InstructionSequenceBuilder ldc_(int constantIndex)
    {
        return appendInstruction(new ConstantInstruction(Instruction.OP_LDC, constantIndex));
    }

    /**
     * Appends an ldc_w instruction that loads an integer constant with the given value.
     */
    public InstructionSequenceBuilder ldc_w(int value)
    {
        return ldc_(constantPoolEditor.addIntegerConstant(value));
    }

    /**
     * Appends an ldc_w instruction that loads a float constant with the given value.
     */
    public InstructionSequenceBuilder ldc_w(float value)
    {
        return ldc_(constantPoolEditor.addFloatConstant(value));
    }

    /**
     * Appends an ldc_w instruction that loads a string constant with the given value.
     */
    public InstructionSequenceBuilder ldc_w(String string)
    {
        return ldc_w(string, null, null);
    }

    /**
     * Appends an ldc_w instruction that loads an (internal) primitive array constant with the given value.
     */
    public InstructionSequenceBuilder ldc_w(Object primitiveArray)
    {
        return ldc_(constantPoolEditor.addPrimitiveArrayConstant(primitiveArray));
    }

    /**
     * Appends an ldc_w instruction that loads a string constant with the given class member name.
     */
    public InstructionSequenceBuilder ldc_w(Clazz  clazz,
                                            Member member)
    {
        return ldc_w(member.getName(clazz), clazz, member);
    }

    /**
     * Appends an ldc_w instruction that loads a string constant with the given value,
     * that references the given class member.
     */
    public InstructionSequenceBuilder ldc_w(String string,
                                            Clazz  referencedClass,
                                            Member referencedMember)
    {
        return ldc_(constantPoolEditor.addStringConstant(string, referencedClass, referencedMember));
    }

    /**
     * Appends an ldc_w instruction that loads a string constant with the given resource file name.
     */
    public InstructionSequenceBuilder ldc_w(ResourceFile resourceFile)
    {
        return ldc_w(resourceFile.getFileName(), resourceFile);
    }

    /**
     * Appends an ldc_w instruction that loads a string constant with the given value,
     * that references the given resource file.
     */
    public InstructionSequenceBuilder ldc_w(String       string,
                                            ResourceFile referencedResourceFile)
    {
        return ldc_(constantPoolEditor.addStringConstant(string, referencedResourceFile));
    }

    /**
     * Appends an ldc_w instruction that loads a class constant for the given class.
     */
    public InstructionSequenceBuilder ldc_w(Clazz clazz)
    {
        return ldc_w(clazz.getName(), clazz);
    }

    /**
     * Appends an ldc_w instruction that loads a class constant for the given type name,
     * that references the given class.
     */
    public InstructionSequenceBuilder ldc_w(String typeName,
                                            Clazz  referencedClass)
    {
        return ldc_(constantPoolEditor.addClassConstant(typeName, referencedClass));
    }

    /**
     * Appends an ldc_w instruction that loads the constant at the given index.
     */
    public InstructionSequenceBuilder ldc_w_(int constantIndex)
    {
        return appendInstruction(new ConstantInstruction(Instruction.OP_LDC_W, constantIndex));
    }

    /**
     * Appends an ldc2_w instruction that loads a long constant with the given value.
     */
    public InstructionSequenceBuilder ldc2_w(long value)
    {
        return ldc2_w(constantPoolEditor.addLongConstant(value));
    }

    /**
     * Appends an ldc2_w instruction that loads a double constant with the given value.
     */
    public InstructionSequenceBuilder ldc2_w(double value)
    {
        return ldc2_w(constantPoolEditor.addDoubleConstant(value));
    }

    /**
     * Appends an ldc2_w instruction that loads the Category 2 constant at the given index.
     */
    public InstructionSequenceBuilder ldc2_w(int constantIndex)
    {
        return add(new ConstantInstruction(Instruction.OP_LDC2_W, constantIndex));
    }

    public InstructionSequenceBuilder iload(int variableIndex)
    {
        return add(new VariableInstruction(Instruction.OP_ILOAD, variableIndex));
    }

    public InstructionSequenceBuilder lload(int variableIndex)
    {
        return add(new VariableInstruction(Instruction.OP_LLOAD, variableIndex));
    }

    public InstructionSequenceBuilder fload(int variableIndex)
    {
        return add(new VariableInstruction(Instruction.OP_FLOAD, variableIndex));
    }

    public InstructionSequenceBuilder dload(int variableIndex)
    {
        return add(new VariableInstruction(Instruction.OP_DLOAD, variableIndex));
    }

    public InstructionSequenceBuilder aload(int variableIndex)
    {
        return add(new VariableInstruction(Instruction.OP_ALOAD, variableIndex));
    }

    public InstructionSequenceBuilder iload_0()
    {
        return add(new VariableInstruction(Instruction.OP_ILOAD_0));
    }

    public InstructionSequenceBuilder iload_1()
    {
        return add(new VariableInstruction(Instruction.OP_ILOAD_1));
    }

    public InstructionSequenceBuilder iload_2()
    {
        return add(new VariableInstruction(Instruction.OP_ILOAD_2));
    }

    public InstructionSequenceBuilder iload_3()
    {
        return add(new VariableInstruction(Instruction.OP_ILOAD_3));
    }

    public InstructionSequenceBuilder lload_0()
    {
        return add(new VariableInstruction(Instruction.OP_LLOAD_0));
    }

    public InstructionSequenceBuilder lload_1()
    {
        return add(new VariableInstruction(Instruction.OP_LLOAD_1));
    }

    public InstructionSequenceBuilder lload_2()
    {
        return add(new VariableInstruction(Instruction.OP_LLOAD_2));
    }

    public InstructionSequenceBuilder lload_3()
    {
        return add(new VariableInstruction(Instruction.OP_LLOAD_3));
    }

    public InstructionSequenceBuilder fload_0()
    {
        return add(new VariableInstruction(Instruction.OP_FLOAD_0));
    }

    public InstructionSequenceBuilder fload_1()
    {
        return add(new VariableInstruction(Instruction.OP_FLOAD_1));
    }

    public InstructionSequenceBuilder fload_2()
    {
        return add(new VariableInstruction(Instruction.OP_FLOAD_2));
    }

    public InstructionSequenceBuilder fload_3()
    {
        return add(new VariableInstruction(Instruction.OP_FLOAD_3));
    }

    public InstructionSequenceBuilder dload_0()
    {
        return add(new VariableInstruction(Instruction.OP_DLOAD_0));
    }

    public InstructionSequenceBuilder dload_1()
    {
        return add(new VariableInstruction(Instruction.OP_DLOAD_1));
    }

    public InstructionSequenceBuilder dload_2()
    {
        return add(new VariableInstruction(Instruction.OP_DLOAD_2));
    }

    public InstructionSequenceBuilder dload_3()
    {
        return add(new VariableInstruction(Instruction.OP_DLOAD_3));
    }

    public InstructionSequenceBuilder aload_0()
    {
        return add(new VariableInstruction(Instruction.OP_ALOAD_0));
    }

    public InstructionSequenceBuilder aload_1()
    {
        return add(new VariableInstruction(Instruction.OP_ALOAD_1));
    }

    public InstructionSequenceBuilder aload_2()
    {
        return add(new VariableInstruction(Instruction.OP_ALOAD_2));
    }

    public InstructionSequenceBuilder aload_3()
    {
        return add(new VariableInstruction(Instruction.OP_ALOAD_3));
    }

    public InstructionSequenceBuilder iaload()
    {
        return add(new SimpleInstruction(Instruction.OP_IALOAD));
    }

    public InstructionSequenceBuilder laload()
    {
        return add(new SimpleInstruction(Instruction.OP_LALOAD));
    }

    public InstructionSequenceBuilder faload()
    {
        return add(new SimpleInstruction(Instruction.OP_FALOAD));
    }

    public InstructionSequenceBuilder daload()
    {
        return add(new SimpleInstruction(Instruction.OP_DALOAD));
    }

    public InstructionSequenceBuilder aaload()
    {
        return add(new SimpleInstruction(Instruction.OP_AALOAD));
    }

    public InstructionSequenceBuilder baload()
    {
        return add(new SimpleInstruction(Instruction.OP_BALOAD));
    }

    public InstructionSequenceBuilder caload()
    {
        return add(new SimpleInstruction(Instruction.OP_CALOAD));
    }

    public InstructionSequenceBuilder saload()
    {
        return add(new SimpleInstruction(Instruction.OP_SALOAD));
    }

    public InstructionSequenceBuilder istore(int variableIndex)
    {
        return add(new VariableInstruction(Instruction.OP_ISTORE, variableIndex));
    }

    public InstructionSequenceBuilder lstore(int variableIndex)
    {
        return add(new VariableInstruction(Instruction.OP_LSTORE, variableIndex));
    }

    public InstructionSequenceBuilder fstore(int variableIndex)
    {
        return add(new VariableInstruction(Instruction.OP_FSTORE, variableIndex));
    }

    public InstructionSequenceBuilder dstore(int variableIndex)
    {
        return add(new VariableInstruction(Instruction.OP_DSTORE, variableIndex));
    }

    public InstructionSequenceBuilder astore(int variableIndex)
    {
        return add(new VariableInstruction(Instruction.OP_ASTORE, variableIndex));
    }

    public InstructionSequenceBuilder istore_0()
    {
        return add(new VariableInstruction(Instruction.OP_ISTORE_0));
    }

    public InstructionSequenceBuilder istore_1()
    {
        return add(new VariableInstruction(Instruction.OP_ISTORE_1));
    }

    public InstructionSequenceBuilder istore_2()
    {
        return add(new VariableInstruction(Instruction.OP_ISTORE_2));
    }

    public InstructionSequenceBuilder istore_3()
    {
        return add(new VariableInstruction(Instruction.OP_ISTORE_3));
    }

    public InstructionSequenceBuilder lstore_0()
    {
        return add(new VariableInstruction(Instruction.OP_LSTORE_0));
    }

    public InstructionSequenceBuilder lstore_1()
    {
        return add(new VariableInstruction(Instruction.OP_LSTORE_1));
    }

    public InstructionSequenceBuilder lstore_2()
    {
        return add(new VariableInstruction(Instruction.OP_LSTORE_2));
    }

    public InstructionSequenceBuilder lstore_3()
    {
        return add(new VariableInstruction(Instruction.OP_LSTORE_3));
    }

    public InstructionSequenceBuilder fstore_0()
    {
        return add(new VariableInstruction(Instruction.OP_FSTORE_0));
    }

    public InstructionSequenceBuilder fstore_1()
    {
        return add(new VariableInstruction(Instruction.OP_FSTORE_1));
    }

    public InstructionSequenceBuilder fstore_2()
    {
        return add(new VariableInstruction(Instruction.OP_FSTORE_2));
    }

    public InstructionSequenceBuilder fstore_3()
    {
        return add(new VariableInstruction(Instruction.OP_FSTORE_3));
    }

    public InstructionSequenceBuilder dstore_0()
    {
        return add(new VariableInstruction(Instruction.OP_DSTORE_0));
    }

    public InstructionSequenceBuilder dstore_1()
    {
        return add(new VariableInstruction(Instruction.OP_DSTORE_1));
    }

    public InstructionSequenceBuilder dstore_2()
    {
        return add(new VariableInstruction(Instruction.OP_DSTORE_2));
    }

    public InstructionSequenceBuilder dstore_3()
    {
        return add(new VariableInstruction(Instruction.OP_DSTORE_3));
    }

    public InstructionSequenceBuilder astore_0()
    {
        return add(new VariableInstruction(Instruction.OP_ASTORE_0));
    }

    public InstructionSequenceBuilder astore_1()
    {
        return add(new VariableInstruction(Instruction.OP_ASTORE_1));
    }

    public InstructionSequenceBuilder astore_2()
    {
        return add(new VariableInstruction(Instruction.OP_ASTORE_2));
    }

    public InstructionSequenceBuilder astore_3()
    {
        return add(new VariableInstruction(Instruction.OP_ASTORE_3));
    }

    public InstructionSequenceBuilder iastore()
    {
        return add(new SimpleInstruction(Instruction.OP_IASTORE));
    }

    public InstructionSequenceBuilder lastore()
    {
        return add(new SimpleInstruction(Instruction.OP_LASTORE));
    }

    public InstructionSequenceBuilder fastore()
    {
        return add(new SimpleInstruction(Instruction.OP_FASTORE));
    }

    public InstructionSequenceBuilder dastore()
    {
        return add(new SimpleInstruction(Instruction.OP_DASTORE));
    }

    public InstructionSequenceBuilder aastore()
    {
        return add(new SimpleInstruction(Instruction.OP_AASTORE));
    }

    public InstructionSequenceBuilder bastore()
    {
        return add(new SimpleInstruction(Instruction.OP_BASTORE));
    }

    public InstructionSequenceBuilder castore()
    {
        return add(new SimpleInstruction(Instruction.OP_CASTORE));
    }

    public InstructionSequenceBuilder sastore()
    {
        return add(new SimpleInstruction(Instruction.OP_SASTORE));
    }

    public InstructionSequenceBuilder pop()
    {
        return add(new SimpleInstruction(Instruction.OP_POP));
    }

    public InstructionSequenceBuilder pop2()
    {
        return add(new SimpleInstruction(Instruction.OP_POP2));
    }

    public InstructionSequenceBuilder dup()
    {
        return add(new SimpleInstruction(Instruction.OP_DUP));
    }

    public InstructionSequenceBuilder dup_x1()
    {
        return add(new SimpleInstruction(Instruction.OP_DUP_X1));
    }

    public InstructionSequenceBuilder dup_x2()
    {
        return add(new SimpleInstruction(Instruction.OP_DUP_X2));
    }

    public InstructionSequenceBuilder dup2()
    {
        return add(new SimpleInstruction(Instruction.OP_DUP2));
    }

    public InstructionSequenceBuilder dup2_x1()
    {
        return add(new SimpleInstruction(Instruction.OP_DUP2_X1));
    }

    public InstructionSequenceBuilder dup2_x2()
    {
        return add(new SimpleInstruction(Instruction.OP_DUP2_X2));
    }

    public InstructionSequenceBuilder swap()
    {
        return add(new SimpleInstruction(Instruction.OP_SWAP));
    }

    public InstructionSequenceBuilder iadd()
    {
        return add(new SimpleInstruction(Instruction.OP_IADD));
    }

    public InstructionSequenceBuilder ladd()
    {
        return add(new SimpleInstruction(Instruction.OP_LADD));
    }

    public InstructionSequenceBuilder fadd()
    {
        return add(new SimpleInstruction(Instruction.OP_FADD));
    }

    public InstructionSequenceBuilder dadd()
    {
        return add(new SimpleInstruction(Instruction.OP_DADD));
    }

    public InstructionSequenceBuilder isub()
    {
        return add(new SimpleInstruction(Instruction.OP_ISUB));
    }

    public InstructionSequenceBuilder lsub()
    {
        return add(new SimpleInstruction(Instruction.OP_LSUB));
    }

    public InstructionSequenceBuilder fsub()
    {
        return add(new SimpleInstruction(Instruction.OP_FSUB));
    }

    public InstructionSequenceBuilder dsub()
    {
        return add(new SimpleInstruction(Instruction.OP_DSUB));
    }

    public InstructionSequenceBuilder imul()
    {
        return add(new SimpleInstruction(Instruction.OP_IMUL));
    }

    public InstructionSequenceBuilder lmul()
    {
        return add(new SimpleInstruction(Instruction.OP_LMUL));
    }

    public InstructionSequenceBuilder fmul()
    {
        return add(new SimpleInstruction(Instruction.OP_FMUL));
    }

    public InstructionSequenceBuilder dmul()
    {
        return add(new SimpleInstruction(Instruction.OP_DMUL));
    }

    public InstructionSequenceBuilder idiv()
    {
        return add(new SimpleInstruction(Instruction.OP_IDIV));
    }

    public InstructionSequenceBuilder ldiv()
    {
        return add(new SimpleInstruction(Instruction.OP_LDIV));
    }

    public InstructionSequenceBuilder fdiv()
    {
        return add(new SimpleInstruction(Instruction.OP_FDIV));
    }

    public InstructionSequenceBuilder ddiv()
    {
        return add(new SimpleInstruction(Instruction.OP_DDIV));
    }

    public InstructionSequenceBuilder irem()
    {
        return add(new SimpleInstruction(Instruction.OP_IREM));
    }

    public InstructionSequenceBuilder lrem()
    {
        return add(new SimpleInstruction(Instruction.OP_LREM));
    }

    public InstructionSequenceBuilder frem()
    {
        return add(new SimpleInstruction(Instruction.OP_FREM));
    }

    public InstructionSequenceBuilder drem()
    {
        return add(new SimpleInstruction(Instruction.OP_DREM));
    }

    public InstructionSequenceBuilder ineg()
    {
        return add(new SimpleInstruction(Instruction.OP_INEG));
    }

    public InstructionSequenceBuilder lneg()
    {
        return add(new SimpleInstruction(Instruction.OP_LNEG));
    }

    public InstructionSequenceBuilder fneg()
    {
        return add(new SimpleInstruction(Instruction.OP_FNEG));
    }

    public InstructionSequenceBuilder dneg()
    {
        return add(new SimpleInstruction(Instruction.OP_DNEG));
    }

    public InstructionSequenceBuilder ishl()
    {
        return add(new SimpleInstruction(Instruction.OP_ISHL));
    }

    public InstructionSequenceBuilder lshl()
    {
        return add(new SimpleInstruction(Instruction.OP_LSHL));
    }

    public InstructionSequenceBuilder ishr()
    {
        return add(new SimpleInstruction(Instruction.OP_ISHR));
    }

    public InstructionSequenceBuilder lshr()
    {
        return add(new SimpleInstruction(Instruction.OP_LSHR));
    }

    public InstructionSequenceBuilder iushr()
    {
        return add(new SimpleInstruction(Instruction.OP_IUSHR));
    }

    public InstructionSequenceBuilder lushr()
    {
        return add(new SimpleInstruction(Instruction.OP_LUSHR));
    }

    public InstructionSequenceBuilder iand()
    {
        return add(new SimpleInstruction(Instruction.OP_IAND));
    }

    public InstructionSequenceBuilder land()
    {
        return add(new SimpleInstruction(Instruction.OP_LAND));
    }

    public InstructionSequenceBuilder ior()
    {
        return add(new SimpleInstruction(Instruction.OP_IOR));
    }

    public InstructionSequenceBuilder lor()
    {
        return add(new SimpleInstruction(Instruction.OP_LOR));
    }

    public InstructionSequenceBuilder ixor()
    {
        return add(new SimpleInstruction(Instruction.OP_IXOR));
    }

    public InstructionSequenceBuilder lxor()
    {
        return add(new SimpleInstruction(Instruction.OP_LXOR));
    }

    public InstructionSequenceBuilder iinc(int variableIndex,
                                           int constant)
    {
        return add(new VariableInstruction(Instruction.OP_IINC, variableIndex, constant));
    }

    public InstructionSequenceBuilder i2l()
    {
        return add(new SimpleInstruction(Instruction.OP_I2L));
    }

    public InstructionSequenceBuilder i2f()
    {
        return add(new SimpleInstruction(Instruction.OP_I2F));
    }

    public InstructionSequenceBuilder i2d()
    {
        return add(new SimpleInstruction(Instruction.OP_I2D));
    }

    public InstructionSequenceBuilder l2i()
    {
        return add(new SimpleInstruction(Instruction.OP_L2I));
    }

    public InstructionSequenceBuilder l2f()
    {
        return add(new SimpleInstruction(Instruction.OP_L2F));
    }

    public InstructionSequenceBuilder l2d()
    {
        return add(new SimpleInstruction(Instruction.OP_L2D));
    }

    public InstructionSequenceBuilder f2i()
    {
        return add(new SimpleInstruction(Instruction.OP_F2I));
    }

    public InstructionSequenceBuilder f2l()
    {
        return add(new SimpleInstruction(Instruction.OP_F2L));
    }

    public InstructionSequenceBuilder f2d()
    {
        return add(new SimpleInstruction(Instruction.OP_F2D));
    }

    public InstructionSequenceBuilder d2i()
    {
        return add(new SimpleInstruction(Instruction.OP_D2I));
    }

    public InstructionSequenceBuilder d2l()
    {
        return add(new SimpleInstruction(Instruction.OP_D2L));
    }

    public InstructionSequenceBuilder d2f()
    {
        return add(new SimpleInstruction(Instruction.OP_D2F));
    }

    public InstructionSequenceBuilder i2b()
    {
        return add(new SimpleInstruction(Instruction.OP_I2B));
    }

    public InstructionSequenceBuilder i2c()
    {
        return add(new SimpleInstruction(Instruction.OP_I2C));
    }

    public InstructionSequenceBuilder i2s()
    {
        return add(new SimpleInstruction(Instruction.OP_I2S));
    }

    public InstructionSequenceBuilder lcmp()
    {
        return add(new SimpleInstruction(Instruction.OP_LCMP));
    }

    public InstructionSequenceBuilder fcmpl()
    {
        return add(new SimpleInstruction(Instruction.OP_FCMPL));
    }

    public InstructionSequenceBuilder fcmpg()
    {
        return add(new SimpleInstruction(Instruction.OP_FCMPG));
    }

    public InstructionSequenceBuilder dcmpl()
    {
        return add(new SimpleInstruction(Instruction.OP_DCMPL));
    }

    public InstructionSequenceBuilder dcmpg()
    {
        return add(new SimpleInstruction(Instruction.OP_DCMPG));
    }

    public InstructionSequenceBuilder ifeq(int branchOffset)
    {
        return add(new BranchInstruction(Instruction.OP_IFEQ, branchOffset));
    }

    public InstructionSequenceBuilder ifne(int branchOffset)
    {
        return add(new BranchInstruction(Instruction.OP_IFNE, branchOffset));
    }

    public InstructionSequenceBuilder iflt(int branchOffset)
    {
        return add(new BranchInstruction(Instruction.OP_IFLT, branchOffset));
    }

    public InstructionSequenceBuilder ifge(int branchOffset)
    {
        return add(new BranchInstruction(Instruction.OP_IFGE, branchOffset));
    }

    public InstructionSequenceBuilder ifgt(int branchOffset)
    {
        return add(new BranchInstruction(Instruction.OP_IFGT, branchOffset));
    }

    public InstructionSequenceBuilder ifle(int branchOffset)
    {
        return add(new BranchInstruction(Instruction.OP_IFLE, branchOffset));
    }

    public InstructionSequenceBuilder ificmpeq(int branchOffset)
    {
        return add(new BranchInstruction(Instruction.OP_IFICMPEQ, branchOffset));
    }

    public InstructionSequenceBuilder ificmpne(int branchOffset)
    {
        return add(new BranchInstruction(Instruction.OP_IFICMPNE, branchOffset));
    }

    public InstructionSequenceBuilder ificmplt(int branchOffset)
    {
        return add(new BranchInstruction(Instruction.OP_IFICMPLT, branchOffset));
    }

    public InstructionSequenceBuilder ificmpge(int branchOffset)
    {
        return add(new BranchInstruction(Instruction.OP_IFICMPGE, branchOffset));
    }

    public InstructionSequenceBuilder ificmpgt(int branchOffset)
    {
        return add(new BranchInstruction(Instruction.OP_IFICMPGT, branchOffset));
    }

    public InstructionSequenceBuilder ificmple(int branchOffset)
    {
        return add(new BranchInstruction(Instruction.OP_IFICMPLE, branchOffset));
    }

    public InstructionSequenceBuilder ifacmpeq(int branchOffset)
    {
        return add(new BranchInstruction(Instruction.OP_IFACMPEQ, branchOffset));
    }

    public InstructionSequenceBuilder ifacmpne(int branchOffset)
    {
        return add(new BranchInstruction(Instruction.OP_IFACMPNE, branchOffset));
    }

    public InstructionSequenceBuilder goto_(int branchOffset)
    {
        return add(new BranchInstruction(Instruction.OP_GOTO, branchOffset));
    }

    public InstructionSequenceBuilder jsr(int branchOffset)
    {
        return add(new BranchInstruction(Instruction.OP_JSR, branchOffset));
    }

    public InstructionSequenceBuilder ret(int variableIndex)
    {
        return add(new VariableInstruction(Instruction.OP_RET, variableIndex));
    }

    public InstructionSequenceBuilder tableswitch(int   defaultOffset,
                                                    int   lowCase,
                                                    int   highCase,
                                                    int[] jumpOffsets)
    {
        return add(new TableSwitchInstruction(Instruction.OP_TABLESWITCH,
                                                    defaultOffset,
                                                    lowCase,
                                                    highCase,
                                                    jumpOffsets));
    }

    public InstructionSequenceBuilder lookupswitch(int  defaultOffset,
                                                    int[] cases,
                                                    int[] jumpOffsets)
    {
        return add(new LookUpSwitchInstruction(Instruction.OP_LOOKUPSWITCH,
                                                     defaultOffset,
                                                     cases,
                                                     jumpOffsets));
    }

    public InstructionSequenceBuilder ireturn()
    {
        return add(new SimpleInstruction(Instruction.OP_IRETURN));
    }

    public InstructionSequenceBuilder lreturn()
    {
        return add(new SimpleInstruction(Instruction.OP_LRETURN));
    }

    public InstructionSequenceBuilder freturn()
    {
        return add(new SimpleInstruction(Instruction.OP_FRETURN));
    }

    public InstructionSequenceBuilder dreturn()
    {
        return add(new SimpleInstruction(Instruction.OP_DRETURN));
    }

    public InstructionSequenceBuilder areturn()
    {
        return add(new SimpleInstruction(Instruction.OP_ARETURN));
    }

    public InstructionSequenceBuilder return_()
    {
        return add(new SimpleInstruction(Instruction.OP_RETURN));
    }

    public InstructionSequenceBuilder getstatic(Clazz clazz,
                                                Field field)
    {
        return getstatic(clazz.getName(),
                         field.getName(clazz),
                         field.getDescriptor(clazz),
                         clazz,
                         field);
    }

    public InstructionSequenceBuilder getstatic(String className,
                                                String name,
                                                String descriptor)
    {
        return getstatic(className, name, descriptor, null, null);
    }

    public InstructionSequenceBuilder getstatic(String className,
                                                String name,
                                                String descriptor,
                                                Clazz  referencedClass,
                                                Field  referencedField)
    {
        return getstatic(constantPoolEditor.addFieldrefConstant(className,
                                                                name,
                                                                descriptor,
                                                                referencedClass,
                                                                referencedField));
    }

    public InstructionSequenceBuilder getstatic(int constantIndex)
    {
        return add(new ConstantInstruction(Instruction.OP_GETSTATIC, constantIndex));
    }

    public InstructionSequenceBuilder putstatic(Clazz clazz,
                                                Field field)
    {
        return putstatic(clazz.getName(),
                         field.getName(clazz),
                         field.getDescriptor(clazz),
                         clazz,
                         field);
    }

    public InstructionSequenceBuilder putstatic(String className,
                                                String name,
                                                String descriptor)
    {
        return putstatic(className, name, descriptor, null, null);
    }

    public InstructionSequenceBuilder putstatic(String className,
                                                String name,
                                                String descriptor,
                                                Clazz  referencedClass,
                                                Field  referencedField)
    {
        return putstatic(constantPoolEditor.addFieldrefConstant(className,
                                                                name,
                                                                descriptor,
                                                                referencedClass,
                                                                referencedField));
    }

    public InstructionSequenceBuilder putstatic(int constantIndex)
    {
        return add(new ConstantInstruction(Instruction.OP_PUTSTATIC, constantIndex));
    }

    public InstructionSequenceBuilder getfield(Clazz clazz,
                                               Field field)
    {
        return getfield(clazz.getName(),
                        field.getName(clazz),
                        field.getDescriptor(clazz),
                        clazz,
                        field);
    }

    public InstructionSequenceBuilder getfield(String className,
                                               String name,
                                               String descriptor)
    {
        return getfield(className, name, descriptor, null, null);
    }

    public InstructionSequenceBuilder getfield(String className,
                                               String name,
                                               String descriptor,
                                               Clazz  referencedClass,
                                               Field  referencedField)
    {
        return getfield(constantPoolEditor.addFieldrefConstant(className,
                                                               name,
                                                               descriptor,
                                                               referencedClass,
                                                               referencedField));
    }

    public InstructionSequenceBuilder getfield(int constantIndex)
    {
        return add(new ConstantInstruction(Instruction.OP_GETFIELD, constantIndex));
    }

    public InstructionSequenceBuilder putfield(Clazz clazz,
                                               Field field)
    {
        return putfield(clazz.getName(),
                        field.getName(clazz),
                        field.getDescriptor(clazz),
                        clazz,
                        field);
    }

    public InstructionSequenceBuilder putfield(String className,
                                               String name,
                                               String descriptor)
    {
        return putfield(className, name, descriptor, null, null);
    }

    public InstructionSequenceBuilder putfield(String className,
                                               String name,
                                               String descriptor,
                                               Clazz  referencedClass,
                                               Field  referencedField)
    {
        return putfield(constantPoolEditor.addFieldrefConstant(className,
                                                               name,
                                                               descriptor,
                                                               referencedClass,
                                                               referencedField));
    }

    public InstructionSequenceBuilder putfield(int constantIndex)
    {
        return add(new ConstantInstruction(Instruction.OP_PUTFIELD, constantIndex));
    }

    public InstructionSequenceBuilder invokevirtual(Clazz  clazz,
                                                    Method method)
    {
        return invokevirtual(clazz.getName(),
                             method.getName(clazz),
                             method.getDescriptor(clazz),
                             clazz,
                             method);
    }

    public InstructionSequenceBuilder invokevirtual(String className,
                                                    String name,
                                                    String descriptor)
    {
        return invokevirtual(className, name, descriptor, null, null);
    }

    public InstructionSequenceBuilder invokevirtual(int    classIndex,
                                                    String name,
                                                    String descriptor)
    {
        return invokevirtual(constantPoolEditor.addMethodrefConstant(classIndex,
                                                                     name,
                                                                     descriptor,
                                                                     null,
                                                                     null));
    }

    public InstructionSequenceBuilder invokevirtual(String className,
                                                    String name,
                                                    String descriptor,
                                                    Clazz  referencedClass,
                                                    Method referencedMethod)
    {
        return invokevirtual(constantPoolEditor.addMethodrefConstant(className,
                                                                     name,
                                                                     descriptor,
                                                                     referencedClass,
                                                                     referencedMethod));
    }

    public InstructionSequenceBuilder invokevirtual(int constantIndex)
    {
        return add(new ConstantInstruction(Instruction.OP_INVOKEVIRTUAL, constantIndex));
    }

    public InstructionSequenceBuilder invokespecial(Clazz  clazz,
                                                    Method method)
    {
        return invokespecial(clazz.getName(),
                             method.getName(clazz),
                             method.getDescriptor(clazz),
                             clazz,
                             method);
    }

    public InstructionSequenceBuilder invokespecial(String className,
                                                    String name,
                                                    String descriptor)
    {
        return invokespecial(className, name, descriptor, null, null);
    }

    public InstructionSequenceBuilder invokespecial(String className,
                                                    String name,
                                                    String descriptor,
                                                    Clazz  referencedClass,
                                                    Method referencedMethod)
    {
        return invokespecial(constantPoolEditor.addMethodrefConstant(className,
                                                                     name,
                                                                     descriptor,
                                                                     referencedClass,
                                                                     referencedMethod));
    }

    public InstructionSequenceBuilder invokespecial_interface(Clazz  clazz,
                                                              Method method)
    {
        return invokespecial_interface(clazz.getName(),
                                       method.getName(clazz),
                                       method.getDescriptor(clazz),
                                       clazz,
                                       method);
    }

    public InstructionSequenceBuilder invokespecial_interface(String className,
                                                              String name,
                                                              String descriptor)
    {
        return invokespecial_interface(className, name, descriptor, null, null);
    }

    public InstructionSequenceBuilder invokespecial_interface(String className,
                                                              String name,
                                                              String descriptor,
                                                              Clazz  referencedClass,
                                                              Method referencedMethod)
    {
        return invokespecial(constantPoolEditor.addInterfaceMethodrefConstant(className,
                                                                              name,
                                                                              descriptor,
                                                                              referencedClass,
                                                                              referencedMethod));
    }

    public InstructionSequenceBuilder invokespecial(int constantIndex)
    {
        return add(new ConstantInstruction(Instruction.OP_INVOKESPECIAL, constantIndex));
    }

    public InstructionSequenceBuilder invokestatic(Clazz  clazz,
                                                   Method method)
    {
        return invokestatic(clazz.getName(),
                            method.getName(clazz),
                            method.getDescriptor(clazz),
                            clazz,
                            method);
    }

    public InstructionSequenceBuilder invokestatic(String className,
                                                   String name,
                                                   String descriptor)
    {
        return invokestatic(className, name, descriptor, null, null);
    }

    public InstructionSequenceBuilder invokestatic(String className,
                                                   String name,
                                                   String descriptor,
                                                   Clazz  referencedClass,
                                                   Method referencedMethod)
    {
        return invokestatic(constantPoolEditor.addMethodrefConstant(className,
                                                                    name,
                                                                    descriptor,
                                                                    referencedClass,
                                                                    referencedMethod));
    }

    public InstructionSequenceBuilder invokestatic_interface(Clazz  clazz,
                                                             Method method)
    {
        return invokestatic_interface(clazz.getName(),
                                      method.getName(clazz),
                                      method.getDescriptor(clazz),
                                      clazz,
                                      method);
    }

    public InstructionSequenceBuilder invokestatic_interface(String className,
                                                             String name,
                                                             String descriptor)
    {
        return invokestatic_interface(className, name, descriptor, null, null);
    }

    public InstructionSequenceBuilder invokestatic_interface(String className,
                                                             String name,
                                                             String descriptor,
                                                             Clazz  referencedClass,
                                                             Method referencedMethod)
    {
        return invokestatic(constantPoolEditor.addInterfaceMethodrefConstant(className,
                                                                             name,
                                                                             descriptor,
                                                                             referencedClass,
                                                                             referencedMethod));
    }

    public InstructionSequenceBuilder invokestatic(int constantIndex)
    {
        return add(new ConstantInstruction(Instruction.OP_INVOKESTATIC, constantIndex));
    }

    public InstructionSequenceBuilder invokeinterface(Clazz  clazz,
                                                      Method method)
    {
        return invokeinterface(clazz.getName(),
                               method.getName(clazz),
                               method.getDescriptor(clazz),
                               clazz,
                               method);
    }

    public InstructionSequenceBuilder invokeinterface(String className,
                                                      String name,
                                                      String descriptor)
    {
        return invokeinterface(className, name, descriptor, null, null);
    }

    public InstructionSequenceBuilder invokeinterface(String className,
                                                      String name,
                                                      String descriptor,
                                                      Clazz  referencedClass,
                                                      Method referencedMethod)
    {
        int invokeinterfaceConstant =
            (ClassUtil.internalMethodParameterSize(descriptor, false)) << 8;

        return invokeinterface(constantPoolEditor.addInterfaceMethodrefConstant(className,
                                                                                name,
                                                                                descriptor,
                                                                                referencedClass,
                                                                                referencedMethod),
                               invokeinterfaceConstant);
    }

    public InstructionSequenceBuilder invokeinterface(int constantIndex, int constant)
    {
        return add(new ConstantInstruction(Instruction.OP_INVOKEINTERFACE, constantIndex, constant));
    }

    public InstructionSequenceBuilder invokedynamic(int    bootStrapMethodIndex,
                                                    String name,
                                                    String descriptor)
    {
        return invokedynamic(bootStrapMethodIndex, name, descriptor, null);
    }

    public InstructionSequenceBuilder invokedynamic(int     bootStrapMethodIndex,
                                                    String  name,
                                                    String  descriptor,
                                                    Clazz[] referencedClasses)
    {
        return invokedynamic(constantPoolEditor.addInvokeDynamicConstant(bootStrapMethodIndex,
                                                                         name,
                                                                         descriptor,
                                                                         referencedClasses));
    }

    public InstructionSequenceBuilder invokedynamic(int constantIndex)
    {
        return add(new ConstantInstruction(Instruction.OP_INVOKEDYNAMIC, constantIndex));
    }

    public InstructionSequenceBuilder new_(Clazz clazz)
    {
        return new_(clazz.getName(), clazz);
    }

    public InstructionSequenceBuilder new_(String className)
    {
        return new_(className, null);
    }

    public InstructionSequenceBuilder new_(String className,
                                           Clazz  referencedClass)
    {
        return new_(constantPoolEditor.addClassConstant(className, referencedClass));
    }

    public InstructionSequenceBuilder new_(int constantIndex)
    {
        return add(new ConstantInstruction(Instruction.OP_NEW, constantIndex));
    }

    public InstructionSequenceBuilder newarray(int constant)
    {
        return add(new SimpleInstruction(Instruction.OP_NEWARRAY, constant));
    }

    public InstructionSequenceBuilder anewarray(Clazz elementType)
    {
        return anewarray(elementType.getName(), elementType);
    }

    public InstructionSequenceBuilder anewarray(String elementTypeName,
                                                Clazz  referencedClass)
    {
        return anewarray(constantPoolEditor.addClassConstant(elementTypeName, referencedClass));
    }

    public InstructionSequenceBuilder anewarray(int constantIndex)
    {
        return add(new ConstantInstruction(Instruction.OP_ANEWARRAY, constantIndex));
    }

    public InstructionSequenceBuilder arraylength()
    {
        return add(new SimpleInstruction(Instruction.OP_ARRAYLENGTH));
    }

    public InstructionSequenceBuilder athrow()
    {
        return add(new SimpleInstruction(Instruction.OP_ATHROW));
    }

    public InstructionSequenceBuilder checkcast(Clazz type)
    {
        return checkcast(type.getName(), type);
    }

    public InstructionSequenceBuilder checkcast(String typeName)
    {
        return checkcast(typeName, null);
    }

    public InstructionSequenceBuilder checkcast(String typeName, Clazz referencedClass)
    {
        return checkcast(constantPoolEditor.addClassConstant(typeName, referencedClass));
    }

    public InstructionSequenceBuilder checkcast(int constantIndex)
    {
        return add(new ConstantInstruction(Instruction.OP_CHECKCAST, constantIndex));
    }

    public InstructionSequenceBuilder instanceof_(Clazz type)
    {
        return instanceof_(type.getName(), type);
    }

    public InstructionSequenceBuilder instanceof_(String typeName, Clazz referencedClass)
    {
        return instanceof_(constantPoolEditor.addClassConstant(typeName, referencedClass));
    }

    public InstructionSequenceBuilder instanceof_(int constantIndex)
    {
        return add(new ConstantInstruction(Instruction.OP_INSTANCEOF, constantIndex));
    }

    public InstructionSequenceBuilder monitorenter()
    {
        return add(new SimpleInstruction(Instruction.OP_MONITORENTER));
    }

    public InstructionSequenceBuilder monitorexit()
    {
        return add(new SimpleInstruction(Instruction.OP_MONITOREXIT));
    }

    public InstructionSequenceBuilder wide()
    {
        return add(new SimpleInstruction(Instruction.OP_WIDE));
    }

    public InstructionSequenceBuilder multianewarray(Clazz type)
    {
        return multianewarray(type.getName(), type);
    }

    public InstructionSequenceBuilder multianewarray(String typeName)
    {
        return multianewarray(typeName, null);
    }

    public InstructionSequenceBuilder multianewarray(String typeName, Clazz referencedClass)
    {
        return multianewarray(constantPoolEditor.addClassConstant(typeName, referencedClass));
    }

    public InstructionSequenceBuilder multianewarray(int constantIndex)
    {
        return add(new ConstantInstruction(Instruction.OP_MULTIANEWARRAY, constantIndex));
    }

    public InstructionSequenceBuilder ifnull(int branchOffset)
    {
        return add(new BranchInstruction(Instruction.OP_IFNULL, branchOffset));
    }

    public InstructionSequenceBuilder ifnonnull(int branchOffset)
    {
        return add(new BranchInstruction(Instruction.OP_IFNONNULL, branchOffset));
    }

    public InstructionSequenceBuilder goto_w(int branchOffset)
    {
        return add(new BranchInstruction(Instruction.OP_GOTO_W, branchOffset));
    }

    public InstructionSequenceBuilder jsr_w(int branchOffset)
    {
        return add(new BranchInstruction(Instruction.OP_JSR_W, branchOffset));
    }


    // Additional convenience methods.

    /**
     * Pushes the given primitive value on the stack.
     *
     * Operand stack:
     * ... -> ..., value
     *
     * @param value        the primitive value to be pushed - should never be null.
     * @param type the internal type of the primitive ('Z','B','I',...)
     */
    public InstructionSequenceBuilder pushPrimitive(Object value,
                                                    char   type)
    {
        switch (type)
        {
            case TypeConstants.BOOLEAN: return ((Boolean)value).booleanValue() ? iconst_1() : iconst_0();
            case TypeConstants.BYTE:
            case TypeConstants.SHORT:
            case TypeConstants.INT:     return pushInt(((Number)value).intValue());
            case TypeConstants.CHAR:    return ldc(((Character)value).charValue());
            case TypeConstants.LONG:    return ldc2_w((Long)value);
            case TypeConstants.FLOAT:   return ldc(((Float)value).floatValue());
            case TypeConstants.DOUBLE:  return ldc2_w((Double)value);
            default: throw new IllegalArgumentException("" + type);
        }
    }


    /**
     * Pushes the given string or primitive on the stack.
     *
     * @param value the primitive value to be pushed - should never be null.
     * @param type  the internal type of the primitive ('Z','B','I',...)
     *
     * @throws IllegalArgumentException if the type is neither primitive or Ljava/lang/String;
     */
    public InstructionSequenceBuilder pushPrimitiveOrString(Object value, String type)
    {
        return pushPrimitiveOrString(value, type, true);
    }


    /**
     * Pushes the given string or primitive on the stack.
     *
     * @param value the primitive value to be pushed - should never be null.
     * @param type  the internal type of the primitive ('Z','B','I',...)
     * @param allowBoxing If the type is a primitive wrapper class, set allowBoxing = true, to push a boxed primitive.
     *
     * @throws IllegalArgumentException if the type is neither primitive or Ljava/lang/String;
     */
    public InstructionSequenceBuilder pushPrimitiveOrString(Object value, String type, boolean allowBoxing)
    {
        if (type == null)
        {
            throw new IllegalArgumentException("Null type found for value: " + value);
        }

        char primitiveType = type.charAt(0);

        if (type.equals(ClassConstants.TYPE_JAVA_LANG_STRING))
        {
            return ldc((String)value);
        }
        else if (allowBoxing && primitiveType == TypeConstants.CLASS_START)
        {
            return pushBoxedPrimitive(value, type);
        }
        else
        {
            if (!allowBoxing && primitiveType == TypeConstants.CLASS_START)
            {
                String internalPrimitiveClassName = ClassUtil.internalClassNameFromType(type);
                if (internalPrimitiveClassName == null)
                {
                    throw new IllegalArgumentException("Invalid type: " + type);
                }
                primitiveType = ClassUtil.internalPrimitiveTypeFromNumericClassName(internalPrimitiveClassName);
            }
            return pushPrimitive(value, primitiveType);
        }
    }


    /**
     * Push a primitive on the stack followed by a call to it's boxed valueOf method.
     *
     * @param value the value.
     * @param type the type e.g. Ljava/lang/Integer;
     */
    public InstructionSequenceBuilder pushBoxedPrimitive(Object value, String type)
    {
        String internalPrimitiveClassName = ClassUtil.internalClassNameFromType(type);
        if (internalPrimitiveClassName == null)
        {
            throw new IllegalArgumentException("Invalid type: " + type);
        }
        char   primitiveType = ClassUtil.internalPrimitiveTypeFromNumericClassName(internalPrimitiveClassName);
        String className     = ClassUtil.internalClassNameFromType(type);
        pushPrimitive(value, primitiveType);
        return invokestatic(className, "valueOf", String.format("(%c)%s", primitiveType, type));
    }


    /**
     * Pushes the given primitive int on the stack in the most efficient way
     * (as an iconst, bipush, sipush, or ldc instruction).
     *
     * @param value the int value to be pushed.
     */
    public InstructionSequenceBuilder pushInt(int value)
    {
        switch (value)
        {
            case -1: return iconst_m1();
            case  0: return iconst_0();
            case  1: return iconst_1();
            case  2: return iconst_2();
            case  3: return iconst_3();
            case  4: return iconst_4();
            case  5: return iconst_5();
            default: return value == (byte)value  ? bipush(value) :
                            value == (short)value ? sipush(value) :
                                                    ldc(value);
        }
    }


    /**
     * Pushes the given primitive float on the stack in the most efficient way
     * (as an fconst or ldc instruction).
     *
     * @param value the float value to be pushed.
     */
    public InstructionSequenceBuilder pushFloat(float value)
    {
        return
            value == 0f ? fconst_0() :
            value == 1f ? fconst_1() :
            value == 2f ? fconst_2() :
                          ldc(value);
    }


    /**
     * Pushes the given primitive long on the stack in the most efficient way
     * (as an lconst or ldc instruction).
     *
     * @param value the inlongue to be pushed.
     */
    public InstructionSequenceBuilder pushLong(long value)
    {
        return
            value == 0L ? lconst_0() :
            value == 1L ? lconst_1() :
                          ldc2_w(value);
    }


    /**
     * Pushes the given primitive double on the stack in the most efficient way
     * (as a dconst or ldc instruction).
     *
     * @param value the double value to be pushed.
     */
    public InstructionSequenceBuilder pushDouble(double value)
    {
        return
            value == 0. ? dconst_0() :
            value == 1. ? dconst_1() :
                          ldc2_w(value);
    }


    /**
     * Pushes a new array on the stack.
     *
     * Operand stack:
     * ... -> ..., array
     *
     * @param type the array element type (or class name in case of objects).
     * @param size the size of the array to be created.
     */
    public InstructionSequenceBuilder pushNewArray(String type,
                                                   int    size)
    {
        // Create new array.
        pushInt(size);

        return ClassUtil.isInternalPrimitiveType(type) ?
            newarray(InstructionUtil.arrayTypeFromInternalType(type.charAt(0))) :
            anewarray(type, null);
    }


    /**
     * Pushes a new array with given values onto the stack.
     *
     * For primitives you can specify, for example, either I or Ljava/lang/Integer; to create an
     * object array or a primitive array.
     *
     * Operand stack:
     * ... -> ..., array
     *
     * @param type   the array element type (or class name in case of objects).
     * @param values the array values.
     */
    public InstructionSequenceBuilder pushPrimitiveOrStringArray(String type, Object[] values)
    {
        String internalClassType = ClassUtil.internalClassTypeFromType(type);
        pushNewArray(internalClassType, values.length);
        dup();
        for (int i = 0; i < values.length; i++)
        {
            pushInt(i);
            pushPrimitiveOrString(values[i], type);
            storeToArray(internalClassType);
            if (i != values.length - 1)
            {
                dup();
            }
        }

        return nop();
    }


    /**
     * Pushes a default value onto the stack.
     *
     * Either 0 for primitives or null for objects.
     *
     * @param type the type.
     */
    public InstructionSequenceBuilder pushDefault(String type)
    {
        switch (type.charAt(0))
        {
            case TypeConstants.CHAR:
            case TypeConstants.BOOLEAN:
            case TypeConstants.BYTE:
            case TypeConstants.SHORT:
            case TypeConstants.INT:    return iconst_0();
            case TypeConstants.LONG:   return lconst_0();
            case TypeConstants.FLOAT:  return fconst_0();
            case TypeConstants.DOUBLE: return dconst_0();
            default:                   return aconst_null();
        }
    }


    /**
     * Loads the given variable onto the stack.
     *
     * Operand stack:
     * ... -> ..., value
     *
     * @param variableIndex the index of the variable to be loaded.
     * @param type  the type of the variable to be loaded.
     */
    public InstructionSequenceBuilder load(int    variableIndex,
                                           String type)
    {
        return load(variableIndex, type.charAt(0));
    }


    /**
     * Loads the given variable of primitive type onto the stack.
     *
     * Operand stack:
     * ... -> ..., value
     *
     * @param variableIndex the index of the variable to be loaded.
     * @param type          the type of the variable to be loaded.
     */
    public InstructionSequenceBuilder load(int  variableIndex,
                                           char type)
    {
        switch (type)
        {
            case TypeConstants.BOOLEAN:
            case TypeConstants.BYTE:
            case TypeConstants.CHAR:
            case TypeConstants.SHORT:
            case TypeConstants.INT:    return iload(variableIndex);
            case TypeConstants.LONG:   return lload(variableIndex);
            case TypeConstants.FLOAT:  return fload(variableIndex);
            case TypeConstants.DOUBLE: return dload(variableIndex);
            default:                         return aload(variableIndex);
        }
    }


    /**
     * Stores the value on top of the stack in the variable with given index.
     *
     * Operand stsack:
     * ..., value -> ...
     *
     * @param variableIndex the index of the variable where to store the
     *                      value.
     * @param type          the type of the value to be stored.
     */
    public InstructionSequenceBuilder store(int    variableIndex,
                                            String type)
    {
        return store(variableIndex, type.charAt(0));
    }


    /**
     * Stores the primitve value on top of the stack in the variable with given
     * index.
     *
     * Operand stack:
     * ..., value -> ...
     *
     * @param variableIndex the index of the variable where to store the
     *                      value.
     * @param type          the type of the value to be stored.
     */
    public InstructionSequenceBuilder store(int  variableIndex,
                                            char type)
    {
        switch (type)
        {
            case TypeConstants.BOOLEAN:
            case TypeConstants.BYTE:
            case TypeConstants.CHAR:
            case TypeConstants.SHORT:
            case TypeConstants.INT:    return istore(variableIndex);
            case TypeConstants.LONG:   return lstore(variableIndex);
            case TypeConstants.FLOAT:  return fstore(variableIndex);
            case TypeConstants.DOUBLE: return dstore(variableIndex);
            default:                         return astore(variableIndex);
        }
    }


    /**
     * Stores an element to an array.
     *
     * Operand stack:
     * ..., array, index, value -> ...
     *
     * @param elementType the type of the value to be stored.
     */
    public InstructionSequenceBuilder storeToArray(String elementType)
    {
        // Store element on stack in array.
        switch (elementType.charAt(0))
        {
            case TypeConstants.BOOLEAN:
            case TypeConstants.BYTE:   return bastore();
            case TypeConstants.CHAR:   return castore();
            case TypeConstants.SHORT:  return sastore();
            case TypeConstants.INT:    return iastore();
            case TypeConstants.LONG:   return lastore();
            case TypeConstants.FLOAT:  return fastore();
            case TypeConstants.DOUBLE: return dastore();
            default:                         return aastore();
        }
    }


    /**
     * Loads an element from an array.
     *
     * Operand stack:
     * ..., array, index -> ..., value
     *
     * @param elementType the type of the value to be loaded.
     */
    public InstructionSequenceBuilder loadFromArray(String elementType)
    {
        // Load element from array on stack.
        switch (elementType.charAt(0))
        {
            case TypeConstants.BOOLEAN:
            case TypeConstants.BYTE:   return baload();
            case TypeConstants.CHAR:   return caload();
            case TypeConstants.SHORT:  return saload();
            case TypeConstants.INT:    return iaload();
            case TypeConstants.LONG:   return laload();
            case TypeConstants.FLOAT:  return faload();
            case TypeConstants.DOUBLE: return daload();
            default:                         return aaload();
        }
    }


    // Small utility methods.

    /**
     * Adds the given instruction, shrinking it if necessary.
     */
    private InstructionSequenceBuilder add(Instruction instruction)
    {
        instructions.add(instruction);

        return this;
    }


    /**
     * Small sample application that illustrates the use of this class.
     */
    public static void main(String[] args)
    {
        InstructionSequenceBuilder builder = new InstructionSequenceBuilder();

        Instruction[] instructions = builder
            .iconst_2()
            .istore_0()
            .iinc(0, 2)
            .iload_0()
            .ldc(12)
            .iadd()
            .putstatic("com/example/SomeClass", "someField", "I", null, null)
            .instructions();

        Constant[] constants = builder.constants();

        System.out.println("Instructions:");
        for (Instruction instruction : instructions)
        {
            System.out.println(instruction);
        }

        System.out.println();

        System.out.println("Constants:");
        for (int index = 0; index < constants.length; index++)
        {
            System.out.println("#"+index+": " + constants[index]);
        }
    }


    /**
     * This ProgramClass is a dummy container for a constant pool, with a null name.
     */
    private static class MyDummyClass
    extends              ProgramClass
    {
        public MyDummyClass()
        {
            super(VersionConstants.CLASS_VERSION_1_0, 1, new Constant[256], 0, 0, 0);
        }


        // Overriding methods for Claaz.

        public String getName()
        {
            return null;
        }
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy