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