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.Const; 24 import org.apache.bcel.classfile.ConstantPool; 25 import org.apache.bcel.util.ByteSequence; 26 27 /** 28 * Abstract super class for all Java byte codes. 29 * 30 * @version $Id$ 31 */ 32 public abstract class Instruction implements Cloneable { 33 34 /** 35 * @deprecated (since 6.0) will be made private; do not access directly, use getter/setter 36 */ 37 @Deprecated 38 protected short length = 1; // Length of instruction in bytes 39 40 /** 41 * @deprecated (since 6.0) will be made private; do not access directly, use getter/setter 42 */ 43 @Deprecated 44 protected short opcode = -1; // Opcode number 45 46 private static InstructionComparator cmp = InstructionComparator.DEFAULT; 47 48 49 /** 50 * Empty constructor needed for Instruction.readInstruction. 51 * Not to be used otherwise. 52 */ Instruction()53 Instruction() { 54 } 55 56 Instruction(final short opcode, final short length)57 public Instruction(final short opcode, final short length) { 58 this.length = length; 59 this.opcode = opcode; 60 } 61 62 63 /** 64 * Dump instruction as byte code to stream out. 65 * @param out Output stream 66 */ dump( final DataOutputStream out )67 public void dump( final DataOutputStream out ) throws IOException { 68 out.writeByte(opcode); // Common for all instructions 69 } 70 71 72 /** @return name of instruction, i.e., opcode name 73 */ getName()74 public String getName() { 75 return Const.getOpcodeName(opcode); 76 } 77 78 79 /** 80 * Long output format: 81 * 82 * <name of opcode> "["<opcode number>"]" 83 * "("<length of instruction>")" 84 * 85 * @param verbose long/short format switch 86 * @return mnemonic for instruction 87 */ toString( final boolean verbose )88 public String toString( final boolean verbose ) { 89 if (verbose) { 90 return getName() + "[" + opcode + "](" + length + ")"; 91 } 92 return getName(); 93 } 94 95 96 /** 97 * @return mnemonic for instruction in verbose format 98 */ 99 @Override toString()100 public String toString() { 101 return toString(true); 102 } 103 104 105 /** 106 * @return mnemonic for instruction with sumbolic references resolved 107 */ toString( final ConstantPool cp )108 public String toString( final ConstantPool cp ) { 109 return toString(false); 110 } 111 112 113 /** 114 * Use with caution, since `BranchInstruction's have a `target' reference which 115 * is not copied correctly (only basic types are). This also applies for 116 * `Select' instructions with their multiple branch targets. 117 * 118 * @see BranchInstruction 119 * @return (shallow) copy of an instruction 120 */ copy()121 public Instruction copy() { 122 Instruction i = null; 123 // "Constant" instruction, no need to duplicate 124 if (InstructionConst.getInstruction(this.getOpcode()) != null) { 125 i = this; 126 } else { 127 try { 128 i = (Instruction) clone(); 129 } catch (final CloneNotSupportedException e) { 130 System.err.println(e); 131 } 132 } 133 return i; 134 } 135 136 137 /** 138 * Read needed data (e.g. index) from file. 139 * 140 * @param bytes byte sequence to read from 141 * @param wide "wide" instruction flag 142 * @throws IOException may be thrown if the implementation needs to read data from the file 143 */ initFromFile( final ByteSequence bytes, final boolean wide )144 protected void initFromFile( final ByteSequence bytes, final boolean wide ) throws IOException { 145 } 146 147 148 /** 149 * Read an instruction from (byte code) input stream and return the 150 * appropiate object. 151 * <p> 152 * If the Instruction is defined in {@link InstructionConst}, then the 153 * singleton instance is returned. 154 * @param bytes input stream bytes 155 * @return instruction object being read 156 * @see InstructionConst#getInstruction(int) 157 */ 158 // @since 6.0 no longer final readInstruction( final ByteSequence bytes )159 public static Instruction readInstruction( final ByteSequence bytes ) throws IOException { 160 boolean wide = false; 161 short opcode = (short) bytes.readUnsignedByte(); 162 Instruction obj = null; 163 if (opcode == Const.WIDE) { // Read next opcode after wide byte 164 wide = true; 165 opcode = (short) bytes.readUnsignedByte(); 166 } 167 final Instruction instruction = InstructionConst.getInstruction(opcode); 168 if (instruction != null) { 169 return instruction; // Used predefined immutable object, if available 170 } 171 172 switch (opcode) { 173 case Const.BIPUSH: 174 obj = new BIPUSH(); 175 break; 176 case Const.SIPUSH: 177 obj = new SIPUSH(); 178 break; 179 case Const.LDC: 180 obj = new LDC(); 181 break; 182 case Const.LDC_W: 183 obj = new LDC_W(); 184 break; 185 case Const.LDC2_W: 186 obj = new LDC2_W(); 187 break; 188 case Const.ILOAD: 189 obj = new ILOAD(); 190 break; 191 case Const.LLOAD: 192 obj = new LLOAD(); 193 break; 194 case Const.FLOAD: 195 obj = new FLOAD(); 196 break; 197 case Const.DLOAD: 198 obj = new DLOAD(); 199 break; 200 case Const.ALOAD: 201 obj = new ALOAD(); 202 break; 203 case Const.ILOAD_0: 204 obj = new ILOAD(0); 205 break; 206 case Const.ILOAD_1: 207 obj = new ILOAD(1); 208 break; 209 case Const.ILOAD_2: 210 obj = new ILOAD(2); 211 break; 212 case Const.ILOAD_3: 213 obj = new ILOAD(3); 214 break; 215 case Const.LLOAD_0: 216 obj = new LLOAD(0); 217 break; 218 case Const.LLOAD_1: 219 obj = new LLOAD(1); 220 break; 221 case Const.LLOAD_2: 222 obj = new LLOAD(2); 223 break; 224 case Const.LLOAD_3: 225 obj = new LLOAD(3); 226 break; 227 case Const.FLOAD_0: 228 obj = new FLOAD(0); 229 break; 230 case Const.FLOAD_1: 231 obj = new FLOAD(1); 232 break; 233 case Const.FLOAD_2: 234 obj = new FLOAD(2); 235 break; 236 case Const.FLOAD_3: 237 obj = new FLOAD(3); 238 break; 239 case Const.DLOAD_0: 240 obj = new DLOAD(0); 241 break; 242 case Const.DLOAD_1: 243 obj = new DLOAD(1); 244 break; 245 case Const.DLOAD_2: 246 obj = new DLOAD(2); 247 break; 248 case Const.DLOAD_3: 249 obj = new DLOAD(3); 250 break; 251 case Const.ALOAD_0: 252 obj = new ALOAD(0); 253 break; 254 case Const.ALOAD_1: 255 obj = new ALOAD(1); 256 break; 257 case Const.ALOAD_2: 258 obj = new ALOAD(2); 259 break; 260 case Const.ALOAD_3: 261 obj = new ALOAD(3); 262 break; 263 case Const.ISTORE: 264 obj = new ISTORE(); 265 break; 266 case Const.LSTORE: 267 obj = new LSTORE(); 268 break; 269 case Const.FSTORE: 270 obj = new FSTORE(); 271 break; 272 case Const.DSTORE: 273 obj = new DSTORE(); 274 break; 275 case Const.ASTORE: 276 obj = new ASTORE(); 277 break; 278 case Const.ISTORE_0: 279 obj = new ISTORE(0); 280 break; 281 case Const.ISTORE_1: 282 obj = new ISTORE(1); 283 break; 284 case Const.ISTORE_2: 285 obj = new ISTORE(2); 286 break; 287 case Const.ISTORE_3: 288 obj = new ISTORE(3); 289 break; 290 case Const.LSTORE_0: 291 obj = new LSTORE(0); 292 break; 293 case Const.LSTORE_1: 294 obj = new LSTORE(1); 295 break; 296 case Const.LSTORE_2: 297 obj = new LSTORE(2); 298 break; 299 case Const.LSTORE_3: 300 obj = new LSTORE(3); 301 break; 302 case Const.FSTORE_0: 303 obj = new FSTORE(0); 304 break; 305 case Const.FSTORE_1: 306 obj = new FSTORE(1); 307 break; 308 case Const.FSTORE_2: 309 obj = new FSTORE(2); 310 break; 311 case Const.FSTORE_3: 312 obj = new FSTORE(3); 313 break; 314 case Const.DSTORE_0: 315 obj = new DSTORE(0); 316 break; 317 case Const.DSTORE_1: 318 obj = new DSTORE(1); 319 break; 320 case Const.DSTORE_2: 321 obj = new DSTORE(2); 322 break; 323 case Const.DSTORE_3: 324 obj = new DSTORE(3); 325 break; 326 case Const.ASTORE_0: 327 obj = new ASTORE(0); 328 break; 329 case Const.ASTORE_1: 330 obj = new ASTORE(1); 331 break; 332 case Const.ASTORE_2: 333 obj = new ASTORE(2); 334 break; 335 case Const.ASTORE_3: 336 obj = new ASTORE(3); 337 break; 338 case Const.IINC: 339 obj = new IINC(); 340 break; 341 case Const.IFEQ: 342 obj = new IFEQ(); 343 break; 344 case Const.IFNE: 345 obj = new IFNE(); 346 break; 347 case Const.IFLT: 348 obj = new IFLT(); 349 break; 350 case Const.IFGE: 351 obj = new IFGE(); 352 break; 353 case Const.IFGT: 354 obj = new IFGT(); 355 break; 356 case Const.IFLE: 357 obj = new IFLE(); 358 break; 359 case Const.IF_ICMPEQ: 360 obj = new IF_ICMPEQ(); 361 break; 362 case Const.IF_ICMPNE: 363 obj = new IF_ICMPNE(); 364 break; 365 case Const.IF_ICMPLT: 366 obj = new IF_ICMPLT(); 367 break; 368 case Const.IF_ICMPGE: 369 obj = new IF_ICMPGE(); 370 break; 371 case Const.IF_ICMPGT: 372 obj = new IF_ICMPGT(); 373 break; 374 case Const.IF_ICMPLE: 375 obj = new IF_ICMPLE(); 376 break; 377 case Const.IF_ACMPEQ: 378 obj = new IF_ACMPEQ(); 379 break; 380 case Const.IF_ACMPNE: 381 obj = new IF_ACMPNE(); 382 break; 383 case Const.GOTO: 384 obj = new GOTO(); 385 break; 386 case Const.JSR: 387 obj = new JSR(); 388 break; 389 case Const.RET: 390 obj = new RET(); 391 break; 392 case Const.TABLESWITCH: 393 obj = new TABLESWITCH(); 394 break; 395 case Const.LOOKUPSWITCH: 396 obj = new LOOKUPSWITCH(); 397 break; 398 case Const.GETSTATIC: 399 obj = new GETSTATIC(); 400 break; 401 case Const.PUTSTATIC: 402 obj = new PUTSTATIC(); 403 break; 404 case Const.GETFIELD: 405 obj = new GETFIELD(); 406 break; 407 case Const.PUTFIELD: 408 obj = new PUTFIELD(); 409 break; 410 case Const.INVOKEVIRTUAL: 411 obj = new INVOKEVIRTUAL(); 412 break; 413 case Const.INVOKESPECIAL: 414 obj = new INVOKESPECIAL(); 415 break; 416 case Const.INVOKESTATIC: 417 obj = new INVOKESTATIC(); 418 break; 419 case Const.INVOKEINTERFACE: 420 obj = new INVOKEINTERFACE(); 421 break; 422 case Const.INVOKEDYNAMIC: 423 obj = new INVOKEDYNAMIC(); 424 break; 425 case Const.NEW: 426 obj = new NEW(); 427 break; 428 case Const.NEWARRAY: 429 obj = new NEWARRAY(); 430 break; 431 case Const.ANEWARRAY: 432 obj = new ANEWARRAY(); 433 break; 434 case Const.CHECKCAST: 435 obj = new CHECKCAST(); 436 break; 437 case Const.INSTANCEOF: 438 obj = new INSTANCEOF(); 439 break; 440 case Const.MULTIANEWARRAY: 441 obj = new MULTIANEWARRAY(); 442 break; 443 case Const.IFNULL: 444 obj = new IFNULL(); 445 break; 446 case Const.IFNONNULL: 447 obj = new IFNONNULL(); 448 break; 449 case Const.GOTO_W: 450 obj = new GOTO_W(); 451 break; 452 case Const.JSR_W: 453 obj = new JSR_W(); 454 break; 455 case Const.BREAKPOINT: 456 obj = new BREAKPOINT(); 457 break; 458 case Const.IMPDEP1: 459 obj = new IMPDEP1(); 460 break; 461 case Const.IMPDEP2: 462 obj = new IMPDEP2(); 463 break; 464 default: 465 throw new ClassGenException("Illegal opcode detected: " + opcode); 466 467 } 468 469 if (wide 470 && !((obj instanceof LocalVariableInstruction) || (obj instanceof IINC) || (obj instanceof RET))) { 471 throw new ClassGenException("Illegal opcode after wide: " + opcode); 472 } 473 obj.setOpcode(opcode); 474 obj.initFromFile(bytes, wide); // Do further initializations, if any 475 return obj; 476 } 477 478 /** 479 * This method also gives right results for instructions whose 480 * effect on the stack depends on the constant pool entry they 481 * reference. 482 * @return Number of words consumed from stack by this instruction, 483 * or Constants.UNPREDICTABLE, if this can not be computed statically 484 */ consumeStack( final ConstantPoolGen cpg )485 public int consumeStack( final ConstantPoolGen cpg ) { 486 return Const.getConsumeStack(opcode); 487 } 488 489 490 /** 491 * This method also gives right results for instructions whose 492 * effect on the stack depends on the constant pool entry they 493 * reference. 494 * @return Number of words produced onto stack by this instruction, 495 * or Constants.UNPREDICTABLE, if this can not be computed statically 496 */ produceStack( final ConstantPoolGen cpg )497 public int produceStack( final ConstantPoolGen cpg ) { 498 return Const.getProduceStack(opcode); 499 } 500 501 502 /** 503 * @return this instructions opcode 504 */ getOpcode()505 public short getOpcode() { 506 return opcode; 507 } 508 509 510 /** 511 * @return length (in bytes) of instruction 512 */ getLength()513 public int getLength() { 514 return length; 515 } 516 517 518 /** 519 * Needed in readInstruction and subclasses in this package 520 */ setOpcode( final short opcode )521 final void setOpcode( final short opcode ) { 522 this.opcode = opcode; 523 } 524 525 526 /** 527 * Needed in readInstruction and subclasses in this package 528 * @since 6.0 529 */ setLength( final int length )530 final void setLength( final int length ) { 531 this.length = (short) length; // TODO check range? 532 } 533 534 535 /** Some instructions may be reused, so don't do anything by default. 536 */ dispose()537 void dispose() { 538 } 539 540 541 /** 542 * Call corresponding visitor method(s). The order is: 543 * Call visitor methods of implemented interfaces first, then 544 * call methods according to the class hierarchy in descending order, 545 * i.e., the most specific visitXXX() call comes last. 546 * 547 * @param v Visitor object 548 */ accept( Visitor v )549 public abstract void accept( Visitor v ); 550 551 552 /** Get Comparator object used in the equals() method to determine 553 * equality of instructions. 554 * 555 * @return currently used comparator for equals() 556 * @deprecated (6.0) use the built in comparator, or wrap this class in another object that implements these methods 557 */ 558 @Deprecated getComparator()559 public static InstructionComparator getComparator() { 560 return cmp; 561 } 562 563 564 /** Set comparator to be used for equals(). 565 * @deprecated (6.0) use the built in comparator, or wrap this class in another object that implements these methods 566 */ 567 @Deprecated setComparator( final InstructionComparator c )568 public static void setComparator( final InstructionComparator c ) { 569 cmp = c; 570 } 571 572 573 /** Check for equality, delegated to comparator 574 * @return true if that is an Instruction and has the same opcode 575 */ 576 @Override equals( final Object that )577 public boolean equals( final Object that ) { 578 return (that instanceof Instruction) ? cmp.equals(this, (Instruction) that) : false; 579 } 580 581 /** calculate the hashCode of this object 582 * @return the hashCode 583 * @since 6.0 584 */ 585 @Override hashCode()586 public int hashCode() { 587 return opcode; 588 } 589 590 /** 591 * Check if the value can fit in a byte (signed) 592 * @param value the value to check 593 * @return true if the value is in range 594 * @since 6.0 595 */ isValidByte(final int value)596 public static boolean isValidByte(final int value) { 597 return value >= Byte.MIN_VALUE && value <= Byte.MAX_VALUE; 598 } 599 600 /** 601 * Check if the value can fit in a short (signed) 602 * @param value the value to check 603 * @return true if the value is in range 604 * @since 6.0 605 */ isValidShort(final int value)606 public static boolean isValidShort(final int value) { 607 return value >= Short.MIN_VALUE && value <= Short.MAX_VALUE; 608 } 609 } 610