Source code: com/techtrader/modules/tools/bytecode/CmpInstruction.java
1 package com.techtrader.modules.tools.bytecode;
2
3
4 import com.techtrader.modules.tools.bytecode.visitor.BCVisitor;
5
6
7 /**
8 * An instruction comparing two stack values that varies depending on the
9 * value type.
10 *
11 * @author Abe White
12 */
13 public class CmpInstruction
14 extends Instruction
15 {
16 private Class _type = null;
17 private int _nan = -1;
18
19
20 protected CmpInstruction (Code owner)
21 {
22 super (owner);
23 }
24
25
26 protected CmpInstruction (Code owner, int opcode, Class type, int nan)
27 {
28 super (owner);
29 _opcode = opcode;
30 _type = type;
31 _nan = nan;
32 }
33
34
35 /**
36 * Get the type of value to operate on; this is one of:
37 * float, double, long.
38 */
39 public Class getType ()
40 {
41 return _type;
42 }
43
44
45 /**
46 * Get the type of value to operate on; this is one of:
47 * float, double, long.
48 */
49 public String getTypeName ()
50 {
51 if (_type == null)
52 return null;
53
54 return _type.getName ();
55 }
56
57
58 /**
59 * Set the type of value to operate on; primitives that have no direct
60 * support (byte, char, boolean, int) will be conerted to long.class.
61 *
62 * @return this Instruction, for method chaining
63 */
64 public CmpInstruction setType (Class type)
65 {
66 if (float.class.equals (type))
67 _type = float.class;
68 else if (double.class.equals (type))
69 _type = double.class;
70 else
71 _type = long.class;
72
73 calculateOpCode ();
74 return this;
75 }
76
77
78 /**
79 * Set the type to load by name.
80 *
81 * @return this Instruction, for method chaining
82 *
83 * @see #setType(java.lang.Class)
84 */
85 public CmpInstruction setTypeName (String name)
86 {
87 if ("float".equals (name))
88 _type = float.class;
89 else if ("double".equals (name))
90 _type = double.class;
91 else
92 _type = long.class;
93
94 calculateOpCode ();
95 return this;
96 }
97
98
99 /**
100 * Get the number that will be placed on the stack if this instruction
101 * is of type float or double and one of the operands is NaN. The
102 * return value will be either 1 or -1.
103 */
104 public int getNaNValue ()
105 {
106 if (_type == null || _type.equals (long.class))
107 return 0;
108
109 return _nan;
110 }
111
112
113 /**
114 * Set the number that will be placed on the stack if this instruction
115 * is of type float or double and one of the operands is NaN. The
116 * value must be either 1 or -1.
117 */
118 public void setNaNValue (int nan)
119 {
120 _nan = nan;
121 }
122
123
124
125 /**
126 * Two cmp instructions are equal if the type and NaN value they
127 * reference is equal or the type of either instruction is unset.
128 */
129 public boolean equals (Object other)
130 {
131 if (this == other)
132 return true;
133 if (!(other instanceof CmpInstruction))
134 return false;
135 if (!super.equals (other))
136 return false;
137
138 CmpInstruction ins = (CmpInstruction) other;
139 if (_type == null || ins._type == null)
140 return true;
141
142
143 return _type.equals (ins._type) && _nan == ins._nan;
144 }
145
146
147 public int getStackChange ()
148 {
149 if (_type.equals (long.class) || _type.equals (double.class))
150 return -3;
151
152 return -1;
153 }
154
155
156 public void acceptVisit (BCVisitor visit)
157 {
158 visit.enterCmpInstruction (this);
159 visit.exitCmpInstruction (this);
160 }
161
162
163 protected void copy (Instruction orig)
164 {
165 super.copy (orig);
166
167 CmpInstruction ins = (CmpInstruction) orig;
168 _type = ins._type;
169 _nan = ins._nan;
170 }
171
172
173 private void calculateOpCode ()
174 {
175 if (_type.equals (long.class))
176 _opcode = LCMP;
177 else if (_type.equals (float.class))
178 _opcode = (_nan == 1) ? FCMPG : FCMPL;
179 else
180 _opcode = (_nan == 1) ? DCMPG : DCMPL;
181 }
182 }