Instruction.java

  1. /*
  2.  * Licensed to the Apache Software Foundation (ASF) under one or more
  3.  * contributor license agreements.  See the NOTICE file distributed with
  4.  * this work for additional information regarding copyright ownership.
  5.  * The ASF licenses this file to You under the Apache License, Version 2.0
  6.  * (the "License"); you may not use this file except in compliance with
  7.  * the License.  You may obtain a copy of the License at
  8.  *
  9.  *      http://www.apache.org/licenses/LICENSE-2.0
  10.  *
  11.  *  Unless required by applicable law or agreed to in writing, software
  12.  *  distributed under the License is distributed on an "AS IS" BASIS,
  13.  *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  14.  *  See the License for the specific language governing permissions and
  15.  *  limitations under the License.
  16.  */
  17. package org.apache.bcel.generic;

  18. import java.io.DataOutputStream;
  19. import java.io.IOException;

  20. import org.apache.bcel.Const;
  21. import org.apache.bcel.classfile.ConstantPool;
  22. import org.apache.bcel.util.ByteSequence;

  23. /**
  24.  * Abstract super class for all Java byte codes.
  25.  */
  26. public abstract class Instruction implements Cloneable {

  27.     static final Instruction[] EMPTY_ARRAY = {};

  28.     private static InstructionComparator cmp = InstructionComparator.DEFAULT;

  29.     /**
  30.      * Gets Comparator object used in the equals() method to determine equality of instructions.
  31.      *
  32.      * @return currently used comparator for equals()
  33.      * @deprecated (6.0) use the built in comparator, or wrap this class in another object that implements these methods
  34.      */
  35.     @Deprecated
  36.     public static InstructionComparator getComparator() {
  37.         return cmp;
  38.     }

  39.     /**
  40.      * Tests if the value can fit in a byte (signed)
  41.      *
  42.      * @param value the value to check
  43.      * @return true if the value is in range
  44.      * @since 6.0
  45.      */
  46.     public static boolean isValidByte(final int value) {
  47.         return value >= Byte.MIN_VALUE && value <= Byte.MAX_VALUE;
  48.     }

  49.     /**
  50.      * Tests if the value can fit in a short (signed)
  51.      *
  52.      * @param value the value to check
  53.      * @return true if the value is in range
  54.      * @since 6.0
  55.      */
  56.     public static boolean isValidShort(final int value) {
  57.         return value >= Short.MIN_VALUE && value <= Short.MAX_VALUE;
  58.     }

  59.     /**
  60.      * Reads an instruction from (byte code) input stream and return the appropriate object.
  61.      * <p>
  62.      * If the Instruction is defined in {@link InstructionConst}, then the singleton instance is returned.
  63.      * </p>
  64.      * @param bytes input stream bytes
  65.      * @return instruction object being read
  66.      * @throws IOException Thrown when an I/O exception of some sort has occurred.
  67.      * @see InstructionConst#getInstruction(int)
  68.      */
  69.     // @since 6.0 no longer final
  70.     public static Instruction readInstruction(final ByteSequence bytes) throws IOException {
  71.         boolean wide = false;
  72.         short opcode = (short) bytes.readUnsignedByte();
  73.         Instruction obj = null;
  74.         if (opcode == Const.WIDE) { // Read next opcode after wide byte
  75.             wide = true;
  76.             opcode = (short) bytes.readUnsignedByte();
  77.         }
  78.         final Instruction instruction = InstructionConst.getInstruction(opcode);
  79.         if (instruction != null) {
  80.             return instruction; // Used predefined immutable object, if available
  81.         }

  82.         switch (opcode) {
  83.         case Const.BIPUSH:
  84.             obj = new BIPUSH();
  85.             break;
  86.         case Const.SIPUSH:
  87.             obj = new SIPUSH();
  88.             break;
  89.         case Const.LDC:
  90.             obj = new LDC();
  91.             break;
  92.         case Const.LDC_W:
  93.             obj = new LDC_W();
  94.             break;
  95.         case Const.LDC2_W:
  96.             obj = new LDC2_W();
  97.             break;
  98.         case Const.ILOAD:
  99.             obj = new ILOAD();
  100.             break;
  101.         case Const.LLOAD:
  102.             obj = new LLOAD();
  103.             break;
  104.         case Const.FLOAD:
  105.             obj = new FLOAD();
  106.             break;
  107.         case Const.DLOAD:
  108.             obj = new DLOAD();
  109.             break;
  110.         case Const.ALOAD:
  111.             obj = new ALOAD();
  112.             break;
  113.         case Const.ILOAD_0:
  114.             obj = new ILOAD(0);
  115.             break;
  116.         case Const.ILOAD_1:
  117.             obj = new ILOAD(1);
  118.             break;
  119.         case Const.ILOAD_2:
  120.             obj = new ILOAD(2);
  121.             break;
  122.         case Const.ILOAD_3:
  123.             obj = new ILOAD(3);
  124.             break;
  125.         case Const.LLOAD_0:
  126.             obj = new LLOAD(0);
  127.             break;
  128.         case Const.LLOAD_1:
  129.             obj = new LLOAD(1);
  130.             break;
  131.         case Const.LLOAD_2:
  132.             obj = new LLOAD(2);
  133.             break;
  134.         case Const.LLOAD_3:
  135.             obj = new LLOAD(3);
  136.             break;
  137.         case Const.FLOAD_0:
  138.             obj = new FLOAD(0);
  139.             break;
  140.         case Const.FLOAD_1:
  141.             obj = new FLOAD(1);
  142.             break;
  143.         case Const.FLOAD_2:
  144.             obj = new FLOAD(2);
  145.             break;
  146.         case Const.FLOAD_3:
  147.             obj = new FLOAD(3);
  148.             break;
  149.         case Const.DLOAD_0:
  150.             obj = new DLOAD(0);
  151.             break;
  152.         case Const.DLOAD_1:
  153.             obj = new DLOAD(1);
  154.             break;
  155.         case Const.DLOAD_2:
  156.             obj = new DLOAD(2);
  157.             break;
  158.         case Const.DLOAD_3:
  159.             obj = new DLOAD(3);
  160.             break;
  161.         case Const.ALOAD_0:
  162.             obj = new ALOAD(0);
  163.             break;
  164.         case Const.ALOAD_1:
  165.             obj = new ALOAD(1);
  166.             break;
  167.         case Const.ALOAD_2:
  168.             obj = new ALOAD(2);
  169.             break;
  170.         case Const.ALOAD_3:
  171.             obj = new ALOAD(3);
  172.             break;
  173.         case Const.ISTORE:
  174.             obj = new ISTORE();
  175.             break;
  176.         case Const.LSTORE:
  177.             obj = new LSTORE();
  178.             break;
  179.         case Const.FSTORE:
  180.             obj = new FSTORE();
  181.             break;
  182.         case Const.DSTORE:
  183.             obj = new DSTORE();
  184.             break;
  185.         case Const.ASTORE:
  186.             obj = new ASTORE();
  187.             break;
  188.         case Const.ISTORE_0:
  189.             obj = new ISTORE(0);
  190.             break;
  191.         case Const.ISTORE_1:
  192.             obj = new ISTORE(1);
  193.             break;
  194.         case Const.ISTORE_2:
  195.             obj = new ISTORE(2);
  196.             break;
  197.         case Const.ISTORE_3:
  198.             obj = new ISTORE(3);
  199.             break;
  200.         case Const.LSTORE_0:
  201.             obj = new LSTORE(0);
  202.             break;
  203.         case Const.LSTORE_1:
  204.             obj = new LSTORE(1);
  205.             break;
  206.         case Const.LSTORE_2:
  207.             obj = new LSTORE(2);
  208.             break;
  209.         case Const.LSTORE_3:
  210.             obj = new LSTORE(3);
  211.             break;
  212.         case Const.FSTORE_0:
  213.             obj = new FSTORE(0);
  214.             break;
  215.         case Const.FSTORE_1:
  216.             obj = new FSTORE(1);
  217.             break;
  218.         case Const.FSTORE_2:
  219.             obj = new FSTORE(2);
  220.             break;
  221.         case Const.FSTORE_3:
  222.             obj = new FSTORE(3);
  223.             break;
  224.         case Const.DSTORE_0:
  225.             obj = new DSTORE(0);
  226.             break;
  227.         case Const.DSTORE_1:
  228.             obj = new DSTORE(1);
  229.             break;
  230.         case Const.DSTORE_2:
  231.             obj = new DSTORE(2);
  232.             break;
  233.         case Const.DSTORE_3:
  234.             obj = new DSTORE(3);
  235.             break;
  236.         case Const.ASTORE_0:
  237.             obj = new ASTORE(0);
  238.             break;
  239.         case Const.ASTORE_1:
  240.             obj = new ASTORE(1);
  241.             break;
  242.         case Const.ASTORE_2:
  243.             obj = new ASTORE(2);
  244.             break;
  245.         case Const.ASTORE_3:
  246.             obj = new ASTORE(3);
  247.             break;
  248.         case Const.IINC:
  249.             obj = new IINC();
  250.             break;
  251.         case Const.IFEQ:
  252.             obj = new IFEQ();
  253.             break;
  254.         case Const.IFNE:
  255.             obj = new IFNE();
  256.             break;
  257.         case Const.IFLT:
  258.             obj = new IFLT();
  259.             break;
  260.         case Const.IFGE:
  261.             obj = new IFGE();
  262.             break;
  263.         case Const.IFGT:
  264.             obj = new IFGT();
  265.             break;
  266.         case Const.IFLE:
  267.             obj = new IFLE();
  268.             break;
  269.         case Const.IF_ICMPEQ:
  270.             obj = new IF_ICMPEQ();
  271.             break;
  272.         case Const.IF_ICMPNE:
  273.             obj = new IF_ICMPNE();
  274.             break;
  275.         case Const.IF_ICMPLT:
  276.             obj = new IF_ICMPLT();
  277.             break;
  278.         case Const.IF_ICMPGE:
  279.             obj = new IF_ICMPGE();
  280.             break;
  281.         case Const.IF_ICMPGT:
  282.             obj = new IF_ICMPGT();
  283.             break;
  284.         case Const.IF_ICMPLE:
  285.             obj = new IF_ICMPLE();
  286.             break;
  287.         case Const.IF_ACMPEQ:
  288.             obj = new IF_ACMPEQ();
  289.             break;
  290.         case Const.IF_ACMPNE:
  291.             obj = new IF_ACMPNE();
  292.             break;
  293.         case Const.GOTO:
  294.             obj = new GOTO();
  295.             break;
  296.         case Const.JSR:
  297.             obj = new JSR();
  298.             break;
  299.         case Const.RET:
  300.             obj = new RET();
  301.             break;
  302.         case Const.TABLESWITCH:
  303.             obj = new TABLESWITCH();
  304.             break;
  305.         case Const.LOOKUPSWITCH:
  306.             obj = new LOOKUPSWITCH();
  307.             break;
  308.         case Const.GETSTATIC:
  309.             obj = new GETSTATIC();
  310.             break;
  311.         case Const.PUTSTATIC:
  312.             obj = new PUTSTATIC();
  313.             break;
  314.         case Const.GETFIELD:
  315.             obj = new GETFIELD();
  316.             break;
  317.         case Const.PUTFIELD:
  318.             obj = new PUTFIELD();
  319.             break;
  320.         case Const.INVOKEVIRTUAL:
  321.             obj = new INVOKEVIRTUAL();
  322.             break;
  323.         case Const.INVOKESPECIAL:
  324.             obj = new INVOKESPECIAL();
  325.             break;
  326.         case Const.INVOKESTATIC:
  327.             obj = new INVOKESTATIC();
  328.             break;
  329.         case Const.INVOKEINTERFACE:
  330.             obj = new INVOKEINTERFACE();
  331.             break;
  332.         case Const.INVOKEDYNAMIC:
  333.             obj = new INVOKEDYNAMIC();
  334.             break;
  335.         case Const.NEW:
  336.             obj = new NEW();
  337.             break;
  338.         case Const.NEWARRAY:
  339.             obj = new NEWARRAY();
  340.             break;
  341.         case Const.ANEWARRAY:
  342.             obj = new ANEWARRAY();
  343.             break;
  344.         case Const.CHECKCAST:
  345.             obj = new CHECKCAST();
  346.             break;
  347.         case Const.INSTANCEOF:
  348.             obj = new INSTANCEOF();
  349.             break;
  350.         case Const.MULTIANEWARRAY:
  351.             obj = new MULTIANEWARRAY();
  352.             break;
  353.         case Const.IFNULL:
  354.             obj = new IFNULL();
  355.             break;
  356.         case Const.IFNONNULL:
  357.             obj = new IFNONNULL();
  358.             break;
  359.         case Const.GOTO_W:
  360.             obj = new GOTO_W();
  361.             break;
  362.         case Const.JSR_W:
  363.             obj = new JSR_W();
  364.             break;
  365.         case Const.BREAKPOINT:
  366.             obj = new BREAKPOINT();
  367.             break;
  368.         case Const.IMPDEP1:
  369.             obj = new IMPDEP1();
  370.             break;
  371.         case Const.IMPDEP2:
  372.             obj = new IMPDEP2();
  373.             break;
  374.         default:
  375.             throw new ClassGenException("Illegal opcode detected: " + opcode);

  376.         }

  377.         if (wide && !(obj instanceof LocalVariableInstruction || obj instanceof RET)) {
  378.             throw new ClassGenException("Illegal opcode after wide: " + opcode);
  379.         }
  380.         obj.setOpcode(opcode);
  381.         obj.initFromFile(bytes, wide); // Do further initializations, if any
  382.         return obj;
  383.     }

  384.     /**
  385.      * Sets comparator to be used for equals().
  386.      *
  387.      * @deprecated (6.0) use the built in comparator, or wrap this class in another object that implements these methods
  388.      */
  389.     @Deprecated
  390.     public static void setComparator(final InstructionComparator c) {
  391.         cmp = c;
  392.     }

  393.     /**
  394.      * @deprecated (since 6.0) will be made private; do not access directly, use getter/setter
  395.      */
  396.     @Deprecated
  397.     protected short length = 1; // Length of instruction in bytes

  398.     /**
  399.      * @deprecated (since 6.0) will be made private; do not access directly, use getter/setter
  400.      */
  401.     @Deprecated
  402.     protected short opcode = -1; // Opcode number

  403.     /**
  404.      * Empty constructor needed for Instruction.readInstruction. Not to be used otherwise.
  405.      */
  406.     Instruction() {
  407.     }

  408.     public Instruction(final short opcode, final short length) {
  409.         this.length = length;
  410.         this.opcode = opcode;
  411.     }

  412.     /**
  413.      * Call corresponding visitor method(s). The order is: Call visitor methods of implemented interfaces first, then call
  414.      * methods according to the class hierarchy in descending order, i.e., the most specific visitXXX() call comes last.
  415.      *
  416.      * @param v Visitor object
  417.      */
  418.     public abstract void accept(Visitor v);

  419.     /**
  420.      * This method also gives right results for instructions whose effect on the stack depends on the constant pool entry
  421.      * they reference.
  422.      *
  423.      * @return Number of words consumed from stack by this instruction, or Constants.UNPREDICTABLE, if this can not be
  424.      *         computed statically
  425.      */
  426.     public int consumeStack(final ConstantPoolGen cpg) {
  427.         return Const.getConsumeStack(opcode);
  428.     }

  429.     /**
  430.      * Use with caution, since 'BranchInstruction's have a 'target' reference which is not copied correctly (only basic
  431.      * types are). This also applies for 'Select' instructions with their multiple branch targets.
  432.      *
  433.      * @see BranchInstruction
  434.      * @return (shallow) copy of an instruction
  435.      */
  436.     public Instruction copy() {
  437.         Instruction i = null;
  438.         // "Constant" instruction, no need to duplicate
  439.         if (InstructionConst.getInstruction(getOpcode()) != null) {
  440.             i = this;
  441.         } else {
  442.             try {
  443.                 i = (Instruction) clone();
  444.             } catch (final CloneNotSupportedException e) {
  445.                 System.err.println(e);
  446.             }
  447.         }
  448.         return i;
  449.     }

  450.     /**
  451.      * Some instructions may be reused, so don't do anything by default.
  452.      */
  453.     void dispose() {
  454.     }

  455.     /**
  456.      * Dumps instruction as byte code to stream out.
  457.      *
  458.      * @param out Output stream
  459.      * @throws IOException Thrown when an I/O exception of some sort has occurred.
  460.      */
  461.     public void dump(final DataOutputStream out) throws IOException {
  462.         out.writeByte(opcode); // Common for all instructions
  463.     }

  464.     /**
  465.      * Tests for equality, delegated to comparator
  466.      *
  467.      * @return true if that is an Instruction and has the same opcode
  468.      */
  469.     @Override
  470.     public boolean equals(final Object that) {
  471.         return that instanceof Instruction && cmp.equals(this, (Instruction) that);
  472.     }

  473.     /**
  474.      * @return length (in bytes) of instruction
  475.      */
  476.     public int getLength() {
  477.         return length;
  478.     }

  479.     /**
  480.      * @return name of instruction, i.e., opcode name
  481.      */
  482.     public String getName() {
  483.         return Const.getOpcodeName(opcode);
  484.     }

  485.     /**
  486.      * @return this instructions opcode
  487.      */
  488.     public short getOpcode() {
  489.         return opcode;
  490.     }

  491.     /**
  492.      * Gets the hashCode of this object.
  493.      *
  494.      * @return the hashCode
  495.      * @since 6.0
  496.      */
  497.     @Override
  498.     public int hashCode() {
  499.         return opcode;
  500.     }

  501.     /**
  502.      * Reads needed data (e.g. index) from file.
  503.      *
  504.      * @param bytes byte sequence to read from
  505.      * @param wide "wide" instruction flag
  506.      * @throws IOException may be thrown if the implementation needs to read data from the file
  507.      */
  508.     @SuppressWarnings("unused") // thrown by subclasses
  509.     protected void initFromFile(final ByteSequence bytes, final boolean wide) throws IOException {
  510.     }

  511.     /**
  512.      * This method also gives right results for instructions whose effect on the stack depends on the constant pool entry
  513.      * they reference.
  514.      *
  515.      * @return Number of words produced onto stack by this instruction, or Constants.UNPREDICTABLE, if this can not be
  516.      *         computed statically
  517.      */
  518.     public int produceStack(final ConstantPoolGen cpg) {
  519.         return Const.getProduceStack(opcode);
  520.     }

  521.     /**
  522.      * Needed in readInstruction and subclasses in this package
  523.      *
  524.      * @since 6.0
  525.      */
  526.     final void setLength(final int length) {
  527.         this.length = (short) length; // TODO check range?
  528.     }

  529.     /**
  530.      * Needed in readInstruction and subclasses in this package
  531.      */
  532.     final void setOpcode(final short opcode) {
  533.         this.opcode = opcode;
  534.     }

  535.     /**
  536.      * @return mnemonic for instruction in verbose format
  537.      */
  538.     @Override
  539.     public String toString() {
  540.         return toString(true);
  541.     }

  542.     /**
  543.      * Long output format:
  544.      *
  545.      * &lt;name of opcode&gt; "["&lt;opcode number&gt;"]" "("&lt;length of instruction&gt;")"
  546.      *
  547.      * @param verbose long/short format switch
  548.      * @return mnemonic for instruction
  549.      */
  550.     public String toString(final boolean verbose) {
  551.         if (verbose) {
  552.             return getName() + "[" + opcode + "](" + length + ")";
  553.         }
  554.         return getName();
  555.     }

  556.     /**
  557.      * @return mnemonic for instruction with sumbolic references resolved
  558.      */
  559.     public String toString(final ConstantPool cp) {
  560.         return toString(false);
  561.     }
  562. }