LocalVariableInstruction.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.util.ByteSequence;

  22. /**
  23.  * Abstract super class for instructions dealing with local variables.
  24.  */
  25. public abstract class LocalVariableInstruction extends Instruction implements TypedInstruction, IndexedInstruction {

  26.     /**
  27.      * @deprecated (since 6.0) will be made private; do not access directly, use getter/setter
  28.      */
  29.     @Deprecated
  30.     protected int n = -1; // index of referenced variable

  31.     private short cTag = -1; // compact version, such as ILOAD_0
  32.     private short canonTag = -1; // canonical tag such as ILOAD

  33.     /**
  34.      * Empty constructor needed for Instruction.readInstruction. Also used by IINC()!
  35.      */
  36.     LocalVariableInstruction() {
  37.     }

  38.     /**
  39.      * Empty constructor needed for Instruction.readInstruction. Not to be used otherwise. tag and length are defined in
  40.      * readInstruction and initFromFile, respectively.
  41.      */
  42.     LocalVariableInstruction(final short canonTag, final short cTag) {
  43.         this.canonTag = canonTag;
  44.         this.cTag = cTag;
  45.     }

  46.     /**
  47.      * @param opcode Instruction opcode
  48.      * @param cTag Instruction number for compact version, ALOAD_0, e.g.
  49.      * @param n local variable index (unsigned short)
  50.      */
  51.     protected LocalVariableInstruction(final short opcode, final short cTag, final int n) {
  52.         super(opcode, (short) 2);
  53.         this.cTag = cTag;
  54.         canonTag = opcode;
  55.         setIndex(n);
  56.     }

  57.     /**
  58.      * Dump instruction as byte code to stream out.
  59.      *
  60.      * @param out Output stream
  61.      */
  62.     @Override
  63.     public void dump(final DataOutputStream out) throws IOException {
  64.         if (wide()) {
  65.             out.writeByte(Const.WIDE);
  66.         }
  67.         out.writeByte(super.getOpcode());
  68.         if (super.getLength() > 1) { // Otherwise ILOAD_n, instruction, e.g.
  69.             if (wide()) {
  70.                 out.writeShort(n);
  71.             } else {
  72.                 out.writeByte(n);
  73.             }
  74.         }
  75.     }

  76.     /**
  77.      * @return canonical tag for instruction, e.g., ALOAD for ALOAD_0
  78.      */
  79.     public short getCanonicalTag() {
  80.         return canonTag;
  81.     }

  82.     /**
  83.      * @return local variable index (n) referred by this instruction.
  84.      */
  85.     @Override
  86.     public final int getIndex() {
  87.         return n;
  88.     }

  89.     /**
  90.      * Returns the type associated with the instruction - in case of ALOAD or ASTORE Type.OBJECT is returned. This is just a
  91.      * bit incorrect, because ALOAD and ASTORE may work on every ReferenceType (including Type.NULL) and ASTORE may even
  92.      * work on a ReturnaddressType .
  93.      *
  94.      * @return type associated with the instruction
  95.      */
  96.     @Override
  97.     public Type getType(final ConstantPoolGen cp) {
  98.         switch (canonTag) {
  99.         case Const.ILOAD:
  100.         case Const.ISTORE:
  101.             return Type.INT;
  102.         case Const.LLOAD:
  103.         case Const.LSTORE:
  104.             return Type.LONG;
  105.         case Const.DLOAD:
  106.         case Const.DSTORE:
  107.             return Type.DOUBLE;
  108.         case Const.FLOAD:
  109.         case Const.FSTORE:
  110.             return Type.FLOAT;
  111.         case Const.ALOAD:
  112.         case Const.ASTORE:
  113.             return Type.OBJECT;
  114.         default:
  115.             throw new ClassGenException("Unknown case in switch" + canonTag);
  116.         }
  117.     }

  118.     /**
  119.      * Read needed data (e.g. index) from file.
  120.      *
  121.      * <pre>
  122.      * (ILOAD &lt;= tag &lt;= ALOAD_3) || (ISTORE &lt;= tag &lt;= ASTORE_3)
  123.      * </pre>
  124.      */
  125.     @Override
  126.     protected void initFromFile(final ByteSequence bytes, final boolean wide) throws IOException {
  127.         if (wide) {
  128.             n = bytes.readUnsignedShort();
  129.             super.setLength(4);
  130.         } else {
  131.             final short opcode = super.getOpcode();
  132.             if (opcode >= Const.ILOAD && opcode <= Const.ALOAD || opcode >= Const.ISTORE && opcode <= Const.ASTORE) {
  133.                 n = bytes.readUnsignedByte();
  134.                 super.setLength(2);
  135.             } else {
  136.                 if (opcode <= Const.ALOAD_3) { // compact load instruction such as ILOAD_2
  137.                     n = (opcode - Const.ILOAD_0) % 4;
  138.                 } else { // Assert ISTORE_0 <= tag <= ASTORE_3
  139.                     n = (opcode - Const.ISTORE_0) % 4;
  140.                 }
  141.                 super.setLength(1);
  142.             }
  143.         }
  144.     }

  145.     /**
  146.      * Sets the local variable index. also updates opcode and length TODO Why?
  147.      *
  148.      * @see #setIndexOnly(int)
  149.      */
  150.     @Override
  151.     public void setIndex(final int n) { // TODO could be package-protected?
  152.         if (n < 0 || n > Const.MAX_SHORT) {
  153.             throw new ClassGenException("Illegal value: " + n);
  154.         }
  155.         this.n = n;
  156.         // Cannot be < 0 as this is checked above
  157.         if (n <= 3) { // Use more compact instruction xLOAD_n
  158.             super.setOpcode((short) (cTag + n));
  159.             super.setLength(1);
  160.         } else {
  161.             super.setOpcode(canonTag);
  162.             if (wide()) {
  163.                 super.setLength(4);
  164.             } else {
  165.                 super.setLength(2);
  166.             }
  167.         }
  168.     }

  169.     /**
  170.      * Sets the index of the referenced variable (n) only
  171.      *
  172.      * @since 6.0
  173.      * @see #setIndex(int)
  174.      */
  175.     final void setIndexOnly(final int n) {
  176.         this.n = n;
  177.     }

  178.     /**
  179.      * Long output format:
  180.      *
  181.      * &lt;name of opcode&gt; "["&lt;opcode number&gt;"]" "("&lt;length of instruction&gt;")" "&lt;"&lt; local variable
  182.      * index&gt;"&gt;"
  183.      *
  184.      * @param verbose long/short format switch
  185.      * @return mnemonic for instruction
  186.      */
  187.     @Override
  188.     public String toString(final boolean verbose) {
  189.         final short opcode = super.getOpcode();
  190.         if (opcode >= Const.ILOAD_0 && opcode <= Const.ALOAD_3 || opcode >= Const.ISTORE_0 && opcode <= Const.ASTORE_3) {
  191.             return super.toString(verbose);
  192.         }
  193.         return super.toString(verbose) + " " + n;
  194.     }

  195.     private boolean wide() {
  196.         return n > Const.MAX_BYTE;
  197.     }
  198. }