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