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 }