1 /* 2 * Copyright (c) 2017, 2020, Oracle and/or its affiliates. All rights reserved. 3 */ 4 /* 5 * Licensed to the Apache Software Foundation (ASF) under one or more 6 * contributor license agreements. See the NOTICE file distributed with 7 * this work for additional information regarding copyright ownership. 8 * The ASF licenses this file to You under the Apache License, Version 2.0 9 * (the "License"); you may not use this file except in compliance with 10 * the License. You may obtain a copy of the License at 11 * 12 * http://www.apache.org/licenses/LICENSE-2.0 13 * 14 * Unless required by applicable law or agreed to in writing, software 15 * distributed under the License is distributed on an "AS IS" BASIS, 16 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 17 * See the License for the specific language governing permissions and 18 * limitations under the License. 19 */ 20 package com.sun.org.apache.bcel.internal.generic; 21 22 import java.io.DataOutputStream; 23 import java.io.IOException; 24 25 import com.sun.org.apache.bcel.internal.Const; 26 import com.sun.org.apache.bcel.internal.classfile.ConstantPool; 27 import com.sun.org.apache.bcel.internal.util.ByteSequence; 28 29 /** 30 * Abstract super class for all Java byte codes. 31 * 32 * @LastModified: July 2020 33 */ 34 public abstract class Instruction implements Cloneable { 35 36 private short length = 1; // Length of instruction in bytes 37 private short opcode = -1; // Opcode number 38 39 private static InstructionComparator cmp = InstructionComparator.DEFAULT; 40 41 42 /** 43 * Empty constructor needed for Instruction.readInstruction. 44 * Not to be used otherwise. 45 */ Instruction()46 Instruction() { 47 } 48 49 Instruction(final short opcode, final short length)50 public Instruction(final short opcode, final short length) { 51 this.length = length; 52 this.opcode = opcode; 53 } 54 55 56 /** 57 * Dump instruction as byte code to stream out. 58 * @param out Output stream 59 */ dump( final DataOutputStream out )60 public void dump( final DataOutputStream out ) throws IOException { 61 out.writeByte(opcode); // Common for all instructions 62 } 63 64 65 /** @return name of instruction, i.e., opcode name 66 */ getName()67 public String getName() { 68 return Const.getOpcodeName(opcode); 69 } 70 71 72 /** 73 * Long output format: 74 * 75 * <name of opcode> "["<opcode number>"]" 76 * "("<length of instruction>")" 77 * 78 * @param verbose long/short format switch 79 * @return mnemonic for instruction 80 */ toString( final boolean verbose )81 public String toString( final boolean verbose ) { 82 if (verbose) { 83 return getName() + "[" + opcode + "](" + length + ")"; 84 } 85 return getName(); 86 } 87 88 89 /** 90 * @return mnemonic for instruction in verbose format 91 */ 92 @Override toString()93 public String toString() { 94 return toString(true); 95 } 96 97 98 /** 99 * @return mnemonic for instruction with sumbolic references resolved 100 */ toString( final ConstantPool cp )101 public String toString( final ConstantPool cp ) { 102 return toString(false); 103 } 104 105 106 /** 107 * Use with caution, since `BranchInstruction's have a `target' reference which 108 * is not copied correctly (only basic types are). This also applies for 109 * `Select' instructions with their multiple branch targets. 110 * 111 * @see BranchInstruction 112 * @return (shallow) copy of an instruction 113 */ copy()114 public Instruction copy() { 115 Instruction i = null; 116 // "Constant" instruction, no need to duplicate 117 if (InstructionConst.getInstruction(this.getOpcode()) != null) { 118 i = this; 119 } else { 120 try { 121 i = (Instruction) clone(); 122 } catch (final CloneNotSupportedException e) { 123 System.err.println(e); 124 } 125 } 126 return i; 127 } 128 129 130 /** 131 * Read needed data (e.g. index) from file. 132 * 133 * @param bytes byte sequence to read from 134 * @param wide "wide" instruction flag 135 * @throws IOException may be thrown if the implementation needs to read data from the file 136 */ initFromFile( final ByteSequence bytes, final boolean wide )137 protected void initFromFile( final ByteSequence bytes, final boolean wide ) throws IOException { 138 } 139 140 141 /** 142 * Read an instruction from (byte code) input stream and return the 143 * appropiate object. 144 * <p> 145 * If the Instruction is defined in {@link InstructionConst}, then the 146 * singleton instance is returned. 147 * @param bytes input stream bytes 148 * @return instruction object being read 149 * @see InstructionConst#getInstruction(int) 150 */ 151 // @since 6.0 no longer final readInstruction( final ByteSequence bytes )152 public static Instruction readInstruction( final ByteSequence bytes ) throws IOException { 153 boolean wide = false; 154 short opcode = (short) bytes.readUnsignedByte(); 155 Instruction obj = null; 156 if (opcode == Const.WIDE) { // Read next opcode after wide byte 157 wide = true; 158 opcode = (short) bytes.readUnsignedByte(); 159 } 160 final Instruction instruction = InstructionConst.getInstruction(opcode); 161 if (instruction != null) { 162 return instruction; // Used predefined immutable object, if available 163 } 164 165 switch (opcode) { 166 case Const.BIPUSH: 167 obj = new BIPUSH(); 168 break; 169 case Const.SIPUSH: 170 obj = new SIPUSH(); 171 break; 172 case Const.LDC: 173 obj = new LDC(); 174 break; 175 case Const.LDC_W: 176 obj = new LDC_W(); 177 break; 178 case Const.LDC2_W: 179 obj = new LDC2_W(); 180 break; 181 case Const.ILOAD: 182 obj = new ILOAD(); 183 break; 184 case Const.LLOAD: 185 obj = new LLOAD(); 186 break; 187 case Const.FLOAD: 188 obj = new FLOAD(); 189 break; 190 case Const.DLOAD: 191 obj = new DLOAD(); 192 break; 193 case Const.ALOAD: 194 obj = new ALOAD(); 195 break; 196 case Const.ILOAD_0: 197 obj = new ILOAD(0); 198 break; 199 case Const.ILOAD_1: 200 obj = new ILOAD(1); 201 break; 202 case Const.ILOAD_2: 203 obj = new ILOAD(2); 204 break; 205 case Const.ILOAD_3: 206 obj = new ILOAD(3); 207 break; 208 case Const.LLOAD_0: 209 obj = new LLOAD(0); 210 break; 211 case Const.LLOAD_1: 212 obj = new LLOAD(1); 213 break; 214 case Const.LLOAD_2: 215 obj = new LLOAD(2); 216 break; 217 case Const.LLOAD_3: 218 obj = new LLOAD(3); 219 break; 220 case Const.FLOAD_0: 221 obj = new FLOAD(0); 222 break; 223 case Const.FLOAD_1: 224 obj = new FLOAD(1); 225 break; 226 case Const.FLOAD_2: 227 obj = new FLOAD(2); 228 break; 229 case Const.FLOAD_3: 230 obj = new FLOAD(3); 231 break; 232 case Const.DLOAD_0: 233 obj = new DLOAD(0); 234 break; 235 case Const.DLOAD_1: 236 obj = new DLOAD(1); 237 break; 238 case Const.DLOAD_2: 239 obj = new DLOAD(2); 240 break; 241 case Const.DLOAD_3: 242 obj = new DLOAD(3); 243 break; 244 case Const.ALOAD_0: 245 obj = new ALOAD(0); 246 break; 247 case Const.ALOAD_1: 248 obj = new ALOAD(1); 249 break; 250 case Const.ALOAD_2: 251 obj = new ALOAD(2); 252 break; 253 case Const.ALOAD_3: 254 obj = new ALOAD(3); 255 break; 256 case Const.ISTORE: 257 obj = new ISTORE(); 258 break; 259 case Const.LSTORE: 260 obj = new LSTORE(); 261 break; 262 case Const.FSTORE: 263 obj = new FSTORE(); 264 break; 265 case Const.DSTORE: 266 obj = new DSTORE(); 267 break; 268 case Const.ASTORE: 269 obj = new ASTORE(); 270 break; 271 case Const.ISTORE_0: 272 obj = new ISTORE(0); 273 break; 274 case Const.ISTORE_1: 275 obj = new ISTORE(1); 276 break; 277 case Const.ISTORE_2: 278 obj = new ISTORE(2); 279 break; 280 case Const.ISTORE_3: 281 obj = new ISTORE(3); 282 break; 283 case Const.LSTORE_0: 284 obj = new LSTORE(0); 285 break; 286 case Const.LSTORE_1: 287 obj = new LSTORE(1); 288 break; 289 case Const.LSTORE_2: 290 obj = new LSTORE(2); 291 break; 292 case Const.LSTORE_3: 293 obj = new LSTORE(3); 294 break; 295 case Const.FSTORE_0: 296 obj = new FSTORE(0); 297 break; 298 case Const.FSTORE_1: 299 obj = new FSTORE(1); 300 break; 301 case Const.FSTORE_2: 302 obj = new FSTORE(2); 303 break; 304 case Const.FSTORE_3: 305 obj = new FSTORE(3); 306 break; 307 case Const.DSTORE_0: 308 obj = new DSTORE(0); 309 break; 310 case Const.DSTORE_1: 311 obj = new DSTORE(1); 312 break; 313 case Const.DSTORE_2: 314 obj = new DSTORE(2); 315 break; 316 case Const.DSTORE_3: 317 obj = new DSTORE(3); 318 break; 319 case Const.ASTORE_0: 320 obj = new ASTORE(0); 321 break; 322 case Const.ASTORE_1: 323 obj = new ASTORE(1); 324 break; 325 case Const.ASTORE_2: 326 obj = new ASTORE(2); 327 break; 328 case Const.ASTORE_3: 329 obj = new ASTORE(3); 330 break; 331 case Const.IINC: 332 obj = new IINC(); 333 break; 334 case Const.IFEQ: 335 obj = new IFEQ(); 336 break; 337 case Const.IFNE: 338 obj = new IFNE(); 339 break; 340 case Const.IFLT: 341 obj = new IFLT(); 342 break; 343 case Const.IFGE: 344 obj = new IFGE(); 345 break; 346 case Const.IFGT: 347 obj = new IFGT(); 348 break; 349 case Const.IFLE: 350 obj = new IFLE(); 351 break; 352 case Const.IF_ICMPEQ: 353 obj = new IF_ICMPEQ(); 354 break; 355 case Const.IF_ICMPNE: 356 obj = new IF_ICMPNE(); 357 break; 358 case Const.IF_ICMPLT: 359 obj = new IF_ICMPLT(); 360 break; 361 case Const.IF_ICMPGE: 362 obj = new IF_ICMPGE(); 363 break; 364 case Const.IF_ICMPGT: 365 obj = new IF_ICMPGT(); 366 break; 367 case Const.IF_ICMPLE: 368 obj = new IF_ICMPLE(); 369 break; 370 case Const.IF_ACMPEQ: 371 obj = new IF_ACMPEQ(); 372 break; 373 case Const.IF_ACMPNE: 374 obj = new IF_ACMPNE(); 375 break; 376 case Const.GOTO: 377 obj = new GOTO(); 378 break; 379 case Const.JSR: 380 obj = new JSR(); 381 break; 382 case Const.RET: 383 obj = new RET(); 384 break; 385 case Const.TABLESWITCH: 386 obj = new TABLESWITCH(); 387 break; 388 case Const.LOOKUPSWITCH: 389 obj = new LOOKUPSWITCH(); 390 break; 391 case Const.GETSTATIC: 392 obj = new GETSTATIC(); 393 break; 394 case Const.PUTSTATIC: 395 obj = new PUTSTATIC(); 396 break; 397 case Const.GETFIELD: 398 obj = new GETFIELD(); 399 break; 400 case Const.PUTFIELD: 401 obj = new PUTFIELD(); 402 break; 403 case Const.INVOKEVIRTUAL: 404 obj = new INVOKEVIRTUAL(); 405 break; 406 case Const.INVOKESPECIAL: 407 obj = new INVOKESPECIAL(); 408 break; 409 case Const.INVOKESTATIC: 410 obj = new INVOKESTATIC(); 411 break; 412 case Const.INVOKEINTERFACE: 413 obj = new INVOKEINTERFACE(); 414 break; 415 case Const.INVOKEDYNAMIC: 416 obj = new INVOKEDYNAMIC(); 417 break; 418 case Const.NEW: 419 obj = new NEW(); 420 break; 421 case Const.NEWARRAY: 422 obj = new NEWARRAY(); 423 break; 424 case Const.ANEWARRAY: 425 obj = new ANEWARRAY(); 426 break; 427 case Const.CHECKCAST: 428 obj = new CHECKCAST(); 429 break; 430 case Const.INSTANCEOF: 431 obj = new INSTANCEOF(); 432 break; 433 case Const.MULTIANEWARRAY: 434 obj = new MULTIANEWARRAY(); 435 break; 436 case Const.IFNULL: 437 obj = new IFNULL(); 438 break; 439 case Const.IFNONNULL: 440 obj = new IFNONNULL(); 441 break; 442 case Const.GOTO_W: 443 obj = new GOTO_W(); 444 break; 445 case Const.JSR_W: 446 obj = new JSR_W(); 447 break; 448 case Const.BREAKPOINT: 449 obj = new BREAKPOINT(); 450 break; 451 case Const.IMPDEP1: 452 obj = new IMPDEP1(); 453 break; 454 case Const.IMPDEP2: 455 obj = new IMPDEP2(); 456 break; 457 default: 458 throw new ClassGenException("Illegal opcode detected: " + opcode); 459 460 } 461 462 if (wide 463 && !((obj instanceof LocalVariableInstruction) || (obj instanceof IINC) || (obj instanceof RET))) { 464 throw new ClassGenException("Illegal opcode after wide: " + opcode); 465 } 466 obj.setOpcode(opcode); 467 obj.initFromFile(bytes, wide); // Do further initializations, if any 468 return obj; 469 } 470 471 /** 472 * This method also gives right results for instructions whose 473 * effect on the stack depends on the constant pool entry they 474 * reference. 475 * @return Number of words consumed from stack by this instruction, 476 * or Constants.UNPREDICTABLE, if this can not be computed statically 477 */ consumeStack( final ConstantPoolGen cpg )478 public int consumeStack( final ConstantPoolGen cpg ) { 479 return Const.getConsumeStack(opcode); 480 } 481 482 483 /** 484 * This method also gives right results for instructions whose 485 * effect on the stack depends on the constant pool entry they 486 * reference. 487 * @return Number of words produced onto stack by this instruction, 488 * or Constants.UNPREDICTABLE, if this can not be computed statically 489 */ produceStack( final ConstantPoolGen cpg )490 public int produceStack( final ConstantPoolGen cpg ) { 491 return Const.getProduceStack(opcode); 492 } 493 494 495 /** 496 * @return this instructions opcode 497 */ getOpcode()498 public short getOpcode() { 499 return opcode; 500 } 501 502 503 /** 504 * @return length (in bytes) of instruction 505 */ getLength()506 public int getLength() { 507 return length; 508 } 509 510 511 /** 512 * Needed in readInstruction and subclasses in this package 513 */ setOpcode( final short opcode )514 void setOpcode( final short opcode ) { 515 this.opcode = opcode; 516 } 517 518 519 /** 520 * Needed in readInstruction and subclasses in this package 521 * @since 6.0 522 */ setLength( final int length )523 final void setLength( final int length ) { 524 this.length = (short) length; // TODO check range? 525 } 526 527 528 /** Some instructions may be reused, so don't do anything by default. 529 */ dispose()530 void dispose() { 531 } 532 533 534 /** 535 * Call corresponding visitor method(s). The order is: 536 * Call visitor methods of implemented interfaces first, then 537 * call methods according to the class hierarchy in descending order, 538 * i.e., the most specific visitXXX() call comes last. 539 * 540 * @param v Visitor object 541 */ accept( Visitor v )542 public abstract void accept( Visitor v ); 543 544 545 /** Get Comparator object used in the equals() method to determine 546 * equality of instructions. 547 * 548 * @return currently used comparator for equals() 549 * @deprecated (6.0) use the built in comparator, or wrap this class in another object that implements these methods 550 */ 551 @Deprecated getComparator()552 public static InstructionComparator getComparator() { 553 return cmp; 554 } 555 556 557 /** Set comparator to be used for equals(). 558 * @deprecated (6.0) use the built in comparator, or wrap this class in another object that implements these methods 559 */ 560 @Deprecated setComparator( final InstructionComparator c )561 public static void setComparator( final InstructionComparator c ) { 562 cmp = c; 563 } 564 565 566 /** Check for equality, delegated to comparator 567 * @return true if that is an Instruction and has the same opcode 568 */ 569 @Override equals( final Object that )570 public boolean equals( final Object that ) { 571 return (that instanceof Instruction) ? cmp.equals(this, (Instruction) that) : false; 572 } 573 574 /** calculate the hashCode of this object 575 * @return the hashCode 576 * @since 6.0 577 */ 578 @Override hashCode()579 public int hashCode() { 580 return opcode; 581 } 582 583 /** 584 * Check if the value can fit in a byte (signed) 585 * @param value the value to check 586 * @return true if the value is in range 587 * @since 6.0 588 */ isValidByte(final int value)589 public static boolean isValidByte(final int value) { 590 return value >= Byte.MIN_VALUE && value <= Byte.MAX_VALUE; 591 } 592 593 /** 594 * Check if the value can fit in a short (signed) 595 * @param value the value to check 596 * @return true if the value is in range 597 * @since 6.0 598 */ isValidShort(final int value)599 public static boolean isValidShort(final int value) { 600 return value >= Short.MIN_VALUE && value <= Short.MAX_VALUE; 601 } 602 } 603