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