View Javadoc

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         // 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 }