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