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