View Javadoc

1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one or more
3    * contributor license agreements.  See the NOTICE file distributed with
4    * this work for additional information regarding copyright ownership.
5    * The ASF licenses this file to You under the Apache License, Version 2.0
6    * (the "License"); you may not use this file except in compliance with
7    * the License.  You may obtain a copy of the License at
8    *
9    *      http://www.apache.org/licenses/LICENSE-2.0
10   *
11   *  Unless required by applicable law or agreed to in writing, software
12   *  distributed under the License is distributed on an "AS IS" BASIS,
13   *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   *  See the License for the specific language governing permissions and
15   *  limitations under the License. 
16   *
17   */
18  package org.apache.bcel.generic;
19  
20  import java.io.DataOutputStream;
21  import java.io.IOException;
22  import java.io.Serializable;
23  import org.apache.bcel.Constants;
24  import org.apache.bcel.classfile.ConstantPool;
25  import org.apache.bcel.util.ByteSequence;
26  
27  /** 
28   * Abstract super class for all Java byte codes.
29   *
30   * @version $Id: Instruction.java 1152072 2011-07-29 01:54:05Z dbrosius $
31   * @author  <A HREF="mailto:m.dahm@gmx.de">M. Dahm</A>
32   */
33  public abstract class Instruction implements Cloneable, Serializable {
34  
35      private static final long serialVersionUID = -2518741982574515847L;
36      protected short length = 1; // Length of instruction in bytes 
37      protected short opcode = -1; // Opcode number
38      private static InstructionComparator cmp = InstructionComparator.DEFAULT;
39  
40  
41      /**
42       * Empty constructor needed for the Class.newInstance() statement in
43       * Instruction.readInstruction(). Not to be used otherwise.
44       */
45      Instruction() {
46      }
47  
48  
49      public Instruction(short opcode, short length) {
50          this.length = length;
51          this.opcode = opcode;
52      }
53  
54  
55      /**
56       * Dump instruction as byte code to stream out.
57       * @param out Output stream
58       */
59      public void dump( DataOutputStream out ) throws IOException {
60          out.writeByte(opcode); // Common for all instructions
61      }
62  
63  
64      /** @return name of instruction, i.e., opcode name
65       */
66      public String getName() {
67          return Constants.OPCODE_NAMES[opcode];
68      }
69  
70  
71      /**
72       * Long output format:
73       *
74       * &lt;name of opcode&gt; "["&lt;opcode number&gt;"]" 
75       * "("&lt;length of instruction&gt;")"
76       *
77       * @param verbose long/short format switch
78       * @return mnemonic for instruction
79       */
80      public String toString( boolean verbose ) {
81          if (verbose) {
82              return getName() + "[" + opcode + "](" + length + ")";
83          } else {
84              return getName();
85          }
86      }
87  
88  
89      /**
90       * @return mnemonic for instruction in verbose format
91       */
92      @Override
93      public String toString() {
94          return toString(true);
95      }
96  
97  
98      /**
99       * @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 }