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/ConstantInstruction.java


1   package com.techtrader.modules.tools.bytecode;
2   
3   
4   import java.io.IOException;
5   import java.io.DataInput;
6   import java.io.DataOutput;
7   
8   import com.techtrader.modules.tools.bytecode.visitor.BCVisitor;
9   
10  
11  /**
12   *  Represents an instruction that that loads a constant onto the stack.  
13   *  The opcode represented by this Instruction may change depending on the
14   *  type and value of the constant set.  For example, if the constant value
15   *  is initially set to '5', the opcode will be iconst_5; if later incremented
16   *  to '6', the opcode will be changed to bipush(6).
17   *
18   *  @author    Abe White
19   */
20  public class ConstantInstruction
21    extends Instruction
22  {
23    private Object   _value   = null;
24    private int    _arg  = -1;
25  
26  
27    protected ConstantInstruction (Code owner)
28    {
29      super (owner);
30    }
31  
32  
33    protected ConstantInstruction (Code owner, int opcode, Object value)
34    {
35      super (owner);
36      _opcode = opcode;
37      _value = value;
38    }
39  
40  
41    /**
42     *  Set the constant to the given Object value.  The Object should be
43     *  an instance of String, Integer, Long, Double, or Float depending
44     *  on the constant type.
45      *  
46     *  @return    this Instruction, for method chaining
47     */
48    public ConstantInstruction setConstant (Object value)
49    {
50      _value = value;
51      calculateOpCode ();
52  
53      return this;
54    }
55  
56  
57    /**
58     *  Return the constant value as an Object; will be an instance of
59     *  String, Integer, Float, Double, or Long, as necessary.  Returns null
60     *  if the constant has not been set, or if this represents the 
61     *  aconst_null opcode.
62     */
63    public Object getConstant ()
64    {
65      return _value;
66    }
67  
68  
69    /**
70     *  Return the class of constant this instruction references.  Will return
71     *  one of: Object.class, String.class, int.class, long.class, 
72     *  double.class, float.class.
73     */
74    public Class getConstantType ()
75    {
76      if (_value == null)
77        return Object.class;
78  
79      Class cls = _value.getClass ();
80      if (cls.equals (Float.class))
81        return float.class;
82      if (cls.equals (Double.class))
83        return double.class;
84      if (cls.equals (Long.class))
85        return long.class;
86      if (cls.equals (String.class))
87        return String.class;
88      return int.class;
89    }
90  
91  
92    /**
93     *  Return the class of constant this instruction references.  Will return
94     *  one of: java.lang.Object, java.lang.String, int, long, double, float.
95     */
96    public String getConstantTypeName ()
97    {
98      return getConstantType ().getName ();
99    }
100 
101 
102   /**
103     *  Set the constant to load, for String constants.
104     *  
105    *  @return    this Instruction, for method chaining
106    */
107   public ConstantInstruction setStringConstant (String value)
108   {
109     return setConstant (value);
110   }
111 
112 
113   /**
114     *  Get the constant to load, for String constants.
115    */
116   public String getStringConstant ()
117   {
118     return (String) getConstant ();
119   }
120 
121 
122   /**
123     *  Set the constant to load, for int constants.
124     *  
125    *  @return    this Instruction, for method chaining
126    */
127   public ConstantInstruction setIntConstant (int value)
128   {
129     return setConstant (new Integer (value));
130   }
131 
132 
133   /**
134     *  Get the constant to load, for int constants.
135    */
136   public int getIntConstant ()
137   {
138     return (_value == null) ? 0 : ((Number) _value).intValue ();
139   }
140 
141 
142   /**
143     *  Set the constant to load, for float constants.
144     *  
145    *  @return    this Instruction, for method chaining
146    */
147   public ConstantInstruction setFloatConstant (float value)
148   {
149     return setConstant (new Float (value));
150   }
151 
152 
153   /**
154     *  Get the constant to load, for float constants.
155    */
156   public float getFloatConstant ()
157   {
158     return (_value == null) ? 0F : ((Number) _value).floatValue ();
159   }
160 
161 
162   /**
163     *  Set the constant to load, for long constants; must be a ldc2
164    *  instruction.
165     *  
166    *  @return    this Instruction, for method chaining
167    */
168   public ConstantInstruction setLongConstant (long value)
169   {
170     return setConstant (new Long (value));
171   }
172 
173 
174   /**
175     *  Get the constant to load, for float constants; must be a ldc2
176    *  instruction.
177    */
178   public long getLongConstant ()
179   {
180     return (_value == null) ? 0L : ((Number) _value).longValue ();
181   }
182 
183 
184   /**
185     *  Set the constant to load, for double constants; must be a ldc2
186    *  instruction.
187     *  
188    *  @return    this Instruction, for method chaining
189    */
190   public ConstantInstruction setDoubleConstant (double value)
191   {
192     return setConstant (new Double (value));
193   }
194 
195 
196   /**
197     *  Get the constant to double, for float constants; must be a ldc2
198    *  instruction.
199    */
200   public double getDoubleConstant ()
201   {
202     return (_value == null) ? 0D : ((Number) _value).doubleValue ();
203   }
204 
205 
206   /**
207    *  ConstantInstructions are equal if the const they reference is the same, 
208    *  or if the const of either is unset.
209    */
210   public boolean equals (Object other)
211   {
212     if (this == other)
213       return true;
214     if (!(other instanceof ConstantInstruction))
215       return false;
216 
217     ConstantInstruction ins = (ConstantInstruction) other;
218 
219     Object value = getConstant ();
220     Object insValue = ins.getConstant ();
221 
222     return (value == null && !Object.class.equals (getConstantType ()))
223       || (insValue == null && !Object.class.equals(ins.getConstantType()))
224       || (value == null && insValue == null)
225       || (value != null && value.equals (insValue));
226   }
227 
228 
229   public int getLength ()
230   {
231     switch (_opcode)
232     {
233     case BIPUSH:
234     case LDC:
235       return super.getLength () + 1;
236     case SIPUSH:
237     case LDC_W:
238     case LDC2_W:
239       return super.getLength () + 2;
240     default:
241       return super.getLength ();
242     }
243   }
244 
245 
246   public int getStackChange ()
247   {
248     if (_value instanceof Long || _value instanceof Double)
249       return 2;
250 
251     return 1;
252   }
253 
254 
255   protected void copy (Instruction orig)
256   {
257     super.copy (orig);
258 
259     ConstantInstruction ci = (ConstantInstruction) orig;
260     _value = ci._value;
261     _arg = ci._arg;
262   }
263 
264 
265   protected void readData (DataInput in)
266     throws IOException
267   {
268     switch (_opcode)
269     {
270     case BIPUSH:
271       _value = new Integer (in.readUnsignedByte ());
272       break;
273     case SIPUSH:
274       _value = new Integer (in.readUnsignedShort ());
275       break;
276     case LDC:
277       _arg = in.readUnsignedByte ();
278       _value = _owner.getPool ().getConstant (_arg);
279       break;
280     case LDC_W:
281     case LDC2_W:
282       _arg = in.readUnsignedShort ();
283       _value = _owner.getPool ().getConstant (_arg);
284       break;
285     }
286   }
287 
288 
289   protected void writeData (DataOutput out)
290     throws IOException
291   {
292     switch (_opcode)
293     {
294     case BIPUSH:
295       out.writeByte (getIntConstant ());
296       break;
297     case SIPUSH:
298       out.writeShort (getIntConstant ());
299       break;
300     case LDC:
301       out.writeByte (_arg);
302       break;
303     case LDC_W:
304     case LDC2_W:
305       out.writeShort (_arg);
306       break;
307     }
308   }
309 
310 
311   /**
312    *  Helper method to calculate the optimal opcode for the constant
313    *  to be pushed onto the stack.
314    */
315   private void calculateOpCode ()
316   {
317     Class type = getConstantType ();
318     double val = 0;
319     if (_value instanceof Number)
320       val = getDoubleConstant ();
321     else if (_value instanceof Boolean)
322       val = (((Boolean) _value).booleanValue ()) ? 1 : 0;
323     _arg = -1;
324       
325     if (type.equals (Object.class))
326       _opcode = ACONST_NULL;
327     else if (type.equals (float.class) && (val == 0 || val == 1 
328       || val == 2))
329       _opcode = FCONST_0 + (int) val;
330     else if (type.equals (long.class) && val > -1 && val < 2)
331       _opcode = LCONST_0 + (int) val;
332     else if (type.equals (double.class) && (val == 0 || val == 1 
333       || val == 2))
334       _opcode = DCONST_0 + (int) val;
335     else if (type.equals(int.class) && val >= -(2 << 15) && val < (2 << 15))
336     {
337       if (val >= -1 && val <= 5)
338         _opcode = ICONST_0 + (int) val;
339       else if (val >= -(2 << 7) && val < (2 << 7))
340         _opcode = BIPUSH;
341       else
342         _opcode = SIPUSH;
343     }
344     else
345     {
346       _arg = _owner.getPool ().setConstant (0, _value);
347       if (type.equals (long.class) || type.equals (double.class))
348         _opcode = LDC2_W;
349       else
350         _opcode = (_arg > 255) ? LDC_W : LDC;
351     }
352   }
353 
354 
355   public void acceptVisit (BCVisitor visit)
356   {
357     visit.enterConstantInstruction (this);  
358     visit.exitConstantInstruction (this);  
359   }
360 }