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