001 package serp.bytecode;
002
003 import java.util.*;
004
005 import serp.bytecode.visitor.*;
006
007 /**
008 * One of the math operations defined in the {@link Constants} interface.
009 * Changing the type or operation of the instruction will automatically
010 * update the underlying opcode.
011 *
012 * @author Abe White
013 */
014 public class MathInstruction extends TypedInstruction {
015 private static final Class[][] _mappings = new Class[][] {
016 { byte.class, int.class },
017 { boolean.class, int.class },
018 { char.class, int.class },
019 { short.class, int.class },
020 { void.class, int.class },
021 { Object.class, int.class },
022 };
023 private int _op = -1;
024 private String _type = null;
025
026 MathInstruction(Code owner) {
027 super(owner);
028 }
029
030 MathInstruction(Code owner, int opcode) {
031 super(owner, opcode);
032 _op = getOperation();
033 }
034
035 public int getStackChange() {
036 int op = getOperation();
037 if (op == Constants.MATH_NEG || getOpcode() == Constants.NOP)
038 return 0;
039
040 String type = getTypeName();
041 if (long.class.getName().equals(type)
042 || double.class.getName().equals(type)) {
043 switch (getOpcode()) {
044 case (Constants.LSHL):
045 case (Constants.LSHR):
046 case (Constants.LUSHR):
047 return -1;
048 default:
049 return -2;
050 }
051 }
052 return -1;
053 }
054
055 public int getLogicalStackChange() {
056 int op = getOperation();
057 if (op == Constants.MATH_NEG || getOpcode() == Constants.NOP)
058 return 0;
059 return -1;
060 }
061
062 public String getTypeName() {
063 switch (getOpcode()) {
064 case Constants.IADD:
065 case Constants.ISUB:
066 case Constants.IMUL:
067 case Constants.IDIV:
068 case Constants.IREM:
069 case Constants.INEG:
070 case Constants.ISHL:
071 case Constants.ISHR:
072 case Constants.IUSHR:
073 case Constants.IAND:
074 case Constants.IOR:
075 case Constants.IXOR:
076 return int.class.getName();
077 case Constants.LADD:
078 case Constants.LSUB:
079 case Constants.LMUL:
080 case Constants.LDIV:
081 case Constants.LREM:
082 case Constants.LNEG:
083 case Constants.LSHL:
084 case Constants.LSHR:
085 case Constants.LUSHR:
086 case Constants.LAND:
087 case Constants.LOR:
088 case Constants.LXOR:
089 return long.class.getName();
090 case Constants.FADD:
091 case Constants.FSUB:
092 case Constants.FMUL:
093 case Constants.FDIV:
094 case Constants.FREM:
095 case Constants.FNEG:
096 return float.class.getName();
097 case Constants.DADD:
098 case Constants.DSUB:
099 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 // if an invalid type or op, revert to nop
113 if (type == null || _op < 0) {
114 _type = type;
115 return (TypedInstruction) setOpcode(Constants.NOP);
116 }
117
118 // valid opcode, unset saved type
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 // this calculates the opcode
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 }