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