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