Docjar: A Java Source and Docuemnt Enginecom.*    java.*    javax.*    org.*    all    new    plug-in

Quick Search    Search Deep

Source code: com/techtrader/modules/tools/bytecode/ConvertInstruction.java


1   package com.techtrader.modules.tools.bytecode;
2   
3   
4   import java.util.Map;
5   import java.util.HashMap;
6   
7   import com.techtrader.modules.tools.bytecode.visitor.BCVisitor;
8   
9   
10  /**
11   *  Represents one of the conversion opcodes defined in the 
12   *  {@link Constants} interface for  converting between primitive types.  
13   *  Changing the types of the instruction will automatically
14   *  update the underlying opcode.  If converting from one type to the same
15   *  type will result in a NOP.  Note that the result of conversions not 
16   *  supported directly by the JVM (i.e. char to double) is undefined.
17   *
18   *  @author    Abe White
19   */
20  public class ConvertInstruction
21    extends Instruction
22  {
23    private static final Map _typeNames = new HashMap ();
24    static
25    {
26      _typeNames.put ("long", long.class);
27      _typeNames.put ("float", float.class);
28      _typeNames.put ("double", double.class);
29    }
30  
31    private Class  _fromType  = null;
32    private Class  _toType    = null;
33  
34  
35    protected ConvertInstruction (Code owner)
36    {
37      super (owner);
38    }
39  
40  
41    protected ConvertInstruction (Code owner, int opcode, Class from, Class to)
42    {
43      super (owner);
44      _opcode = opcode;
45      _fromType = from;
46      _toType = to;
47    }
48  
49  
50    /**
51     *  Get the type of being converted from; will be one of:
52     *  int, float, double, long.
53     *  If the type has not been set, this method will return null.
54     */
55    public Class getFromType ()
56    {
57      return _fromType;
58    }
59  
60  
61    /**
62     *  Get the type of being converted from; will be one of:
63     *  int, float, double, long.
64     *  If the type has not been set, this method will return null.
65     */
66    public String getFromTypeName ()
67    {
68      if (_fromType == null)
69        return null;
70  
71      return _fromType.getName ();
72    }
73  
74  
75    /**
76     *  Set the type to convert from.  Types without direct support are
77     *  demoted to int.class.
78     *
79     *  @return  this Instruction, for method chaining
80     */
81    public ConvertInstruction setFromType (Class type)
82    {
83      if (float.class.equals (type) || double.class.equals (type)
84        || long.class.equals (type))
85        _fromType = type;
86      else
87        _fromType = int.class;
88      
89      calculateOpCode ();
90      return this;
91    }
92  
93  
94    /**
95     *  Set the type to convert from by name.
96     *
97     *  @return  this Instruction, for method chaining
98     *  
99     *  @see  #setFromType(java.lang.Class)
100    */
101   public ConvertInstruction setFromTypeName (String name)
102   {
103     _fromType = (Class) _typeNames.get (name);
104     if (_fromType == null && name != null)
105       _fromType = int.class;
106 
107     calculateOpCode ();
108     return this;
109   }
110 
111 
112   /**
113    *  Get the type being converted to; will be one of:
114    *  int, float, double, long, byte, char, short.
115    *  If the type has not been set, this method will return null.
116    */
117   public Class getToType ()
118   {
119     return _toType;
120   }
121 
122 
123   /**
124    *  Get the type being converted to; will be one of:
125    *  int, float, double, long, byte, char, short.
126    *  If the type has not been set, this method will return null.
127    */
128   public String getToTypeName ()
129   {
130     if (_toType == null)
131       return null;
132 
133     return _toType.getName ();
134   }
135 
136 
137   /**
138    *  Set the type to convert to.  Types without direct support are
139    *  demoted to int.class.
140    *
141    *  @return  this Instruction, for method chaining
142    */
143   public ConvertInstruction setToType (Class type)
144   {
145     if (_opcodeTypes.indexOf (type) != -1)
146       _toType = type;
147     else
148       _toType = int.class;
149     
150     calculateOpCode ();
151     return this;
152   }
153 
154 
155   /**
156    *  Set the type to convert to by name.
157    *
158    *  @return  this Instruction, for method chaining
159    *  
160    *  @see  #setToType(java.lang.Class)
161    */
162   public ConvertInstruction setToTypeName (String name)
163   {
164     _toType = (Class) _typeNames.get (name);
165 
166     // there are more 'to' types available than 'from' types
167     if (_toType == null && name != null)
168     {
169       if (name.equals ("byte"))
170         _toType = byte.class;
171       else if (name.equals ("char"))
172         _toType = char.class;
173       else if (name.equals ("short"))
174         _toType = short.class;
175       else
176         _toType = int.class;
177     }
178 
179     calculateOpCode ();
180     return this;
181   }
182 
183 
184   /**
185    *  ConvertInstructions are equal if they convert between the same types,
186    *  or the types of either is unset.
187    */
188   public boolean equals (Object other)
189   {
190     if (this == other)
191       return true;
192     if (!(other instanceof ConvertInstruction))
193       return false;
194 
195     ConvertInstruction ins = (ConvertInstruction) other;
196 
197     boolean fromEq = (_fromType == null || ins._fromType == null
198       || _fromType.equals (ins._fromType));
199     boolean toEq = (_toType == null || ins._toType == null
200       || _toType.equals (ins._toType));
201 
202     return fromEq && toEq;
203   }
204 
205 
206   public int getStackChange ()
207   {
208     switch (_opcode)
209     {
210     case I2L:
211     case I2D:
212     case F2L:
213     case F2D:
214       return 1;
215     case L2I:
216     case L2F:
217     case D2I:
218     case D2F:
219       return -1;
220     default:
221       return 0;
222     }
223   }
224 
225 
226   protected void copy (Instruction orig)
227   {
228     super.copy (orig);
229 
230     ConvertInstruction ins = (ConvertInstruction) orig;
231     _fromType = ins._fromType;
232     _toType = ins._toType;
233   }
234 
235 
236   /**
237    *  Helper method to calculate the correct opcode for this conversion.
238    */
239   private void calculateOpCode ()
240   {
241     int fromIdx    = _opcodeTypes.indexOf (_fromType);
242     int toIdx     = _opcodeTypes.indexOf (_toType);
243 
244     // take advantage of the grouping of the opcodes
245     _opcode  = I2L + 3 * fromIdx;
246 
247     // if not converting from int then any conversion to byte,char,float
248     // should be considered a conversion to int
249     if (fromIdx != 0 && toIdx > 4)
250       toIdx = 0;
251     else if (toIdx > 4)  // the weird 'to' types are placed after the rest 
252       _opcode += 8;
253 
254     // do nothing if converting to the same type
255     if (fromIdx == toIdx)
256     {
257       _opcode = NOP;
258       return;
259     }
260 
261     // move from the <fromtype>2I opcode to <fromtype>2<totype>
262     _opcode += toIdx;
263     // compensate: there is no <fromtype>2<fromtype> opcode
264     if (toIdx > fromIdx)
265       _opcode--;
266   }
267 
268 
269   public void acceptVisit (BCVisitor visit)
270   {
271     visit.enterConvertInstruction (this);  
272     visit.exitConvertInstruction (this);  
273   }
274 }