1   package org.apache.bcel.generic;
2   
3   /* ====================================================================
4    * The Apache Software License, Version 1.1
5    *
6    * Copyright (c) 2001 The Apache Software Foundation.  All rights
7    * reserved.
8    *
9    * Redistribution and use in source and binary forms, with or without
10   * modification, are permitted provided that the following conditions
11   * are met:
12   *
13   * 1. Redistributions of source code must retain the above copyright
14   *    notice, this list of conditions and the following disclaimer.
15   *
16   * 2. Redistributions in binary form must reproduce the above copyright
17   *    notice, this list of conditions and the following disclaimer in
18   *    the documentation and/or other materials provided with the
19   *    distribution.
20   *
21   * 3. The end-user documentation included with the redistribution,
22   *    if any, must include the following acknowledgment:
23   *       "This product includes software developed by the
24   *        Apache Software Foundation (http://www.apache.org/)."
25   *    Alternately, this acknowledgment may appear in the software itself,
26   *    if and wherever such third-party acknowledgments normally appear.
27   *
28   * 4. The names "Apache" and "Apache Software Foundation" and
29   *    "Apache BCEL" must not be used to endorse or promote products
30   *    derived from this software without prior written permission. For
31   *    written permission, please contact apache@apache.org.
32   *
33   * 5. Products derived from this software may not be called "Apache",
34   *    "Apache BCEL", nor may "Apache" appear in their name, without
35   *    prior written permission of the Apache Software Foundation.
36   *
37   * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
38   * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
39   * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
40   * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
41   * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
42   * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
43   * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
44   * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
45   * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
46   * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
47   * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
48   * SUCH DAMAGE.
49   * ====================================================================
50   *
51   * This software consists of voluntary contributions made by many
52   * individuals on behalf of the Apache Software Foundation.  For more
53   * information on the Apache Software Foundation, please see
54   * <http://www.apache.org/>.
55   */
56  
57  import org.apache.bcel.Constants;
58  import org.apache.bcel.classfile.Utility;
59  import org.apache.bcel.classfile.ConstantPool;
60  import java.io.*;
61  import org.apache.bcel.util.ByteSequence;
62  
63  /*** 
64   * Abstract super class for all Java byte codes.
65   *
66   * @version $Id: Instruction.java,v 1.3 2002/08/07 18:01:32 mdahm Exp $
67   * @author  <A HREF="mailto:markus.dahm@berlin.de">M. Dahm</A>
68   */
69  public abstract class Instruction implements Cloneable, Serializable {
70    protected short length = 1;  // Length of instruction in bytes 
71    protected short opcode = -1; // Opcode number
72  
73    private static InstructionComparator cmp = InstructionComparator.DEFAULT;
74  
75    /***
76     * Empty constructor needed for the Class.newInstance() statement in
77     * Instruction.readInstruction(). Not to be used otherwise.
78     */
79    Instruction() {}
80  
81    public Instruction(short opcode, short length) {
82      this.length = length;
83      this.opcode = opcode;
84    }
85  
86    /***
87     * Dump instruction as byte code to stream out.
88     * @param out Output stream
89     */
90    public void dump(DataOutputStream out) throws IOException {
91      out.writeByte(opcode); // Common for all instructions
92    }
93  
94    /*** @return name of instruction, i.e., opcode name
95     */
96    public String getName() {
97      return Constants.OPCODE_NAMES[opcode];
98    }
99  
100   /***
101    * Long output format:
102    *
103    * <name of opcode> "["<opcode number>"]" 
104    * "("<length of instruction>")"
105    *
106    * @param verbose long/short format switch
107    * @return mnemonic for instruction
108    */
109   public String toString(boolean verbose) {
110     if(verbose)
111       return getName() + "[" + opcode + "](" + length + ")";
112     else
113       return getName();
114   }
115 
116   /***
117    * @return mnemonic for instruction in verbose format
118    */
119   public String toString() {
120     return toString(true);
121   }
122 
123   /***
124    * @return mnemonic for instruction with sumbolic references resolved
125    */
126   public String toString(ConstantPool cp) {
127     return toString(false);
128   }
129 
130   /***
131    * Use with caution, since `BranchInstruction's have a `target' reference which
132    * is not copied correctly (only basic types are). This also applies for 
133    * `Select' instructions with their multiple branch targets.
134    *
135    * @see BranchInstruction
136    * @return (shallow) copy of an instruction
137    */
138   public Instruction copy() {
139     Instruction i = null;
140 
141     // "Constant" instruction, no need to duplicate
142     if(InstructionConstants.INSTRUCTIONS[this.getOpcode()] != null)
143       i = this;
144     else {
145       try {
146 	i = (Instruction)clone();
147       } catch(CloneNotSupportedException e) {
148 	System.err.println(e);
149       }
150     }
151 
152     return i;
153   }
154   
155   /***
156    * Read needed data (e.g. index) from file.
157    *
158    * @param bytes byte sequence to read from
159    * @param wide "wide" instruction flag
160    */
161   protected void initFromFile(ByteSequence bytes, boolean wide)
162     throws IOException
163   {}  
164 
165   /***
166    * Read an instruction from (byte code) input stream and return the
167    * appropiate object.
168    *
169    * @param file file to read from
170    * @return instruction object being read
171    */
172   public static final Instruction readInstruction(ByteSequence bytes)
173     throws IOException
174   {
175     boolean     wide   = false;
176     short       opcode = (short)bytes.readUnsignedByte();
177     Instruction obj    = null;
178 
179     if(opcode == Constants.WIDE) { // Read next opcode after wide byte
180       wide = true;
181       opcode  = (short)bytes.readUnsignedByte();
182     }
183 
184     if(InstructionConstants.INSTRUCTIONS[opcode] != null)
185       return InstructionConstants.INSTRUCTIONS[opcode]; // Used predefined immutable object, if available
186 
187     /* Find appropiate class, instantiate an (empty) instruction object
188      * and initialize it by hand.
189      */
190     Class clazz;
191 
192     try {
193       clazz = Class.forName(className(opcode));
194     } catch (ClassNotFoundException cnfe){
195       // If a class by that name does not exist, the opcode is illegal.
196       // Note that IMPDEP1, IMPDEP2, BREAKPOINT are also illegal in a sense.
197       throw new ClassGenException("Illegal opcode detected.");
198     }
199 
200     try {
201       obj = (Instruction)clazz.newInstance();
202 
203       if(wide && !((obj instanceof LocalVariableInstruction) ||
204 		   (obj instanceof IINC) ||
205 		   (obj instanceof RET)))
206 	throw new Exception("Illegal opcode after wide: " + opcode);
207 
208       obj.setOpcode(opcode);
209       obj.initFromFile(bytes, wide); // Do further initializations, if any
210       // Byte code offset set in InstructionList
211     } catch(Exception e) { throw new ClassGenException(e.toString()); }
212 
213     return obj;
214   }
215 
216   private static final String className(short opcode) {
217     String name = Constants.OPCODE_NAMES[opcode].toUpperCase();
218 
219     /* ICONST_0, etc. will be shortened to ICONST, etc., since ICONST_0 and the like
220      * are not implemented (directly).
221      */
222     try {
223       int  len = name.length();
224       char ch1 = name.charAt(len - 2), ch2 = name.charAt(len - 1);
225 
226       if((ch1 == '_') && (ch2 >= '0')  && (ch2 <= '5'))
227 	name = name.substring(0, len - 2);
228       
229       if(name.equals("ICONST_M1")) // Special case
230 	name = "ICONST";
231     } catch(StringIndexOutOfBoundsException e) { System.err.println(e); }
232 
233     return "org.apache.bcel.generic." + name;
234   }
235 
236   /***
237    * This method also gives right results for instructions whose
238    * effect on the stack depends on the constant pool entry they
239    * reference.
240    *  @return Number of words consumed from stack by this instruction,
241    * or Constants.UNPREDICTABLE, if this can not be computed statically
242    */
243   public int consumeStack(ConstantPoolGen cpg) {
244     return Constants.CONSUME_STACK[opcode];
245   }
246 
247   /***
248    * This method also gives right results for instructions whose
249    * effect on the stack depends on the constant pool entry they
250    * reference.
251    * @return Number of words produced onto stack by this instruction,
252    * or Constants.UNPREDICTABLE, if this can not be computed statically
253    */
254   public int produceStack(ConstantPoolGen cpg) {
255     return Constants.PRODUCE_STACK[opcode];
256   }
257 
258   /***
259    * @return this instructions opcode
260    */
261   public short getOpcode()    { return opcode; }
262 
263   /***
264    * @return length (in bytes) of instruction
265    */
266   public int getLength()   { return length; }
267 
268   /***
269    * Needed in readInstruction.
270    */
271   private void setOpcode(short opcode) { this.opcode = opcode; }
272 
273   /*** Some instructions may be reused, so don't do anything by default.
274    */
275   void dispose() {}
276 
277   /***
278    * Call corresponding visitor method(s). The order is:
279    * Call visitor methods of implemented interfaces first, then
280    * call methods according to the class hierarchy in descending order,
281    * i.e., the most specific visitXXX() call comes last.
282    *
283    * @param v Visitor object
284    */
285   public abstract void accept(Visitor v);
286 
287   /*** Get Comparator object used in the equals() method to determine
288    * equality of instructions.
289    *
290    * @return currently used comparator for equals()
291    */
292   public static InstructionComparator getComparator() { return cmp; }
293 
294   /*** Set comparator to be used for equals().
295    */
296   public static void setComparator(InstructionComparator c) { cmp = c; }
297 
298   /*** Check for equality, delegated to comparator
299    * @return true if that is an Instruction and has the same opcode
300    */
301   public boolean equals(Object that) {
302     return (that instanceof Instruction)?
303       cmp.equals(this, (Instruction)that) : false;
304   }
305 }
This page was automatically generated by Maven