    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}