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