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 * 017 */ 018package org.apache.bcel.generic; 019 020import java.io.DataOutputStream; 021import java.io.IOException; 022 023import org.apache.bcel.Const; 024import org.apache.bcel.classfile.ConstantPool; 025import org.apache.bcel.util.ByteSequence; 026 027/** 028 * Abstract super class for all Java byte codes. 029 * 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 * Get 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 * Check 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 * Check 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 * Read 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 * 075 * @param bytes input stream bytes 076 * @return instruction object being read 077 * @see InstructionConst#getInstruction(int) 078 */ 079 // @since 6.0 no longer final 080 public static Instruction readInstruction(final ByteSequence bytes) throws IOException { 081 boolean wide = false; 082 short opcode = (short) bytes.readUnsignedByte(); 083 Instruction obj = null; 084 if (opcode == Const.WIDE) { // Read next opcode after wide byte 085 wide = true; 086 opcode = (short) bytes.readUnsignedByte(); 087 } 088 final Instruction instruction = InstructionConst.getInstruction(opcode); 089 if (instruction != null) { 090 return instruction; // Used predefined immutable object, if available 091 } 092 093 switch (opcode) { 094 case Const.BIPUSH: 095 obj = new BIPUSH(); 096 break; 097 case Const.SIPUSH: 098 obj = new SIPUSH(); 099 break; 100 case Const.LDC: 101 obj = new LDC(); 102 break; 103 case Const.LDC_W: 104 obj = new LDC_W(); 105 break; 106 case Const.LDC2_W: 107 obj = new LDC2_W(); 108 break; 109 case Const.ILOAD: 110 obj = new ILOAD(); 111 break; 112 case Const.LLOAD: 113 obj = new LLOAD(); 114 break; 115 case Const.FLOAD: 116 obj = new FLOAD(); 117 break; 118 case Const.DLOAD: 119 obj = new DLOAD(); 120 break; 121 case Const.ALOAD: 122 obj = new ALOAD(); 123 break; 124 case Const.ILOAD_0: 125 obj = new ILOAD(0); 126 break; 127 case Const.ILOAD_1: 128 obj = new ILOAD(1); 129 break; 130 case Const.ILOAD_2: 131 obj = new ILOAD(2); 132 break; 133 case Const.ILOAD_3: 134 obj = new ILOAD(3); 135 break; 136 case Const.LLOAD_0: 137 obj = new LLOAD(0); 138 break; 139 case Const.LLOAD_1: 140 obj = new LLOAD(1); 141 break; 142 case Const.LLOAD_2: 143 obj = new LLOAD(2); 144 break; 145 case Const.LLOAD_3: 146 obj = new LLOAD(3); 147 break; 148 case Const.FLOAD_0: 149 obj = new FLOAD(0); 150 break; 151 case Const.FLOAD_1: 152 obj = new FLOAD(1); 153 break; 154 case Const.FLOAD_2: 155 obj = new FLOAD(2); 156 break; 157 case Const.FLOAD_3: 158 obj = new FLOAD(3); 159 break; 160 case Const.DLOAD_0: 161 obj = new DLOAD(0); 162 break; 163 case Const.DLOAD_1: 164 obj = new DLOAD(1); 165 break; 166 case Const.DLOAD_2: 167 obj = new DLOAD(2); 168 break; 169 case Const.DLOAD_3: 170 obj = new DLOAD(3); 171 break; 172 case Const.ALOAD_0: 173 obj = new ALOAD(0); 174 break; 175 case Const.ALOAD_1: 176 obj = new ALOAD(1); 177 break; 178 case Const.ALOAD_2: 179 obj = new ALOAD(2); 180 break; 181 case Const.ALOAD_3: 182 obj = new ALOAD(3); 183 break; 184 case Const.ISTORE: 185 obj = new ISTORE(); 186 break; 187 case Const.LSTORE: 188 obj = new LSTORE(); 189 break; 190 case Const.FSTORE: 191 obj = new FSTORE(); 192 break; 193 case Const.DSTORE: 194 obj = new DSTORE(); 195 break; 196 case Const.ASTORE: 197 obj = new ASTORE(); 198 break; 199 case Const.ISTORE_0: 200 obj = new ISTORE(0); 201 break; 202 case Const.ISTORE_1: 203 obj = new ISTORE(1); 204 break; 205 case Const.ISTORE_2: 206 obj = new ISTORE(2); 207 break; 208 case Const.ISTORE_3: 209 obj = new ISTORE(3); 210 break; 211 case Const.LSTORE_0: 212 obj = new LSTORE(0); 213 break; 214 case Const.LSTORE_1: 215 obj = new LSTORE(1); 216 break; 217 case Const.LSTORE_2: 218 obj = new LSTORE(2); 219 break; 220 case Const.LSTORE_3: 221 obj = new LSTORE(3); 222 break; 223 case Const.FSTORE_0: 224 obj = new FSTORE(0); 225 break; 226 case Const.FSTORE_1: 227 obj = new FSTORE(1); 228 break; 229 case Const.FSTORE_2: 230 obj = new FSTORE(2); 231 break; 232 case Const.FSTORE_3: 233 obj = new FSTORE(3); 234 break; 235 case Const.DSTORE_0: 236 obj = new DSTORE(0); 237 break; 238 case Const.DSTORE_1: 239 obj = new DSTORE(1); 240 break; 241 case Const.DSTORE_2: 242 obj = new DSTORE(2); 243 break; 244 case Const.DSTORE_3: 245 obj = new DSTORE(3); 246 break; 247 case Const.ASTORE_0: 248 obj = new ASTORE(0); 249 break; 250 case Const.ASTORE_1: 251 obj = new ASTORE(1); 252 break; 253 case Const.ASTORE_2: 254 obj = new ASTORE(2); 255 break; 256 case Const.ASTORE_3: 257 obj = new ASTORE(3); 258 break; 259 case Const.IINC: 260 obj = new IINC(); 261 break; 262 case Const.IFEQ: 263 obj = new IFEQ(); 264 break; 265 case Const.IFNE: 266 obj = new IFNE(); 267 break; 268 case Const.IFLT: 269 obj = new IFLT(); 270 break; 271 case Const.IFGE: 272 obj = new IFGE(); 273 break; 274 case Const.IFGT: 275 obj = new IFGT(); 276 break; 277 case Const.IFLE: 278 obj = new IFLE(); 279 break; 280 case Const.IF_ICMPEQ: 281 obj = new IF_ICMPEQ(); 282 break; 283 case Const.IF_ICMPNE: 284 obj = new IF_ICMPNE(); 285 break; 286 case Const.IF_ICMPLT: 287 obj = new IF_ICMPLT(); 288 break; 289 case Const.IF_ICMPGE: 290 obj = new IF_ICMPGE(); 291 break; 292 case Const.IF_ICMPGT: 293 obj = new IF_ICMPGT(); 294 break; 295 case Const.IF_ICMPLE: 296 obj = new IF_ICMPLE(); 297 break; 298 case Const.IF_ACMPEQ: 299 obj = new IF_ACMPEQ(); 300 break; 301 case Const.IF_ACMPNE: 302 obj = new IF_ACMPNE(); 303 break; 304 case Const.GOTO: 305 obj = new GOTO(); 306 break; 307 case Const.JSR: 308 obj = new JSR(); 309 break; 310 case Const.RET: 311 obj = new RET(); 312 break; 313 case Const.TABLESWITCH: 314 obj = new TABLESWITCH(); 315 break; 316 case Const.LOOKUPSWITCH: 317 obj = new LOOKUPSWITCH(); 318 break; 319 case Const.GETSTATIC: 320 obj = new GETSTATIC(); 321 break; 322 case Const.PUTSTATIC: 323 obj = new PUTSTATIC(); 324 break; 325 case Const.GETFIELD: 326 obj = new GETFIELD(); 327 break; 328 case Const.PUTFIELD: 329 obj = new PUTFIELD(); 330 break; 331 case Const.INVOKEVIRTUAL: 332 obj = new INVOKEVIRTUAL(); 333 break; 334 case Const.INVOKESPECIAL: 335 obj = new INVOKESPECIAL(); 336 break; 337 case Const.INVOKESTATIC: 338 obj = new INVOKESTATIC(); 339 break; 340 case Const.INVOKEINTERFACE: 341 obj = new INVOKEINTERFACE(); 342 break; 343 case Const.INVOKEDYNAMIC: 344 obj = new INVOKEDYNAMIC(); 345 break; 346 case Const.NEW: 347 obj = new NEW(); 348 break; 349 case Const.NEWARRAY: 350 obj = new NEWARRAY(); 351 break; 352 case Const.ANEWARRAY: 353 obj = new ANEWARRAY(); 354 break; 355 case Const.CHECKCAST: 356 obj = new CHECKCAST(); 357 break; 358 case Const.INSTANCEOF: 359 obj = new INSTANCEOF(); 360 break; 361 case Const.MULTIANEWARRAY: 362 obj = new MULTIANEWARRAY(); 363 break; 364 case Const.IFNULL: 365 obj = new IFNULL(); 366 break; 367 case Const.IFNONNULL: 368 obj = new IFNONNULL(); 369 break; 370 case Const.GOTO_W: 371 obj = new GOTO_W(); 372 break; 373 case Const.JSR_W: 374 obj = new JSR_W(); 375 break; 376 case Const.BREAKPOINT: 377 obj = new BREAKPOINT(); 378 break; 379 case Const.IMPDEP1: 380 obj = new IMPDEP1(); 381 break; 382 case Const.IMPDEP2: 383 obj = new IMPDEP2(); 384 break; 385 default: 386 throw new ClassGenException("Illegal opcode detected: " + opcode); 387 388 } 389 390 if (wide && !(obj instanceof LocalVariableInstruction || obj instanceof RET)) { 391 throw new ClassGenException("Illegal opcode after wide: " + opcode); 392 } 393 obj.setOpcode(opcode); 394 obj.initFromFile(bytes, wide); // Do further initializations, if any 395 return obj; 396 } 397 398 /** 399 * Set comparator to be used for equals(). 400 * 401 * @deprecated (6.0) use the built in comparator, or wrap this class in another object that implements these methods 402 */ 403 @Deprecated 404 public static void setComparator(final InstructionComparator c) { 405 cmp = c; 406 } 407 408 /** 409 * @deprecated (since 6.0) will be made private; do not access directly, use getter/setter 410 */ 411 @Deprecated 412 protected short length = 1; // Length of instruction in bytes 413 414 /** 415 * @deprecated (since 6.0) will be made private; do not access directly, use getter/setter 416 */ 417 @Deprecated 418 protected short opcode = -1; // Opcode number 419 420 /** 421 * Empty constructor needed for Instruction.readInstruction. Not to be used otherwise. 422 */ 423 Instruction() { 424 } 425 426 public Instruction(final short opcode, final short length) { 427 this.length = length; 428 this.opcode = opcode; 429 } 430 431 /** 432 * Call corresponding visitor method(s). The order is: Call visitor methods of implemented interfaces first, then call 433 * methods according to the class hierarchy in descending order, i.e., the most specific visitXXX() call comes last. 434 * 435 * @param v Visitor object 436 */ 437 public abstract void accept(Visitor v); 438 439 /** 440 * This method also gives right results for instructions whose effect on the stack depends on the constant pool entry 441 * they reference. 442 * 443 * @return Number of words consumed from stack by this instruction, or Constants.UNPREDICTABLE, if this can not be 444 * computed statically 445 */ 446 public int consumeStack(final ConstantPoolGen cpg) { 447 return Const.getConsumeStack(opcode); 448 } 449 450 /** 451 * Use with caution, since `BranchInstruction's have a `target' reference which is not copied correctly (only basic 452 * types are). This also applies for `Select' instructions with their multiple branch targets. 453 * 454 * @see BranchInstruction 455 * @return (shallow) copy of an instruction 456 */ 457 public Instruction copy() { 458 Instruction i = null; 459 // "Constant" instruction, no need to duplicate 460 if (InstructionConst.getInstruction(this.getOpcode()) != null) { 461 i = this; 462 } else { 463 try { 464 i = (Instruction) clone(); 465 } catch (final CloneNotSupportedException e) { 466 System.err.println(e); 467 } 468 } 469 return i; 470 } 471 472 /** 473 * Some instructions may be reused, so don't do anything by default. 474 */ 475 void dispose() { 476 } 477 478 /** 479 * Dump instruction as byte code to stream out. 480 * 481 * @param out Output stream 482 */ 483 public void dump(final DataOutputStream out) throws IOException { 484 out.writeByte(opcode); // Common for all instructions 485 } 486 487 /** 488 * Check 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 * calculate 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 * Read 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}