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