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    */
Select()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    */
Select(short opcode, int[] match, InstructionHandle[] targets, InstructionHandle target)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
updatePosition(int offset, int max_offset)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
dump(DataOutputStream out)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
initFromFile(ByteSequence bytes, boolean wide)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
toString(boolean verbose)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    */
setTarget(int i, InstructionHandle target)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
updateTarget(InstructionHandle old_ih, InstructionHandle new_ih)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
containsTarget(InstructionHandle ih)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
dispose()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    */
getMatchs()256   public int[] getMatchs() { return match; }
257 
258   /**
259    * @return array of match target offsets
260    */
getIndices()261   public int[] getIndices() { return indices; }
262 
263   /**
264    * @return array of match targets
265    */
getTargets()266   public InstructionHandle[] getTargets() { return targets; }
267 }
268