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