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