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 
  61 import java.io.*;
  62 import com.sun.org.apache.bcel.internal.util.ByteSequence;
  63 
  64 /**
  65  * Abstract super class for branching instructions like GOTO, IFEQ, etc..
  66  * Branch instructions may have a variable length, namely GOTO, JSR,
  67  * LOOKUPSWITCH and TABLESWITCH.
  68  *
  69  * @see InstructionList
  70  * @author  <A HREF="mailto:markus.dahm@berlin.de">M. Dahm</A>
  71  */
  72 public abstract class BranchInstruction extends Instruction implements InstructionTargeter {
  73   protected int               index;    // Branch target relative to this instruction
  74   protected InstructionHandle target;   // Target object in instruction list
  75   protected int               position; // Byte code offset
  76 
  77   /**
  78    * Empty constructor needed for the Class.newInstance() statement in
  79    * Instruction.readInstruction(). Not to be used otherwise.
  80    */
  81   BranchInstruction() {}
  82 
  83   /** Common super constructor
  84    * @param opcodee Instruction opcode
  85    * @param target instruction to branch to
  86    */
  87   protected BranchInstruction(short opcode, InstructionHandle target) {
  88     super(opcode, (short)3);
  89     setTarget(target);
  90   }
  91 
  92   /**
  93    * Dump instruction as byte code to stream out.
  94    * @param out Output stream
  95    */
  96   @Override
  97   public void dump(DataOutputStream out) throws IOException {
  98     out.writeByte(opcode);
  99 
 100     index = getTargetOffset();
 101 
 102     if(Math.abs(index) >= 32767) // too large for short
 103       throw new ClassGenException("Branch target offset too large for short");
 104 
 105     out.writeShort(index); // May be negative, i.e., point backwards
 106   }
 107 
 108   /**
 109    * @param target branch target
 110    * @return the offset to  `target' relative to this instruction
 111    */
 112   protected int getTargetOffset(InstructionHandle target) {
 113     if(target == null)
 114       throw new ClassGenException("Target of " + super.toString(true) +
 115                                   " is invalid null handle");
 116 
 117     int t = target.getPosition();
 118 
 119     if(t < 0)
 120       throw new ClassGenException("Invalid branch target position offset for " +
 121                                   super.toString(true) + ":" + t + ":" + target);
 122 
 123     return t - position;
 124   }
 125 
 126   /**
 127    * @return the offset to this instruction's target
 128    */
 129   protected int getTargetOffset() { return getTargetOffset(target); }
 130 
 131   /**
 132    * Called by InstructionList.setPositions when setting the position for every
 133    * instruction. In the presence of variable length instructions `setPositions'
 134    * performs multiple passes over the instruction list to calculate the
 135    * correct (byte) positions and offsets by calling this function.
 136    *
 137    * @param offset additional offset caused by preceding (variable length) instructions
 138    * @param max_offset the maximum offset that may be caused by these instructions
 139    * @return additional offset caused by possible change of this instruction's length
 140    */
 141   protected int updatePosition(int offset, int max_offset) {
 142     position += offset;
 143     return 0;
 144   }
 145 
 146   /**
 147    * Long output format:
 148    *
 149    * &lt;position in byte code&gt;
 150    * &lt;name of opcode&gt; "["&lt;opcode number&gt;"]"
 151    * "("&lt;length of instruction&gt;")"
 152    * "&lt;"&lt;target instruction&gt;"&gt;" "@"&lt;branch target offset&gt;
 153    *
 154    * @param verbose long/short format switch
 155    * @return mnemonic for instruction
 156    */
 157   @Override
 158   public String toString(boolean verbose) {
 159     String s = super.toString(verbose);
 160     String t = "null";
 161 
 162     if(verbose) {
 163       if(target != null) {
 164         if(target.getInstruction() == this)
 165           t = "<points to itself>";
 166         else if(target.getInstruction() == null)
 167           t = "<null instruction!!!?>";
 168         else
 169           t = target.getInstruction().toString(false); // Avoid circles
 170       }
 171     } else {
 172       if(target != null) {
 173         index = getTargetOffset();
 174         t = "" + (index + position);
 175       }
 176     }
 177 
 178     return s + " -> " + t;
 179   }
 180 
 181   /**
 182    * Read needed data (e.g. index) from file. Conversion to a InstructionHandle
 183    * is done in InstructionList(byte[]).
 184    *
 185    * @param bytes input stream
 186    * @param wide wide prefix?
 187    * @see InstructionList
 188    */
 189   @Override
 190   protected void initFromFile(ByteSequence bytes, boolean wide) throws IOException
 191   {
 192     length = 3;
 193     index  = bytes.readShort();
 194   }
 195 
 196   /**
 197    * @return target offset in byte code
 198    */
 199   public final int getIndex() { return index; }
 200 
 201   /**
 202    * @return target of branch instruction
 203    */
 204   public InstructionHandle getTarget() { return target; }
 205 
 206   /**
 207    * Set branch target
 208    * @param target branch target
 209    */
 210   public final void setTarget(InstructionHandle target) {
 211     notifyTargetChanging(this.target, this);
 212     this.target = target;
 213     notifyTargetChanged(this.target, this);
 214   }
 215 
 216   /**
 217    * Used by BranchInstruction, LocalVariableGen, CodeExceptionGen.
 218    * Must be called before the target is actually changed in the
 219    * InstructionTargeter.
 220    */
 221   static void notifyTargetChanging(InstructionHandle old_ih,
 222                                  InstructionTargeter t) {
 223     if(old_ih != null) {
 224       old_ih.removeTargeter(t);
 225     }
 226   }
 227 
 228   /**
 229    * Used by BranchInstruction, LocalVariableGen, CodeExceptionGen.
 230    * Must be called after the target is actually changed in the
 231    * InstructionTargeter.
 232    */
 233   static void notifyTargetChanged(InstructionHandle new_ih,
 234                                  InstructionTargeter t) {
 235     if(new_ih != null) {
 236       new_ih.addTargeter(t);
 237     }
 238   }
 239 
 240   /**
 241    * @param old_ih old target
 242    * @param new_ih new target
 243    */
 244   @Override
 245   public void updateTarget(InstructionHandle old_ih, InstructionHandle new_ih) {
 246     if(target == old_ih)
 247       setTarget(new_ih);
 248     else
 249       throw new ClassGenException("Not targeting " + old_ih + ", but " + target);
 250   }
 251 
 252   /**
 253    * @return true, if ih is target of this instruction
 254    */
 255   @Override
 256   public boolean containsTarget(InstructionHandle ih) {
 257     return (target == ih);
 258   }
 259 
 260   /**
 261    * Inform target that it's not targeted anymore.
 262    */
 263   @Override
 264   void dispose() {
 265     setTarget(null);
 266     index=-1;
 267     position=-1;
 268   }
 269 }