KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > alt > jiapi > reflect > InstructionList


1 package alt.jiapi.reflect;
2
3 import java.util.Iterator JavaDoc;
4 import java.util.List JavaDoc;
5 import java.util.LinkedList JavaDoc;
6
7 import alt.jiapi.file.ConstantPool;
8 import alt.jiapi.reflect.instruction.CPInstruction;
9 import alt.jiapi.reflect.instruction.Opcodes;
10
11 /**
12  * InstructionList is a place holder for Instructions.
13  *
14  * @author Mika Riekkinen
15  */

16 public class InstructionList {
17
18     private JiapiMethod declaringMethod;
19     ConstantPool constantPool;
20     List JavaDoc instructions;
21
22     // modified indicates whether or not bytes are up-to-date
23
private boolean modified = false;
24 // private byte[] bytes;
25

26     public InstructionList() {
27         this.constantPool = new ConstantPool();
28         this.instructions = new LinkedList JavaDoc();
29     }
30
31     /**
32      * Constructor for InstructionList. Bytecode of hte method is given
33      * as an argument to this Constructor. This bytecode is parsed and
34      * Instructions are created for each byte level instruction(opcode).
35      *
36      * @param byteCode Bytecode of a method.
37      */

38     InstructionList(byte[] byteCode, ConstantPool cp) {
39         this.constantPool = cp;
40
41         InstructionFactory factory = new InstructionFactory(cp);
42         instructions = factory.createInstructionList(byteCode);
43     }
44
45
46
47     /**
48      * Constructor for InstructionList.
49      *
50      * @param byteCode Bytecode of a method.
51      */

52     private InstructionList(ConstantPool cp, List JavaDoc instructions) {
53         this.constantPool = cp;
54         this.instructions = instructions;
55     }
56     
57
58     /**
59      * Constructor for InstructionList.
60      *
61      * @param factory InstructionFactory
62      */

63     InstructionList(ConstantPool cp) {
64         this.constantPool = cp;
65         this.instructions = new LinkedList JavaDoc();
66     }
67     
68
69     /**
70      * Create an empty list.
71      */

72     public InstructionList createEmptyList() {
73         return new InstructionList(constantPool);
74     }
75
76     /**
77      * Gets this InstructionList as a byte array. This byte array
78      * may be put into alt.jiapi.file.Method as a code attribute.
79      * No checking is being made, whether this byte array
80      * makes any sense or not. It is thus the responsibility of
81      * the developer to keep this list in a correct form.
82      *
83      * @return a byte array representing this InstructionList
84      */

85     public byte[] getBytes() {
86         // Calculate byte-size of list
87
Iterator JavaDoc i = instructions.iterator();
88         int bSize = 0;
89         while(i.hasNext()) {
90             bSize += ((Instruction)i.next()).length();
91         }
92
93         // Copy each instructions bytes to main bytes list
94
byte[] bytes = new byte[bSize];
95         int bIdx = 0;
96         i = instructions.iterator();
97         while(i.hasNext()) {
98             Instruction ins = (Instruction)i.next();
99             byte[] iBytes = ins.getBytes();
100
101             for (int j = 0; j < iBytes.length; j++) {
102                 bytes[bIdx] = iBytes[j];
103                 bIdx++;
104             }
105         }
106         
107         // Turn this flag to false.
108
this.modified = false;
109
110         return bytes;
111     }
112
113
114     /**
115      * Adds an Instruction to this InstructionList
116      */

117     public void add(Instruction i) {
118         modified = true;
119         i.setAttribute("synthetic");
120
121         if (i instanceof CPInstruction) {
122             CPInstruction cpIns = (CPInstruction)i;
123             ConstantPool cp = cpIns.getConstantPool();
124
125             if (!constantPool.equals(cp)) {
126                 cpIns.replaceConstantPool(constantPool);
127             }
128         }
129
130         instructions.add(i);
131     }
132
133     /**
134      * Adds all the Instructions in given list to this list.
135      *
136      * @param il InstructionList to add
137      */

138     public void add(InstructionList il) {
139         modified = true;
140         if (il.size() == 0) {
141             return;
142         }
143         
144     for (int i = 0; i < il.size(); i++) {
145         add(il.get(i));
146     }
147     }
148
149     /**
150      * Insert an Instruction to this InstructionList
151      *
152      * @param idx index of the Instruction
153      * @param i Instruction to insert
154      */

155     public boolean insert(int idx, Instruction i) {
156         modified = true;
157         i.setAttribute("synthetic");
158         
159         if (i instanceof CPInstruction) {
160             CPInstruction cpIns = (CPInstruction)i;
161             ConstantPool cp = cpIns.getConstantPool();
162
163             if (!constantPool.equals(cp)) {
164                 cpIns.replaceConstantPool(constantPool);
165             }
166         }
167
168         
169         return instructions.subList(0, idx).add(i);
170     }
171
172     /**
173      * Insert an InstructionList to this InstructionList
174      *
175      * @param idx index of the InstructionList
176      * @param i Instruction to insert
177      */

178     public boolean insert(int idx, InstructionList il) {
179         modified = true;
180
181         if (il.size() == 0) {
182             return true;
183         }
184         
185 // if (constantPool.equals(il.constantPool)) {
186
// // If two lists share constantpool, just insert all of them
187
// return instructions.subList(0, idx).addAll(il.instructions);
188
// //instructions.addAll(il.instructions);
189
// }
190
// else {
191
// else insert instructions one by one
192
for (int i = 0; i < il.size(); i++) {
193                 insert(idx + i, il.get(i));
194             }
195 // }
196

197
198         return true;
199     }
200
201
202     /**
203      * Gets an Instruction at given index.
204      * IndexOutOfBoundsException is thrown if index is not within
205      * this InstructionList
206      *
207      * @param i index
208      * @return Instruction
209      */

210     public Instruction get(int i) {
211         Instruction ins = (Instruction)instructions.get(i);
212
213         if (ins instanceof TargetInstruction) {
214             return ((TargetInstruction)ins).getTarget();
215         }
216
217         return ins;
218     }
219
220
221     /**
222      * Replace an Instruction at given index
223      *
224      * @param idx Index of the Instruction to replace
225      * @param idx Index of the Instruction to replace
226      */

227     public void replace(int idx, Instruction i) {
228         if (i == null) {
229             // fail fast
230
throw new NullPointerException JavaDoc("Instruction may not be null");
231         }
232         
233         // NOTE: We should make sure, that branches, exception table,
234
// etc. remain valid.
235
instructions.set(idx, i);
236     }
237
238     public void replace(InstructionList il) {
239         replace(0, size(), il);
240     }
241
242     /**
243      * Replaces instructions with given range. Stack-usages are
244      * checked before replace. If stack usages do not match,
245      * an exception is thrown.
246      * Furthermore, if instructions to be replaced contain
247      * some sort of 'target', like with BranchInstruction,
248      * an exception is thrown. Only first instruction to be replaced
249      * is allowed to be a 'target'. If this is the case, first
250      * Instruction in new list becames that target.<p>
251      *
252      * Note, that exception table might get corrupted with this method.
253      *
254      * @param start start of old Instructions, inclusive
255      * @param end end of old Instructions, exclusive
256      * @param il InstructionList containing new Instructions.
257      * @exception IllegalArgumentException is thrown, if stack-usages
258      * do not match
259      * @exception IllegalArgumentException is thrown, if there is
260      * an instruction in the range, that is a target to some
261      * other entity.
262      */

263     public void replace(int start, int end, InstructionList il) {
264         InstructionList __il = createView(start, end);
265         int su1 = __il.stackUsage();
266         int su2 = il.stackUsage();
267
268         if (su1 != su2) {
269             System.out.println("Replacing ");
270             print(__il);
271             System.out.println("with");
272             print(il);
273             
274             throw new IllegalArgumentException JavaDoc("Cannot replace instruction list; stack usages differ: " + su1 + "(this list), " + su2 + " (other list)");
275         }
276
277
278         Instruction first = (Instruction)__il.instructions.get(0);
279         if (first instanceof TargetInstruction) {
280             // If first Instruction is a TargetInstruction,
281
// Move it to new list
282
TargetInstruction tIns = (TargetInstruction)first;
283             tIns.setTarget((Instruction)il.get(0));
284             il.instructions.set(0, tIns);
285         }
286
287         // Check, if view contains targets. If so, throw a n exception
288
// Only forst is allowed to be a target, so skip it
289
for (int i = 1; i < __il.size(); i++) {
290             if (__il.instructions.get(i) instanceof TargetInstruction) {
291                 throw new IllegalArgumentException JavaDoc("Cannot replace instructions since there are at least one 'target' instruction in it");
292             }
293         }
294
295         // replace instructions
296
__il.clear();
297         __il.add(il);
298     }
299
300
301     /**
302      * Calculates stack-usage of this InstructionList
303      *
304      * @return stack usage
305      */

306     public int stackUsage() {
307         int su = 0;
308         for (int i = 0; i < size(); i++) {
309             su += get(i).stackUsage();
310         }
311
312         return su;
313     }
314
315     /**
316      * Gets the size of this InstructionList.
317      *
318      * @return number of instructions in this InstructionList
319      */

320     public int size() {
321         return instructions.size();
322     }
323
324
325     /**
326      * Scans this InstructionList for a opcode. Scanning is started from
327      * the beginning of the InstructionList.
328      *
329      * @param ins Instruction to look for
330      * @return index of the instruction that was found, or -1 if not found.
331      */

332     public int indexOf(Instruction ins) {
333         return instructions.indexOf(ins);
334     }
335
336
337
338     /**
339      * Scans this InstructionList for a opcode. Scanning is started from
340      * the beginning of the InstructionList.
341      *
342      * @param opcode Opcode to look for
343      * @return index of the instruction that was found, or -1 if not found.
344      */

345     public int indexOf(byte opcode) {
346         return indexOf(new byte[]{opcode}, 0);
347     }
348
349     /**
350      * Scans this InstructionList for a opcode.
351      *
352      * @param start Index to start scanning from
353      * @param opcode Opcode to look for
354      * @return index of the instruction that was found, or -1 if not found.
355      */

356     public int indexOf(byte opcode, int fromIndex) {
357         return indexOf(new byte[]{opcode}, fromIndex);
358     }
359
360     /**
361      * Scans this InstructionList for opcodes.
362      *
363      * @param fromIndex Index to start scanning from
364      * @param opcodes opcode to look for
365      * @return index of the instruction that was found, or -1 if not found.
366      */

367     public int indexOf(byte[] opcodes, int fromIndex) {
368         for (int i = fromIndex; i < instructions.size(); i++) {
369             Instruction ins = (Instruction)instructions.get(i);
370             short opCode = ins.getOpcode();
371             
372             for (int j = 0; j < opcodes.length; j++) {
373                 if (opcodes[j] == opCode) {
374                     return i;
375                 }
376             }
377         }
378
379         return -1;
380     }
381
382     
383     int offset(Instruction i) {
384         return offset(0, i);
385     }
386
387     int offset(int start, Instruction ins) {
388         int offset = 0;
389         for (int i = start; i < instructions.size(); i++) {
390             if (instructions.get(i).equals(ins)) {
391                 return offset;
392             }
393
394             offset += ((Instruction)instructions.get(i)).length();
395         }
396
397         throw new JiapiRuntimeException("Isntruction not found; " + ins);
398     }
399
400     /**
401      * Get the Instruction at given offset.
402      *
403      * @return Instruction at offset, or null if there is no instruction
404      * at given offset.
405      */

406     Instruction instructionAtOffset(short offset) {
407         Iterator JavaDoc i = instructions.iterator();
408
409         while(i.hasNext()) {
410             Instruction ins = (Instruction)i.next();
411             if (ins.getOffset() == offset) {
412                 return ins;
413             }
414
415             if (ins.getOffset() > offset) {
416                 break;
417             }
418         }
419
420         return null;
421     }
422
423
424     public String JavaDoc toString() {
425         if (instructions.size() == 0) {
426             return "<empty>";
427         }
428
429         StringBuffer JavaDoc sb = new StringBuffer JavaDoc();
430         Iterator JavaDoc i = instructions.iterator();
431         int offset = 0;
432         int count = 0;
433         while(i.hasNext()) {
434             Instruction ins = (Instruction)i.next();
435             sb.append(" #");
436             sb.append(count);
437             if (count < 10) {
438                 sb.append(' ');
439             }
440             if (count < 100) {
441                 if (size() >= 100) {
442                     sb.append(' ');
443                 }
444             }
445
446             sb.append(" (");
447             sb.append(offset);
448             sb.append(") ");
449
450             sb.append(ins.toString());
451             if (i.hasNext()) {
452                 sb.append('\n');
453             }
454
455             count++;
456             offset += ins.length();
457         }
458
459         return sb.toString();
460     }
461
462
463     private boolean isModified() {
464         return modified;
465     }
466
467     /**
468      * Clears this InstructionList. All the Instructions are removed.
469      */

470     public void clear() {
471         instructions.clear();
472     }
473
474     /**
475      * Get the InstructionFactory, that is associated with this
476      * InstructionList.
477      */

478     public InstructionFactory getInstructionFactory() {
479         return new InstructionFactory(constantPool);
480     }
481
482     /**
483      * Gets the declaring JiapiMethod of this InstructionList
484      */

485     public JiapiMethod getDeclaringMethod() {
486         return declaringMethod;
487     }
488
489     // Package protected methods
490
void setDeclaringMethod(JiapiMethod jm) {
491         this.declaringMethod = jm;
492     }
493
494
495     /**
496      * Creates a view. View is created from <code>start</code> to the
497      * end of this list.
498      *
499      * @param start start of the view, inclusive
500      */

501     public InstructionList createView(int start) {
502         return createView(0, instructions.size());
503     }
504
505
506     /**
507      * Creates a view.
508      *
509      * @param start start of the view, inclusive
510      * @param end end of the view, exclusive
511      */

512     public InstructionList createView(int start, int end) {
513         InstructionList il =
514             new InstructionList(constantPool,instructions.subList(start, end));
515         il.setDeclaringMethod(declaringMethod);
516
517         return il;
518     }
519
520
521     /**
522      * Updates offsets of each instruction.
523      */

524     void updateOffsets() {
525         short offset = 0;
526         Iterator JavaDoc i = instructions.iterator();
527
528         while(i.hasNext()) {
529             Instruction ins = (Instruction)i.next();
530             ins.setOffset(offset);
531
532             // BUG: If instruction needs byte padding,
533
// we must do it here.
534
// if (ins instanceof CaseInstruction) ....
535
offset += ins.length();
536         }
537     }
538
539
540     private void print(InstructionList il) {
541         for (int i = 0; i < il.size(); i++) {
542             Instruction ins = il.get(i);
543             System.out.println(" #" + (i) + " " + ins + ", stack-usage: " +
544                                ins.stackUsage());
545         }
546     }
547
548
549         /**
550          * Change usage of local variables in target InstructionList so,
551          * that it will not overlap with 'other' list.
552          *
553          * If Advice declares local variables, they start from index 0,
554          * but so do local vars in target class. So this method changes
555          * local variable accesses in advice to start from
556          * <target.getMaxLocals()>
557          *
558          * @param advice InstructionList to change
559          * @param maxLocalsInOtherList Max-Locals in other list
560          */

561         private Instruction changeLocalVars(Instruction ins) {
562 // if (maxLocalsInOtherList == 0) {
563
// // Nothing to do, other list does not contain
564
// // local variables
565
// return advice;
566
// }
567

568             // BUG: These should not be needed. For some reason,
569
// JiapiMethod.getMaxLocals() returns wrong values?
570
// Commenting these out has no harm other than
571
// missing unused local variable slots
572
int maxLocals = getDeclaringMethod().getMaxLocals();
573             // following could be added, if no longs/doubles are in target
574
// list; they reserve two slots for local vars. Another
575
// silly stuff for longs/doubles in JVMs
576
// maxLocalsInOtherList--;
577

578             InstructionFactory factory = new InstructionFactory();
579         switch(ins.getOpcode()) {
580                     // -- ALOAD family --------------------------------------
581
case Opcodes.ALOAD_0:
582                         return factory.aload(maxLocals);
583                     case Opcodes.ALOAD_1:
584                         return factory.aload(maxLocals + 1);
585                     case Opcodes.ALOAD_2:
586                         return factory.aload(maxLocals + 2);
587                     case Opcodes.ALOAD_3:
588                         return factory.aload(maxLocals + 3);
589                     case Opcodes.ALOAD:
590                         // Handle this differently. This
591
// form of handling does not break exception table
592
// So, we minimize damage by handling this differently
593
ins.getBytes()[1] += (byte)maxLocals;
594                         break;
595                     case Opcodes.ASTORE_0:
596                         return factory.astore(maxLocals);
597                     case Opcodes.ASTORE_1:
598                         return factory.astore(maxLocals + 1);
599                     case Opcodes.ASTORE_2:
600                         return factory.astore(maxLocals + 2);
601                     case Opcodes.ASTORE_3:
602                         return factory.astore(maxLocals + 3);
603                     case Opcodes.ASTORE:
604                         // Handle this differently. This
605
// form of handling does not break exception table
606
// So, we minimize damage by handling this differently
607
ins.getBytes()[1] += (byte)maxLocals;
608                         break;
609
610                     // -- ILOAD family --------------------------------------
611
case Opcodes.ILOAD_0:
612                         return factory.iload(maxLocals);
613                     case Opcodes.ILOAD_1:
614                         return factory.iload(maxLocals + 1);
615                     case Opcodes.ILOAD_2:
616                         return factory.iload(maxLocals + 2);
617                     case Opcodes.ILOAD_3:
618                         return factory.iload(maxLocals + 3);
619                     case Opcodes.ILOAD:
620                         // Handle this differently. This
621
// form of handling does not break exception table
622
// So, we minimize damage by handling this differently
623
ins.getBytes()[1] += (byte)maxLocals;
624                         break;
625                     case Opcodes.ISTORE_0:
626                         return factory.istore(maxLocals);
627                     case Opcodes.ISTORE_1:
628                         return factory.istore(maxLocals + 1);
629                     case Opcodes.ISTORE_2:
630                         return factory.istore(maxLocals + 2);
631                     case Opcodes.ISTORE_3:
632                         return factory.istore(maxLocals + 3);
633                     case Opcodes.ISTORE:
634                         // Handle this differently. This
635
// form of handling does not break exception table
636
// So, we minimize damage by handling this differently
637
ins.getBytes()[1] += (byte)maxLocals;
638                         break;
639
640                     // -- DLOAD family --------------------------------------
641
case Opcodes.DLOAD_0:
642                         return factory.dload(maxLocals);
643                     case Opcodes.DLOAD_1:
644                         return factory.dload(maxLocals + 1);
645                     case Opcodes.DLOAD_2:
646                         return factory.dload(maxLocals + 2);
647                     case Opcodes.DLOAD_3:
648                         return factory.dload(maxLocals + 3);
649                     case Opcodes.DLOAD:
650                         // Handle this differently. This
651
// form of handling does not break exception table
652
// So, we minimize damage by handling this differently
653
ins.getBytes()[1] += (byte)maxLocals;
654                         break;
655                     case Opcodes.DSTORE_0:
656                         return factory.dstore(maxLocals);
657                     case Opcodes.DSTORE_1:
658                         return factory.dstore(maxLocals + 1);
659                     case Opcodes.DSTORE_2:
660                         return factory.dstore(maxLocals + 2);
661                     case Opcodes.DSTORE_3:
662                         return factory.dstore(maxLocals + 3);
663                     case Opcodes.DSTORE:
664                         // Handle this differently. This
665
// form of handling does not break exception table
666
// So, we minimize damage by handling this differently
667
ins.getBytes()[1] += (byte)maxLocals;
668                         break;
669
670                     // -- LLOAD family --------------------------------------
671
case Opcodes.LLOAD_0:
672                         return factory.lload(maxLocals);
673                     case Opcodes.LLOAD_1:
674                         return factory.lload(maxLocals + 1);
675                     case Opcodes.LLOAD_2:
676                         return factory.lload(maxLocals + 2);
677                     case Opcodes.LLOAD_3:
678                         return factory.lload(maxLocals + 3);
679                     case Opcodes.LLOAD:
680                         // Handle this differently. This
681
// form of handling does not break exception table
682
// So, we minimize damage by handling this differently
683
ins.getBytes()[1] += (byte)maxLocals;
684                         break;
685                     case Opcodes.LSTORE_0:
686                         return factory.lstore(maxLocals);
687                     case Opcodes.LSTORE_1:
688                         return factory.lstore(maxLocals + 1);
689                     case Opcodes.LSTORE_2:
690                         return factory.lstore(maxLocals + 2);
691                     case Opcodes.LSTORE_3:
692                         return factory.lstore(maxLocals + 3);
693                     case Opcodes.LSTORE:
694                         // Handle this differently. This
695
// form of handling does not break exception table
696
// So, we minimize damage by handling this differently
697
ins.getBytes()[1] += (byte)maxLocals;
698                         break;
699                         
700                     // -- FLOAD family --------------------------------------
701
case Opcodes.FLOAD_0:
702                         return factory.fload(maxLocals);
703                     case Opcodes.FLOAD_1:
704                         return factory.fload(maxLocals + 1);
705                     case Opcodes.FLOAD_2:
706                         return factory.fload(maxLocals + 2);
707                     case Opcodes.FLOAD_3:
708                         return factory.fload(maxLocals + 3);
709                     case Opcodes.FLOAD:
710                         // Handle this differently. This
711
// form of handling does not break exception table
712
// So, we minimize damage by handling this differently
713
ins.getBytes()[1] += (byte)maxLocals;
714                         break;
715                     case Opcodes.FSTORE_0:
716                         return factory.fstore(maxLocals);
717                     case Opcodes.FSTORE_1:
718                         return factory.fstore(maxLocals + 1);
719                     case Opcodes.FSTORE_2:
720                         return factory.fstore(maxLocals + 2);
721                     case Opcodes.FSTORE_3:
722                         return factory.fstore(maxLocals + 3);
723                     case Opcodes.FSTORE:
724                         // Handle this differently. This
725
// form of handling does not break exception table
726
// So, we minimize damage by handling this differently
727
ins.getBytes()[1] += (byte)maxLocals;
728                         break;
729                         
730         }
731
732             return ins;
733         }
734 }
735
Popular Tags