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