View Javadoc
1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one or more
3    * contributor license agreements.  See the NOTICE file distributed with
4    * this work for additional information regarding copyright ownership.
5    * The ASF licenses this file to You under the Apache License, Version 2.0
6    * (the "License"); you may not use this file except in compliance with
7    * the License.  You may obtain a copy of the License at
8    *
9    *      http://www.apache.org/licenses/LICENSE-2.0
10   *
11   *  Unless required by applicable law or agreed to in writing, software
12   *  distributed under the License is distributed on an "AS IS" BASIS,
13   *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   *  See the License for the specific language governing permissions and
15   *  limitations under the License.
16   *
17   */
18  package org.apache.bcel.generic;
19  
20  import java.io.DataOutputStream;
21  import java.io.IOException;
22  
23  import org.apache.bcel.util.ByteSequence;
24  
25  /**
26   * Select - Abstract super class for LOOKUPSWITCH and TABLESWITCH instructions.
27   *
28   * <p>We use our super's {@code target} property as the default target.
29   *
30   * @see LOOKUPSWITCH
31   * @see TABLESWITCH
32   * @see InstructionList
33   */
34  public abstract class Select extends BranchInstruction implements VariableLengthInstruction,
35          StackConsumer /* @since 6.0 */, StackProducer {
36  
37      /**
38       * @deprecated (since 6.0) will be made private; do not access directly, use getter/setter
39       */
40      @Deprecated
41      protected int[] match; // matches, i.e., case 1: ... TODO could be package-protected?
42  
43      /**
44       * @deprecated (since 6.0) will be made private; do not access directly, use getter/setter
45       */
46      @Deprecated
47      protected int[] indices; // target offsets TODO could be package-protected?
48  
49      /**
50       * @deprecated (since 6.0) will be made private; do not access directly, use getter/setter
51       */
52      @Deprecated
53      protected InstructionHandle[] targets; // target objects in instruction list TODO could be package-protected?
54  
55      /**
56       * @deprecated (since 6.0) will be made private; do not access directly, use getter/setter
57       */
58      @Deprecated
59      protected int fixed_length; // fixed length defined by subclasses TODO could be package-protected?
60  
61      /**
62       * @deprecated (since 6.0) will be made private; do not access directly, use getter/setter
63       */
64      @Deprecated
65      protected int match_length; // number of cases TODO could be package-protected?
66  
67      /**
68       * @deprecated (since 6.0) will be made private; do not access directly, use getter/setter
69       */
70      @Deprecated
71      protected int padding = 0; // number of pad bytes for alignment TODO could be package-protected?
72  
73  
74      /**
75       * Empty constructor needed for Instruction.readInstruction.
76       * Not to be used otherwise.
77       */
78      Select() {
79      }
80  
81  
82      /**
83       * (Match, target) pairs for switch.
84       * `Match' and `targets' must have the same length of course.
85       *
86       * @param match array of matching values
87       * @param targets instruction targets
88       * @param defaultTarget default instruction target
89       */
90      Select(final short opcode, final int[] match, final InstructionHandletml#InstructionHandle">InstructionHandle[] targets, final InstructionHandle defaultTarget) {
91          // don't set default target before instuction is built
92          super(opcode, null);
93          this.match = match;
94          this.targets = targets;
95          // now it's safe to set default target
96          setTarget(defaultTarget);
97          for (final InstructionHandle target2 : targets) {
98              notifyTarget(null, target2, this);
99          }
100         if ((match_length = match.length) != targets.length) {
101             throw new ClassGenException("Match and target array have not the same length: Match length: " +
102                 match.length + " Target length: " + targets.length);
103         }
104         indices = new int[match_length];
105     }
106 
107 
108     /**
109      * Since this is a variable length instruction, it may shift the following
110      * instructions which then need to update their position.
111      *
112      * Called by InstructionList.setPositions when setting the position for every
113      * instruction. In the presence of variable length instructions `setPositions'
114      * performs multiple passes over the instruction list to calculate the
115      * correct (byte) positions and offsets by calling this function.
116      *
117      * @param offset additional offset caused by preceding (variable length) instructions
118      * @param max_offset the maximum offset that may be caused by these instructions
119      * @return additional offset caused by possible change of this instruction's length
120      */
121     @Override
122     protected int updatePosition( final int offset, final int max_offset ) {
123         setPosition(getPosition() + offset); // Additional offset caused by preceding SWITCHs, GOTOs, etc.
124         final short old_length = (short) super.getLength();
125         /* Alignment on 4-byte-boundary, + 1, because of tag byte.
126          */
127         padding = (4 - ((getPosition() + 1) % 4)) % 4;
128         super.setLength((short) (fixed_length + padding)); // Update length
129         return super.getLength() - old_length;
130     }
131 
132 
133     /**
134      * Dump instruction as byte code to stream out.
135      * @param out Output stream
136      */
137     @Override
138     public void dump( final DataOutputStream out ) throws IOException {
139         out.writeByte(super.getOpcode());
140         for (int i = 0; i < padding; i++) {
141             out.writeByte(0);
142         }
143         super.setIndex(getTargetOffset()); // Write default target offset
144         out.writeInt(super.getIndex());
145     }
146 
147 
148     /**
149      * Read needed data (e.g. index) from file.
150      */
151     @Override
152     protected void initFromFile( final ByteSequence bytes, final boolean wide ) throws IOException {
153         padding = (4 - (bytes.getIndex() % 4)) % 4; // Compute number of pad bytes
154         for (int i = 0; i < padding; i++) {
155             bytes.readByte();
156         }
157         // Default branch target common for both cases (TABLESWITCH, LOOKUPSWITCH)
158         super.setIndex(bytes.readInt());
159     }
160 
161 
162     /**
163      * @return mnemonic for instruction
164      */
165     @Override
166     public String toString( final boolean verbose ) {
167         final StringBuilder buf = new StringBuilder(super.toString(verbose));
168         if (verbose) {
169             for (int i = 0; i < match_length; i++) {
170                 String s = "null";
171                 if (targets[i] != null) {
172                     s = targets[i].getInstruction().toString();
173                 }
174                 buf.append("(").append(match[i]).append(", ").append(s).append(" = {").append(
175                         indices[i]).append("})");
176             }
177         } else {
178             buf.append(" ...");
179         }
180         return buf.toString();
181     }
182 
183 
184     /**
185      * Set branch target for `i'th case
186      */
187     public void setTarget( final int i, final InstructionHandle target ) { // TODO could be package-protected?
188         notifyTarget(targets[i], target, this);
189         targets[i] = target;
190     }
191 
192 
193     /**
194      * @param old_ih old target
195      * @param new_ih new target
196      */
197     @Override
198     public void updateTarget( final InstructionHandlee.html#InstructionHandle">InstructionHandle old_ih, final InstructionHandle new_ih ) {
199         boolean targeted = false;
200         if (super.getTarget() == old_ih) {
201             targeted = true;
202             setTarget(new_ih);
203         }
204         for (int i = 0; i < targets.length; i++) {
205             if (targets[i] == old_ih) {
206                 targeted = true;
207                 setTarget(i, new_ih);
208             }
209         }
210         if (!targeted) {
211             throw new ClassGenException("Not targeting " + old_ih);
212         }
213     }
214 
215 
216     /**
217      * @return true, if ih is target of this instruction
218      */
219     @Override
220     public boolean containsTarget( final InstructionHandle ih ) {
221         if (super.getTarget() == ih) {
222             return true;
223         }
224         for (final InstructionHandle target2 : targets) {
225             if (target2 == ih) {
226                 return true;
227             }
228         }
229         return false;
230     }
231 
232 
233     @Override
234     protected Object clone() throws CloneNotSupportedException {
235         final Select="../../../../org/apache/bcel/generic/Select.html#Select">Select copy = (Select) super.clone();
236         copy.match = match.clone();
237         copy.indices = indices.clone();
238         copy.targets = targets.clone();
239         return copy;
240     }
241 
242 
243     /**
244      * Inform targets that they're not targeted anymore.
245      */
246     @Override
247     void dispose() {
248         super.dispose();
249         for (final InstructionHandle target2 : targets) {
250             target2.removeTargeter(this);
251         }
252     }
253 
254 
255     /**
256      * @return array of match indices
257      */
258     public int[] getMatchs() {
259         return match;
260     }
261 
262 
263     /**
264      * @return array of match target offsets
265      */
266     public int[] getIndices() {
267         return indices;
268     }
269 
270 
271     /**
272      * @return array of match targets
273      */
274     public InstructionHandle[] getTargets() {
275         return targets;
276     }
277 
278     /**
279      * @return match entry
280      * @since 6.0
281      */
282     final int getMatch(final int index) {
283         return match[index];
284     }
285 
286 
287     /**
288      * @return index entry from indices
289      * @since 6.0
290      */
291     final int getIndices(final int index) {
292         return indices[index];
293     }
294 
295     /**
296      * @return target entry
297      * @since 6.0
298      */
299     final InstructionHandle getTarget(final int index) {
300         return targets[index];
301     }
302 
303 
304     /**
305      * @return the fixed_length
306      * @since 6.0
307      */
308     final int getFixed_length() {
309         return fixed_length;
310     }
311 
312 
313     /**
314      * @param fixed_length the fixed_length to set
315      * @since 6.0
316      */
317     final void setFixed_length(final int fixed_length) {
318         this.fixed_length = fixed_length;
319     }
320 
321 
322     /**
323      * @return the match_length
324      * @since 6.0
325      */
326     final int getMatch_length() {
327         return match_length;
328     }
329 
330 
331     /**
332      * @param match_length the match_length to set
333      * @since 6.0
334      */
335     final int setMatch_length(final int match_length) {
336         this.match_length = match_length;
337         return match_length;
338     }
339 
340     /**
341      *
342      * @param index
343      * @param value
344      * @since 6.0
345      */
346     final void setMatch(final int index, final int value) {
347         match[index] = value;
348     }
349 
350     /**
351      *
352      * @param array
353      * @since 6.0
354      */
355     final void setIndices(final int[] array) {
356         indices = array;
357     }
358 
359     /**
360      *
361      * @param array
362      * @since 6.0
363      */
364     final void setMatches(final int[] array) {
365         match = array;
366     }
367 
368     /**
369      *
370      * @param array
371      * @since 6.0
372      */
373     final void setTargets(final InstructionHandle[] array) {
374         targets = array;
375     }
376 
377     /**
378      *
379      * @return the padding
380      * @since 6.0
381      */
382     final int getPadding() {
383         return padding;
384     }
385 
386 
387     /** @since 6.0 */
388     final int setIndices(final int i, final int value) {
389         indices[i] = value;
390         return value;  // Allow use in nested calls
391     }
392 }