1 /*
   2  * reserved comment block
   3  * DO NOT REMOVE OR ALTER!
   4  */
   5 package com.sun.org.apache.bcel.internal.generic;
   6 
   7 /* ====================================================================
   8  * The Apache Software License, Version 1.1
   9  *
  10  * Copyright (c) 2001 The Apache Software Foundation.  All rights
  11  * reserved.
  12  *
  13  * Redistribution and use in source and binary forms, with or without
  14  * modification, are permitted provided that the following conditions
  15  * are met:
  16  *
  17  * 1. Redistributions of source code must retain the above copyright
  18  *    notice, this list of conditions and the following disclaimer.
  19  *
  20  * 2. Redistributions in binary form must reproduce the above copyright
  21  *    notice, this list of conditions and the following disclaimer in
  22  *    the documentation and/or other materials provided with the
  23  *    distribution.
  24  *
  25  * 3. The end-user documentation included with the redistribution,
  26  *    if any, must include the following acknowledgment:
  27  *       "This product includes software developed by the
  28  *        Apache Software Foundation (http://www.apache.org/)."
  29  *    Alternately, this acknowledgment may appear in the software itself,
  30  *    if and wherever such third-party acknowledgments normally appear.
  31  *
  32  * 4. The names "Apache" and "Apache Software Foundation" and
  33  *    "Apache BCEL" must not be used to endorse or promote products
  34  *    derived from this software without prior written permission. For
  35  *    written permission, please contact apache@apache.org.
  36  *
  37  * 5. Products derived from this software may not be called "Apache",
  38  *    "Apache BCEL", nor may "Apache" appear in their name, without
  39  *    prior written permission of the Apache Software Foundation.
  40  *
  41  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
  42  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
  43  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
  44  * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
  45  * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  46  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
  47  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
  48  * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
  49  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
  50  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
  51  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  52  * SUCH DAMAGE.
  53  * ====================================================================
  54  *
  55  * This software consists of voluntary contributions made by many
  56  * individuals on behalf of the Apache Software Foundation.  For more
  57  * information on the Apache Software Foundation, please see
  58  * <http://www.apache.org/>.
  59  */
  60 import java.io.*;
  61 import com.sun.org.apache.bcel.internal.util.ByteSequence;
  62 
  63 /**
  64  * Select - Abstract super class for LOOKUPSWITCH and TABLESWITCH instructions.
  65  *
  66  * @author  <A HREF="mailto:markus.dahm@berlin.de">M. Dahm</A>
  67  * @see LOOKUPSWITCH
  68  * @see TABLESWITCH
  69  * @see InstructionList
  70  */
  71 public abstract class Select extends BranchInstruction
  72   implements VariableLengthInstruction, StackProducer
  73 {
  74   protected int[]               match;        // matches, i.e., case 1: ...
  75   protected int[]               indices;      // target offsets
  76   protected InstructionHandle[] targets;      // target objects in instruction list
  77   protected int                 fixed_length; // fixed length defined by subclasses
  78   protected int                 match_length; // number of cases
  79   protected int                 padding = 0;  // number of pad bytes for alignment
  80 
  81   /**
  82    * Empty constructor needed for the Class.newInstance() statement in
  83    * Instruction.readInstruction(). Not to be used otherwise.
  84    */
  85   Select() {}
  86 
  87   /**
  88    * (Match, target) pairs for switch.
  89    * `Match' and `targets' must have the same length of course.
  90    *
  91    * @param match array of matching values
  92    * @param targets instruction targets
  93    * @param target default instruction target
  94    */
  95   Select(short opcode, int[] match, InstructionHandle[] targets,
  96          InstructionHandle target) {
  97     super(opcode, target);
  98 
  99     this.targets = targets;
 100     for(int i=0; i < targets.length; i++) {
 101       BranchInstruction.notifyTargetChanged(targets[i], this);
 102     }
 103 
 104     this.match = match;
 105 
 106     if((match_length = match.length) != targets.length)
 107       throw new ClassGenException("Match and target array have not the same length");
 108 
 109     indices = new int[match_length];
 110   }
 111 
 112   /**
 113    * Since this is a variable length instruction, it may shift the following
 114    * instructions which then need to update their position.
 115    *
 116    * Called by InstructionList.setPositions when setting the position for every
 117    * instruction. In the presence of variable length instructions `setPositions'
 118    * performs multiple passes over the instruction list to calculate the
 119    * correct (byte) positions and offsets by calling this function.
 120    *
 121    * @param offset additional offset caused by preceding (variable length) instructions
 122    * @param max_offset the maximum offset that may be caused by these instructions
 123    * @return additional offset caused by possible change of this instruction's length
 124    */
 125   @Override
 126   protected int updatePosition(int offset, int max_offset) {
 127     position += offset; // Additional offset caused by preceding SWITCHs, GOTOs, etc.
 128 
 129     short old_length = length;
 130 
 131     /* Alignment on 4-byte-boundary, + 1, because of tag byte.
 132      */
 133     padding = (4 - ((position + 1) % 4)) % 4;
 134     length  = (short)(fixed_length + padding); // Update length
 135 
 136     return length - old_length;
 137   }
 138 
 139   /**
 140    * Dump instruction as byte code to stream out.
 141    * @param out Output stream
 142    */
 143   @Override
 144   public void dump(DataOutputStream out) throws IOException {
 145     out.writeByte(opcode);
 146 
 147     for(int i=0; i < padding; i++) // Padding bytes
 148       out.writeByte(0);
 149 
 150     index = getTargetOffset();     // Write default target offset
 151     out.writeInt(index);
 152   }
 153 
 154   /**
 155    * Read needed data (e.g. index) from file.
 156    */
 157   @Override
 158   protected void initFromFile(ByteSequence bytes, boolean wide) throws IOException
 159   {
 160     padding = (4 - (bytes.getIndex() % 4)) % 4; // Compute number of pad bytes
 161 
 162     for(int i=0; i < padding; i++) {
 163       bytes.readByte();
 164     }
 165 
 166     // Default branch target common for both cases (TABLESWITCH, LOOKUPSWITCH)
 167     index = bytes.readInt();
 168   }
 169 
 170   /**
 171    * @return mnemonic for instruction
 172    */
 173   @Override
 174   public String toString(boolean verbose) {
 175     final StringBuilder buf = new StringBuilder(super.toString(verbose));
 176 
 177     if(verbose) {
 178       for(int i=0; i < match_length; i++) {
 179         String s = "null";
 180 
 181         if(targets[i] != null)
 182           s = targets[i].getInstruction().toString();
 183 
 184           buf.append("(").append(match[i]).append(", ")
 185              .append(s).append(" = {").append(indices[i]).append("})");
 186       }
 187     }
 188     else
 189       buf.append(" ...");
 190 
 191     return buf.toString();
 192   }
 193 
 194   /**
 195    * Set branch target for `i'th case
 196    */
 197   public final void setTarget(int i, InstructionHandle target) {
 198     notifyTargetChanging(targets[i], this);
 199     targets[i] = target;
 200     notifyTargetChanged(targets[i], this);
 201   }
 202 
 203   /**
 204    * @param old_ih old target
 205    * @param new_ih new target
 206    */
 207   @Override
 208   public void updateTarget(InstructionHandle old_ih, InstructionHandle new_ih) {
 209     boolean targeted = false;
 210 
 211     if(target == old_ih) {
 212       targeted = true;
 213       setTarget(new_ih);
 214     }
 215 
 216     for(int i=0; i < targets.length; i++) {
 217       if(targets[i] == old_ih) {
 218         targeted = true;
 219         setTarget(i, new_ih);
 220       }
 221     }
 222 
 223     if(!targeted)
 224       throw new ClassGenException("Not targeting " + old_ih);
 225   }
 226 
 227   /**
 228    * @return true, if ih is target of this instruction
 229    */
 230   @Override
 231   public boolean containsTarget(InstructionHandle ih) {
 232     if(target == ih)
 233       return true;
 234 
 235     for(int i=0; i < targets.length; i++)
 236       if(targets[i] == ih)
 237         return true;
 238 
 239     return false;
 240   }
 241 
 242   /**
 243    * Inform targets that they're not targeted anymore.
 244    */
 245   @Override
 246   void dispose() {
 247     super.dispose();
 248 
 249     for(int i=0; i < targets.length; i++)
 250       targets[i].removeTargeter(this);
 251   }
 252 
 253   /**
 254    * @return array of match indices
 255    */
 256   public int[] getMatchs() { return match; }
 257 
 258   /**
 259    * @return array of match target offsets
 260    */
 261   public int[] getIndices() { return indices; }
 262 
 263   /**
 264    * @return array of match targets
 265    */
 266   public InstructionHandle[] getTargets() { return targets; }
 267 }