Source code: com/techtrader/modules/tools/bytecode/MathInstruction.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 math operations defined in the
12 * {@link Constants} interface.
13 * Changing the type or operation of the instruction will automatically
14 * update the underlying opcode. Note, however, that some operations
15 * cannot act on floating point types.
16 *
17 * @author Abe White
18 */
19 public class MathInstruction
20 extends Instruction
21 {
22 private static final Map _typeNames = new HashMap ();
23 static
24 {
25 _typeNames.put ("long", long.class);
26 _typeNames.put ("float", float.class);
27 _typeNames.put ("double", double.class);
28 }
29
30 private Class _type = null;
31 private int _operation = -1;
32
33
34 protected MathInstruction (Code owner)
35 {
36 super (owner);
37 }
38
39
40 protected MathInstruction (Code owner, int opcode, int operation,
41 Class type)
42 {
43 super (owner);
44 _opcode = opcode;
45 _operation = operation;
46 _type = type;
47 }
48
49
50 /**
51 * Set the math operation to be performed. This should be one of the
52 * math constant defined in {@link Constants}.
53 *
54 * @return this Instruction, for method chaining
55 */
56 public MathInstruction setOperation (int operation)
57 {
58 _operation = operation;
59 calculateOpCode ();
60 return this;
61 }
62
63
64 /**
65 * Return the operation for this math instruction; will be one of the
66 * math constant defined in {@link Constants}, or -1 if
67 * unset.
68 */
69 public int getOperation ()
70 {
71 return _operation;
72 }
73
74
75 /**
76 * Get the type of args to operation on; will be one of:
77 * int, float, double, long.
78 * If the type has not been set, this method will return null.
79 */
80 public Class getType ()
81 {
82 return _type;
83 }
84
85
86 /**
87 * Set the type of args to operate on. Types without direct support are
88 * demoted to int.class.
89 *
90 * @return this Instruction, for method chaining
91 */
92 public MathInstruction setType (Class type)
93 {
94 if (float.class.equals (type) || double.class.equals (type)
95 || long.class.equals (type))
96 _type = type;
97 else
98 _type = int.class;
99
100 calculateOpCode ();
101 return this;
102 }
103
104
105 /**
106 * Set the type to load by name.
107 *
108 * @return this Instruction, for method chaining
109 *
110 * @see #setType(java.lang.Class)
111 */
112 public MathInstruction setTypeName (String name)
113 {
114 _type = (Class) _typeNames.get (name);
115 if (_type == null && name != null)
116 _type = int.class;
117
118 calculateOpCode ();
119 return this;
120 }
121
122
123 /**
124 * MathInstructions are equal if they have the same operation and type,
125 * or the type of either is unset.
126 */
127 public boolean equals (Object other)
128 {
129 if (this == other)
130 return true;
131 if (!(other instanceof MathInstruction))
132 return false;
133
134 MathInstruction ins = (MathInstruction) other;
135
136 boolean opEq = (_operation == -1 || ins._operation == -1
137 || _operation == ins._operation);
138 boolean typeEq = (_type == null || ins._type == null
139 || _type.equals (ins._type));
140
141 return opEq && typeEq;
142 }
143
144
145 public int getStackChange ()
146 {
147 if (_operation == MATH_NEG)
148 return 0;
149
150 if (_type.equals (long.class) || _type.equals (double.class))
151 return -2;
152
153 return -1;
154 }
155
156
157 protected void copy (Instruction orig)
158 {
159 super.copy (orig);
160
161 MathInstruction mi = (MathInstruction) orig;
162 _type = mi._type;
163 _operation = mi._operation;
164 }
165
166
167 /**
168 * Helper method to calculate the correct opcode for this instruction.
169 * Takes advantage of the arrangements of the opcodes and constants.
170 */
171 private void calculateOpCode ()
172 {
173 _opcode = _operation + _opcodeTypes.indexOf (_type);
174 }
175
176
177 public void acceptVisit (BCVisitor visit)
178 {
179 visit.enterMathInstruction (this);
180 visit.exitMathInstruction (this);
181 }
182 }