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