View Javadoc
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   */
18  package org.apache.bcel.generic;
19  
20  import java.io.DataOutputStream;
21  import java.io.IOException;
22  
23  import org.apache.bcel.Const;
24  import org.apache.bcel.util.ByteSequence;
25  
26  /**
27   * Abstract super class for instructions dealing with local variables.
28   *
29   * @version $Id: LocalVariableInstruction.html 1021978 2017-12-09 17:38:21Z ggregory $
30   */
31  public abstract class LocalVariableInstruction extends Instruction implements TypedInstruction,
32          IndexedInstruction {
33  
34      /**
35       * @deprecated (since 6.0) will be made private; do not access directly, use getter/setter
36       */
37      @Deprecated
38      protected int n = -1; // index of referenced variable
39  
40      private short c_tag = -1; // compact version, such as ILOAD_0
41      private short canon_tag = -1; // canonical tag such as ILOAD
42  
43  
44      private boolean wide() {
45          return n > Const.MAX_BYTE;
46      }
47  
48  
49      /**
50       * Empty constructor needed for Instruction.readInstruction.
51       * Not to be used otherwise.
52       * tag and length are defined in readInstruction and initFromFile, respectively.
53       */
54      LocalVariableInstruction(final short canon_tag, final short c_tag) {
55          super();
56          this.canon_tag = canon_tag;
57          this.c_tag = c_tag;
58      }
59  
60  
61      /**
62       * Empty constructor needed for Instruction.readInstruction.
63       * Also used by IINC()!
64       */
65      LocalVariableInstruction() {
66      }
67  
68  
69      /**
70       * @param opcode Instruction opcode
71       * @param c_tag Instruction number for compact version, ALOAD_0, e.g.
72       * @param n local variable index (unsigned short)
73       */
74      protected LocalVariableInstruction(final short opcode, final short c_tag, final int n) {
75          super(opcode, (short) 2);
76          this.c_tag = c_tag;
77          canon_tag = opcode;
78          setIndex(n);
79      }
80  
81  
82      /**
83       * Dump instruction as byte code to stream out.
84       * @param out Output stream
85       */
86      @Override
87      public void dump( final DataOutputStream out ) throws IOException {
88          if (wide()) {
89              out.writeByte(Const.WIDE);
90          }
91          out.writeByte(super.getOpcode());
92          if (super.getLength() > 1) { // Otherwise ILOAD_n, instruction, e.g.
93              if (wide()) {
94                  out.writeShort(n);
95              } else {
96                  out.writeByte(n);
97              }
98          }
99      }
100 
101 
102     /**
103      * Long output format:
104      *
105      * <name of opcode> "["<opcode number>"]"
106      * "("<length of instruction>")" "<"< local variable index>">"
107      *
108      * @param verbose long/short format switch
109      * @return mnemonic for instruction
110      */
111     @Override
112     public String toString( final boolean verbose ) {
113         final short _opcode = super.getOpcode();
114         if (((_opcode >= Const.ILOAD_0) && (_opcode <= Const.ALOAD_3))
115          || ((_opcode >= Const.ISTORE_0) && (_opcode <= Const.ASTORE_3))) {
116             return super.toString(verbose);
117         }
118         return super.toString(verbose) + " " + n;
119     }
120 
121 
122     /**
123      * Read needed data (e.g. index) from file.
124      * <pre>
125      * (ILOAD &lt;= tag &lt;= ALOAD_3) || (ISTORE &lt;= tag &lt;= ASTORE_3)
126      * </pre>
127      */
128     @Override
129     protected void initFromFile( final ByteSequence bytes, final boolean wide ) throws IOException {
130         if (wide) {
131             n = bytes.readUnsignedShort();
132             super.setLength(4);
133         } else {
134             final short _opcode = super.getOpcode();
135             if (((_opcode >= Const.ILOAD) && (_opcode <= Const.ALOAD))
136              || ((_opcode >= Const.ISTORE) && (_opcode <= Const.ASTORE))) {
137                 n = bytes.readUnsignedByte();
138                 super.setLength(2);
139             } else if (_opcode <= Const.ALOAD_3) { // compact load instruction such as ILOAD_2
140                 n = (_opcode - Const.ILOAD_0) % 4;
141                 super.setLength(1);
142             } else { // Assert ISTORE_0 <= tag <= ASTORE_3
143                 n = (_opcode - Const.ISTORE_0) % 4;
144                 super.setLength(1);
145             }
146         }
147     }
148 
149 
150     /**
151      * @return local variable index (n) referred by this instruction.
152      */
153     @Override
154     public final int getIndex() {
155         return n;
156     }
157 
158 
159     /**
160      * Set the local variable index.
161      * also updates opcode and length
162      * TODO Why?
163      * @see #setIndexOnly(int)
164      */
165     @Override
166     public void setIndex( final int n ) { // TODO could be package-protected?
167         if ((n < 0) || (n > Const.MAX_SHORT)) {
168             throw new ClassGenException("Illegal value: " + n);
169         }
170         this.n = n;
171         // Cannot be < 0 as this is checked above
172         if (n <= 3) { // Use more compact instruction xLOAD_n
173             super.setOpcode((short) (c_tag + n));
174             super.setLength(1);
175         } else {
176             super.setOpcode(canon_tag);
177             if (wide()) {
178                 super.setLength(4);
179             } else {
180                 super.setLength(2);
181             }
182         }
183     }
184 
185 
186     /** @return canonical tag for instruction, e.g., ALOAD for ALOAD_0
187      */
188     public short getCanonicalTag() {
189         return canon_tag;
190     }
191 
192 
193     /**
194      * Returns the type associated with the instruction -
195      * in case of ALOAD or ASTORE Type.OBJECT is returned.
196      * This is just a bit incorrect, because ALOAD and ASTORE
197      * may work on every ReferenceType (including Type.NULL) and
198      * ASTORE may even work on a ReturnaddressType .
199      * @return type associated with the instruction
200      */
201     @Override
202     public Type getType( final ConstantPoolGen cp ) {
203         switch (canon_tag) {
204             case Const.ILOAD:
205             case Const.ISTORE:
206                 return Type.INT;
207             case Const.LLOAD:
208             case Const.LSTORE:
209                 return Type.LONG;
210             case Const.DLOAD:
211             case Const.DSTORE:
212                 return Type.DOUBLE;
213             case Const.FLOAD:
214             case Const.FSTORE:
215                 return Type.FLOAT;
216             case Const.ALOAD:
217             case Const.ASTORE:
218                 return Type.OBJECT;
219             default:
220                 throw new ClassGenException("Oops: unknown case in switch" + canon_tag);
221         }
222     }
223 
224     /**
225      * Sets the index of the referenced variable (n) only
226      * @since 6.0
227      * @see #setIndex(int)
228      */
229     final void setIndexOnly(final int n) {
230         this.n = n;
231     }
232 }