1 package serp.bytecode;
2
3 import java.util.*;
4
5 import serp.bytecode.visitor.*;
6
7 /***
8 * One of the math operations defined in the {@link Constants} interface.
9 * Changing the type or operation of the instruction will automatically
10 * update the underlying opcode.
11 *
12 * @author Abe White
13 */
14 public class MathInstruction extends TypedInstruction {
15 private static final Class[][] _mappings = new Class[][] {
16 { byte.class, int.class },
17 { boolean.class, int.class },
18 { char.class, int.class },
19 { short.class, int.class },
20 { void.class, int.class },
21 { Object.class, int.class },
22 };
23 private int _op = -1;
24 private String _type = null;
25
26 MathInstruction(Code owner) {
27 super(owner);
28 }
29
30 MathInstruction(Code owner, int opcode) {
31 super(owner, opcode);
32 _op = getOperation();
33 }
34
35 public int getStackChange() {
36 int op = getOperation();
37 if (op == Constants.MATH_NEG || getOpcode() == Constants.NOP)
38 return 0;
39
40 String type = getTypeName();
41 if (long.class.getName().equals(type)
42 || double.class.getName().equals(type)) {
43 switch (getOpcode()) {
44 case (Constants.LSHL):
45 case (Constants.LSHR):
46 case (Constants.LUSHR):
47 return -1;
48 default:
49 return -2;
50 }
51 }
52 return -1;
53 }
54
55 public int getLogicalStackChange() {
56 int op = getOperation();
57 if (op == Constants.MATH_NEG || getOpcode() == Constants.NOP)
58 return 0;
59 return -1;
60 }
61
62 public String getTypeName() {
63 switch (getOpcode()) {
64 case Constants.IADD:
65 case Constants.ISUB:
66 case Constants.IMUL:
67 case Constants.IDIV:
68 case Constants.IREM:
69 case Constants.INEG:
70 case Constants.ISHL:
71 case Constants.ISHR:
72 case Constants.IUSHR:
73 case Constants.IAND:
74 case Constants.IOR:
75 case Constants.IXOR:
76 return int.class.getName();
77 case Constants.LADD:
78 case Constants.LSUB:
79 case Constants.LMUL:
80 case Constants.LDIV:
81 case Constants.LREM:
82 case Constants.LNEG:
83 case Constants.LSHL:
84 case Constants.LSHR:
85 case Constants.LUSHR:
86 case Constants.LAND:
87 case Constants.LOR:
88 case Constants.LXOR:
89 return long.class.getName();
90 case Constants.FADD:
91 case Constants.FSUB:
92 case Constants.FMUL:
93 case Constants.FDIV:
94 case Constants.FREM:
95 case Constants.FNEG:
96 return float.class.getName();
97 case Constants.DADD:
98 case Constants.DSUB:
99 case Constants.DMUL:
100 case Constants.DDIV:
101 case Constants.DREM:
102 case Constants.DNEG:
103 return double.class.getName();
104 default:
105 return _type;
106 }
107 }
108
109 public TypedInstruction setType(String type) {
110 type = mapType(type, _mappings, true);
111
112
113 if (type == null || _op < 0) {
114 _type = type;
115 return (TypedInstruction) setOpcode(Constants.NOP);
116 }
117
118
119 _type = null;
120 switch (type.charAt(0)) {
121 case 'i':
122 return (TypedInstruction) setOpcode(_op);
123 case 'l':
124 return (TypedInstruction) setOpcode(_op + 1);
125 case 'f':
126 return (TypedInstruction) setOpcode(_op + 2);
127 case 'd':
128 return (TypedInstruction) setOpcode(_op + 3);
129 default:
130 throw new IllegalStateException();
131 }
132 }
133
134 /***
135 * Set the math operation to be performed. This should be one of the
136 * math constant defined in {@link Constants}.
137 *
138 * @return this instruction, for method chaining
139 */
140 public MathInstruction setOperation(int operation) {
141 _op = operation;
142
143
144 setType(getTypeName());
145 return this;
146 }
147
148 /***
149 * Return the operation for this math instruction; will be one of the
150 * math constant defined in {@link Constants}, or -1 if unset.
151 */
152 public int getOperation() {
153 switch (getOpcode()) {
154 case Constants.IADD:
155 case Constants.LADD:
156 case Constants.FADD:
157 case Constants.DADD:
158 return Constants.MATH_ADD;
159 case Constants.ISUB:
160 case Constants.LSUB:
161 case Constants.FSUB:
162 case Constants.DSUB:
163 return Constants.MATH_SUB;
164 case Constants.IMUL:
165 case Constants.LMUL:
166 case Constants.FMUL:
167 case Constants.DMUL:
168 return Constants.MATH_MUL;
169 case Constants.IDIV:
170 case Constants.LDIV:
171 case Constants.FDIV:
172 case Constants.DDIV:
173 return Constants.MATH_DIV;
174 case Constants.IREM:
175 case Constants.LREM:
176 case Constants.FREM:
177 case Constants.DREM:
178 return Constants.MATH_REM;
179 case Constants.INEG:
180 case Constants.LNEG:
181 case Constants.FNEG:
182 case Constants.DNEG:
183 return Constants.MATH_NEG;
184 case Constants.ISHL:
185 case Constants.LSHL:
186 return Constants.MATH_SHL;
187 case Constants.ISHR:
188 case Constants.LSHR:
189 return Constants.MATH_SHR;
190 case Constants.IUSHR:
191 case Constants.LUSHR:
192 return Constants.MATH_USHR;
193 case Constants.IAND:
194 case Constants.LAND:
195 return Constants.MATH_AND;
196 case Constants.IOR:
197 case Constants.LOR:
198 return Constants.MATH_OR;
199 case Constants.IXOR:
200 case Constants.LXOR:
201 return Constants.MATH_XOR;
202 default:
203 return _op;
204 }
205 }
206
207 /***
208 * MathInstructions are equal if they have the same operation and type,
209 * or the operation and type of either is unset.
210 */
211 public boolean equalsInstruction(Instruction other) {
212 if (this == other)
213 return true;
214 if (!(other instanceof MathInstruction))
215 return false;
216
217 MathInstruction ins = (MathInstruction) other;
218 int op = getOperation();
219 int otherOp = ins.getOperation();
220 boolean opEq = op == -1 || otherOp == -1 || op == otherOp;
221
222 String type = getTypeName();
223 String otherType = ins.getTypeName();
224 boolean typeEq = type == null || otherType == null
225 || type.equals(otherType);
226 return opEq && typeEq;
227 }
228
229 public void acceptVisit(BCVisitor visit) {
230 visit.enterMathInstruction(this);
231 visit.exitMathInstruction(this);
232 }
233
234 void read(Instruction orig) {
235 super.read(orig);
236 MathInstruction ins = (MathInstruction) orig;
237 _type = ins._type;
238 _op = ins._op;
239 }
240 }