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