25 import com.sun.org.apache.bcel.internal.util.ByteSequence; |
25 import com.sun.org.apache.bcel.internal.util.ByteSequence; |
26 |
26 |
27 /** |
27 /** |
28 * Select - Abstract super class for LOOKUPSWITCH and TABLESWITCH instructions. |
28 * Select - Abstract super class for LOOKUPSWITCH and TABLESWITCH instructions. |
29 * |
29 * |
30 * <p> |
30 * <p>We use our super's <code>target</code> property as the default target. |
31 * We use our super's <code>target</code> property as the default target. |
|
32 * |
31 * |
33 * @version $Id: Select.java 1749603 2016-06-21 20:50:19Z ggregory $ |
32 * @version $Id$ |
34 * @see LOOKUPSWITCH |
33 * @see LOOKUPSWITCH |
35 * @see TABLESWITCH |
34 * @see TABLESWITCH |
36 * @see InstructionList |
35 * @see InstructionList |
|
36 * @LastModified: Jun 2019 |
37 */ |
37 */ |
38 public abstract class Select extends BranchInstruction implements VariableLengthInstruction, |
38 public abstract class Select extends BranchInstruction implements VariableLengthInstruction, |
39 StackConsumer /* @since 6.0 */, StackProducer { |
39 StackConsumer /* @since 6.0 */, StackProducer { |
40 |
40 |
41 private int[] match; // matches, i.e., case 1: ... TODO could be package-protected? |
41 private int[] match; // matches, i.e., case 1: ... TODO could be package-protected? |
69 setTarget(defaultTarget); |
70 setTarget(defaultTarget); |
70 for (final InstructionHandle target2 : targets) { |
71 for (final InstructionHandle target2 : targets) { |
71 notifyTarget(null, target2, this); |
72 notifyTarget(null, target2, this); |
72 } |
73 } |
73 if ((match_length = match.length) != targets.length) { |
74 if ((match_length = match.length) != targets.length) { |
74 throw new ClassGenException("Match and target array have not the same length: Match length: " |
75 throw new ClassGenException("Match and target array have not the same length: Match length: " + |
75 + match.length + " Target length: " + targets.length); |
76 match.length + " Target length: " + targets.length); |
76 } |
77 } |
77 indices = new int[match_length]; |
78 indices = new int[match_length]; |
78 } |
79 } |
|
80 |
79 |
81 |
80 /** |
82 /** |
81 * Since this is a variable length instruction, it may shift the following |
83 * Since this is a variable length instruction, it may shift the following |
82 * instructions which then need to update their position. |
84 * instructions which then need to update their position. |
83 * |
85 * |
84 * Called by InstructionList.setPositions when setting the position for |
86 * Called by InstructionList.setPositions when setting the position for every |
85 * every instruction. In the presence of variable length instructions |
87 * instruction. In the presence of variable length instructions `setPositions' |
86 * `setPositions' performs multiple passes over the instruction list to |
88 * performs multiple passes over the instruction list to calculate the |
87 * calculate the correct (byte) positions and offsets by calling this |
89 * correct (byte) positions and offsets by calling this function. |
88 * function. |
90 * |
89 * |
91 * @param offset additional offset caused by preceding (variable length) instructions |
90 * @param offset additional offset caused by preceding (variable length) |
92 * @param max_offset the maximum offset that may be caused by these instructions |
91 * instructions |
93 * @return additional offset caused by possible change of this instruction's length |
92 * @param max_offset the maximum offset that may be caused by these |
94 */ |
93 * instructions |
95 @Override |
94 * @return additional offset caused by possible change of this instruction's |
96 protected int updatePosition( final int offset, final int max_offset ) { |
95 * length |
|
96 */ |
|
97 @Override |
|
98 protected int updatePosition(final int offset, final int max_offset) { |
|
99 setPosition(getPosition() + offset); // Additional offset caused by preceding SWITCHs, GOTOs, etc. |
97 setPosition(getPosition() + offset); // Additional offset caused by preceding SWITCHs, GOTOs, etc. |
100 final short old_length = (short) super.getLength(); |
98 final short old_length = (short) super.getLength(); |
101 /* Alignment on 4-byte-boundary, + 1, because of tag byte. |
99 /* Alignment on 4-byte-boundary, + 1, because of tag byte. |
102 */ |
100 */ |
103 padding = (4 - ((getPosition() + 1) % 4)) % 4; |
101 padding = (4 - ((getPosition() + 1) % 4)) % 4; |
104 super.setLength((short) (fixed_length + padding)); // Update length |
102 super.setLength((short) (fixed_length + padding)); // Update length |
105 return super.getLength() - old_length; |
103 return super.getLength() - old_length; |
106 } |
104 } |
107 |
105 |
|
106 |
108 /** |
107 /** |
109 * Dump instruction as byte code to stream out. |
108 * Dump instruction as byte code to stream out. |
110 * |
|
111 * @param out Output stream |
109 * @param out Output stream |
112 */ |
110 */ |
113 @Override |
111 @Override |
114 public void dump(final DataOutputStream out) throws IOException { |
112 public void dump( final DataOutputStream out ) throws IOException { |
115 out.writeByte(super.getOpcode()); |
113 out.writeByte(super.getOpcode()); |
116 for (int i = 0; i < padding; i++) { |
114 for (int i = 0; i < padding; i++) { |
117 out.writeByte(0); |
115 out.writeByte(0); |
118 } |
116 } |
119 super.setIndex(getTargetOffset()); // Write default target offset |
117 super.setIndex(getTargetOffset()); // Write default target offset |
120 out.writeInt(super.getIndex()); |
118 out.writeInt(super.getIndex()); |
121 } |
119 } |
122 |
120 |
|
121 |
123 /** |
122 /** |
124 * Read needed data (e.g. index) from file. |
123 * Read needed data (e.g. index) from file. |
125 */ |
124 */ |
126 @Override |
125 @Override |
127 protected void initFromFile(final ByteSequence bytes, final boolean wide) throws IOException { |
126 protected void initFromFile( final ByteSequence bytes, final boolean wide ) throws IOException { |
128 padding = (4 - (bytes.getIndex() % 4)) % 4; // Compute number of pad bytes |
127 padding = (4 - (bytes.getIndex() % 4)) % 4; // Compute number of pad bytes |
129 for (int i = 0; i < padding; i++) { |
128 for (int i = 0; i < padding; i++) { |
130 bytes.readByte(); |
129 bytes.readByte(); |
131 } |
130 } |
132 // Default branch target common for both cases (TABLESWITCH, LOOKUPSWITCH) |
131 // Default branch target common for both cases (TABLESWITCH, LOOKUPSWITCH) |
133 super.setIndex(bytes.readInt()); |
132 super.setIndex(bytes.readInt()); |
134 } |
133 } |
135 |
134 |
|
135 |
136 /** |
136 /** |
137 * @return mnemonic for instruction |
137 * @return mnemonic for instruction |
138 */ |
138 */ |
139 @Override |
139 @Override |
140 public String toString(final boolean verbose) { |
140 public String toString( final boolean verbose ) { |
141 final StringBuilder buf = new StringBuilder(super.toString(verbose)); |
141 final StringBuilder buf = new StringBuilder(super.toString(verbose)); |
142 if (verbose) { |
142 if (verbose) { |
143 for (int i = 0; i < match_length; i++) { |
143 for (int i = 0; i < match_length; i++) { |
144 String s = "null"; |
144 String s = "null"; |
145 if (targets[i] != null) { |
145 if (targets[i] != null) { |
152 buf.append(" ..."); |
152 buf.append(" ..."); |
153 } |
153 } |
154 return buf.toString(); |
154 return buf.toString(); |
155 } |
155 } |
156 |
156 |
|
157 |
157 /** |
158 /** |
158 * Set branch target for `i'th case |
159 * Set branch target for `i'th case |
159 */ |
160 */ |
160 public void setTarget(final int i, final InstructionHandle target) { // TODO could be package-protected? |
161 public void setTarget( final int i, final InstructionHandle target ) { // TODO could be package-protected? |
161 notifyTarget(targets[i], target, this); |
162 notifyTarget(targets[i], target, this); |
162 targets[i] = target; |
163 targets[i] = target; |
163 } |
164 } |
164 |
165 |
|
166 |
165 /** |
167 /** |
166 * @param old_ih old target |
168 * @param old_ih old target |
167 * @param new_ih new target |
169 * @param new_ih new target |
168 */ |
170 */ |
169 @Override |
171 @Override |
170 public void updateTarget(final InstructionHandle old_ih, final InstructionHandle new_ih) { |
172 public void updateTarget( final InstructionHandle old_ih, final InstructionHandle new_ih ) { |
171 boolean targeted = false; |
173 boolean targeted = false; |
172 if (super.getTarget() == old_ih) { |
174 if (super.getTarget() == old_ih) { |
173 targeted = true; |
175 targeted = true; |
174 setTarget(new_ih); |
176 setTarget(new_ih); |
175 } |
177 } |
182 if (!targeted) { |
184 if (!targeted) { |
183 throw new ClassGenException("Not targeting " + old_ih); |
185 throw new ClassGenException("Not targeting " + old_ih); |
184 } |
186 } |
185 } |
187 } |
186 |
188 |
|
189 |
187 /** |
190 /** |
188 * @return true, if ih is target of this instruction |
191 * @return true, if ih is target of this instruction |
189 */ |
192 */ |
190 @Override |
193 @Override |
191 public boolean containsTarget(final InstructionHandle ih) { |
194 public boolean containsTarget( final InstructionHandle ih ) { |
192 if (super.getTarget() == ih) { |
195 if (super.getTarget() == ih) { |
193 return true; |
196 return true; |
194 } |
197 } |
195 for (final InstructionHandle target2 : targets) { |
198 for (final InstructionHandle target2 : targets) { |
196 if (target2 == ih) { |
199 if (target2 == ih) { |
197 return true; |
200 return true; |
198 } |
201 } |
199 } |
202 } |
200 return false; |
203 return false; |
201 } |
204 } |
|
205 |
202 |
206 |
203 @Override |
207 @Override |
204 protected Object clone() throws CloneNotSupportedException { |
208 protected Object clone() throws CloneNotSupportedException { |
205 final Select copy = (Select) super.clone(); |
209 final Select copy = (Select) super.clone(); |
206 copy.match = match.clone(); |
210 copy.match = match.clone(); |
207 copy.indices = indices.clone(); |
211 copy.indices = indices.clone(); |
208 copy.targets = targets.clone(); |
212 copy.targets = targets.clone(); |
209 return copy; |
213 return copy; |
210 } |
214 } |
211 |
215 |
|
216 |
212 /** |
217 /** |
213 * Inform targets that they're not targeted anymore. |
218 * Inform targets that they're not targeted anymore. |
214 */ |
219 */ |
215 @Override |
220 @Override |
216 void dispose() { |
221 void dispose() { |