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       notifyTarget(null, targets[i], this);
 102 
 103     this.match = match;
 104 
 105     if((match_length = match.length) != targets.length)
 106       throw new ClassGenException("Match and target array have not the same length");
 107 
 108     indices = new int[match_length];
 109   }
 110 
 111   /**
 112    * Since this is a variable length instruction, it may shift the following
 113    * instructions which then need to update their position.
 114    *
 115    * Called by InstructionList.setPositions when setting the position for every
 116    * instruction. In the presence of variable length instructions `setPositions'
 117    * performs multiple passes over the instruction list to calculate the
 118    * correct (byte) positions and offsets by calling this function.
 119    *
 120    * @param offset additional offset caused by preceding (variable length) instructions
 121    * @param max_offset the maximum offset that may be caused by these instructions
 122    * @return additional offset caused by possible change of this instruction's length
 123    */
 124   protected int updatePosition(int offset, int max_offset) {
 125     position += offset; // Additional offset caused by preceding SWITCHs, GOTOs, etc.
 126 
 127     short old_length = length;
 128 
 129     /* Alignment on 4-byte-boundary, + 1, because of tag byte.
 130      */
 131     padding = (4 - ((position + 1) % 4)) % 4;
 132     length  = (short)(fixed_length + padding); // Update length
 133 
 134     return length - old_length;
 135   }
 136 
 137   /**
 138    * Dump instruction as byte code to stream out.
 139    * @param out Output stream
 140    */
 141   public void dump(DataOutputStream out) throws IOException {
 142     out.writeByte(opcode);
 143 
 144     for(int i=0; i < padding; i++) // Padding bytes
 145       out.writeByte(0);
 146 
 147     index = getTargetOffset();     // Write default target offset
 148     out.writeInt(index);
 149   }
 150 
 151   /**
 152    * Read needed data (e.g. index) from file.
 153    */
 154   protected void initFromFile(ByteSequence bytes, boolean wide) throws IOException
 155   {
 156     padding = (4 - (bytes.getIndex() % 4)) % 4; // Compute number of pad bytes
 157 
 158     for(int i=0; i < padding; i++) {
 159       bytes.readByte();
 160     }
 161 
 162     // Default branch target common for both cases (TABLESWITCH, LOOKUPSWITCH)
 163     index = bytes.readInt();
 164   }
 165 
 166   /**
 167    * @return mnemonic for instruction
 168    */
 169   public String toString(boolean verbose) {
 170     StringBuffer buf = new StringBuffer(super.toString(verbose));
 171 
 172     if(verbose) {
 173       for(int i=0; i < match_length; i++) {
 174         String s = "null";
 175 
 176         if(targets[i] != null)
 177           s = targets[i].getInstruction().toString();
 178 
 179         buf.append("(" + match[i] + ", " + s + " = {" + indices[i] + "})");
 180       }
 181     }
 182     else
 183       buf.append(" ...");
 184 
 185     return buf.toString();
 186   }
 187 
 188   /**
 189    * Set branch target for `i'th case
 190    */
 191   public void setTarget(int i, InstructionHandle target) {
 192     notifyTarget(targets[i], target, this);
 193     targets[i] = target;
 194   }
 195 
 196   /**
 197    * @param old_ih old target
 198    * @param new_ih new target
 199    */
 200   public void updateTarget(InstructionHandle old_ih, InstructionHandle new_ih) {
 201     boolean targeted = false;
 202 
 203     if(target == old_ih) {
 204       targeted = true;
 205       setTarget(new_ih);
 206     }
 207 
 208     for(int i=0; i < targets.length; i++) {
 209       if(targets[i] == old_ih) {
 210         targeted = true;
 211         setTarget(i, new_ih);
 212       }
 213     }
 214 
 215     if(!targeted)
 216       throw new ClassGenException("Not targeting " + old_ih);
 217   }
 218 
 219   /**
 220    * @return true, if ih is target of this instruction
 221    */
 222   public boolean containsTarget(InstructionHandle ih) {
 223     if(target == ih)
 224       return true;
 225 
 226     for(int i=0; i < targets.length; i++)
 227       if(targets[i] == ih)
 228         return true;
 229 
 230     return false;
 231   }
 232 
 233   /**
 234    * Inform targets that they're not targeted anymore.
 235    */
 236   void dispose() {
 237     super.dispose();
 238 
 239     for(int i=0; i < targets.length; i++)
 240       targets[i].removeTargeter(this);
 241   }
 242 
 243   /**
 244    * @return array of match indices
 245    */
 246   public int[] getMatchs() { return match; }
 247 
 248   /**
 249    * @return array of match target offsets
 250    */
 251   public int[] getIndices() { return indices; }
 252 
 253   /**
 254    * @return array of match targets
 255    */
 256   public InstructionHandle[] getTargets() { return targets; }
 257 }