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