1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.apache.bcel.generic;
18
19 import java.io.DataOutputStream;
20 import java.io.IOException;
21 import org.apache.bcel.Constants;
22 import org.apache.bcel.util.ByteSequence;
23
24 /***
25 * Abstract super class for instructions dealing with local variables.
26 *
27 * @version $Id: LocalVariableInstruction.java 386056 2006-03-15 11:31:56Z tcurdt $
28 * @author <A HREF="mailto:m.dahm@gmx.de">M. Dahm</A>
29 */
30 public abstract class LocalVariableInstruction extends Instruction implements TypedInstruction,
31 IndexedInstruction {
32
33 protected int n = -1;
34 private short c_tag = -1;
35 private short canon_tag = -1;
36
37
38 private final boolean wide() {
39 return n > Constants.MAX_BYTE;
40 }
41
42
43 /***
44 * Empty constructor needed for the Class.newInstance() statement in
45 * Instruction.readInstruction(). Not to be used otherwise.
46 * tag and length are defined in readInstruction and initFromFile, respectively.
47 */
48 LocalVariableInstruction(short canon_tag, short c_tag) {
49 super();
50 this.canon_tag = canon_tag;
51 this.c_tag = c_tag;
52 }
53
54
55 /***
56 * Empty constructor needed for the Class.newInstance() statement in
57 * Instruction.readInstruction(). Also used by IINC()!
58 */
59 LocalVariableInstruction() {
60 }
61
62
63 /***
64 * @param opcode Instruction opcode
65 * @param c_tag Instruction number for compact version, ALOAD_0, e.g.
66 * @param n local variable index (unsigned short)
67 */
68 protected LocalVariableInstruction(short opcode, short c_tag, int n) {
69 super(opcode, (short) 2);
70 this.c_tag = c_tag;
71 canon_tag = opcode;
72 setIndex(n);
73 }
74
75
76 /***
77 * Dump instruction as byte code to stream out.
78 * @param out Output stream
79 */
80 public void dump( DataOutputStream out ) throws IOException {
81 if (wide()) {
82 out.writeByte(Constants.WIDE);
83 }
84 out.writeByte(opcode);
85 if (length > 1) {
86 if (wide()) {
87 out.writeShort(n);
88 } else {
89 out.writeByte(n);
90 }
91 }
92 }
93
94
95 /***
96 * Long output format:
97 *
98 * <name of opcode> "["<opcode number>"]"
99 * "("<length of instruction>")" "<"< local variable index>">"
100 *
101 * @param verbose long/short format switch
102 * @return mnemonic for instruction
103 */
104 public String toString( boolean verbose ) {
105 if (((opcode >= Constants.ILOAD_0) && (opcode <= Constants.ALOAD_3))
106 || ((opcode >= Constants.ISTORE_0) && (opcode <= Constants.ASTORE_3))) {
107 return super.toString(verbose);
108 } else {
109 return super.toString(verbose) + " " + n;
110 }
111 }
112
113
114 /***
115 * Read needed data (e.g. index) from file.
116 * PRE: (ILOAD <= tag <= ALOAD_3) || (ISTORE <= tag <= ASTORE_3)
117 */
118 protected void initFromFile( ByteSequence bytes, boolean wide ) throws IOException {
119 if (wide) {
120 n = bytes.readUnsignedShort();
121 length = 4;
122 } else if (((opcode >= Constants.ILOAD) && (opcode <= Constants.ALOAD))
123 || ((opcode >= Constants.ISTORE) && (opcode <= Constants.ASTORE))) {
124 n = bytes.readUnsignedByte();
125 length = 2;
126 } else if (opcode <= Constants.ALOAD_3) {
127 n = (opcode - Constants.ILOAD_0) % 4;
128 length = 1;
129 } else {
130 n = (opcode - Constants.ISTORE_0) % 4;
131 length = 1;
132 }
133 }
134
135
136 /***
137 * @return local variable index referred by this instruction.
138 */
139 public final int getIndex() {
140 return n;
141 }
142
143
144 /***
145 * Set the local variable index
146 */
147 public void setIndex( int n ) {
148 if ((n < 0) || (n > Constants.MAX_SHORT)) {
149 throw new ClassGenException("Illegal value: " + n);
150 }
151 this.n = n;
152 if (n >= 0 && n <= 3) {
153 opcode = (short) (c_tag + n);
154 length = 1;
155 } else {
156 opcode = canon_tag;
157 if (wide()) {
158 length = 4;
159 } else {
160 length = 2;
161 }
162 }
163 }
164
165
166 /*** @return canonical tag for instruction, e.g., ALOAD for ALOAD_0
167 */
168 public short getCanonicalTag() {
169 return canon_tag;
170 }
171
172
173 /***
174 * Returns the type associated with the instruction -
175 * in case of ALOAD or ASTORE Type.OBJECT is returned.
176 * This is just a bit incorrect, because ALOAD and ASTORE
177 * may work on every ReferenceType (including Type.NULL) and
178 * ASTORE may even work on a ReturnaddressType .
179 * @return type associated with the instruction
180 */
181 public Type getType( ConstantPoolGen cp ) {
182 switch (canon_tag) {
183 case Constants.ILOAD:
184 case Constants.ISTORE:
185 return Type.INT;
186 case Constants.LLOAD:
187 case Constants.LSTORE:
188 return Type.LONG;
189 case Constants.DLOAD:
190 case Constants.DSTORE:
191 return Type.DOUBLE;
192 case Constants.FLOAD:
193 case Constants.FSTORE:
194 return Type.FLOAT;
195 case Constants.ALOAD:
196 case Constants.ASTORE:
197 return Type.OBJECT;
198 default:
199 throw new ClassGenException("Oops: unknown case in switch" + canon_tag);
200 }
201 }
202 }