001 /*
002 * Licensed to the Apache Software Foundation (ASF) under one or more
003 * contributor license agreements. See the NOTICE file distributed with
004 * this work for additional information regarding copyright ownership.
005 * The ASF licenses this file to You under the Apache License, Version 2.0
006 * (the "License"); you may not use this file except in compliance with
007 * the License. You may obtain a copy of the License at
008 *
009 * http://www.apache.org/licenses/LICENSE-2.0
010 *
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 * See the License for the specific language governing permissions and
015 * limitations under the License.
016 *
017 */
018 package org.apache.bcel.generic;
019
020 import java.io.DataOutputStream;
021 import java.io.IOException;
022 import java.io.Serializable;
023 import org.apache.bcel.Constants;
024 import org.apache.bcel.classfile.ConstantPool;
025 import org.apache.bcel.util.ByteSequence;
026
027 /**
028 * Abstract super class for all Java byte codes.
029 *
030 * @version $Id: Instruction.java 1152072 2011-07-29 01:54:05Z dbrosius $
031 * @author <A HREF="mailto:m.dahm@gmx.de">M. Dahm</A>
032 */
033 public abstract class Instruction implements Cloneable, Serializable {
034
035 private static final long serialVersionUID = -2518741982574515847L;
036 protected short length = 1; // Length of instruction in bytes
037 protected short opcode = -1; // Opcode number
038 private static InstructionComparator cmp = InstructionComparator.DEFAULT;
039
040
041 /**
042 * Empty constructor needed for the Class.newInstance() statement in
043 * Instruction.readInstruction(). Not to be used otherwise.
044 */
045 Instruction() {
046 }
047
048
049 public Instruction(short opcode, short length) {
050 this.length = length;
051 this.opcode = opcode;
052 }
053
054
055 /**
056 * Dump instruction as byte code to stream out.
057 * @param out Output stream
058 */
059 public void dump( DataOutputStream out ) throws IOException {
060 out.writeByte(opcode); // Common for all instructions
061 }
062
063
064 /** @return name of instruction, i.e., opcode name
065 */
066 public String getName() {
067 return Constants.OPCODE_NAMES[opcode];
068 }
069
070
071 /**
072 * Long output format:
073 *
074 * <name of opcode> "["<opcode number>"]"
075 * "("<length of instruction>")"
076 *
077 * @param verbose long/short format switch
078 * @return mnemonic for instruction
079 */
080 public String toString( boolean verbose ) {
081 if (verbose) {
082 return getName() + "[" + opcode + "](" + length + ")";
083 } else {
084 return getName();
085 }
086 }
087
088
089 /**
090 * @return mnemonic for instruction in verbose format
091 */
092 @Override
093 public String toString() {
094 return toString(true);
095 }
096
097
098 /**
099 * @return mnemonic for instruction with sumbolic references resolved
100 */
101 public String toString( ConstantPool cp ) {
102 return toString(false);
103 }
104
105
106 /**
107 * Use with caution, since `BranchInstruction's have a `target' reference which
108 * is not copied correctly (only basic types are). This also applies for
109 * `Select' instructions with their multiple branch targets.
110 *
111 * @see BranchInstruction
112 * @return (shallow) copy of an instruction
113 */
114 public Instruction copy() {
115 Instruction i = null;
116 // "Constant" instruction, no need to duplicate
117 if (InstructionConstants.INSTRUCTIONS[this.getOpcode()] != null) {
118 i = this;
119 } else {
120 try {
121 i = (Instruction) clone();
122 } catch (CloneNotSupportedException e) {
123 System.err.println(e);
124 }
125 }
126 return i;
127 }
128
129
130 /**
131 * Read needed data (e.g. index) from file.
132 *
133 * @param bytes byte sequence to read from
134 * @param wide "wide" instruction flag
135 */
136 protected void initFromFile( ByteSequence bytes, boolean wide ) throws IOException {
137 }
138
139
140 /**
141 * Read an instruction from (byte code) input stream and return the
142 * appropiate object.
143 *
144 * @param bytes input stream bytes
145 * @return instruction object being read
146 */
147 public static final Instruction readInstruction( ByteSequence bytes ) throws IOException {
148 boolean wide = false;
149 short opcode = (short) bytes.readUnsignedByte();
150 Instruction obj = null;
151 if (opcode == Constants.WIDE) { // Read next opcode after wide byte
152 wide = true;
153 opcode = (short) bytes.readUnsignedByte();
154 }
155 if (InstructionConstants.INSTRUCTIONS[opcode] != null) {
156 return InstructionConstants.INSTRUCTIONS[opcode]; // Used predefined immutable object, if available
157 }
158
159 switch (opcode) {
160 case Constants.BIPUSH:
161 obj = new BIPUSH();
162 break;
163 case Constants.SIPUSH:
164 obj = new SIPUSH();
165 break;
166 case Constants.LDC:
167 obj = new LDC();
168 break;
169 case Constants.LDC_W:
170 obj = new LDC_W();
171 break;
172 case Constants.LDC2_W:
173 obj = new LDC2_W();
174 break;
175 case Constants.ILOAD:
176 obj = new ILOAD();
177 break;
178 case Constants.LLOAD:
179 obj = new LLOAD();
180 break;
181 case Constants.FLOAD:
182 obj = new FLOAD();
183 break;
184 case Constants.DLOAD:
185 obj = new DLOAD();
186 break;
187 case Constants.ALOAD:
188 obj = new ALOAD();
189 break;
190 case Constants.ILOAD_0:
191 obj = new ILOAD(0);
192 break;
193 case Constants.ILOAD_1:
194 obj = new ILOAD(1);
195 break;
196 case Constants.ILOAD_2:
197 obj = new ILOAD(2);
198 break;
199 case Constants.ILOAD_3:
200 obj = new ILOAD(3);
201 break;
202 case Constants.LLOAD_0:
203 obj = new LLOAD(0);
204 break;
205 case Constants.LLOAD_1:
206 obj = new LLOAD(1);
207 break;
208 case Constants.LLOAD_2:
209 obj = new LLOAD(2);
210 break;
211 case Constants.LLOAD_3:
212 obj = new LLOAD(3);
213 break;
214 case Constants.FLOAD_0:
215 obj = new FLOAD(0);
216 break;
217 case Constants.FLOAD_1:
218 obj = new FLOAD(1);
219 break;
220 case Constants.FLOAD_2:
221 obj = new FLOAD(2);
222 break;
223 case Constants.FLOAD_3:
224 obj = new FLOAD(3);
225 break;
226 case Constants.DLOAD_0:
227 obj = new DLOAD(0);
228 break;
229 case Constants.DLOAD_1:
230 obj = new DLOAD(1);
231 break;
232 case Constants.DLOAD_2:
233 obj = new DLOAD(2);
234 break;
235 case Constants.DLOAD_3:
236 obj = new DLOAD(3);
237 break;
238 case Constants.ALOAD_0:
239 obj = new ALOAD(0);
240 break;
241 case Constants.ALOAD_1:
242 obj = new ALOAD(1);
243 break;
244 case Constants.ALOAD_2:
245 obj = new ALOAD(2);
246 break;
247 case Constants.ALOAD_3:
248 obj = new ALOAD(3);
249 break;
250 case Constants.ISTORE:
251 obj = new ISTORE();
252 break;
253 case Constants.LSTORE:
254 obj = new LSTORE();
255 break;
256 case Constants.FSTORE:
257 obj = new FSTORE();
258 break;
259 case Constants.DSTORE:
260 obj = new DSTORE();
261 break;
262 case Constants.ASTORE:
263 obj = new ASTORE();
264 break;
265 case Constants.ISTORE_0:
266 obj = new ISTORE(0);
267 break;
268 case Constants.ISTORE_1:
269 obj = new ISTORE(1);
270 break;
271 case Constants.ISTORE_2:
272 obj = new ISTORE(2);
273 break;
274 case Constants.ISTORE_3:
275 obj = new ISTORE(3);
276 break;
277 case Constants.LSTORE_0:
278 obj = new LSTORE(0);
279 break;
280 case Constants.LSTORE_1:
281 obj = new LSTORE(1);
282 break;
283 case Constants.LSTORE_2:
284 obj = new LSTORE(2);
285 break;
286 case Constants.LSTORE_3:
287 obj = new LSTORE(3);
288 break;
289 case Constants.FSTORE_0:
290 obj = new FSTORE(0);
291 break;
292 case Constants.FSTORE_1:
293 obj = new FSTORE(1);
294 break;
295 case Constants.FSTORE_2:
296 obj = new FSTORE(2);
297 break;
298 case Constants.FSTORE_3:
299 obj = new FSTORE(3);
300 break;
301 case Constants.DSTORE_0:
302 obj = new DSTORE(0);
303 break;
304 case Constants.DSTORE_1:
305 obj = new DSTORE(1);
306 break;
307 case Constants.DSTORE_2:
308 obj = new DSTORE(2);
309 break;
310 case Constants.DSTORE_3:
311 obj = new DSTORE(3);
312 break;
313 case Constants.ASTORE_0:
314 obj = new ASTORE(0);
315 break;
316 case Constants.ASTORE_1:
317 obj = new ASTORE(1);
318 break;
319 case Constants.ASTORE_2:
320 obj = new ASTORE(2);
321 break;
322 case Constants.ASTORE_3:
323 obj = new ASTORE(3);
324 break;
325 case Constants.IINC:
326 obj = new IINC();
327 break;
328 case Constants.IFEQ:
329 obj = new IFEQ();
330 break;
331 case Constants.IFNE:
332 obj = new IFNE();
333 break;
334 case Constants.IFLT:
335 obj = new IFLT();
336 break;
337 case Constants.IFGE:
338 obj = new IFGE();
339 break;
340 case Constants.IFGT:
341 obj = new IFGT();
342 break;
343 case Constants.IFLE:
344 obj = new IFLE();
345 break;
346 case Constants.IF_ICMPEQ:
347 obj = new IF_ICMPEQ();
348 break;
349 case Constants.IF_ICMPNE:
350 obj = new IF_ICMPNE();
351 break;
352 case Constants.IF_ICMPLT:
353 obj = new IF_ICMPLT();
354 break;
355 case Constants.IF_ICMPGE:
356 obj = new IF_ICMPGE();
357 break;
358 case Constants.IF_ICMPGT:
359 obj = new IF_ICMPGT();
360 break;
361 case Constants.IF_ICMPLE:
362 obj = new IF_ICMPLE();
363 break;
364 case Constants.IF_ACMPEQ:
365 obj = new IF_ACMPEQ();
366 break;
367 case Constants.IF_ACMPNE:
368 obj = new IF_ACMPNE();
369 break;
370 case Constants.GOTO:
371 obj = new GOTO();
372 break;
373 case Constants.JSR:
374 obj = new JSR();
375 break;
376 case Constants.RET:
377 obj = new RET();
378 break;
379 case Constants.TABLESWITCH:
380 obj = new TABLESWITCH();
381 break;
382 case Constants.LOOKUPSWITCH:
383 obj = new LOOKUPSWITCH();
384 break;
385 case Constants.GETSTATIC:
386 obj = new GETSTATIC();
387 break;
388 case Constants.PUTSTATIC:
389 obj = new PUTSTATIC();
390 break;
391 case Constants.GETFIELD:
392 obj = new GETFIELD();
393 break;
394 case Constants.PUTFIELD:
395 obj = new PUTFIELD();
396 break;
397 case Constants.INVOKEVIRTUAL:
398 obj = new INVOKEVIRTUAL();
399 break;
400 case Constants.INVOKESPECIAL:
401 obj = new INVOKESPECIAL();
402 break;
403 case Constants.INVOKESTATIC:
404 obj = new INVOKESTATIC();
405 break;
406 case Constants.INVOKEINTERFACE:
407 obj = new INVOKEINTERFACE();
408 break;
409 case Constants.NEW:
410 obj = new NEW();
411 break;
412 case Constants.NEWARRAY:
413 obj = new NEWARRAY();
414 break;
415 case Constants.ANEWARRAY:
416 obj = new ANEWARRAY();
417 break;
418 case Constants.CHECKCAST:
419 obj = new CHECKCAST();
420 break;
421 case Constants.INSTANCEOF:
422 obj = new INSTANCEOF();
423 break;
424 case Constants.MULTIANEWARRAY:
425 obj = new MULTIANEWARRAY();
426 break;
427 case Constants.IFNULL:
428 obj = new IFNULL();
429 break;
430 case Constants.IFNONNULL:
431 obj = new IFNONNULL();
432 break;
433 case Constants.GOTO_W:
434 obj = new GOTO_W();
435 break;
436 case Constants.JSR_W:
437 obj = new JSR_W();
438 break;
439 case Constants.BREAKPOINT:
440 obj = new BREAKPOINT();
441 break;
442 case Constants.IMPDEP1:
443 obj = new IMPDEP1();
444 break;
445 case Constants.IMPDEP2:
446 obj = new IMPDEP2();
447 break;
448 default:
449 throw new ClassGenException("Illegal opcode detected: " + opcode);
450
451 }
452
453 if (wide
454 && !((obj instanceof LocalVariableInstruction) || (obj instanceof IINC) || (obj instanceof RET))) {
455 throw new ClassGenException("Illegal opcode after wide: " + opcode);
456 }
457 obj.setOpcode(opcode);
458 obj.initFromFile(bytes, wide); // Do further initializations, if any
459 return obj;
460 }
461
462 /**
463 * This method also gives right results for instructions whose
464 * effect on the stack depends on the constant pool entry they
465 * reference.
466 * @return Number of words consumed from stack by this instruction,
467 * or Constants.UNPREDICTABLE, if this can not be computed statically
468 */
469 public int consumeStack( ConstantPoolGen cpg ) {
470 return Constants.CONSUME_STACK[opcode];
471 }
472
473
474 /**
475 * This method also gives right results for instructions whose
476 * effect on the stack depends on the constant pool entry they
477 * reference.
478 * @return Number of words produced onto stack by this instruction,
479 * or Constants.UNPREDICTABLE, if this can not be computed statically
480 */
481 public int produceStack( ConstantPoolGen cpg ) {
482 return Constants.PRODUCE_STACK[opcode];
483 }
484
485
486 /**
487 * @return this instructions opcode
488 */
489 public short getOpcode() {
490 return opcode;
491 }
492
493
494 /**
495 * @return length (in bytes) of instruction
496 */
497 public int getLength() {
498 return length;
499 }
500
501
502 /**
503 * Needed in readInstruction.
504 */
505 private void setOpcode( short opcode ) {
506 this.opcode = opcode;
507 }
508
509
510 /** Some instructions may be reused, so don't do anything by default.
511 */
512 void dispose() {
513 }
514
515
516 /**
517 * Call corresponding visitor method(s). The order is:
518 * Call visitor methods of implemented interfaces first, then
519 * call methods according to the class hierarchy in descending order,
520 * i.e., the most specific visitXXX() call comes last.
521 *
522 * @param v Visitor object
523 */
524 public abstract void accept( Visitor v );
525
526
527 /** Get Comparator object used in the equals() method to determine
528 * equality of instructions.
529 *
530 * @return currently used comparator for equals()
531 * @deprecated use the built in comparator, or wrap this class in another object that implements these methods
532 */
533 @Deprecated
534 public static InstructionComparator getComparator() {
535 return cmp;
536 }
537
538
539 /** Set comparator to be used for equals().
540 * @deprecated use the built in comparator, or wrap this class in another object that implements these methods
541 */
542 @Deprecated
543 public static void setComparator( InstructionComparator c ) {
544 cmp = c;
545 }
546
547
548 /** Check for equality, delegated to comparator
549 * @return true if that is an Instruction and has the same opcode
550 */
551 @Override
552 public boolean equals( Object that ) {
553 return (that instanceof Instruction) ? cmp.equals(this, (Instruction) that) : false;
554 }
555 }