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