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