001/* 002 * Licensed to the Apache Software Foundation (ASF) under one 003 * or more contributor license agreements. See the NOTICE file 004 * distributed with this work for additional information 005 * regarding copyright ownership. The ASF licenses this file 006 * to you under the Apache License, Version 2.0 (the 007 * "License"); you may not use this file except in compliance 008 * with the License. You may obtain a copy of the License at 009 * 010 * https://www.apache.org/licenses/LICENSE-2.0 011 * 012 * Unless required by applicable law or agreed to in writing, 013 * software distributed under the License is distributed on an 014 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 015 * KIND, either express or implied. See the License for the 016 * specific language governing permissions and limitations 017 * under the License. 018 */ 019package org.apache.bcel.generic; 020 021import java.io.DataOutputStream; 022import java.io.IOException; 023 024import org.apache.bcel.Const; 025import org.apache.bcel.classfile.ConstantPool; 026import org.apache.bcel.util.ByteSequence; 027 028/** 029 * Abstract super class for all Java byte codes. 030 */ 031public abstract class Instruction implements Cloneable { 032 033 static final Instruction[] EMPTY_ARRAY = {}; 034 035 private static InstructionComparator cmp = InstructionComparator.DEFAULT; 036 037 /** 038 * Gets Comparator object used in the equals() method to determine equality of instructions. 039 * 040 * @return currently used comparator for equals(). 041 * @deprecated (6.0) use the built in comparator, or wrap this class in another object that implements these methods 042 */ 043 @Deprecated 044 public static InstructionComparator getComparator() { 045 return cmp; 046 } 047 048 /** 049 * Tests if the value can fit in a byte (signed) 050 * 051 * @param value the value to check. 052 * @return true if the value is in range. 053 * @since 6.0 054 */ 055 public static boolean isValidByte(final int value) { 056 return value >= Byte.MIN_VALUE && value <= Byte.MAX_VALUE; 057 } 058 059 /** 060 * Tests if the value can fit in a short (signed) 061 * 062 * @param value the value to check. 063 * @return true if the value is in range. 064 * @since 6.0 065 */ 066 public static boolean isValidShort(final int value) { 067 return value >= Short.MIN_VALUE && value <= Short.MAX_VALUE; 068 } 069 070 /** 071 * Reads an instruction from (byte code) input stream and return the appropriate object. 072 * <p> 073 * If the Instruction is defined in {@link InstructionConst}, then the singleton instance is returned. 074 * </p> 075 * 076 * @param bytes input stream bytes. 077 * @return instruction object being read. 078 * @throws IOException Thrown when an I/O exception of some sort has occurred. 079 * @see InstructionConst#getInstruction(int) 080 */ 081 // @since 6.0 no longer final 082 public static Instruction readInstruction(final ByteSequence bytes) throws IOException { 083 boolean wide = false; 084 short opcode = (short) bytes.readUnsignedByte(); 085 Instruction obj = null; 086 if (opcode == Const.WIDE) { // Read next opcode after wide byte 087 wide = true; 088 opcode = (short) bytes.readUnsignedByte(); 089 } 090 final Instruction instruction = InstructionConst.getInstruction(opcode); 091 if (instruction != null) { 092 return instruction; // Used predefined immutable object, if available 093 } 094 095 switch (opcode) { 096 case Const.BIPUSH: 097 obj = new BIPUSH(); 098 break; 099 case Const.SIPUSH: 100 obj = new SIPUSH(); 101 break; 102 case Const.LDC: 103 obj = new LDC(); 104 break; 105 case Const.LDC_W: 106 obj = new LDC_W(); 107 break; 108 case Const.LDC2_W: 109 obj = new LDC2_W(); 110 break; 111 case Const.ILOAD: 112 obj = new ILOAD(); 113 break; 114 case Const.LLOAD: 115 obj = new LLOAD(); 116 break; 117 case Const.FLOAD: 118 obj = new FLOAD(); 119 break; 120 case Const.DLOAD: 121 obj = new DLOAD(); 122 break; 123 case Const.ALOAD: 124 obj = new ALOAD(); 125 break; 126 case Const.ILOAD_0: 127 obj = new ILOAD(0); 128 break; 129 case Const.ILOAD_1: 130 obj = new ILOAD(1); 131 break; 132 case Const.ILOAD_2: 133 obj = new ILOAD(2); 134 break; 135 case Const.ILOAD_3: 136 obj = new ILOAD(3); 137 break; 138 case Const.LLOAD_0: 139 obj = new LLOAD(0); 140 break; 141 case Const.LLOAD_1: 142 obj = new LLOAD(1); 143 break; 144 case Const.LLOAD_2: 145 obj = new LLOAD(2); 146 break; 147 case Const.LLOAD_3: 148 obj = new LLOAD(3); 149 break; 150 case Const.FLOAD_0: 151 obj = new FLOAD(0); 152 break; 153 case Const.FLOAD_1: 154 obj = new FLOAD(1); 155 break; 156 case Const.FLOAD_2: 157 obj = new FLOAD(2); 158 break; 159 case Const.FLOAD_3: 160 obj = new FLOAD(3); 161 break; 162 case Const.DLOAD_0: 163 obj = new DLOAD(0); 164 break; 165 case Const.DLOAD_1: 166 obj = new DLOAD(1); 167 break; 168 case Const.DLOAD_2: 169 obj = new DLOAD(2); 170 break; 171 case Const.DLOAD_3: 172 obj = new DLOAD(3); 173 break; 174 case Const.ALOAD_0: 175 obj = new ALOAD(0); 176 break; 177 case Const.ALOAD_1: 178 obj = new ALOAD(1); 179 break; 180 case Const.ALOAD_2: 181 obj = new ALOAD(2); 182 break; 183 case Const.ALOAD_3: 184 obj = new ALOAD(3); 185 break; 186 case Const.ISTORE: 187 obj = new ISTORE(); 188 break; 189 case Const.LSTORE: 190 obj = new LSTORE(); 191 break; 192 case Const.FSTORE: 193 obj = new FSTORE(); 194 break; 195 case Const.DSTORE: 196 obj = new DSTORE(); 197 break; 198 case Const.ASTORE: 199 obj = new ASTORE(); 200 break; 201 case Const.ISTORE_0: 202 obj = new ISTORE(0); 203 break; 204 case Const.ISTORE_1: 205 obj = new ISTORE(1); 206 break; 207 case Const.ISTORE_2: 208 obj = new ISTORE(2); 209 break; 210 case Const.ISTORE_3: 211 obj = new ISTORE(3); 212 break; 213 case Const.LSTORE_0: 214 obj = new LSTORE(0); 215 break; 216 case Const.LSTORE_1: 217 obj = new LSTORE(1); 218 break; 219 case Const.LSTORE_2: 220 obj = new LSTORE(2); 221 break; 222 case Const.LSTORE_3: 223 obj = new LSTORE(3); 224 break; 225 case Const.FSTORE_0: 226 obj = new FSTORE(0); 227 break; 228 case Const.FSTORE_1: 229 obj = new FSTORE(1); 230 break; 231 case Const.FSTORE_2: 232 obj = new FSTORE(2); 233 break; 234 case Const.FSTORE_3: 235 obj = new FSTORE(3); 236 break; 237 case Const.DSTORE_0: 238 obj = new DSTORE(0); 239 break; 240 case Const.DSTORE_1: 241 obj = new DSTORE(1); 242 break; 243 case Const.DSTORE_2: 244 obj = new DSTORE(2); 245 break; 246 case Const.DSTORE_3: 247 obj = new DSTORE(3); 248 break; 249 case Const.ASTORE_0: 250 obj = new ASTORE(0); 251 break; 252 case Const.ASTORE_1: 253 obj = new ASTORE(1); 254 break; 255 case Const.ASTORE_2: 256 obj = new ASTORE(2); 257 break; 258 case Const.ASTORE_3: 259 obj = new ASTORE(3); 260 break; 261 case Const.IINC: 262 obj = new IINC(); 263 break; 264 case Const.IFEQ: 265 obj = new IFEQ(); 266 break; 267 case Const.IFNE: 268 obj = new IFNE(); 269 break; 270 case Const.IFLT: 271 obj = new IFLT(); 272 break; 273 case Const.IFGE: 274 obj = new IFGE(); 275 break; 276 case Const.IFGT: 277 obj = new IFGT(); 278 break; 279 case Const.IFLE: 280 obj = new IFLE(); 281 break; 282 case Const.IF_ICMPEQ: 283 obj = new IF_ICMPEQ(); 284 break; 285 case Const.IF_ICMPNE: 286 obj = new IF_ICMPNE(); 287 break; 288 case Const.IF_ICMPLT: 289 obj = new IF_ICMPLT(); 290 break; 291 case Const.IF_ICMPGE: 292 obj = new IF_ICMPGE(); 293 break; 294 case Const.IF_ICMPGT: 295 obj = new IF_ICMPGT(); 296 break; 297 case Const.IF_ICMPLE: 298 obj = new IF_ICMPLE(); 299 break; 300 case Const.IF_ACMPEQ: 301 obj = new IF_ACMPEQ(); 302 break; 303 case Const.IF_ACMPNE: 304 obj = new IF_ACMPNE(); 305 break; 306 case Const.GOTO: 307 obj = new GOTO(); 308 break; 309 case Const.JSR: 310 obj = new JSR(); 311 break; 312 case Const.RET: 313 obj = new RET(); 314 break; 315 case Const.TABLESWITCH: 316 obj = new TABLESWITCH(); 317 break; 318 case Const.LOOKUPSWITCH: 319 obj = new LOOKUPSWITCH(); 320 break; 321 case Const.GETSTATIC: 322 obj = new GETSTATIC(); 323 break; 324 case Const.PUTSTATIC: 325 obj = new PUTSTATIC(); 326 break; 327 case Const.GETFIELD: 328 obj = new GETFIELD(); 329 break; 330 case Const.PUTFIELD: 331 obj = new PUTFIELD(); 332 break; 333 case Const.INVOKEVIRTUAL: 334 obj = new INVOKEVIRTUAL(); 335 break; 336 case Const.INVOKESPECIAL: 337 obj = new INVOKESPECIAL(); 338 break; 339 case Const.INVOKESTATIC: 340 obj = new INVOKESTATIC(); 341 break; 342 case Const.INVOKEINTERFACE: 343 obj = new INVOKEINTERFACE(); 344 break; 345 case Const.INVOKEDYNAMIC: 346 obj = new INVOKEDYNAMIC(); 347 break; 348 case Const.NEW: 349 obj = new NEW(); 350 break; 351 case Const.NEWARRAY: 352 obj = new NEWARRAY(); 353 break; 354 case Const.ANEWARRAY: 355 obj = new ANEWARRAY(); 356 break; 357 case Const.CHECKCAST: 358 obj = new CHECKCAST(); 359 break; 360 case Const.INSTANCEOF: 361 obj = new INSTANCEOF(); 362 break; 363 case Const.MULTIANEWARRAY: 364 obj = new MULTIANEWARRAY(); 365 break; 366 case Const.IFNULL: 367 obj = new IFNULL(); 368 break; 369 case Const.IFNONNULL: 370 obj = new IFNONNULL(); 371 break; 372 case Const.GOTO_W: 373 obj = new GOTO_W(); 374 break; 375 case Const.JSR_W: 376 obj = new JSR_W(); 377 break; 378 case Const.BREAKPOINT: 379 obj = new BREAKPOINT(); 380 break; 381 case Const.IMPDEP1: 382 obj = new IMPDEP1(); 383 break; 384 case Const.IMPDEP2: 385 obj = new IMPDEP2(); 386 break; 387 default: 388 throw new ClassGenException("Illegal opcode detected: " + opcode); 389 390 } 391 392 if (wide && !(obj instanceof LocalVariableInstruction || obj instanceof RET)) { 393 throw new ClassGenException("Illegal opcode after wide: " + opcode); 394 } 395 obj.setOpcode(opcode); 396 obj.initFromFile(bytes, wide); // Do further initializations, if any 397 return obj; 398 } 399 400 /** 401 * Sets comparator to be used for equals(). 402 * 403 * @param c the comparator. 404 * @deprecated (6.0) use the built in comparator, or wrap this class in another object that implements these methods 405 */ 406 @Deprecated 407 public static void setComparator(final InstructionComparator c) { 408 cmp = c; 409 } 410 411 /** 412 * @deprecated (since 6.0) will be made private; do not access directly, use getter/setter 413 */ 414 @Deprecated 415 protected short length = 1; // Length of instruction in bytes 416 417 /** 418 * @deprecated (since 6.0) will be made private; do not access directly, use getter/setter 419 */ 420 @Deprecated 421 protected short opcode = -1; // Opcode number 422 423 /** 424 * Empty constructor needed for Instruction.readInstruction. Not to be used otherwise. 425 */ 426 Instruction() { 427 } 428 429 /** 430 * Constructs an Instruction. 431 * 432 * @param opcode the opcode. 433 * @param length the instruction length. 434 */ 435 public Instruction(final short opcode, final short length) { 436 this.length = length; 437 this.opcode = opcode; 438 } 439 440 /** 441 * Call corresponding visitor method(s). The order is: Call visitor methods of implemented interfaces first, then call 442 * methods according to the class hierarchy in descending order, that is, the most specific visitXXX() call comes last. 443 * 444 * @param v Visitor object. 445 */ 446 public abstract void accept(Visitor v); 447 448 /** 449 * This method also gives right results for instructions whose effect on the stack depends on the constant pool entry 450 * they reference. 451 * 452 * @param cpg the constant pool generator. 453 * @return Number of words consumed from stack by this instruction, or Constants.UNPREDICTABLE, if this cannot be 454 * computed statically 455 */ 456 public int consumeStack(final ConstantPoolGen cpg) { 457 return Const.getConsumeStack(opcode); 458 } 459 460 /** 461 * Use with caution, since 'BranchInstruction's have a 'target' reference which is not copied correctly (only basic 462 * types are). This also applies for 'Select' instructions with their multiple branch targets. 463 * 464 * @see BranchInstruction 465 * @return (shallow) copy of an instruction. 466 */ 467 public Instruction copy() { 468 Instruction i = null; 469 // "Constant" instruction, no need to duplicate 470 if (InstructionConst.getInstruction(getOpcode()) != null) { 471 i = this; 472 } else { 473 try { 474 i = (Instruction) clone(); 475 } catch (final CloneNotSupportedException e) { 476 System.err.println(e); 477 } 478 } 479 return i; 480 } 481 482 /** 483 * Some instructions may be reused, so don't do anything by default. 484 */ 485 void dispose() { 486 } 487 488 /** 489 * Dumps instruction as byte code to stream out. 490 * 491 * @param out Output stream. 492 * @throws IOException Thrown when an I/O exception of some sort has occurred. 493 */ 494 public void dump(final DataOutputStream out) throws IOException { 495 out.writeByte(opcode); // Common for all instructions 496 } 497 498 /** 499 * Tests for equality, delegated to comparator 500 * 501 * @return true if that is an Instruction and has the same opcode. 502 */ 503 @Override 504 public boolean equals(final Object that) { 505 return that instanceof Instruction && cmp.equals(this, (Instruction) that); 506 } 507 508 /** 509 * Gets the length (in bytes) of instruction. 510 * 511 * @return length (in bytes) of instruction. 512 */ 513 public int getLength() { 514 return length; 515 } 516 517 /** 518 * Gets the name of instruction, that is, opcode name. 519 * 520 * @return name of instruction, that is, opcode name. 521 */ 522 public String getName() { 523 return Const.getOpcodeName(opcode); 524 } 525 526 /** 527 * Gets this instruction's opcode. 528 * 529 * @return this instruction's opcode. 530 */ 531 public short getOpcode() { 532 return opcode; 533 } 534 535 /** 536 * Gets the hashCode of this object. 537 * 538 * @return the hashCode. 539 * @since 6.0 540 */ 541 @Override 542 public int hashCode() { 543 return opcode; 544 } 545 546 /** 547 * Reads needed data (for example index) from file. 548 * 549 * @param bytes byte sequence to read from. 550 * @param wide "wide" instruction flag. 551 * @throws IOException may be thrown if the implementation needs to read data from the file 552 */ 553 @SuppressWarnings("unused") // thrown by subclasses 554 protected void initFromFile(final ByteSequence bytes, final boolean wide) throws IOException { 555 } 556 557 /** 558 * This method also gives right results for instructions whose effect on the stack depends on the constant pool entry 559 * they reference. 560 * 561 * @param cpg the constant pool generator. 562 * @return Number of words produced onto stack by this instruction, or Constants.UNPREDICTABLE, if this cannot be 563 * computed statically 564 */ 565 public int produceStack(final ConstantPoolGen cpg) { 566 return Const.getProduceStack(opcode); 567 } 568 569 /** 570 * Needed in readInstruction and subclasses in this package 571 * 572 * @since 6.0 573 */ 574 final void setLength(final int length) { 575 this.length = (short) length; // TODO check range? 576 } 577 578 /** 579 * Needed in readInstruction and subclasses in this package 580 */ 581 final void setOpcode(final short opcode) { 582 this.opcode = opcode; 583 } 584 585 /** 586 * @return mnemonic for instruction in verbose format. 587 */ 588 @Override 589 public String toString() { 590 return toString(true); 591 } 592 593 /** 594 * Long output format: 595 * 596 * <name of opcode> "["<opcode number>"]" "("<length of instruction>")" 597 * 598 * @param verbose long/short format switch. 599 * @return mnemonic for instruction. 600 */ 601 public String toString(final boolean verbose) { 602 if (verbose) { 603 return getName() + "[" + opcode + "](" + length + ")"; 604 } 605 return getName(); 606 } 607 608 /** 609 * Gets the mnemonic for instruction with symbolic references resolved. 610 * 611 * @param cp the constant pool. 612 * @return mnemonic for instruction with symbolic references resolved. 613 */ 614 public String toString(final ConstantPool cp) { 615 return toString(false); 616 } 617}