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