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