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