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