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