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 static proguard.classfile.ClassConstants.METHOD_NAME_BOOLEAN_VALUE;
import static proguard.classfile.ClassConstants.METHOD_NAME_BYTE_VALUE;
import static proguard.classfile.ClassConstants.METHOD_NAME_CHAR_VALUE;
import static proguard.classfile.ClassConstants.METHOD_NAME_DOUBLE_VALUE;
import static proguard.classfile.ClassConstants.METHOD_NAME_FLOAT_VALUE;
import static proguard.classfile.ClassConstants.METHOD_NAME_INT_VALUE;
import static proguard.classfile.ClassConstants.METHOD_NAME_LONG_VALUE;
import static proguard.classfile.ClassConstants.METHOD_NAME_SHORT_VALUE;
import static proguard.classfile.ClassConstants.METHOD_NAME_VALUEOF;
import static proguard.classfile.ClassConstants.METHOD_TYPE_BOOLEAN_VALUE;
import static proguard.classfile.ClassConstants.METHOD_TYPE_BYTE_VALUE;
import static proguard.classfile.ClassConstants.METHOD_TYPE_CHAR_VALUE;
import static proguard.classfile.ClassConstants.METHOD_TYPE_DOUBLE_VALUE;
import static proguard.classfile.ClassConstants.METHOD_TYPE_FLOAT_VALUE;
import static proguard.classfile.ClassConstants.METHOD_TYPE_INT_VALUE;
import static proguard.classfile.ClassConstants.METHOD_TYPE_LONG_VALUE;
import static proguard.classfile.ClassConstants.METHOD_TYPE_SHORT_VALUE;
import static proguard.classfile.ClassConstants.METHOD_TYPE_VALUE_OF_BOOLEAN;
import static proguard.classfile.ClassConstants.METHOD_TYPE_VALUE_OF_BYTE;
import static proguard.classfile.ClassConstants.METHOD_TYPE_VALUE_OF_CHAR;
import static proguard.classfile.ClassConstants.METHOD_TYPE_VALUE_OF_DOUBLE;
import static proguard.classfile.ClassConstants.METHOD_TYPE_VALUE_OF_FLOAT;
import static proguard.classfile.ClassConstants.METHOD_TYPE_VALUE_OF_INT;
import static proguard.classfile.ClassConstants.METHOD_TYPE_VALUE_OF_LONG;
import static proguard.classfile.ClassConstants.METHOD_TYPE_VALUE_OF_SHORT;
import static proguard.classfile.ClassConstants.NAME_JAVA_LANG_BOOLEAN;
import static proguard.classfile.ClassConstants.NAME_JAVA_LANG_BYTE;
import static proguard.classfile.ClassConstants.NAME_JAVA_LANG_CHARACTER;
import static proguard.classfile.ClassConstants.NAME_JAVA_LANG_DOUBLE;
import static proguard.classfile.ClassConstants.NAME_JAVA_LANG_FLOAT;
import static proguard.classfile.ClassConstants.NAME_JAVA_LANG_INTEGER;
import static proguard.classfile.ClassConstants.NAME_JAVA_LANG_LONG;
import static proguard.classfile.ClassConstants.NAME_JAVA_LANG_NUMBER;
import static proguard.classfile.ClassConstants.NAME_JAVA_LANG_SHORT;
import static proguard.classfile.ClassConstants.TYPE_JAVA_LANG_OBJECT;

import java.util.ArrayList;
import java.util.List;
import proguard.classfile.ClassConstants;
import proguard.classfile.ClassPool;
import proguard.classfile.Clazz;
import proguard.classfile.Field;
import proguard.classfile.Member;
import proguard.classfile.Method;
import proguard.classfile.ProgramClass;
import proguard.classfile.TypeConstants;
import proguard.classfile.VersionConstants;
import proguard.classfile.constant.Constant;
import proguard.classfile.instruction.BranchInstruction;
import proguard.classfile.instruction.ConstantInstruction;
import proguard.classfile.instruction.Instruction;
import proguard.classfile.instruction.InstructionUtil;
import proguard.classfile.instruction.LookUpSwitchInstruction;
import proguard.classfile.instruction.SimpleInstruction;
import proguard.classfile.instruction.TableSwitchInstruction;
import proguard.classfile.instruction.VariableInstruction;
import proguard.classfile.util.ClassUtil;
import proguard.resources.file.ResourceFile;

