View Javadoc
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 }