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