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