001 package serp.bytecode; 002 003 import java.io.*; 004 005 import serp.bytecode.visitor.*; 006 007 /** 008 * The <code>wide</code> instruction, which is used to allow other 009 * instructions to index values beyond what they can normally index baed 010 * on the length of their arguments. 011 * 012 * @author Abe White 013 */ 014 public class WideInstruction extends LocalVariableInstruction { 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 }; 022 private int _ins = Constants.NOP; 023 private int _inc = -1; 024 025 WideInstruction(Code owner) { 026 super(owner, Constants.WIDE); 027 } 028 029 int getLength() { 030 // opcode, ins, index 031 int length = super.getLength() + 1 + 2; 032 033 // increment 034 if (_ins == Constants.IINC) 035 length += 2; 036 return length; 037 } 038 039 public int getStackChange() { 040 switch (_ins) { 041 case Constants.ILOAD: 042 case Constants.FLOAD: 043 case Constants.ALOAD: 044 return 1; 045 case Constants.LLOAD: 046 case Constants.DLOAD: 047 return 2; 048 case Constants.ISTORE: 049 case Constants.FSTORE: 050 case Constants.ASTORE: 051 return -1; 052 case Constants.LSTORE: 053 case Constants.DSTORE: 054 return -2; 055 default: 056 return 0; 057 } 058 } 059 060 public int getLogicalStackChange() { 061 switch (_ins) { 062 case Constants.ILOAD: 063 case Constants.FLOAD: 064 case Constants.ALOAD: 065 case Constants.LLOAD: 066 case Constants.DLOAD: 067 return 1; 068 case Constants.ISTORE: 069 case Constants.FSTORE: 070 case Constants.ASTORE: 071 case Constants.LSTORE: 072 case Constants.DSTORE: 073 return -1; 074 default: 075 return 0; 076 } 077 } 078 079 public String getTypeName() { 080 switch (_ins) { 081 case Constants.ILOAD: 082 case Constants.ISTORE: 083 return int.class.getName(); 084 case Constants.LLOAD: 085 case Constants.LSTORE: 086 return long.class.getName(); 087 case Constants.FLOAD: 088 case Constants.FSTORE: 089 return float.class.getName(); 090 case Constants.DLOAD: 091 case Constants.DSTORE: 092 return double.class.getName(); 093 case Constants.ALOAD: 094 case Constants.ASTORE: 095 return Object.class.getName(); 096 default: 097 return null; 098 } 099 } 100 101 public TypedInstruction setType(String type) { 102 type = mapType(type, _mappings, true); 103 switch (_ins) { 104 case Constants.ILOAD: 105 case Constants.LLOAD: 106 case Constants.FLOAD: 107 case Constants.DLOAD: 108 case Constants.ALOAD: 109 if (type == null) 110 throw new IllegalStateException(); 111 switch (type.charAt(0)) { 112 case 'i': 113 return (TypedInstruction) setInstruction(Constants.ILOAD); 114 case 'l': 115 return (TypedInstruction) setInstruction(Constants.LLOAD); 116 case 'f': 117 return (TypedInstruction) setInstruction(Constants.FLOAD); 118 case 'd': 119 return (TypedInstruction) setInstruction(Constants.DLOAD); 120 default: 121 return (TypedInstruction) setInstruction(Constants.ALOAD); 122 } 123 case Constants.ISTORE: 124 case Constants.LSTORE: 125 case Constants.FSTORE: 126 case Constants.DSTORE: 127 case Constants.ASTORE: 128 if (type == null) 129 throw new IllegalStateException(); 130 switch (type.charAt(0)) { 131 case 'i': 132 return (TypedInstruction) setInstruction(Constants.ISTORE); 133 case 'l': 134 return (TypedInstruction) setInstruction(Constants.LSTORE); 135 case 'f': 136 return (TypedInstruction) setInstruction(Constants.FSTORE); 137 case 'd': 138 return (TypedInstruction) setInstruction(Constants.DSTORE); 139 default: 140 return (TypedInstruction) setInstruction(Constants.ASTORE); 141 } 142 default: 143 if (type != null) 144 throw new IllegalStateException("Augmented instruction not " 145 + "typed"); 146 return this; 147 } 148 } 149 150 /** 151 * Return the opcode of the instruction to modify; this will return one 152 * of the constants defined in {@link Constants}. 153 */ 154 public int getInstruction() { 155 return _ins; 156 } 157 158 /** 159 * Set the type of instruction this wide instruction modifies. 160 */ 161 public WideInstruction setInstruction(Instruction ins) { 162 if (ins == null) 163 return setInstruction(Constants.NOP); 164 setInstruction(ins.getOpcode()); 165 if (_ins == Constants.IINC) 166 _inc = ((IIncInstruction) ins).getIncrement(); 167 return this; 168 } 169 170 /** 171 * Set the type of instruction this wide instruction modifies. 172 */ 173 public WideInstruction setInstruction(int opcode) { 174 int len = getLength(); 175 _ins = opcode; 176 if (len != getLength()) 177 invalidateByteIndexes(); 178 return this; 179 } 180 181 /** 182 * Set the type of instruction this wide instruction modifies. 183 * 184 * @return this instruction, for method chaining 185 */ 186 public WideInstruction iinc() { 187 return setInstruction(Constants.IINC); 188 } 189 190 /** 191 * Set the type of instruction this wide instruction modifies. 192 * 193 * @return this instruction, for method chaining 194 */ 195 public WideInstruction ret() { 196 return setInstruction(Constants.RET); 197 } 198 199 /** 200 * Set the type of instruction this wide instruction modifies. 201 * 202 * @return this instruction, for method chaining 203 */ 204 public WideInstruction iload() { 205 return setInstruction(Constants.ILOAD); 206 } 207 208 /** 209 * Set the type of instruction this wide instruction modifies. 210 * 211 * @return this instruction, for method chaining 212 */ 213 public WideInstruction fload() { 214 return setInstruction(Constants.FLOAD); 215 } 216 217 /** 218 * Set the type of instruction this wide instruction modifies. 219 * 220 * @return this instruction, for method chaining 221 */ 222 public WideInstruction aload() { 223 return setInstruction(Constants.ALOAD); 224 } 225 226 /** 227 * Set the type of instruction this wide instruction modifies. 228 * 229 * @return this instruction, for method chaining 230 */ 231 public WideInstruction lload() { 232 return setInstruction(Constants.LLOAD); 233 } 234 235 /** 236 * Set the type of instruction this wide instruction modifies. 237 * 238 * @return this instruction, for method chaining 239 */ 240 public WideInstruction dload() { 241 return setInstruction(Constants.DLOAD); 242 } 243 244 /** 245 * Set the type of instruction this wide instruction modifies. 246 * 247 * @return this instruction, for method chaining 248 */ 249 public WideInstruction istore() { 250 return setInstruction(Constants.ISTORE); 251 } 252 253 /** 254 * Set the type of instruction this wide instruction modifies. 255 * 256 * @return this instruction, for method chaining 257 */ 258 public WideInstruction fstore() { 259 return setInstruction(Constants.FSTORE); 260 } 261 262 /** 263 * Set the type of instruction this wide instruction modifies. 264 * 265 * @return this instruction, for method chaining 266 */ 267 public WideInstruction astore() { 268 return setInstruction(Constants.ASTORE); 269 } 270 271 /** 272 * Set the type of instruction this wide instruction modifies. 273 * 274 * @return this instruction, for method chaining 275 */ 276 public WideInstruction lstore() { 277 return setInstruction(Constants.LSTORE); 278 } 279 280 /** 281 * Set the type of instruction this wide instruction modifies. 282 * 283 * @return this instruction, for method chaining 284 */ 285 public WideInstruction dstore() { 286 return setInstruction(Constants.DSTORE); 287 } 288 289 /** 290 * Return the increment for this instruction if it augments IINC, or -1 291 * if unset. 292 */ 293 public int getIncrement() { 294 return _inc; 295 } 296 297 /** 298 * Set the increment on this instruction if it augments IINC. 299 * 300 * @return this Instruction, for method chaining 301 */ 302 public WideInstruction setIncrement(int val) { 303 _inc = val; 304 return this; 305 } 306 307 /** 308 * WideInstructions are equal if the instruction they augment is the same 309 * or unset. 310 */ 311 public boolean equalsInstruction(Instruction other) { 312 if (other == this) 313 return true; 314 if (!super.equalsInstruction(other)) 315 return false; 316 if (!(other instanceof WideInstruction)) 317 return false; 318 319 WideInstruction ins = (WideInstruction) other; 320 int code = getInstruction(); 321 int otherCode = ins.getInstruction(); 322 if (code != otherCode) 323 return false; 324 if (code == Constants.IINC) { 325 int inc = getIncrement(); 326 int otherInc = ins.getIncrement(); 327 return (inc == -1) || (otherInc == -1) || (inc == otherInc); 328 } 329 return true; 330 } 331 332 public void acceptVisit(BCVisitor visit) { 333 visit.enterWideInstruction(this); 334 visit.exitWideInstruction(this); 335 } 336 337 void read(Instruction orig) { 338 super.read(orig); 339 setInstruction(((WideInstruction) orig).getInstruction()); 340 } 341 342 void read(DataInput in) throws IOException { 343 super.read(in); 344 _ins = in.readUnsignedByte(); 345 setLocal(in.readUnsignedShort()); 346 if (_ins == Constants.IINC) 347 _inc = in.readUnsignedShort(); 348 } 349 350 void write(DataOutput out) throws IOException { 351 super.write(out); 352 out.writeByte(_ins); 353 out.writeShort(getLocal()); 354 if (_ins == Constants.IINC) 355 out.writeShort(_inc); 356 } 357 }