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