001/* 002 * Licensed to the Apache Software Foundation (ASF) under one or more 003 * contributor license agreements. See the NOTICE file distributed with 004 * this work for additional information regarding copyright ownership. 005 * The ASF licenses this file to You under the Apache License, Version 2.0 006 * (the "License"); you may not use this file except in compliance with 007 * the License. You may obtain a copy of the License at 008 * 009 * http://www.apache.org/licenses/LICENSE-2.0 010 * 011 * Unless required by applicable law or agreed to in writing, software 012 * distributed under the License is distributed on an "AS IS" BASIS, 013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 014 * See the License for the specific language governing permissions and 015 * limitations under the License. 016 * 017 */ 018package org.apache.bcel.generic; 019 020import java.io.DataOutputStream; 021import java.io.IOException; 022 023import org.apache.bcel.util.ByteSequence; 024 025/** 026 * Select - Abstract super class for LOOKUPSWITCH and TABLESWITCH instructions. 027 * 028 * <p>We use our super's <code>target</code> property as the default target. 029 * 030 * @see LOOKUPSWITCH 031 * @see TABLESWITCH 032 * @see InstructionList 033 */ 034public abstract class Select extends BranchInstruction implements VariableLengthInstruction, 035 StackConsumer /* @since 6.0 */, StackProducer { 036 037 /** 038 * @deprecated (since 6.0) will be made private; do not access directly, use getter/setter 039 */ 040 @Deprecated 041 protected int[] match; // matches, i.e., case 1: ... TODO could be package-protected? 042 043 /** 044 * @deprecated (since 6.0) will be made private; do not access directly, use getter/setter 045 */ 046 @Deprecated 047 protected int[] indices; // target offsets TODO could be package-protected? 048 049 /** 050 * @deprecated (since 6.0) will be made private; do not access directly, use getter/setter 051 */ 052 @Deprecated 053 protected InstructionHandle[] targets; // target objects in instruction list TODO could be package-protected? 054 055 /** 056 * @deprecated (since 6.0) will be made private; do not access directly, use getter/setter 057 */ 058 @Deprecated 059 protected int fixed_length; // fixed length defined by subclasses TODO could be package-protected? 060 061 /** 062 * @deprecated (since 6.0) will be made private; do not access directly, use getter/setter 063 */ 064 @Deprecated 065 protected int match_length; // number of cases TODO could be package-protected? 066 067 /** 068 * @deprecated (since 6.0) will be made private; do not access directly, use getter/setter 069 */ 070 @Deprecated 071 protected int padding = 0; // number of pad bytes for alignment TODO could be package-protected? 072 073 074 /** 075 * Empty constructor needed for Instruction.readInstruction. 076 * Not to be used otherwise. 077 */ 078 Select() { 079 } 080 081 082 /** 083 * (Match, target) pairs for switch. 084 * `Match' and `targets' must have the same length of course. 085 * 086 * @param match array of matching values 087 * @param targets instruction targets 088 * @param defaultTarget default instruction target 089 */ 090 Select(final short opcode, final int[] match, final InstructionHandle[] targets, final InstructionHandle defaultTarget) { 091 // don't set default target before instuction is built 092 super(opcode, null); 093 this.match = match; 094 this.targets = targets; 095 // now it's safe to set default target 096 setTarget(defaultTarget); 097 for (final InstructionHandle target2 : targets) { 098 notifyTarget(null, target2, this); 099 } 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 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 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}