View Javadoc

    1   /*
    2    * Copyright  2000-2004 The Apache Software Foundation
    3    *
    4    *  Licensed under the Apache License, Version 2.0 (the "License");
    5    *  you may not use this file except in compliance with the License.
    6    *  You may obtain a copy of the License at
    7    *
    8    *      http://www.apache.org/licenses/LICENSE-2.0
    9    *
    10   *  Unless required by applicable law or agreed to in writing, software
    11   *  distributed under the License is distributed on an "AS IS" BASIS,
    12   *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13   *  See the License for the specific language governing permissions and
    14   *  limitations under the License.
    15   *
    16   */
    17  package org.apache.bcel.generic;
    18
    19  import java.io.DataOutputStream;
    20  import java.io.IOException;
    21  import org.apache.bcel.util.ByteSequence;
    22
    23  /***
    24   * Select - Abstract super class for LOOKUPSWITCH and TABLESWITCH instructions.
    25   *
    26   * <p>We use our super's <code>target</code> property as the default target.
    27   *
    28   * @version $Id: Select.java 386056 2006-03-15 11:31:56Z tcurdt $
    29   * @author  <A HREF="mailto:m.dahm@gmx.de">M. Dahm</A>
    30   * @see LOOKUPSWITCH
    31   * @see TABLESWITCH
    32   * @see InstructionList
    33   */
    34  public abstract class Select extends BranchInstruction implements VariableLengthInstruction,
    35          StackProducer {
    36
    37      protected int[] match; // matches, i.e., case 1: ...
    38      protected int[] indices; // target offsets
    39      protected InstructionHandle[] targets; // target objects in instruction list
    40      protected int fixed_length; // fixed length defined by subclasses
    41      protected int match_length; // number of cases
    42      protected int padding = 0; // number of pad bytes for alignment
    43
    44
    45      /***
    46       * Empty constructor needed for the Class.newInstance() statement in
    47       * Instruction.readInstruction(). Not to be used otherwise.
    48       */
    49      Select() {
    50      }
    51
    52
    53      /***
    54       * (Match, target) pairs for switch.
    55       * `Match' and `targets' must have the same length of course.
    56       *
    57       * @param match array of matching values
    58       * @param targets instruction targets
    59       * @param defaultTarget default instruction target
    60       */
    61      Select(short opcode, int[] match, InstructionHandle[] targets, InstructionHandle defaultTarget) {
    62          super(opcode, defaultTarget);
    63          this.targets = targets;
    64          for (int i = 0; i < targets.length; i++) {
    65              notifyTarget(null, targets[i], this);
    66          }
    67          this.match = match;
    68          if ((match_length = match.length) != targets.length) {
    69              throw new ClassGenException("Match and target array have not the same length");
    70          }
    71          indices = new int[match_length];
    72      }
    73
    74
    75      /***
    76       * Since this is a variable length instruction, it may shift the following
    77       * instructions which then need to update their position.
    78       *
    79       * Called by InstructionList.setPositions when setting the position for every
    80       * instruction. In the presence of variable length instructions `setPositions'
    81       * performs multiple passes over the instruction list to calculate the
    82       * correct (byte) positions and offsets by calling this function.
    83       *
    84       * @param offset additional offset caused by preceding (variable length) instructions
    85       * @param max_offset the maximum offset that may be caused by these instructions
    86       * @return additional offset caused by possible change of this instruction's length
    87       */
    88      protected int updatePosition( int offset, int max_offset ) {
    89          position += offset; // Additional offset caused by preceding SWITCHs, GOTOs, etc.
    90          short old_length = length;
    91          /* Alignment on 4-byte-boundary, + 1, because of tag byte.
    92           */
    93          padding = (4 - ((position + 1) % 4)) % 4;
    94          length = (short) (fixed_length + padding); // Update length
    95          return length - old_length;
    96      }
    97
    98
    99      /***
    100      * Dump instruction as byte code to stream out.
    101      * @param out Output stream
    102      */
    103     public void dump( DataOutputStream out ) throws IOException {
    104         out.writeByte(opcode);
    105         for (int i = 0; i < padding; i++) {
    106             out.writeByte(0);
    107         }
    108         index = getTargetOffset(); // Write default target offset
    109         out.writeInt(index);
    110     }
    111
    112
    113     /***
    114      * Read needed data (e.g. index) from file.
    115      */
    116     protected void initFromFile( ByteSequence bytes, boolean wide ) throws IOException {
    117         padding = (4 - (bytes.getIndex() % 4)) % 4; // Compute number of pad bytes
    118         for (int i = 0; i < padding; i++) {
    119             bytes.readByte();
    120         }
    121         // Default branch target common for both cases (TABLESWITCH, LOOKUPSWITCH)
    122         index = bytes.readInt();
    123     }
    124
    125
    126     /***
    127      * @return mnemonic for instruction
    128      */
    129     public String toString( boolean verbose ) {
    130         StringBuffer buf = new StringBuffer(super.toString(verbose));
    131         if (verbose) {
    132             for (int i = 0; i < match_length; i++) {
    133                 String s = "null";
    134                 if (targets[i] != null) {
    135                     s = targets[i].getInstruction().toString();
    136                 }
    137                 buf.append("(").append(match[i]).append(", ").append(s).append(" = {").append(
    138                         indices[i]).append("})");
    139             }
    140         } else {
    141             buf.append(" ...");
    142         }
    143         return buf.toString();
    144     }
    145
    146
    147     /***
    148      * Set branch target for `i'th case
    149      */
    150     public void setTarget( int i, InstructionHandle target ) {
    151         notifyTarget(targets[i], target, this);
    152         targets[i] = target;
    153     }
    154
    155
    156     /***
    157      * @param old_ih old target
    158      * @param new_ih new target
    159      */
    160     public void updateTarget( InstructionHandle old_ih, InstructionHandle new_ih ) {
    161         boolean targeted = false;
    162         if (target == old_ih) {
    163             targeted = true;
    164             setTarget(new_ih);
    165         }
    166         for (int i = 0; i < targets.length; i++) {
    167             if (targets[i] == old_ih) {
    168                 targeted = true;
    169                 setTarget(i, new_ih);
    170             }
    171         }
    172         if (!targeted) {
    173             throw new ClassGenException("Not targeting " + old_ih);
    174         }
    175     }
    176
    177
    178     /***
    179      * @return true, if ih is target of this instruction
    180      */
    181     public boolean containsTarget( InstructionHandle ih ) {
    182         if (target == ih) {
    183             return true;
    184         }
    185         for (int i = 0; i < targets.length; i++) {
    186             if (targets[i] == ih) {
    187                 return true;
    188             }
    189         }
    190         return false;
    191     }
    192
    193
    194     protected Object clone() throws CloneNotSupportedException {
    195         Select copy = (Select) super.clone();
    196         copy.match = (int[]) match.clone();
    197         copy.indices = (int[]) indices.clone();
    198         copy.targets = (InstructionHandle[]) targets.clone();
    199         return copy;
    200     }
    201
    202
    203     /***
    204      * Inform targets that they're not targeted anymore.
    205      */
    206     void dispose() {
    207         super.dispose();
    208         for (int i = 0; i < targets.length; i++) {
    209             targets[i].removeTargeter(this);
    210         }
    211     }
    212
    213
    214     /***
    215      * @return array of match indices
    216      */
    217     public int[] getMatchs() {
    218         return match;
    219     }
    220
    221
    222     /***
    223      * @return array of match target offsets
    224      */
    225     public int[] getIndices() {
    226         return indices;
    227     }
    228
    229
    230     /***
    231      * @return array of match targets
    232      */
    233     public InstructionHandle[] getTargets() {
    234         return targets;
    235     }
    236 }