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