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