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