View Javadoc
1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one
3    * or more contributor license agreements.  See the NOTICE file
4    * distributed with this work for additional information
5    * regarding copyright ownership.  The ASF licenses this file
6    * to you under the Apache License, Version 2.0 (the
7    * "License"); you may not use this file except in compliance
8    * with the License.  You may obtain a copy of the License at
9    *
10   *   https://www.apache.org/licenses/LICENSE-2.0
11   *
12   * Unless required by applicable law or agreed to in writing,
13   * software distributed under the License is distributed on an
14   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15   * KIND, either express or implied.  See the License for the
16   * specific language governing permissions and limitations
17   * under the License.
18   */
19  package org.apache.bcel.generic;
20  
21  import java.io.DataOutputStream;
22  import java.io.IOException;
23  
24  import org.apache.bcel.Const;
25  import org.apache.bcel.classfile.ConstantPool;
26  import org.apache.bcel.util.ByteSequence;
27  
28  /**
29   * Abstract super class for all Java byte codes.
30   */
31  public abstract class Instruction implements Cloneable {
32  
33      static final Instruction[] EMPTY_ARRAY = {};
34  
35      private static InstructionComparator cmp = InstructionComparator.DEFAULT;
36  
37      /**
38       * Gets Comparator object used in the equals() method to determine equality of instructions.
39       *
40       * @return currently used comparator for equals().
41       * @deprecated (6.0) use the built in comparator, or wrap this class in another object that implements these methods
42       */
43      @Deprecated
44      public static InstructionComparator getComparator() {
45          return cmp;
46      }
47  
48      /**
49       * Tests if the value can fit in a byte (signed)
50       *
51       * @param value the value to check.
52       * @return true if the value is in range.
53       * @since 6.0
54       */
55      public static boolean isValidByte(final int value) {
56          return value >= Byte.MIN_VALUE && value <= Byte.MAX_VALUE;
57      }
58  
59      /**
60       * Tests if the value can fit in a short (signed)
61       *
62       * @param value the value to check.
63       * @return true if the value is in range.
64       * @since 6.0
65       */
66      public static boolean isValidShort(final int value) {
67          return value >= Short.MIN_VALUE && value <= Short.MAX_VALUE;
68      }
69  
70      /**
71       * Reads an instruction from (byte code) input stream and return the appropriate object.
72       * <p>
73       * If the Instruction is defined in {@link InstructionConst}, then the singleton instance is returned.
74       * </p>
75       *
76       * @param bytes input stream bytes.
77       * @return instruction object being read.
78       * @throws IOException Thrown when an I/O exception of some sort has occurred.
79       * @see InstructionConst#getInstruction(int)
80       */
81      // @since 6.0 no longer final
82      public static Instruction readInstruction(final ByteSequence bytes) throws IOException {
83          boolean wide = false;
84          short opcode = (short) bytes.readUnsignedByte();
85          Instruction obj = null;
86          if (opcode == Const.WIDE) { // Read next opcode after wide byte
87              wide = true;
88              opcode = (short) bytes.readUnsignedByte();
89          }
90          final Instruction instruction = InstructionConst.getInstruction(opcode);
91          if (instruction != null) {
92              return instruction; // Used predefined immutable object, if available
93          }
94  
95          switch (opcode) {
96          case Const.BIPUSH:
97              obj = new BIPUSH();
98              break;
99          case Const.SIPUSH:
100             obj = new SIPUSH();
101             break;
102         case Const.LDC:
103             obj = new LDC();
104             break;
105         case Const.LDC_W:
106             obj = new LDC_W();
107             break;
108         case Const.LDC2_W:
109             obj = new LDC2_W();
110             break;
111         case Const.ILOAD:
112             obj = new ILOAD();
113             break;
114         case Const.LLOAD:
115             obj = new LLOAD();
116             break;
117         case Const.FLOAD:
118             obj = new FLOAD();
119             break;
120         case Const.DLOAD:
121             obj = new DLOAD();
122             break;
123         case Const.ALOAD:
124             obj = new ALOAD();
125             break;
126         case Const.ILOAD_0:
127             obj = new ILOAD(0);
128             break;
129         case Const.ILOAD_1:
130             obj = new ILOAD(1);
131             break;
132         case Const.ILOAD_2:
133             obj = new ILOAD(2);
134             break;
135         case Const.ILOAD_3:
136             obj = new ILOAD(3);
137             break;
138         case Const.LLOAD_0:
139             obj = new LLOAD(0);
140             break;
141         case Const.LLOAD_1:
142             obj = new LLOAD(1);
143             break;
144         case Const.LLOAD_2:
145             obj = new LLOAD(2);
146             break;
147         case Const.LLOAD_3:
148             obj = new LLOAD(3);
149             break;
150         case Const.FLOAD_0:
151             obj = new FLOAD(0);
152             break;
153         case Const.FLOAD_1:
154             obj = new FLOAD(1);
155             break;
156         case Const.FLOAD_2:
157             obj = new FLOAD(2);
158             break;
159         case Const.FLOAD_3:
160             obj = new FLOAD(3);
161             break;
162         case Const.DLOAD_0:
163             obj = new DLOAD(0);
164             break;
165         case Const.DLOAD_1:
166             obj = new DLOAD(1);
167             break;
168         case Const.DLOAD_2:
169             obj = new DLOAD(2);
170             break;
171         case Const.DLOAD_3:
172             obj = new DLOAD(3);
173             break;
174         case Const.ALOAD_0:
175             obj = new ALOAD(0);
176             break;
177         case Const.ALOAD_1:
178             obj = new ALOAD(1);
179             break;
180         case Const.ALOAD_2:
181             obj = new ALOAD(2);
182             break;
183         case Const.ALOAD_3:
184             obj = new ALOAD(3);
185             break;
186         case Const.ISTORE:
187             obj = new ISTORE();
188             break;
189         case Const.LSTORE:
190             obj = new LSTORE();
191             break;
192         case Const.FSTORE:
193             obj = new FSTORE();
194             break;
195         case Const.DSTORE:
196             obj = new DSTORE();
197             break;
198         case Const.ASTORE:
199             obj = new ASTORE();
200             break;
201         case Const.ISTORE_0:
202             obj = new ISTORE(0);
203             break;
204         case Const.ISTORE_1:
205             obj = new ISTORE(1);
206             break;
207         case Const.ISTORE_2:
208             obj = new ISTORE(2);
209             break;
210         case Const.ISTORE_3:
211             obj = new ISTORE(3);
212             break;
213         case Const.LSTORE_0:
214             obj = new LSTORE(0);
215             break;
216         case Const.LSTORE_1:
217             obj = new LSTORE(1);
218             break;
219         case Const.LSTORE_2:
220             obj = new LSTORE(2);
221             break;
222         case Const.LSTORE_3:
223             obj = new LSTORE(3);
224             break;
225         case Const.FSTORE_0:
226             obj = new FSTORE(0);
227             break;
228         case Const.FSTORE_1:
229             obj = new FSTORE(1);
230             break;
231         case Const.FSTORE_2:
232             obj = new FSTORE(2);
233             break;
234         case Const.FSTORE_3:
235             obj = new FSTORE(3);
236             break;
237         case Const.DSTORE_0:
238             obj = new DSTORE(0);
239             break;
240         case Const.DSTORE_1:
241             obj = new DSTORE(1);
242             break;
243         case Const.DSTORE_2:
244             obj = new DSTORE(2);
245             break;
246         case Const.DSTORE_3:
247             obj = new DSTORE(3);
248             break;
249         case Const.ASTORE_0:
250             obj = new ASTORE(0);
251             break;
252         case Const.ASTORE_1:
253             obj = new ASTORE(1);
254             break;
255         case Const.ASTORE_2:
256             obj = new ASTORE(2);
257             break;
258         case Const.ASTORE_3:
259             obj = new ASTORE(3);
260             break;
261         case Const.IINC:
262             obj = new IINC();
263             break;
264         case Const.IFEQ:
265             obj = new IFEQ();
266             break;
267         case Const.IFNE:
268             obj = new IFNE();
269             break;
270         case Const.IFLT:
271             obj = new IFLT();
272             break;
273         case Const.IFGE:
274             obj = new IFGE();
275             break;
276         case Const.IFGT:
277             obj = new IFGT();
278             break;
279         case Const.IFLE:
280             obj = new IFLE();
281             break;
282         case Const.IF_ICMPEQ:
283             obj = new IF_ICMPEQ();
284             break;
285         case Const.IF_ICMPNE:
286             obj = new IF_ICMPNE();
287             break;
288         case Const.IF_ICMPLT:
289             obj = new IF_ICMPLT();
290             break;
291         case Const.IF_ICMPGE:
292             obj = new IF_ICMPGE();
293             break;
294         case Const.IF_ICMPGT:
295             obj = new IF_ICMPGT();
296             break;
297         case Const.IF_ICMPLE:
298             obj = new IF_ICMPLE();
299             break;
300         case Const.IF_ACMPEQ:
301             obj = new IF_ACMPEQ();
302             break;
303         case Const.IF_ACMPNE:
304             obj = new IF_ACMPNE();
305             break;
306         case Const.GOTO:
307             obj = new GOTO();
308             break;
309         case Const.JSR:
310             obj = new JSR();
311             break;
312         case Const.RET:
313             obj = new RET();
314             break;
315         case Const.TABLESWITCH:
316             obj = new TABLESWITCH();
317             break;
318         case Const.LOOKUPSWITCH:
319             obj = new LOOKUPSWITCH();
320             break;
321         case Const.GETSTATIC:
322             obj = new GETSTATIC();
323             break;
324         case Const.PUTSTATIC:
325             obj = new PUTSTATIC();
326             break;
327         case Const.GETFIELD:
328             obj = new GETFIELD();
329             break;
330         case Const.PUTFIELD:
331             obj = new PUTFIELD();
332             break;
333         case Const.INVOKEVIRTUAL:
334             obj = new INVOKEVIRTUAL();
335             break;
336         case Const.INVOKESPECIAL:
337             obj = new INVOKESPECIAL();
338             break;
339         case Const.INVOKESTATIC:
340             obj = new INVOKESTATIC();
341             break;
342         case Const.INVOKEINTERFACE:
343             obj = new INVOKEINTERFACE();
344             break;
345         case Const.INVOKEDYNAMIC:
346             obj = new INVOKEDYNAMIC();
347             break;
348         case Const.NEW:
349             obj = new NEW();
350             break;
351         case Const.NEWARRAY:
352             obj = new NEWARRAY();
353             break;
354         case Const.ANEWARRAY:
355             obj = new ANEWARRAY();
356             break;
357         case Const.CHECKCAST:
358             obj = new CHECKCAST();
359             break;
360         case Const.INSTANCEOF:
361             obj = new INSTANCEOF();
362             break;
363         case Const.MULTIANEWARRAY:
364             obj = new MULTIANEWARRAY();
365             break;
366         case Const.IFNULL:
367             obj = new IFNULL();
368             break;
369         case Const.IFNONNULL:
370             obj = new IFNONNULL();
371             break;
372         case Const.GOTO_W:
373             obj = new GOTO_W();
374             break;
375         case Const.JSR_W:
376             obj = new JSR_W();
377             break;
378         case Const.BREAKPOINT:
379             obj = new BREAKPOINT();
380             break;
381         case Const.IMPDEP1:
382             obj = new IMPDEP1();
383             break;
384         case Const.IMPDEP2:
385             obj = new IMPDEP2();
386             break;
387         default:
388             throw new ClassGenException("Illegal opcode detected: " + opcode);
389 
390         }
391 
392         if (wide && !(obj instanceof LocalVariableInstruction || obj instanceof RET)) {
393             throw new ClassGenException("Illegal opcode after wide: " + opcode);
394         }
395         obj.setOpcode(opcode);
396         obj.initFromFile(bytes, wide); // Do further initializations, if any
397         return obj;
398     }
399 
400     /**
401      * Sets comparator to be used for equals().
402      *
403      * @param c the comparator.
404      * @deprecated (6.0) use the built in comparator, or wrap this class in another object that implements these methods
405      */
406     @Deprecated
407     public static void setComparator(final InstructionComparator c) {
408         cmp = c;
409     }
410 
411     /**
412      * @deprecated (since 6.0) will be made private; do not access directly, use getter/setter
413      */
414     @Deprecated
415     protected short length = 1; // Length of instruction in bytes
416 
417     /**
418      * @deprecated (since 6.0) will be made private; do not access directly, use getter/setter
419      */
420     @Deprecated
421     protected short opcode = -1; // Opcode number
422 
423     /**
424      * Empty constructor needed for Instruction.readInstruction. Not to be used otherwise.
425      */
426     Instruction() {
427     }
428 
429     /**
430      * Constructs an Instruction.
431      *
432      * @param opcode the opcode.
433      * @param length the instruction length.
434      */
435     public Instruction(final short opcode, final short length) {
436         this.length = length;
437         this.opcode = opcode;
438     }
439 
440     /**
441      * Call corresponding visitor method(s). The order is: Call visitor methods of implemented interfaces first, then call
442      * methods according to the class hierarchy in descending order, that is, the most specific visitXXX() call comes last.
443      *
444      * @param v Visitor object.
445      */
446     public abstract void accept(Visitor v);
447 
448     /**
449      * This method also gives right results for instructions whose effect on the stack depends on the constant pool entry
450      * they reference.
451      *
452      * @param cpg the constant pool generator.
453      * @return Number of words consumed from stack by this instruction, or Constants.UNPREDICTABLE, if this cannot be
454      *         computed statically
455      */
456     public int consumeStack(final ConstantPoolGen cpg) {
457         return Const.getConsumeStack(opcode);
458     }
459 
460     /**
461      * Use with caution, since 'BranchInstruction's have a 'target' reference which is not copied correctly (only basic
462      * types are). This also applies for 'Select' instructions with their multiple branch targets.
463      *
464      * @see BranchInstruction
465      * @return (shallow) copy of an instruction.
466      */
467     public Instruction copy() {
468         Instruction i = null;
469         // "Constant" instruction, no need to duplicate
470         if (InstructionConst.getInstruction(getOpcode()) != null) {
471             i = this;
472         } else {
473             try {
474                 i = (Instruction) clone();
475             } catch (final CloneNotSupportedException e) {
476                 System.err.println(e);
477             }
478         }
479         return i;
480     }
481 
482     /**
483      * Some instructions may be reused, so don't do anything by default.
484      */
485     void dispose() {
486     }
487 
488     /**
489      * Dumps instruction as byte code to stream out.
490      *
491      * @param out Output stream.
492      * @throws IOException Thrown when an I/O exception of some sort has occurred.
493      */
494     public void dump(final DataOutputStream out) throws IOException {
495         out.writeByte(opcode); // Common for all instructions
496     }
497 
498     /**
499      * Tests for equality, delegated to comparator
500      *
501      * @return true if that is an Instruction and has the same opcode.
502      */
503     @Override
504     public boolean equals(final Object that) {
505         return that instanceof Instruction && cmp.equals(this, (Instruction) that);
506     }
507 
508     /**
509      * Gets the length (in bytes) of instruction.
510      *
511      * @return length (in bytes) of instruction.
512      */
513     public int getLength() {
514         return length;
515     }
516 
517     /**
518      * Gets the name of instruction, that is, opcode name.
519      *
520      * @return name of instruction, that is, opcode name.
521      */
522     public String getName() {
523         return Const.getOpcodeName(opcode);
524     }
525 
526     /**
527      * Gets this instruction's opcode.
528      *
529      * @return this instruction's opcode.
530      */
531     public short getOpcode() {
532         return opcode;
533     }
534 
535     /**
536      * Gets the hashCode of this object.
537      *
538      * @return the hashCode.
539      * @since 6.0
540      */
541     @Override
542     public int hashCode() {
543         return opcode;
544     }
545 
546     /**
547      * Reads needed data (for example index) from file.
548      *
549      * @param bytes byte sequence to read from.
550      * @param wide "wide" instruction flag.
551      * @throws IOException may be thrown if the implementation needs to read data from the file
552      */
553     @SuppressWarnings("unused") // thrown by subclasses
554     protected void initFromFile(final ByteSequence bytes, final boolean wide) throws IOException {
555     }
556 
557     /**
558      * This method also gives right results for instructions whose effect on the stack depends on the constant pool entry
559      * they reference.
560      *
561      * @param cpg the constant pool generator.
562      * @return Number of words produced onto stack by this instruction, or Constants.UNPREDICTABLE, if this cannot be
563      *         computed statically
564      */
565     public int produceStack(final ConstantPoolGen cpg) {
566         return Const.getProduceStack(opcode);
567     }
568 
569     /**
570      * Needed in readInstruction and subclasses in this package
571      *
572      * @since 6.0
573      */
574     final void setLength(final int length) {
575         this.length = (short) length; // TODO check range?
576     }
577 
578     /**
579      * Needed in readInstruction and subclasses in this package
580      */
581     final void setOpcode(final short opcode) {
582         this.opcode = opcode;
583     }
584 
585     /**
586      * @return mnemonic for instruction in verbose format.
587      */
588     @Override
589     public String toString() {
590         return toString(true);
591     }
592 
593     /**
594      * Long output format:
595      *
596      * &lt;name of opcode&gt; "["&lt;opcode number&gt;"]" "("&lt;length of instruction&gt;")"
597      *
598      * @param verbose long/short format switch.
599      * @return mnemonic for instruction.
600      */
601     public String toString(final boolean verbose) {
602         if (verbose) {
603             return getName() + "[" + opcode + "](" + length + ")";
604         }
605         return getName();
606     }
607 
608     /**
609      * Gets the mnemonic for instruction with symbolic references resolved.
610      *
611      * @param cp the constant pool.
612      * @return mnemonic for instruction with symbolic references resolved.
613      */
614     public String toString(final ConstantPool cp) {
615         return toString(false);
616     }
617 }