Home | History | Annotate | Download | only in generic
      1 /*
      2  * Licensed to the Apache Software Foundation (ASF) under one or more
      3  * contributor license agreements.  See the NOTICE file distributed with
      4  * this work for additional information regarding copyright ownership.
      5  * The ASF licenses this file to You under the Apache License, Version 2.0
      6  * (the "License"); you may not use this file except in compliance with
      7  * the License.  You may obtain a copy of the License at
      8  *
      9  *      http://www.apache.org/licenses/LICENSE-2.0
     10  *
     11  *  Unless required by applicable law or agreed to in writing, software
     12  *  distributed under the License is distributed on an "AS IS" BASIS,
     13  *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     14  *  See the License for the specific language governing permissions and
     15  *  limitations under the License.
     16  *
     17  */
     18 package org.apache.bcel.generic;
     19 
     20 import java.io.DataOutputStream;
     21 import java.io.IOException;
     22 
     23 import org.apache.bcel.Const;
     24 import org.apache.bcel.classfile.ConstantPool;
     25 import org.apache.bcel.util.ByteSequence;
     26 
     27 /**
     28  * Abstract super class for all Java byte codes.
     29  *
     30  * @version $Id$
     31  */
     32 public abstract class Instruction implements Cloneable {
     33 
     34     /**
     35      * @deprecated (since 6.0) will be made private; do not access directly, use getter/setter
     36      */
     37     @Deprecated
     38     protected short length = 1; // Length of instruction in bytes
     39 
     40     /**
     41      * @deprecated (since 6.0) will be made private; do not access directly, use getter/setter
     42      */
     43     @Deprecated
     44     protected short opcode = -1; // Opcode number
     45 
     46     private static InstructionComparator cmp = InstructionComparator.DEFAULT;
     47 
     48 
     49     /**
     50      * Empty constructor needed for Instruction.readInstruction.
     51      * Not to be used otherwise.
     52      */
     53     Instruction() {
     54     }
     55 
     56 
     57     public Instruction(final short opcode, final short length) {
     58         this.length = length;
     59         this.opcode = opcode;
     60     }
     61 
     62 
     63     /**
     64      * Dump instruction as byte code to stream out.
     65      * @param out Output stream
     66      */
     67     public void dump( final DataOutputStream out ) throws IOException {
     68         out.writeByte(opcode); // Common for all instructions
     69     }
     70 
     71 
     72     /** @return name of instruction, i.e., opcode name
     73      */
     74     public String getName() {
     75         return Const.getOpcodeName(opcode);
     76     }
     77 
     78 
     79     /**
     80      * Long output format:
     81      *
     82      * <name of opcode> "["<opcode number>"]"
     83      * "("<length of instruction>")"
     84      *
     85      * @param verbose long/short format switch
     86      * @return mnemonic for instruction
     87      */
     88     public String toString( final boolean verbose ) {
     89         if (verbose) {
     90             return getName() + "[" + opcode + "](" + length + ")";
     91         }
     92         return getName();
     93     }
     94 
     95 
     96     /**
     97      * @return mnemonic for instruction in verbose format
     98      */
     99     @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 }
    610