1 // This is not visible outside the 2 // package. It is used to 3 // handle the various types 4 // of operands used by Insns. 5 package jas; 6 7 import java.io.*; 8 9 abstract class InsnOperand 10 { write(ClassEnv e, CodeAttr ce, DataOutputStream out)11 abstract void write(ClassEnv e, CodeAttr ce, DataOutputStream out) 12 throws IOException, jasError; size(ClassEnv e, CodeAttr code)13 abstract int size(ClassEnv e, CodeAttr code) throws jasError; resolve(ClassEnv e)14 abstract void resolve(ClassEnv e); writePrefix(ClassEnv e, CodeAttr ce, DataOutputStream out)15 void writePrefix(ClassEnv e, CodeAttr ce, DataOutputStream out) 16 throws IOException, jasError 17 { return; } 18 } 19 20 // Used to implement targets of Insns 21 class LabelOperand extends InsnOperand 22 { 23 Label target; 24 Insn source; 25 boolean wide; 26 int ref; 27 LabelOperand(Label l, Insn source, int line)28 LabelOperand(Label l, Insn source, int line) 29 { target = l; this.source = source; this.wide = false; this.ref = line; } LabelOperand(Label l, Insn source, boolean wide, int line)30 LabelOperand(Label l, Insn source, boolean wide, int line) 31 { target = l; this.source = source; this.wide = wide; this.ref = line; } size(ClassEnv ce, CodeAttr code)32 int size(ClassEnv ce, CodeAttr code) { if (wide) return 4; else return 2; } resolve(ClassEnv e)33 void resolve(ClassEnv e) { return; } write(ClassEnv e, CodeAttr ce, DataOutputStream out)34 void write(ClassEnv e, CodeAttr ce, DataOutputStream out) 35 throws IOException, jasError 36 { 37 if (wide) { target.writeWideOffset(ce, source, out); } 38 else { 39 int offset = ce.getPc(target); 40 if (source != null) 41 offset -= ce.getPc(source); 42 if (offset > 32767 || offset < -32768) 43 throw new jasError 44 ("reference from line " +ref+ " exceed size for short"); 45 target.writeOffset(ce, source, out); } 46 } 47 } 48 49 class UnsignedByteOperand extends InsnOperand 50 { 51 int val; 52 UnsignedByteOperand(int n)53 UnsignedByteOperand(int n) { val = n; } size(ClassEnv ce, CodeAttr code)54 int size(ClassEnv ce, CodeAttr code) { return 1; } write(ClassEnv e, CodeAttr ce, DataOutputStream out)55 void write(ClassEnv e, CodeAttr ce, DataOutputStream out) 56 throws IOException, jasError 57 { 58 if (val >= 256) 59 throw 60 new jasError("Operand is too large (" +val+ ") for this instruction"); 61 out.writeByte((byte)(0xff & val)); 62 } resolve(ClassEnv e)63 void resolve(ClassEnv e) { return; } 64 } 65 66 // This (conditionally) adds a wide 67 // prefix if the value is larger than 68 // 256 69 class UnsignedByteWideOperand extends InsnOperand 70 implements RuntimeConstants 71 { 72 int val; 73 boolean Wide; 74 UnsignedByteWideOperand(int n, boolean Wide)75 UnsignedByteWideOperand(int n, boolean Wide) 76 { 77 val = n; 78 this.Wide = (Wide || val > 255); 79 } 80 size(ClassEnv ce, CodeAttr code)81 int size(ClassEnv ce, CodeAttr code) 82 { return Wide ? 3: 1; } 83 writePrefix(ClassEnv e, CodeAttr ce, DataOutputStream out)84 void writePrefix(ClassEnv e, CodeAttr ce, DataOutputStream out) 85 throws IOException 86 { 87 if (Wide) 88 out.writeByte((byte)(opc_wide)); 89 } 90 write(ClassEnv e, CodeAttr ce, DataOutputStream out)91 void write(ClassEnv e, CodeAttr ce, DataOutputStream out) 92 throws IOException 93 { 94 if (Wide) 95 out.writeShort((short)(0xffff & val)); 96 else 97 out.writeByte((byte)(val & 0xff)); 98 } resolve(ClassEnv e)99 void resolve(ClassEnv e) { return; } 100 } 101 102 class ByteOperand extends InsnOperand 103 { 104 int val; 105 ByteOperand(int n)106 ByteOperand(int n) { val = n; } size(ClassEnv ce, CodeAttr code)107 int size(ClassEnv ce, CodeAttr code) { return 1; } resolve(ClassEnv e)108 void resolve(ClassEnv e) { return; } write(ClassEnv e, CodeAttr ce, DataOutputStream out)109 void write(ClassEnv e, CodeAttr ce, DataOutputStream out) 110 throws IOException 111 { out.writeByte((byte)val); } 112 } 113 114 class IntegerOperand extends InsnOperand 115 { 116 int val; 117 IntegerOperand(int n)118 IntegerOperand(int n) { val = n; } size(ClassEnv ce, CodeAttr code)119 int size(ClassEnv ce, CodeAttr code) { return 4; } resolve(ClassEnv e)120 void resolve(ClassEnv e) { return; } write(ClassEnv e, CodeAttr ce, DataOutputStream out)121 void write(ClassEnv e, CodeAttr ce, DataOutputStream out) 122 throws IOException 123 { out.writeInt(val); } 124 } 125 126 class ShortOperand extends InsnOperand 127 { 128 int offset; ShortOperand(int n)129 ShortOperand(int n) { offset = n; } resolve(ClassEnv e)130 void resolve(ClassEnv e) { return; } size(ClassEnv ce, CodeAttr code)131 int size(ClassEnv ce, CodeAttr code) { return 2; } write(ClassEnv e, CodeAttr ce, DataOutputStream out)132 void write(ClassEnv e, CodeAttr ce, DataOutputStream out) 133 throws IOException 134 { out.writeShort((short)offset); } 135 } 136 137 class CPOperand extends InsnOperand 138 { 139 CP cpe; 140 boolean wide; size(ClassEnv ce, CodeAttr code)141 int size(ClassEnv ce, CodeAttr code) { if (wide) return 2; else return 1; } CPOperand(CP cpe)142 CPOperand(CP cpe) { this.cpe = cpe; wide = true; } CPOperand(CP cpe, boolean wide)143 CPOperand(CP cpe, boolean wide) 144 { this.cpe = cpe; this.wide = wide; } resolve(ClassEnv e)145 void resolve(ClassEnv e) 146 { e.addCPItem(cpe); } write(ClassEnv e, CodeAttr ce, DataOutputStream out)147 void write(ClassEnv e, CodeAttr ce, DataOutputStream out) 148 throws IOException, jasError 149 { 150 int idx = e.getCPIndex(cpe); 151 if (wide) 152 { out.writeShort((short) idx); } 153 else 154 { 155 if (idx > 255) 156 { throw new jasError("exceeded size for small cpidx" + cpe); } 157 out.writeByte((byte) (0xff & (idx))); 158 } 159 } 160 } 161 162 // these are unique enough that 163 // they need a separate handler for their 164 // args 165 class LdcOperand extends InsnOperand implements RuntimeConstants 166 { 167 CP cpe; 168 Insn source; 169 boolean wide; 170 size(ClassEnv ce, CodeAttr code)171 int size(ClassEnv ce, CodeAttr code) throws jasError 172 { 173 if (wide) 174 { return 2; } 175 else 176 { 177 // Should we promote it? 178 int idx = ce.getCPIndex(cpe); 179 if (idx > 255) 180 { 181 wide = true; 182 source.opc = opc_ldc_w; 183 return 2; 184 } 185 return 1; 186 } 187 } LdcOperand(Insn s, CP cpe)188 LdcOperand(Insn s, CP cpe) { source = s; this.cpe = cpe; wide = true; } LdcOperand(Insn s, CP cpe, boolean wide)189 LdcOperand(Insn s, CP cpe, boolean wide) 190 { source = s; this.cpe = cpe; this.wide = wide; } resolve(ClassEnv e)191 void resolve(ClassEnv e) 192 { e.addCPItem(cpe); } write(ClassEnv e, CodeAttr ce, DataOutputStream out)193 void write(ClassEnv e, CodeAttr ce, DataOutputStream out) 194 throws IOException, jasError 195 { 196 int idx = e.getCPIndex(cpe); 197 if (wide) 198 { out.writeShort((short) idx); } 199 else 200 { 201 if (idx > 255) 202 { throw new jasError("exceeded size for small cpidx" + cpe); } 203 out.writeByte((byte) (0xff & (idx))); 204 } 205 } 206 } 207 208 209 class InvokeinterfaceOperand extends InsnOperand 210 { 211 CP cpe; 212 int nargs; 213 InvokeinterfaceOperand(CP cpe, int nargs)214 InvokeinterfaceOperand(CP cpe, int nargs) 215 { this.cpe = cpe; this.nargs = nargs; } 216 size(ClassEnv ce, CodeAttr code)217 int size(ClassEnv ce, CodeAttr code) { return 4; } 218 resolve(ClassEnv e)219 void resolve(ClassEnv e) 220 { e.addCPItem(cpe); } 221 write(ClassEnv e, CodeAttr ce, DataOutputStream out)222 void write (ClassEnv e, CodeAttr ce, DataOutputStream out) 223 throws IOException, jasError 224 { 225 out.writeShort(e.getCPIndex(cpe)); 226 out.writeByte((byte) (0xff & nargs)); 227 out.writeByte(0); 228 } 229 } 230 231 class IincOperand extends InsnOperand 232 implements RuntimeConstants 233 { 234 int vindex, constt; 235 boolean Wide; 236 IincOperand(int vindex, int constt, boolean Wide)237 IincOperand(int vindex, int constt, boolean Wide) 238 { 239 this.vindex = vindex; 240 this.constt = constt; 241 this.Wide = (Wide || 242 vindex > 255 || 243 constt > 127 || 244 constt < 127); 245 } 246 size(ClassEnv ce, CodeAttr code)247 int size(ClassEnv ce, CodeAttr code) 248 { 249 return Wide ? 5 : 2; 250 } 251 resolve(ClassEnv e)252 void resolve(ClassEnv e) { return; } 253 writePrefix(ClassEnv e, CodeAttr ce, DataOutputStream out)254 void writePrefix(ClassEnv e, CodeAttr ce, DataOutputStream out) 255 throws IOException 256 { 257 if (Wide) 258 out.writeByte((byte)opc_wide); 259 } 260 write(ClassEnv e, CodeAttr ce, DataOutputStream out)261 void write(ClassEnv e, CodeAttr ce, DataOutputStream out) 262 throws IOException 263 { 264 if (Wide) 265 { 266 out.writeShort((short)(0xffff & vindex)); 267 out.writeShort((short)(0xffff & constt)); 268 } 269 else 270 { 271 out.writeByte((byte) (0xff & vindex)); 272 out.writeByte((byte) (0xff & constt)); 273 } 274 } 275 } 276 277 class MultiarrayOperand extends InsnOperand 278 { 279 CP cpe; 280 int sz; 281 MultiarrayOperand(CP cpe, int sz)282 MultiarrayOperand(CP cpe, int sz) 283 { this.cpe = cpe; this.sz = sz; } resolve(ClassEnv e)284 void resolve(ClassEnv e) { e.addCPItem(cpe); } size(ClassEnv ce, CodeAttr code)285 int size(ClassEnv ce, CodeAttr code) { return 3; } write(ClassEnv e, CodeAttr ce, DataOutputStream out)286 void write(ClassEnv e, CodeAttr ce, DataOutputStream out) 287 throws IOException, jasError 288 { 289 out.writeShort(e.getCPIndex(cpe)); 290 out.writeByte((byte)(0xff & sz)); 291 } 292 } 293 294 class LookupswitchOperand extends InsnOperand 295 { 296 LabelOrOffset dflt; 297 Insn source; 298 int match[]; 299 LabelOrOffset jmp[]; 300 LookupswitchOperand(Insn s, LabelOrOffset def, int m[], LabelOrOffset j[])301 LookupswitchOperand(Insn s, LabelOrOffset def, int m[], LabelOrOffset j[]) 302 { dflt = def; jmp = j; match = m; source = s; } 303 resolve(ClassEnv e)304 void resolve (ClassEnv e) { return; } size(ClassEnv ce, CodeAttr code)305 int size(ClassEnv ce, CodeAttr code) throws jasError 306 { 307 int sz = 8; // 4 + 4 + padding + jumptable 308 int source_pc = code.getPc(source); 309 if (((source_pc+1) % 4) != 0) 310 { 311 // need padding 312 sz += (4 - ((source_pc+1) % 4)); 313 } 314 315 if (jmp != null) 316 { sz += 8*(jmp.length); } 317 return sz; 318 } 319 write(ClassEnv e, CodeAttr ce, DataOutputStream out)320 void write(ClassEnv e, CodeAttr ce, DataOutputStream out) 321 throws IOException, jasError 322 { 323 int pad; 324 int source_pc = ce.getPc(source); 325 326 if (((source_pc+1) % 4) != 0) 327 { // need padding 328 pad = (4 - ((source_pc+1) % 4)); 329 for (int x=0; x<pad; x++) out.writeByte(0); 330 } 331 332 // write offset to default 333 // as a 4 byte signed value 334 dflt.writeWideOffset(ce, source, out); 335 if (jmp == null) 336 { out.writeInt(0); } 337 else 338 { 339 out.writeInt(jmp.length); 340 for (int x=0; x<jmp.length; x++) 341 { 342 out.writeInt(match[x]); 343 jmp[x].writeWideOffset(ce, source, out); 344 } 345 } 346 } 347 } 348 349 350 class TableswitchOperand extends InsnOperand 351 { 352 int min, max; 353 LabelOrOffset dflt; 354 LabelOrOffset jmp[]; 355 Insn source; 356 TableswitchOperand(Insn s,int min, int max, LabelOrOffset def, LabelOrOffset j[])357 TableswitchOperand(Insn s,int min, int max, LabelOrOffset def, 358 LabelOrOffset j[]) 359 { 360 this.min = min; this.max = max; 361 dflt = def; jmp = j; source = s; 362 } 363 resolve(ClassEnv e)364 void resolve(ClassEnv e) { return; } 365 size(ClassEnv ce, CodeAttr code)366 int size(ClassEnv ce, CodeAttr code) 367 throws jasError 368 // the *real* reason for making it a 369 // method.. 370 { 371 int sz = 12; // 4+4+4+jmptable+padding... 372 int source_pc = code.getPc(source); 373 if (((source_pc+1) % 4) != 0) 374 { // need padding 375 sz += (4 - ((source_pc+1) % 4)); 376 } 377 if (jmp != null) 378 { sz += 4*(jmp.length); } 379 return sz; 380 } 381 write(ClassEnv e, CodeAttr ce, DataOutputStream out)382 void write(ClassEnv e, CodeAttr ce, DataOutputStream out) 383 throws IOException, jasError 384 { 385 int pad; 386 int source_pc = ce.getPc(source); 387 388 if (((source_pc+1) % 4) != 0) 389 { // need padding 390 pad = (4 - ((source_pc+1) % 4)); 391 for (int x=0; x<pad; x++) out.writeByte(0); 392 } 393 dflt.writeWideOffset(ce, source, out); 394 out.writeInt(min); 395 out.writeInt(max); 396 int cnt = jmp.length; 397 for (int x=0; x<cnt; x++) 398 { jmp[x].writeWideOffset(ce, source, out); } 399 } 400 } 401 402 class OffsetOperand extends InsnOperand { 403 int val; 404 boolean wide; 405 Insn parent; 406 OffsetOperand(Insn parent, int val)407 OffsetOperand(Insn parent, int val) { 408 this(parent, val, false); 409 } 410 OffsetOperand(Insn parent, int val, boolean wide)411 OffsetOperand(Insn parent, int val, boolean wide) { 412 this.parent = parent; 413 this.val = val; 414 this.wide = wide; 415 } 416 resolve(ClassEnv e)417 void resolve(ClassEnv e) { return; } 418 size(ClassEnv e, CodeAttr ce)419 int size(ClassEnv e, CodeAttr ce) { 420 return wide ? 4 : 2; 421 } 422 write(ClassEnv e, CodeAttr ce, DataOutputStream out)423 void write(ClassEnv e, CodeAttr ce, DataOutputStream out) 424 throws IOException, jasError { 425 if(wide) 426 out.writeInt(val); 427 else 428 out.writeShort(val); 429 } 430 } 431 432 class RelativeOffsetOperand extends InsnOperand { 433 int val; 434 boolean wide; 435 Insn parent; 436 RelativeOffsetOperand(Insn parent, int val)437 RelativeOffsetOperand(Insn parent, int val) { 438 this(parent, val, false); 439 } 440 RelativeOffsetOperand(Insn parent, int val, boolean wide)441 RelativeOffsetOperand(Insn parent, int val, boolean wide) { 442 this.parent = parent; 443 this.val = val; 444 this.wide = wide; 445 } 446 resolve(ClassEnv e)447 void resolve(ClassEnv e) { return; } 448 size(ClassEnv e, CodeAttr ce)449 int size(ClassEnv e, CodeAttr ce) { 450 return wide ? 4 : 2; 451 } 452 write(ClassEnv e, CodeAttr ce, DataOutputStream out)453 void write(ClassEnv e, CodeAttr ce, DataOutputStream out) 454 throws IOException, jasError { 455 if(wide) 456 out.writeInt(val); 457 else 458 out.writeShort(val); 459 } 460 } 461 462 /* --- Revision History --------------------------------------------------- 463 --- Iouri Kharon, Aug 10 2006 464 Added 'Wide' prefix support to IincOperand and UnsideWideOperand 465 */ 466