/**
 * 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);
  }

  /** Short for {@link #appendInstruction(Instruction)}. */
  public InstructionSequenceBuilder line(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_w_(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_w_(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_w_(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_w_(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_w_(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_w_(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 ldc or ldc_w instruction that loads the constant at the given index, using the
   * correct instruction for the given index.
   */
  private InstructionSequenceBuilder ldc_x_(int constantIndex) {
    if (constantIndex > 255) {
      return ldc_w_(constantIndex);
    } else {
      return ldc_(constantIndex);
    }
  }

  /**
   * Appends an ldc or ldc_w instruction that loads an integer constant with the given value, using
   * the correct instruction for the constant index the given value will get.
   */
  private InstructionSequenceBuilder ldc_x(int value) {
    return ldc_x_(constantPoolEditor.addIntegerConstant(value));
  }

  /**
   * Appends an ldc or ldc_w instruction that loads a float constant with the given value, using the
   * correct instruction for the constant index the given value will get.
   */
  private InstructionSequenceBuilder ldc_x(float value) {
    return ldc_x_(constantPoolEditor.addFloatConstant(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); } } /** * Box the primitive value present on the stack. * *

Operand stack: ..., primitive -> ..., boxed_primitive * * @param sourceType type of the primitive on the stack. * @return this */ public InstructionSequenceBuilder boxPrimitiveType(char sourceType) { // Perform auto-boxing. switch (sourceType) { case TypeConstants.INT: this.invokestatic(NAME_JAVA_LANG_INTEGER, METHOD_NAME_VALUEOF, METHOD_TYPE_VALUE_OF_INT); break; case TypeConstants.BYTE: this.invokestatic(NAME_JAVA_LANG_BYTE, METHOD_NAME_VALUEOF, METHOD_TYPE_VALUE_OF_BYTE); break; case TypeConstants.CHAR: this.invokestatic(NAME_JAVA_LANG_CHARACTER, METHOD_NAME_VALUEOF, METHOD_TYPE_VALUE_OF_CHAR); break; case TypeConstants.SHORT: this.invokestatic(NAME_JAVA_LANG_SHORT, METHOD_NAME_VALUEOF, METHOD_TYPE_VALUE_OF_SHORT); break; case TypeConstants.BOOLEAN: this.invokestatic( NAME_JAVA_LANG_BOOLEAN, METHOD_NAME_VALUEOF, METHOD_TYPE_VALUE_OF_BOOLEAN); break; case TypeConstants.LONG: this.invokestatic(NAME_JAVA_LANG_LONG, METHOD_NAME_VALUEOF, METHOD_TYPE_VALUE_OF_LONG); break; case TypeConstants.FLOAT: this.invokestatic(NAME_JAVA_LANG_FLOAT, METHOD_NAME_VALUEOF, METHOD_TYPE_VALUE_OF_FLOAT); break; case TypeConstants.DOUBLE: this.invokestatic(NAME_JAVA_LANG_DOUBLE, METHOD_NAME_VALUEOF, METHOD_TYPE_VALUE_OF_DOUBLE); break; default: throw new IllegalArgumentException("Unknown primitive: " + sourceType); } return this; } /** * Unbox the object on the stack to a primitive value. * *

Operand stack: ..., boxed_primitive -> ..., primitive * * @param sourceType type of the primitive that should be unboxed. * @param targetType resulting type. */ public InstructionSequenceBuilder unboxPrimitiveType(String sourceType, String targetType) { boolean castRequired = sourceType.equals(TYPE_JAVA_LANG_OBJECT); // Perform auto-unboxing. switch (targetType.charAt(0)) { case TypeConstants.INT: if (castRequired) { this.checkcast(NAME_JAVA_LANG_NUMBER); } this.invokevirtual(NAME_JAVA_LANG_NUMBER, METHOD_NAME_INT_VALUE, METHOD_TYPE_INT_VALUE); break; case TypeConstants.BYTE: if (castRequired) { this.checkcast(NAME_JAVA_LANG_BYTE); } this.invokevirtual(NAME_JAVA_LANG_BYTE, METHOD_NAME_BYTE_VALUE, METHOD_TYPE_BYTE_VALUE); break; case TypeConstants.CHAR: if (castRequired) { this.checkcast(NAME_JAVA_LANG_CHARACTER); } this.invokevirtual( NAME_JAVA_LANG_CHARACTER, METHOD_NAME_CHAR_VALUE, METHOD_TYPE_CHAR_VALUE); break; case TypeConstants.SHORT: if (castRequired) { this.checkcast(NAME_JAVA_LANG_SHORT); } this.invokevirtual(NAME_JAVA_LANG_SHORT, METHOD_NAME_SHORT_VALUE, METHOD_TYPE_SHORT_VALUE); break; case TypeConstants.BOOLEAN: if (castRequired) { this.checkcast(NAME_JAVA_LANG_BOOLEAN); } this.invokevirtual( NAME_JAVA_LANG_BOOLEAN, METHOD_NAME_BOOLEAN_VALUE, METHOD_TYPE_BOOLEAN_VALUE); break; case TypeConstants.LONG: if (castRequired) { this.checkcast(NAME_JAVA_LANG_NUMBER); } this.invokevirtual(NAME_JAVA_LANG_NUMBER, METHOD_NAME_LONG_VALUE, METHOD_TYPE_LONG_VALUE); break; case TypeConstants.FLOAT: if (castRequired) { this.checkcast(NAME_JAVA_LANG_NUMBER); } this.invokevirtual(NAME_JAVA_LANG_NUMBER, METHOD_NAME_FLOAT_VALUE, METHOD_TYPE_FLOAT_VALUE); break; case TypeConstants.DOUBLE: if (castRequired) { this.checkcast(NAME_JAVA_LANG_NUMBER); } this.invokevirtual( NAME_JAVA_LANG_NUMBER, METHOD_NAME_DOUBLE_VALUE, METHOD_TYPE_DOUBLE_VALUE); break; default: throw new IllegalArgumentException("Unknown primitive: " + sourceType); } return this; } /** * 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_x(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_x(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