KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > oracle > toplink > libraries > asm > CodeWriter


1 /***
2  * ASM: a very small and fast Java bytecode manipulation framework
3  * Copyright (c) 2000,2002,2003 INRIA, France Telecom
4  * All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  * 1. Redistributions of source code must retain the above copyright
10  * notice, this list of conditions and the following disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  * notice, this list of conditions and the following disclaimer in the
13  * documentation and/or other materials provided with the distribution.
14  * 3. Neither the name of the copyright holders nor the names of its
15  * contributors may be used to endorse or promote products derived from
16  * this software without specific prior written permission.
17  *
18  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
19  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
22  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
23  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
24  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
25  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
26  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
27  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
28  * THE POSSIBILITY OF SUCH DAMAGE.
29  */

30
31 package oracle.toplink.libraries.asm;
32
33 /**
34  * A {@link CodeVisitor CodeVisitor} that generates Java bytecode instructions.
35  * Each visit method of this class appends the bytecode corresponding to the
36  * visited instruction to a byte vector, in the order these methods are called.
37  *
38  * @author Eric Bruneton
39  */

40
41 public class CodeWriter implements CodeVisitor {
42
43   /**
44    * <tt>true</tt> if preconditions must be checked at runtime or not.
45    */

46
47   final static boolean CHECK = false;
48
49   /**
50    * Next code writer (see {@link ClassWriter#firstMethod firstMethod}).
51    */

52
53   CodeWriter next;
54
55   /**
56    * The class writer to which this method must be added.
57    */

58
59   private ClassWriter cw;
60
61   /**
62    * The index of the constant pool item that contains the name of this method.
63    */

64
65   private int name;
66
67   /**
68    * The index of the constant pool item that contains the descriptor of this
69    * method.
70    */

71
72   private int desc;
73
74   /**
75    * Access flags of this method.
76    */

77
78   private int access;
79
80   /**
81    * Maximum stack size of this method.
82    */

83
84   private int maxStack;
85
86   /**
87    * Maximum number of local variables for this method.
88    */

89
90   private int maxLocals;
91
92   /**
93    * The bytecode of this method.
94    */

95
96   private ByteVector code = new ByteVector();
97
98   /**
99    * Number of entries in the catch table of this method.
100    */

101
102   private int catchCount;
103
104   /**
105    * The catch table of this method.
106    */

107
108   private ByteVector catchTable;
109
110   /**
111    * Number of exceptions that can be thrown by this method.
112    */

113
114   private int exceptionCount;
115
116   /**
117    * The exceptions that can be thrown by this method. More
118    * precisely, this array contains the indexes of the constant pool items
119    * that contain the internal names of these exception classes.
120    */

121
122   private int[] exceptions;
123
124   /**
125    * The non standard attributes of the method.
126    */

127
128   private Attribute attrs;
129
130   /**
131    * Number of entries in the LocalVariableTable attribute.
132    */

133
134   private int localVarCount;
135
136   /**
137    * The LocalVariableTable attribute.
138    */

139
140   private ByteVector localVar;
141
142   /**
143    * Number of entries in the LineNumberTable attribute.
144    */

145
146   private int lineNumberCount;
147
148   /**
149    * The LineNumberTable attribute.
150    */

151
152   private ByteVector lineNumber;
153
154   /**
155    * The non standard attributes of the method's code.
156    */

157
158   private Attribute cattrs;
159
160   /**
161    * Indicates if some jump instructions are too small and need to be resized.
162    */

163
164   private boolean resize;
165
166   // --------------------------------------------------------------------------
167
// Fields for the control flow graph analysis algorithm (used to compute the
168
// maximum stack size). A control flow graph contains one node per "basic
169
// block", and one edge per "jump" from one basic block to another. Each node
170
// (i.e., each basic block) is represented by the Label object that
171
// corresponds to the first instruction of this basic block. Each node also
172
// stores the list of its successors in the graph, as a linked list of Edge
173
// objects.
174
// --------------------------------------------------------------------------
175

176   /**
177    * <tt>true</tt> if the maximum stack size and number of local variables must
178    * be automatically computed.
179    */

180
181   private final boolean computeMaxs;
182
183   /**
184    * The (relative) stack size after the last visited instruction. This size is
185    * relative to the beginning of the current basic block, i.e., the true stack
186    * size after the last visited instruction is equal to the {@link
187    * Label#beginStackSize beginStackSize} of the current basic block plus
188    * <tt>stackSize</tt>.
189    */

190
191   private int stackSize;
192
193   /**
194    * The (relative) maximum stack size after the last visited instruction. This
195    * size is relative to the beginning of the current basic block, i.e., the
196    * true maximum stack size after the last visited instruction is equal to the
197    * {@link Label#beginStackSize beginStackSize} of the current basic block plus
198    * <tt>stackSize</tt>.
199    */

200
201   private int maxStackSize;
202
203   /**
204    * The current basic block. This block is the basic block to which the next
205    * instruction to be visited must be added.
206    */

207
208   private Label currentBlock;
209
210   /**
211    * The basic block stack used by the control flow analysis algorithm. This
212    * stack is represented by a linked list of {@link Label Label} objects,
213    * linked to each other by their {@link Label#next} field. This stack must
214    * not be confused with the JVM stack used to execute the JVM instructions!
215    */

216
217   private Label blockStack;
218
219   /**
220    * The stack size variation corresponding to each JVM instruction. This stack
221    * variation is equal to the size of the values produced by an instruction,
222    * minus the size of the values consumed by this instruction.
223    */

224
225   private final static int[] SIZE;
226
227   // --------------------------------------------------------------------------
228
// Fields to optimize the creation of {@link Edge Edge} objects by using a
229
// pool of reusable objects. The (shared) pool is a linked list of Edge
230
// objects, linked to each other by their {@link Edge#poolNext} field. Each
231
// time a CodeWriter needs to allocate an Edge, it removes the first Edge
232
// of the pool and adds it to a private list of Edge objects. After the end
233
// of the control flow analysis algorithm, the Edge objects in the private
234
// list of the CodeWriter are added back to the pool (by appending this
235
// private list to the pool list; in order to do this in constant time, both
236
// head and tail of the private list are stored in this CodeWriter).
237
// --------------------------------------------------------------------------
238

239   /**
240    * The head of the list of {@link Edge Edge} objects used by this {@link
241    * CodeWriter CodeWriter}. These objects, linked to each other by their
242    * {@link Edge#poolNext} field, are added back to the shared pool at the
243    * end of the control flow analysis algorithm.
244    */

245
246   private Edge head;
247
248   /**
249    * The tail of the list of {@link Edge Edge} objects used by this {@link
250    * CodeWriter CodeWriter}. These objects, linked to each other by their
251    * {@link Edge#poolNext} field, are added back to the shared pool at the
252    * end of the control flow analysis algorithm.
253    */

254
255   private Edge tail;
256
257   /**
258    * The shared pool of {@link Edge Edge} objects. This pool is a linked list
259    * of Edge objects, linked to each other by their {@link Edge#poolNext} field.
260    */

261
262   private static Edge pool;
263
264   // --------------------------------------------------------------------------
265
// Static initializer
266
// --------------------------------------------------------------------------
267

268   /**
269    * Computes the stack size variation corresponding to each JVM instruction.
270    */

271
272   static {
273     int i;
274     int[] b = new int[202];
275     String JavaDoc s =
276       "EFFFFFFFFGGFFFGGFFFEEFGFGFEEEEEEEEEEEEEEEEEEEEDEDEDDDDDCDCDEEEEEEEEE" +
277       "EEEEEEEEEEEBABABBBBDCFFFGGGEDCDCDCDCDCDCDCDCDCDCEEEEDDDDDDDCDCDCEFEF" +
278       "DDEEFFDEDEEEBDDBBDDDDDDCCCCCCCCEFEDDDCDCDEEEEEEEEEEFEEEEEEDDEEDDEE";
279     for (i = 0; i < b.length; ++i) {
280       b[i] = s.charAt(i) - 'E';
281     }
282     SIZE = b;
283
284     /* code to generate the above string
285
286     int NA = 0; // not applicable (unused opcode or variable size opcode)
287
288     b = new int[] {
289       0, //NOP, // visitInsn
290       1, //ACONST_NULL, // -
291       1, //ICONST_M1, // -
292       1, //ICONST_0, // -
293       1, //ICONST_1, // -
294       1, //ICONST_2, // -
295       1, //ICONST_3, // -
296       1, //ICONST_4, // -
297       1, //ICONST_5, // -
298       2, //LCONST_0, // -
299       2, //LCONST_1, // -
300       1, //FCONST_0, // -
301       1, //FCONST_1, // -
302       1, //FCONST_2, // -
303       2, //DCONST_0, // -
304       2, //DCONST_1, // -
305       1, //BIPUSH, // visitIntInsn
306       1, //SIPUSH, // -
307       1, //LDC, // visitLdcInsn
308       NA, //LDC_W, // -
309       NA, //LDC2_W, // -
310       1, //ILOAD, // visitVarInsn
311       2, //LLOAD, // -
312       1, //FLOAD, // -
313       2, //DLOAD, // -
314       1, //ALOAD, // -
315       NA, //ILOAD_0, // -
316       NA, //ILOAD_1, // -
317       NA, //ILOAD_2, // -
318       NA, //ILOAD_3, // -
319       NA, //LLOAD_0, // -
320       NA, //LLOAD_1, // -
321       NA, //LLOAD_2, // -
322       NA, //LLOAD_3, // -
323       NA, //FLOAD_0, // -
324       NA, //FLOAD_1, // -
325       NA, //FLOAD_2, // -
326       NA, //FLOAD_3, // -
327       NA, //DLOAD_0, // -
328       NA, //DLOAD_1, // -
329       NA, //DLOAD_2, // -
330       NA, //DLOAD_3, // -
331       NA, //ALOAD_0, // -
332       NA, //ALOAD_1, // -
333       NA, //ALOAD_2, // -
334       NA, //ALOAD_3, // -
335       -1, //IALOAD, // visitInsn
336       0, //LALOAD, // -
337       -1, //FALOAD, // -
338       0, //DALOAD, // -
339       -1, //AALOAD, // -
340       -1, //BALOAD, // -
341       -1, //CALOAD, // -
342       -1, //SALOAD, // -
343       -1, //ISTORE, // visitVarInsn
344       -2, //LSTORE, // -
345       -1, //FSTORE, // -
346       -2, //DSTORE, // -
347       -1, //ASTORE, // -
348       NA, //ISTORE_0, // -
349       NA, //ISTORE_1, // -
350       NA, //ISTORE_2, // -
351       NA, //ISTORE_3, // -
352       NA, //LSTORE_0, // -
353       NA, //LSTORE_1, // -
354       NA, //LSTORE_2, // -
355       NA, //LSTORE_3, // -
356       NA, //FSTORE_0, // -
357       NA, //FSTORE_1, // -
358       NA, //FSTORE_2, // -
359       NA, //FSTORE_3, // -
360       NA, //DSTORE_0, // -
361       NA, //DSTORE_1, // -
362       NA, //DSTORE_2, // -
363       NA, //DSTORE_3, // -
364       NA, //ASTORE_0, // -
365       NA, //ASTORE_1, // -
366       NA, //ASTORE_2, // -
367       NA, //ASTORE_3, // -
368       -3, //IASTORE, // visitInsn
369       -4, //LASTORE, // -
370       -3, //FASTORE, // -
371       -4, //DASTORE, // -
372       -3, //AASTORE, // -
373       -3, //BASTORE, // -
374       -3, //CASTORE, // -
375       -3, //SASTORE, // -
376       -1, //POP, // -
377       -2, //POP2, // -
378       1, //DUP, // -
379       1, //DUP_X1, // -
380       1, //DUP_X2, // -
381       2, //DUP2, // -
382       2, //DUP2_X1, // -
383       2, //DUP2_X2, // -
384       0, //SWAP, // -
385       -1, //IADD, // -
386       -2, //LADD, // -
387       -1, //FADD, // -
388       -2, //DADD, // -
389       -1, //ISUB, // -
390       -2, //LSUB, // -
391       -1, //FSUB, // -
392       -2, //DSUB, // -
393       -1, //IMUL, // -
394       -2, //LMUL, // -
395       -1, //FMUL, // -
396       -2, //DMUL, // -
397       -1, //IDIV, // -
398       -2, //LDIV, // -
399       -1, //FDIV, // -
400       -2, //DDIV, // -
401       -1, //IREM, // -
402       -2, //LREM, // -
403       -1, //FREM, // -
404       -2, //DREM, // -
405       0, //INEG, // -
406       0, //LNEG, // -
407       0, //FNEG, // -
408       0, //DNEG, // -
409       -1, //ISHL, // -
410       -1, //LSHL, // -
411       -1, //ISHR, // -
412       -1, //LSHR, // -
413       -1, //IUSHR, // -
414       -1, //LUSHR, // -
415       -1, //IAND, // -
416       -2, //LAND, // -
417       -1, //IOR, // -
418       -2, //LOR, // -
419       -1, //IXOR, // -
420       -2, //LXOR, // -
421       0, //IINC, // visitIincInsn
422       1, //I2L, // visitInsn
423       0, //I2F, // -
424       1, //I2D, // -
425       -1, //L2I, // -
426       -1, //L2F, // -
427       0, //L2D, // -
428       0, //F2I, // -
429       1, //F2L, // -
430       1, //F2D, // -
431       -1, //D2I, // -
432       0, //D2L, // -
433       -1, //D2F, // -
434       0, //I2B, // -
435       0, //I2C, // -
436       0, //I2S, // -
437       -3, //LCMP, // -
438       -1, //FCMPL, // -
439       -1, //FCMPG, // -
440       -3, //DCMPL, // -
441       -3, //DCMPG, // -
442       -1, //IFEQ, // visitJumpInsn
443       -1, //IFNE, // -
444       -1, //IFLT, // -
445       -1, //IFGE, // -
446       -1, //IFGT, // -
447       -1, //IFLE, // -
448       -2, //IF_ICMPEQ, // -
449       -2, //IF_ICMPNE, // -
450       -2, //IF_ICMPLT, // -
451       -2, //IF_ICMPGE, // -
452       -2, //IF_ICMPGT, // -
453       -2, //IF_ICMPLE, // -
454       -2, //IF_ACMPEQ, // -
455       -2, //IF_ACMPNE, // -
456       0, //GOTO, // -
457       1, //JSR, // -
458       0, //RET, // visitVarInsn
459       -1, //TABLESWITCH, // visiTableSwitchInsn
460       -1, //LOOKUPSWITCH, // visitLookupSwitch
461       -1, //IRETURN, // visitInsn
462       -2, //LRETURN, // -
463       -1, //FRETURN, // -
464       -2, //DRETURN, // -
465       -1, //ARETURN, // -
466       0, //RETURN, // -
467       NA, //GETSTATIC, // visitFieldInsn
468       NA, //PUTSTATIC, // -
469       NA, //GETFIELD, // -
470       NA, //PUTFIELD, // -
471       NA, //INVOKEVIRTUAL, // visitMethodInsn
472       NA, //INVOKESPECIAL, // -
473       NA, //INVOKESTATIC, // -
474       NA, //INVOKEINTERFACE, // -
475       NA, //UNUSED, // NOT VISITED
476       1, //NEW, // visitTypeInsn
477       0, //NEWARRAY, // visitIntInsn
478       0, //ANEWARRAY, // visitTypeInsn
479       0, //ARRAYLENGTH, // visitInsn
480       NA, //ATHROW, // -
481       0, //CHECKCAST, // visitTypeInsn
482       0, //INSTANCEOF, // -
483       -1, //MONITORENTER, // visitInsn
484       -1, //MONITOREXIT, // -
485       NA, //WIDE, // NOT VISITED
486       NA, //MULTIANEWARRAY, // visitMultiANewArrayInsn
487       -1, //IFNULL, // visitJumpInsn
488       -1, //IFNONNULL, // -
489       NA, //GOTO_W, // -
490       NA, //JSR_W, // -
491     };
492     for (i = 0; i < b.length; ++i) {
493       System.err.print((char)('E' + b[i]));
494     }
495     System.err.println();
496     */

497   }
498
499   // --------------------------------------------------------------------------
500
// Constructor
501
// --------------------------------------------------------------------------
502

503   /**
504    * Constructs a CodeWriter.
505    *
506    * @param cw the class writer in which the method must be added.
507    * @param computeMaxs <tt>true</tt> if the maximum stack size and number of
508    * local variables must be automatically computed.
509    */

510
511   protected CodeWriter (final ClassWriter cw, final boolean computeMaxs) {
512     if (cw.firstMethod == null) {
513       cw.firstMethod = this;
514     } else {
515       cw.lastMethod.next = this;
516     }
517     cw.lastMethod = this;
518     this.cw = cw;
519     this.computeMaxs = computeMaxs;
520     if (computeMaxs) {
521       // pushes the first block onto the stack of blocks to be visited
522
currentBlock = new Label();
523       currentBlock.pushed = true;
524       blockStack = currentBlock;
525     }
526   }
527
528   /**
529    * Initializes this CodeWriter to define the bytecode of the specified method.
530    *
531    * @param access the method's access flags (see {@link Constants}).
532    * @param name the method's name.
533    * @param desc the method's descriptor (see {@link Type Type}).
534    * @param exceptions the internal names of the method's exceptions. May be
535    * <tt>null</tt>.
536    * @param attrs the non standard attributes of the method.
537    */

538
539   protected void init (
540     final int access,
541     final String JavaDoc name,
542     final String JavaDoc desc,
543     final String JavaDoc[] exceptions,
544     final Attribute attrs)
545   {
546     this.access = access;
547     this.name = cw.newUTF8(name);
548     this.desc = cw.newUTF8(desc);
549     if (exceptions != null && exceptions.length > 0) {
550       exceptionCount = exceptions.length;
551       this.exceptions = new int[exceptionCount];
552       for (int i = 0; i < exceptionCount; ++i) {
553         this.exceptions[i] = cw.newClass(exceptions[i]);
554       }
555     }
556     this.attrs = attrs;
557     if (computeMaxs) {
558       // updates maxLocals
559
int size = getArgumentsAndReturnSizes(desc) >> 2;
560       if ((access & Constants.ACC_STATIC) != 0) {
561         --size;
562       }
563       if (size > maxLocals) {
564         maxLocals = size;
565       }
566     }
567   }
568
569   // --------------------------------------------------------------------------
570
// Implementation of the CodeVisitor interface
571
// --------------------------------------------------------------------------
572

573   public void visitInsn (final int opcode) {
574     if (computeMaxs) {
575       // updates current and max stack sizes
576
int size = stackSize + SIZE[opcode];
577       if (size > maxStackSize) {
578         maxStackSize = size;
579       }
580       stackSize = size;
581       // if opcode == ATHROW or xRETURN, ends current block (no successor)
582
if ((opcode >= Constants.IRETURN && opcode <= Constants.RETURN) ||
583           opcode == Constants.ATHROW)
584       {
585         if (currentBlock != null) {
586           currentBlock.maxStackSize = maxStackSize;
587           currentBlock = null;
588         }
589       }
590     }
591     // adds the instruction to the bytecode of the method
592
code.putByte(opcode);
593   }
594
595   public void visitIntInsn (final int opcode, final int operand) {
596     if (computeMaxs && opcode != Constants.NEWARRAY) {
597       // updates current and max stack sizes only if opcode == NEWARRAY
598
// (stack size variation = 0 for BIPUSH or SIPUSH)
599
int size = stackSize + 1;
600       if (size > maxStackSize) {
601         maxStackSize = size;
602       }
603       stackSize = size;
604     }
605     // adds the instruction to the bytecode of the method
606
if (opcode == Constants.SIPUSH) {
607       code.put12(opcode, operand);
608     } else { // BIPUSH or NEWARRAY
609
code.put11(opcode, operand);
610     }
611   }
612
613   public void visitVarInsn (final int opcode, final int var) {
614     if (computeMaxs) {
615       // updates current and max stack sizes
616
if (opcode == Constants.RET) {
617         // no stack change, but end of current block (no successor)
618
if (currentBlock != null) {
619           currentBlock.maxStackSize = maxStackSize;
620           currentBlock = null;
621         }
622       } else { // xLOAD or xSTORE
623
int size = stackSize + SIZE[opcode];
624         if (size > maxStackSize) {
625           maxStackSize = size;
626         }
627         stackSize = size;
628       }
629       // updates max locals
630
int n;
631       if (opcode == Constants.LLOAD || opcode == Constants.DLOAD ||
632           opcode == Constants.LSTORE || opcode == Constants.DSTORE)
633       {
634         n = var + 2;
635       } else {
636         n = var + 1;
637       }
638       if (n > maxLocals) {
639         maxLocals = n;
640       }
641     }
642     // adds the instruction to the bytecode of the method
643
if (var < 4 && opcode != Constants.RET) {
644       int opt;
645       if (opcode < Constants.ISTORE) {
646         opt = 26 /*ILOAD_0*/ + ((opcode - Constants.ILOAD) << 2) + var;
647       } else {
648         opt = 59 /*ISTORE_0*/ + ((opcode - Constants.ISTORE) << 2) + var;
649       }
650       code.putByte(opt);
651     } else if (var >= 256) {
652       code.putByte(196 /*WIDE*/).put12(opcode, var);
653     } else {
654       code.put11(opcode, var);
655     }
656   }
657
658   public void visitTypeInsn (final int opcode, final String JavaDoc desc) {
659     if (computeMaxs && opcode == Constants.NEW) {
660       // updates current and max stack sizes only if opcode == NEW
661
// (stack size variation = 0 for ANEWARRAY, CHECKCAST, INSTANCEOF)
662
int size = stackSize + 1;
663       if (size > maxStackSize) {
664         maxStackSize = size;
665       }
666       stackSize = size;
667     }
668     // adds the instruction to the bytecode of the method
669
code.put12(opcode, cw.newClass(desc));
670   }
671
672   public void visitFieldInsn (
673     final int opcode,
674     final String JavaDoc owner,
675     final String JavaDoc name,
676     final String JavaDoc desc)
677   {
678     if (computeMaxs) {
679       int size;
680       // computes the stack size variation
681
char c = desc.charAt(0);
682       switch (opcode) {
683         case Constants.GETSTATIC:
684           size = stackSize + (c == 'D' || c == 'J' ? 2 : 1);
685           break;
686         case Constants.PUTSTATIC:
687           size = stackSize + (c == 'D' || c == 'J' ? -2 : -1);
688           break;
689         case Constants.GETFIELD:
690           size = stackSize + (c == 'D' || c == 'J' ? 1 : 0);
691           break;
692         //case Constants.PUTFIELD:
693
default:
694           size = stackSize + (c == 'D' || c == 'J' ? -3 : -2);
695           break;
696       }
697       // updates current and max stack sizes
698
if (size > maxStackSize) {
699         maxStackSize = size;
700       }
701       stackSize = size;
702     }
703     // adds the instruction to the bytecode of the method
704
code.put12(opcode, cw.newField(owner, name, desc));
705   }
706
707   public void visitMethodInsn (
708     final int opcode,
709     final String JavaDoc owner,
710     final String JavaDoc name,
711     final String JavaDoc desc)
712   {
713     boolean itf = opcode == Constants.INVOKEINTERFACE;
714     Item i = cw.newMethodItem(owner, name, desc, itf);
715     int argSize = i.intVal;
716     if (computeMaxs) {
717       // computes the stack size variation. In order not to recompute several
718
// times this variation for the same Item, we use the intVal field of
719
// this item to store this variation, once it has been computed. More
720
// precisely this intVal field stores the sizes of the arguments and of
721
// the return value corresponding to desc.
722
if (argSize == 0) {
723         // the above sizes have not been computed yet, so we compute them...
724
argSize = getArgumentsAndReturnSizes(desc);
725         // ... and we save them in order not to recompute them in the future
726
i.intVal = argSize;
727       }
728       int size;
729       if (opcode == Constants.INVOKESTATIC) {
730         size = stackSize - (argSize >> 2) + (argSize & 0x03) + 1;
731       } else {
732         size = stackSize - (argSize >> 2) + (argSize & 0x03);
733       }
734       // updates current and max stack sizes
735
if (size > maxStackSize) {
736         maxStackSize = size;
737       }
738       stackSize = size;
739     }
740     // adds the instruction to the bytecode of the method
741
if (itf) {
742       if (!computeMaxs) {
743         if (argSize == 0) {
744           argSize = getArgumentsAndReturnSizes(desc);
745           i.intVal = argSize;
746         }
747       }
748       code.put12(Constants.INVOKEINTERFACE, i.index).put11(argSize >> 2, 0);
749     } else {
750       code.put12(opcode, i.index);
751     }
752   }
753
754   public void visitJumpInsn (final int opcode, final Label label) {
755     if (CHECK) {
756       if (label.owner == null) {
757         label.owner = this;
758       } else if (label.owner != this) {
759         throw new IllegalArgumentException JavaDoc();
760       }
761     }
762     if (computeMaxs) {
763       if (opcode == Constants.GOTO) {
764         // no stack change, but end of current block (with one new successor)
765
if (currentBlock != null) {
766           currentBlock.maxStackSize = maxStackSize;
767           addSuccessor(stackSize, label);
768           currentBlock = null;
769         }
770       } else if (opcode == Constants.JSR) {
771         if (currentBlock != null) {
772           addSuccessor(stackSize + 1, label);
773         }
774       } else {
775         // updates current stack size (max stack size unchanged because stack
776
// size variation always negative in this case)
777
stackSize += SIZE[opcode];
778         if (currentBlock != null) {
779           addSuccessor(stackSize, label);
780         }
781       }
782     }
783     // adds the instruction to the bytecode of the method
784
if (label.resolved && label.position - code.length < Short.MIN_VALUE) {
785       // case of a backward jump with an offset < -32768. In this case we
786
// automatically replace GOTO with GOTO_W, JSR with JSR_W and IFxxx <l>
787
// with IFNOTxxx <l'> GOTO_W <l>, where IFNOTxxx is the "opposite" opcode
788
// of IFxxx (i.e., IFNE for IFEQ) and where <l'> designates the
789
// instruction just after the GOTO_W.
790
if (opcode == Constants.GOTO) {
791         code.putByte(200); // GOTO_W
792
} else if (opcode == Constants.JSR) {
793         code.putByte(201); // JSR_W
794
} else {
795         code.putByte(opcode <= 166 ? ((opcode + 1) ^ 1) - 1 : opcode ^ 1);
796         code.putShort(8); // jump offset
797
code.putByte(200); // GOTO_W
798
}
799       label.put(this, code, code.length - 1, true);
800     } else {
801       // case of a backward jump with an offset >= -32768, or of a forward jump
802
// with, of course, an unknown offset. In these cases we store the offset
803
// in 2 bytes (which will be increased in resizeInstructions, if needed).
804
code.putByte(opcode);
805       label.put(this, code, code.length - 1, false);
806     }
807   }
808
809   public void visitLabel (final Label label) {
810     if (CHECK) {
811       if (label.owner == null) {
812         label.owner = this;
813       } else if (label.owner != this) {
814         throw new IllegalArgumentException JavaDoc();
815       }
816     }
817     if (computeMaxs) {
818       if (currentBlock != null) {
819         // ends current block (with one new successor)
820
currentBlock.maxStackSize = maxStackSize;
821         addSuccessor(stackSize, label);
822       }
823       // begins a new current block,
824
// resets the relative current and max stack sizes
825
currentBlock = label;
826       stackSize = 0;
827       maxStackSize = 0;
828     }
829     // resolves previous forward references to label, if any
830
resize |= label.resolve(this, code.length, code.data);
831   }
832
833   public void visitLdcInsn (final Object JavaDoc cst) {
834     Item i = cw.newConstItem(cst);
835     if (computeMaxs) {
836       int size;
837       // computes the stack size variation
838
if (i.type == ClassWriter.LONG || i.type == ClassWriter.DOUBLE) {
839         size = stackSize + 2;
840       } else {
841         size = stackSize + 1;
842       }
843       // updates current and max stack sizes
844
if (size > maxStackSize) {
845         maxStackSize = size;
846       }
847       stackSize = size;
848     }
849     // adds the instruction to the bytecode of the method
850
int index = i.index;
851     if (i.type == ClassWriter.LONG || i.type == ClassWriter.DOUBLE) {
852       code.put12(20 /*LDC2_W*/, index);
853     } else if (index >= 256) {
854       code.put12(19 /*LDC_W*/, index);
855     } else {
856       code.put11(Constants.LDC, index);
857     }
858   }
859
860   public void visitIincInsn (final int var, final int increment) {
861     if (computeMaxs) {
862       // updates max locals only (no stack change)
863
int n = var + 1;
864       if (n > maxLocals) {
865         maxLocals = n;
866       }
867     }
868     // adds the instruction to the bytecode of the method
869
if ((var > 255) || (increment > 127) || (increment < -128)) {
870       code.putByte(196 /*WIDE*/).put12(Constants.IINC, var).putShort(increment);
871     } else {
872       code.putByte(Constants.IINC).put11(var, increment);
873     }
874   }
875
876   public void visitTableSwitchInsn (
877     final int min,
878     final int max,
879     final Label dflt,
880     final Label labels[])
881   {
882     if (computeMaxs) {
883       // updates current stack size (max stack size unchanged)
884
--stackSize;
885       // ends current block (with many new successors)
886
if (currentBlock != null) {
887         currentBlock.maxStackSize = maxStackSize;
888         addSuccessor(stackSize, dflt);
889         for (int i = 0; i < labels.length; ++i) {
890           addSuccessor(stackSize, labels[i]);
891         }
892         currentBlock = null;
893       }
894     }
895     // adds the instruction to the bytecode of the method
896
int source = code.length;
897     code.putByte(Constants.TABLESWITCH);
898     while (code.length % 4 != 0) {
899       code.putByte(0);
900     }
901     dflt.put(this, code, source, true);
902     code.putInt(min).putInt(max);
903     for (int i = 0; i < labels.length; ++i) {
904       labels[i].put(this, code, source, true);
905     }
906   }
907
908   public void visitLookupSwitchInsn (
909     final Label dflt,
910     final int keys[],
911     final Label labels[])
912   {
913     if (computeMaxs) {
914       // updates current stack size (max stack size unchanged)
915
--stackSize;
916       // ends current block (with many new successors)
917
if (currentBlock != null) {
918         currentBlock.maxStackSize = maxStackSize;
919         addSuccessor(stackSize, dflt);
920         for (int i = 0; i < labels.length; ++i) {
921           addSuccessor(stackSize, labels[i]);
922         }
923         currentBlock = null;
924       }
925     }
926     // adds the instruction to the bytecode of the method
927
int source = code.length;
928     code.putByte(Constants.LOOKUPSWITCH);
929     while (code.length % 4 != 0) {
930       code.putByte(0);
931     }
932     dflt.put(this, code, source, true);
933     code.putInt(labels.length);
934     for (int i = 0; i < labels.length; ++i) {
935       code.putInt(keys[i]);
936       labels[i].put(this, code, source, true);
937     }
938   }
939
940   public void visitMultiANewArrayInsn (final String JavaDoc desc, final int dims) {
941     if (computeMaxs) {
942       // updates current stack size (max stack size unchanged because stack
943
// size variation always negative or null)
944
stackSize += 1 - dims;
945     }
946     // adds the instruction to the bytecode of the method
947
code.put12(Constants.MULTIANEWARRAY, cw.newClass(desc)).putByte(dims);
948   }
949
950   public void visitTryCatchBlock (
951     final Label start,
952     final Label end,
953     final Label handler,
954     final String JavaDoc type)
955   {
956     if (CHECK) {
957       if (start.owner != this || end.owner != this || handler.owner != this) {
958         throw new IllegalArgumentException JavaDoc();
959       }
960       if (!start.resolved || !end.resolved || !handler.resolved) {
961         throw new IllegalArgumentException JavaDoc();
962       }
963     }
964     if (computeMaxs) {
965       // pushes handler block onto the stack of blocks to be visited
966
if (!handler.pushed) {
967         handler.beginStackSize = 1;
968         handler.pushed = true;
969         handler.next = blockStack;
970         blockStack = handler;
971       }
972     }
973     ++catchCount;
974     if (catchTable == null) {
975       catchTable = new ByteVector();
976     }
977     catchTable.putShort(start.position);
978     catchTable.putShort(end.position);
979     catchTable.putShort(handler.position);
980     catchTable.putShort(type != null ? cw.newClass(type) : 0);
981   }
982
983   public void visitMaxs (final int maxStack, final int maxLocals) {
984     if (computeMaxs) {
985       // true (non relative) max stack size
986
int max = 0;
987       // control flow analysis algorithm: while the block stack is not empty,
988
// pop a block from this stack, update the max stack size, compute
989
// the true (non relative) begin stack size of the successors of this
990
// block, and push these successors onto the stack (unless they have
991
// already been pushed onto the stack). Note: by hypothesis, the {@link
992
// Label#beginStackSize} of the blocks in the block stack are the true
993
// (non relative) beginning stack sizes of these blocks.
994
Label stack = blockStack;
995       while (stack != null) {
996         // pops a block from the stack
997
Label l = stack;
998         stack = stack.next;
999         // computes the true (non relative) max stack size of this block
1000
int start = l.beginStackSize;
1001        int blockMax = start + l.maxStackSize;
1002        // updates the global max stack size
1003
if (blockMax > max) {
1004          max = blockMax;
1005        }
1006        // analyses the successors of the block
1007
Edge b = l.successors;
1008        while (b != null) {
1009          l = b.successor;
1010          // if this successor has not already been pushed onto the stack...
1011
if (!l.pushed) {
1012            // computes the true beginning stack size of this successor block
1013
l.beginStackSize = start + b.stackSize;
1014            // pushes this successor onto the stack
1015
l.pushed = true;
1016            l.next = stack;
1017            stack = l;
1018          }
1019          b = b.next;
1020        }
1021      }
1022      this.maxStack = max;
1023      // releases all the Edge objects used by this CodeWriter
1024
synchronized (SIZE) {
1025        // appends the [head ... tail] list at the beginning of the pool list
1026
if (tail != null) {
1027          tail.poolNext = pool;
1028          pool = head;
1029        }
1030      }
1031    } else {
1032      this.maxStack = maxStack;
1033      this.maxLocals = maxLocals;
1034    }
1035  }
1036
1037  public void visitLocalVariable (
1038    final String JavaDoc name,
1039    final String JavaDoc desc,
1040    final Label start,
1041    final Label end,
1042    final int index)
1043  {
1044    if (CHECK) {
1045      if (start.owner != this || !start.resolved) {
1046        throw new IllegalArgumentException JavaDoc();
1047      }
1048      if (end.owner != this || !end.resolved) {
1049        throw new IllegalArgumentException JavaDoc();
1050      }
1051    }
1052    if (localVar == null) {
1053      cw.newUTF8("LocalVariableTable");
1054      localVar = new ByteVector();
1055    }
1056    ++localVarCount;
1057    localVar.putShort(start.position);
1058    localVar.putShort(end.position - start.position);
1059    localVar.putShort(cw.newUTF8(name));
1060    localVar.putShort(cw.newUTF8(desc));
1061    localVar.putShort(index);
1062  }
1063
1064  public void visitLineNumber (final int line, final Label start) {
1065    if (CHECK) {
1066      if (start.owner != this || !start.resolved) {
1067        throw new IllegalArgumentException JavaDoc();
1068      }
1069    }
1070    if (lineNumber == null) {
1071      cw.newUTF8("LineNumberTable");
1072      lineNumber = new ByteVector();
1073    }
1074    ++lineNumberCount;
1075    lineNumber.putShort(start.position);
1076    lineNumber.putShort(line);
1077  }
1078
1079  public void visitAttribute (final Attribute attr) {
1080    attr.next = cattrs;
1081    cattrs = attr;
1082  }
1083
1084  // --------------------------------------------------------------------------
1085
// Utility methods: control flow analysis algorithm
1086
// --------------------------------------------------------------------------
1087

1088  /**
1089   * Computes the size of the arguments and of the return value of a method.
1090   *
1091   * @param desc the descriptor of a method.
1092   * @return the size of the arguments of the method (plus one for the implicit
1093   * this argument), argSize, and the size of its return value, retSize,
1094   * packed into a single int i = <tt>(argSize << 2) | retSize</tt>
1095   * (argSize is therefore equal to <tt>i >> 2</tt>, and retSize to
1096   * <tt>i & 0x03</tt>).
1097   */

1098
1099  private static int getArgumentsAndReturnSizes (final String JavaDoc desc) {
1100    int n = 1;
1101    int c = 1;
1102    while (true) {
1103      char car = desc.charAt(c++);
1104      if (car == ')') {
1105        car = desc.charAt(c);
1106        return n << 2 | (car == 'V' ? 0 : (car == 'D' || car == 'J' ? 2 : 1));
1107      } else if (car == 'L') {
1108        while (desc.charAt(c++) != ';') {
1109        }
1110        n += 1;
1111      } else if (car == '[') {
1112        while ((car = desc.charAt(c)) == '[') {
1113          ++c;
1114        }
1115        if (car == 'D' || car == 'J') {
1116          n -= 1;
1117        }
1118      } else if (car == 'D' || car == 'J') {
1119        n += 2;
1120      } else {
1121        n += 1;
1122      }
1123    }
1124  }
1125
1126  /**
1127   * Adds a successor to the {@link #currentBlock currentBlock} block.
1128   *
1129   * @param stackSize the current (relative) stack size in the current block.
1130   * @param successor the successor block to be added to the current block.
1131   */

1132
1133  private void addSuccessor (final int stackSize, final Label successor) {
1134    Edge b;
1135    // creates a new Edge object or reuses one from the shared pool
1136
synchronized (SIZE) {
1137      if (pool == null) {
1138        b = new Edge();
1139      } else {
1140        b = pool;
1141        // removes b from the pool
1142
pool = pool.poolNext;
1143      }
1144    }
1145    // adds the previous Edge to the list of Edges used by this CodeWriter
1146
if (tail == null) {
1147      tail = b;
1148    }
1149    b.poolNext = head;
1150    head = b;
1151    // initializes the previous Edge object...
1152
b.stackSize = stackSize;
1153    b.successor = successor;
1154    // ...and adds it to the successor list of the currentBlock block
1155
b.next = currentBlock.successors;
1156    currentBlock.successors = b;
1157  }
1158
1159  // --------------------------------------------------------------------------
1160
// Utility methods: dump bytecode array
1161
// --------------------------------------------------------------------------
1162

1163  /**
1164   * Returns the size of the bytecode of this method.
1165   *
1166   * @return the size of the bytecode of this method.
1167   */

1168
1169  final int getSize () {
1170    if (resize) {
1171      // replaces the temporary jump opcodes introduced by Label.resolve.
1172
resizeInstructions(new int[0], new int[0], 0);
1173    }
1174    int size = 8;
1175    if (code.length > 0) {
1176      cw.newUTF8("Code");
1177      size += 18 + code.length + 8 * catchCount;
1178      if (localVar != null) {
1179        size += 8 + localVar.length;
1180      }
1181      if (lineNumber != null) {
1182        size += 8 + lineNumber.length;
1183      }
1184      if (cattrs != null) {
1185        size += cattrs.getSize(cw, code.data, code.length, maxStack, maxLocals);
1186      }
1187    }
1188    if (exceptionCount > 0) {
1189      cw.newUTF8("Exceptions");
1190      size += 8 + 2 * exceptionCount;
1191    }
1192    if ((access & Constants.ACC_SYNTHETIC) != 0) {
1193      cw.newUTF8("Synthetic");
1194      size += 6;
1195    }
1196    if ((access & Constants.ACC_DEPRECATED) != 0) {
1197      cw.newUTF8("Deprecated");
1198      size += 6;
1199    }
1200    if (attrs != null) {
1201      size += attrs.getSize(cw, null, 0, -1, -1);
1202    }
1203    return size;
1204  }
1205
1206  /**
1207   * Puts the bytecode of this method in the given byte vector.
1208   *
1209   * @param out the byte vector into which the bytecode of this method must be
1210   * copied.
1211   */

1212
1213  final void put (final ByteVector out) {
1214    out.putShort(access).putShort(name).putShort(desc);
1215    int attributeCount = 0;
1216    if (code.length > 0) {
1217      ++attributeCount;
1218    }
1219    if (exceptionCount > 0) {
1220      ++attributeCount;
1221    }
1222    if ((access & Constants.ACC_SYNTHETIC) != 0) {
1223      ++attributeCount;
1224    }
1225    if ((access & Constants.ACC_DEPRECATED) != 0) {
1226      ++attributeCount;
1227    }
1228    if (attrs != null) {
1229      attributeCount += attrs.getCount();
1230    }
1231    out.putShort(attributeCount);
1232    if (code.length > 0) {
1233      int size = 12 + code.length + 8 * catchCount;
1234      if (localVar != null) {
1235        size += 8 + localVar.length;
1236      }
1237      if (lineNumber != null) {
1238        size += 8 + lineNumber.length;
1239      }
1240      if (cattrs != null) {
1241        size += cattrs.getSize(cw, code.data, code.length, maxStack, maxLocals);
1242      }
1243      out.putShort(cw.newUTF8("Code")).putInt(size);
1244      out.putShort(maxStack).putShort(maxLocals);
1245      out.putInt(code.length).putByteArray(code.data, 0, code.length);
1246      out.putShort(catchCount);
1247      if (catchCount > 0) {
1248        out.putByteArray(catchTable.data, 0, catchTable.length);
1249      }
1250      attributeCount = 0;
1251      if (localVar != null) {
1252        ++attributeCount;
1253      }
1254      if (lineNumber != null) {
1255        ++attributeCount;
1256      }
1257      if (cattrs != null) {
1258        attributeCount += cattrs.getCount();
1259      }
1260      out.putShort(attributeCount);
1261      if (localVar != null) {
1262        out.putShort(cw.newUTF8("LocalVariableTable"));
1263        out.putInt(localVar.length + 2).putShort(localVarCount);
1264        out.putByteArray(localVar.data, 0, localVar.length);
1265      }
1266      if (lineNumber != null) {
1267        out.putShort(cw.newUTF8("LineNumberTable"));
1268        out.putInt(lineNumber.length + 2).putShort(lineNumberCount);
1269        out.putByteArray(lineNumber.data, 0, lineNumber.length);
1270      }
1271      if (cattrs != null) {
1272        cattrs.put(cw, code.data, code.length, maxLocals, maxStack, out);
1273      }
1274    }
1275    if (exceptionCount > 0) {
1276      out.putShort(cw.newUTF8("Exceptions")).putInt(2 * exceptionCount + 2);
1277      out.putShort(exceptionCount);
1278      for (int i = 0; i < exceptionCount; ++i) {
1279        out.putShort(exceptions[i]);
1280      }
1281    }
1282    if ((access & Constants.ACC_SYNTHETIC) != 0) {
1283      out.putShort(cw.newUTF8("Synthetic")).putInt(0);
1284    }
1285    if ((access & Constants.ACC_DEPRECATED) != 0) {
1286      out.putShort(cw.newUTF8("Deprecated")).putInt(0);
1287    }
1288    if (attrs != null) {
1289      attrs.put(cw, null, 0, -1, -1, out);
1290    }
1291  }
1292
1293  // --------------------------------------------------------------------------
1294
// Utility methods: instruction resizing (used to handle GOTO_W and JSR_W)
1295
// --------------------------------------------------------------------------
1296

1297  /**
1298   * Resizes the designated instructions, while keeping jump offsets and
1299   * instruction addresses consistent. This may require to resize other existing
1300   * instructions, or even to introduce new instructions: for example,
1301   * increasing the size of an instruction by 2 at the middle of a method can
1302   * increases the offset of an IFEQ instruction from 32766 to 32768, in which
1303   * case IFEQ 32766 must be replaced with IFNEQ 8 GOTO_W 32765. This, in turn,
1304   * may require to increase the size of another jump instruction, and so on...
1305   * All these operations are handled automatically by this method.
1306   * <p>
1307   * <i>This method must be called after all the method that is being built has
1308   * been visited</i>. In particular, the {@link Label Label} objects used to
1309   * construct the method are no longer valid after this method has been called.
1310   *
1311   * @param indexes current positions of the instructions to be resized. Each
1312   * instruction must be designated by the index of its <i>last</i> byte,
1313   * plus one (or, in other words, by the index of the <i>first</i> byte of
1314   * the <i>next</i> instruction).
1315   * @param sizes the number of bytes to be <i>added</i> to the above
1316   * instructions. More precisely, for each i &lt; <tt>len</tt>,
1317   * <tt>sizes</tt>[i] bytes will be added at the end of the instruction
1318   * designated by <tt>indexes</tt>[i] or, if <tt>sizes</tt>[i] is
1319   * negative, the <i>last</i> |<tt>sizes[i]</tt>| bytes of the instruction
1320   * will be removed (the instruction size <i>must not</i> become negative
1321   * or null). The gaps introduced by this method must be filled in
1322   * "manually" in the array returned by the {@link #getCode getCode}
1323   * method.
1324   * @param len the number of instruction to be resized. Must be smaller than or
1325   * equal to <tt>indexes</tt>.length and <tt>sizes</tt>.length.
1326   * @return the <tt>indexes</tt> array, which now contains the new positions of
1327   * the resized instructions (designated as above).
1328   */

1329
1330  protected int[] resizeInstructions (
1331    final int[] indexes,
1332    final int[] sizes,
1333    final int len)
1334  {
1335    byte[] b = code.data; // bytecode of the method
1336
int u, v, label; // indexes in b
1337
int i, j; // loop indexes
1338

1339    // 1st step:
1340
// As explained above, resizing an instruction may require to resize another
1341
// one, which may require to resize yet another one, and so on. The first
1342
// step of the algorithm consists in finding all the instructions that
1343
// need to be resized, without modifying the code. This is done by the
1344
// following "fix point" algorithm:
1345
// - parse the code to find the jump instructions whose offset will need
1346
// more than 2 bytes to be stored (the future offset is computed from the
1347
// current offset and from the number of bytes that will be inserted or
1348
// removed between the source and target instructions). For each such
1349
// instruction, adds an entry in (a copy of) the indexes and sizes arrays
1350
// (if this has not already been done in a previous iteration!)
1351
// - if at least one entry has been added during the previous step, go back
1352
// to the beginning, otherwise stop.
1353
// In fact the real algorithm is complicated by the fact that the size of
1354
// TABLESWITCH and LOOKUPSWITCH instructions depends on their position in
1355
// the bytecode (because of padding). In order to ensure the convergence of
1356
// the algorithm, the number of bytes to be added or removed from these
1357
// instructions is over estimated during the previous loop, and computed
1358
// exactly only after the loop is finished (this requires another pass to
1359
// parse the bytecode of the method).
1360

1361    int[] allIndexes = new int[len]; // copy of indexes
1362
int[] allSizes = new int[len]; // copy of sizes
1363
boolean[] resize; // instructions to be resized
1364
int newOffset; // future offset of a jump instruction
1365

1366    System.arraycopy(indexes, 0, allIndexes, 0, len);
1367    System.arraycopy(sizes, 0, allSizes, 0, len);
1368    resize = new boolean[code.length];
1369
1370    int state = 3; // 3 = loop again, 2 = loop ended, 1 = last pass, 0 = done
1371
do {
1372      if (state == 3) {
1373        state = 2;
1374      }
1375      u = 0;
1376      while (u < b.length) {
1377        int opcode = b[u] & 0xFF; // opcode of current instruction
1378
int insert = 0; // bytes to be added after this instruction
1379

1380        switch (ClassWriter.TYPE[opcode]) {
1381          case ClassWriter.NOARG_INSN:
1382          case ClassWriter.IMPLVAR_INSN:
1383            u += 1;
1384            break;
1385          case ClassWriter.LABEL_INSN:
1386            if (opcode > 201) {
1387              // converts temporary opcodes 202 to 217 (inclusive), 218 and 219
1388
// to IFEQ ... JSR (inclusive), IFNULL and IFNONNULL
1389
opcode = opcode < 218 ? opcode - 49 : opcode - 20;
1390              label = u + readUnsignedShort(b, u + 1);
1391            } else {
1392              label = u + readShort(b, u + 1);
1393            }
1394            newOffset = getNewOffset(allIndexes, allSizes, u, label);
1395            if (newOffset < Short.MIN_VALUE || newOffset > Short.MAX_VALUE) {
1396              if (!resize[u]) {
1397                if (opcode == Constants.GOTO || opcode == Constants.JSR) {
1398                  // two additional bytes will be required to replace this
1399
// GOTO or JSR instruction with a GOTO_W or a JSR_W
1400
insert = 2;
1401                } else {
1402                  // five additional bytes will be required to replace this
1403
// IFxxx <l> instruction with IFNOTxxx <l'> GOTO_W <l>, where
1404
// IFNOTxxx is the "opposite" opcode of IFxxx (i.e., IFNE for
1405
// IFEQ) and where <l'> designates the instruction just after
1406
// the GOTO_W.
1407
insert = 5;
1408                }
1409                resize[u] = true;
1410              }
1411            }
1412            u += 3;
1413            break;
1414          case ClassWriter.LABELW_INSN:
1415            u += 5;
1416            break;
1417          case ClassWriter.TABL_INSN:
1418            if (state == 1) {
1419              // true number of bytes to be added (or removed) from this
1420
// instruction = (future number of padding bytes - current number
1421
// of padding byte) - previously over estimated variation =
1422
// = ((3 - newOffset%4) - (3 - u%4)) - u%4
1423
// = (-newOffset%4 + u%4) - u%4
1424
// = -(newOffset & 3)
1425
newOffset = getNewOffset(allIndexes, allSizes, 0, u);
1426              insert = -(newOffset & 3);
1427            } else if (!resize[u]) {
1428              // over estimation of the number of bytes to be added to this
1429
// instruction = 3 - current number of padding bytes = 3 - (3 -
1430
// u%4) = u%4 = u & 3
1431
insert = u & 3;
1432              resize[u] = true;
1433            }
1434            // skips instruction
1435
u = u + 4 - (u & 3);
1436            u += 4*(readInt(b, u + 8) - readInt(b, u + 4) + 1) + 12;
1437            break;
1438          case ClassWriter.LOOK_INSN:
1439            if (state == 1) {
1440              // like TABL_INSN
1441
newOffset = getNewOffset(allIndexes, allSizes, 0, u);
1442              insert = -(newOffset & 3);
1443            } else if (!resize[u]) {
1444              // like TABL_INSN
1445
insert = u & 3;
1446              resize[u] = true;
1447            }
1448            // skips instruction
1449
u = u + 4 - (u & 3);
1450            u += 8*readInt(b, u + 4) + 8;
1451            break;
1452          case ClassWriter.WIDE_INSN:
1453            opcode = b[u + 1] & 0xFF;
1454            if (opcode == Constants.IINC) {
1455              u += 6;
1456            } else {
1457              u += 4;
1458            }
1459            break;
1460          case ClassWriter.VAR_INSN:
1461          case ClassWriter.SBYTE_INSN:
1462          case ClassWriter.LDC_INSN:
1463            u += 2;
1464            break;
1465          case ClassWriter.SHORT_INSN:
1466          case ClassWriter.LDCW_INSN:
1467          case ClassWriter.FIELDORMETH_INSN:
1468          case ClassWriter.TYPE_INSN:
1469          case ClassWriter.IINC_INSN:
1470            u += 3;
1471            break;
1472          case ClassWriter.ITFMETH_INSN:
1473            u += 5;
1474            break;
1475          // case ClassWriter.MANA_INSN:
1476
default:
1477            u += 4;
1478            break;
1479        }
1480        if (insert != 0) {
1481          // adds a new (u, insert) entry in the allIndexes and allSizes arrays
1482
int[] newIndexes = new int[allIndexes.length + 1];
1483          int[] newSizes = new int[allSizes.length + 1];
1484          System.arraycopy(allIndexes, 0, newIndexes, 0, allIndexes.length);
1485          System.arraycopy(allSizes, 0, newSizes, 0, allSizes.length);
1486          newIndexes[allIndexes.length] = u;
1487          newSizes[allSizes.length] = insert;
1488          allIndexes = newIndexes;
1489          allSizes = newSizes;
1490          if (insert > 0) {
1491            state = 3;
1492          }
1493        }
1494      }
1495      if (state < 3) {
1496        --state;
1497      }
1498    } while (state != 0);
1499
1500    // 2nd step:
1501
// copies the bytecode of the method into a new bytevector, updates the
1502
// offsets, and inserts (or removes) bytes as requested.
1503

1504    ByteVector newCode = new ByteVector(code.length);
1505
1506    u = 0;
1507    while (u < code.length) {
1508      for (i = allIndexes.length - 1; i >= 0; --i) {
1509        if (allIndexes[i] == u) {
1510          if (i < len) {
1511            if (sizes[i] > 0) {
1512              newCode.putByteArray(null, 0, sizes[i]);
1513            } else {
1514              newCode.length += sizes[i];
1515            }
1516            indexes[i] = newCode.length;
1517          }
1518        }
1519      }
1520      int opcode = b[u] & 0xFF;
1521      switch (ClassWriter.TYPE[opcode]) {
1522        case ClassWriter.NOARG_INSN:
1523        case ClassWriter.IMPLVAR_INSN:
1524          newCode.putByte(opcode);
1525          u += 1;
1526          break;
1527        case ClassWriter.LABEL_INSN:
1528          if (opcode > 201) {
1529            // changes temporary opcodes 202 to 217 (inclusive), 218 and 219
1530
// to IFEQ ... JSR (inclusive), IFNULL and IFNONNULL
1531
opcode = opcode < 218 ? opcode - 49 : opcode - 20;
1532            label = u + readUnsignedShort(b, u + 1);
1533          } else {
1534            label = u + readShort(b, u + 1);
1535          }
1536          newOffset = getNewOffset(allIndexes, allSizes, u, label);
1537          if (resize[u]) {
1538            // replaces GOTO with GOTO_W, JSR with JSR_W and IFxxx <l> with
1539
// IFNOTxxx <l'> GOTO_W <l>, where IFNOTxxx is the "opposite" opcode
1540
// of IFxxx (i.e., IFNE for IFEQ) and where <l'> designates the
1541
// instruction just after the GOTO_W.
1542
if (opcode == Constants.GOTO) {
1543              newCode.putByte(200); // GOTO_W
1544
} else if (opcode == Constants.JSR) {
1545              newCode.putByte(201); // JSR_W
1546
} else {
1547              newCode.putByte(opcode <= 166 ? ((opcode + 1) ^ 1) - 1 : opcode ^ 1);
1548              newCode.putShort(8); // jump offset
1549
newCode.putByte(200); // GOTO_W
1550
newOffset -= 3; // newOffset now computed from start of GOTO_W
1551
}
1552            newCode.putInt(newOffset);
1553          } else {
1554            newCode.putByte(opcode);
1555            newCode.putShort(newOffset);
1556          }
1557          u += 3;
1558          break;
1559        case ClassWriter.LABELW_INSN:
1560          label = u + readInt(b, u + 1);
1561          newOffset = getNewOffset(allIndexes, allSizes, u, label);
1562          newCode.putByte(opcode);
1563          newCode.putInt(newOffset);
1564          u += 5;
1565          break;
1566        case ClassWriter.TABL_INSN:
1567          // skips 0 to 3 padding bytes
1568
v = u;
1569          u = u + 4 - (v & 3);
1570          // reads and copies instruction
1571
newCode.putByte(Constants.TABLESWITCH);
1572          while (newCode.length % 4 != 0) {
1573            newCode.putByte(0);
1574          }
1575          label = v + readInt(b, u); u += 4;
1576          newOffset = getNewOffset(allIndexes, allSizes, v, label);
1577          newCode.putInt(newOffset);
1578          j = readInt(b, u); u += 4;
1579          newCode.putInt(j);
1580          j = readInt(b, u) - j + 1; u += 4;
1581          newCode.putInt(readInt(b, u - 4));
1582          for ( ; j > 0; --j) {
1583            label = v + readInt(b, u); u += 4;
1584            newOffset = getNewOffset(allIndexes, allSizes, v, label);
1585            newCode.putInt(newOffset);
1586          }
1587          break;
1588        case ClassWriter.LOOK_INSN:
1589          // skips 0 to 3 padding bytes
1590
v = u;
1591          u = u + 4 - (v & 3);
1592          // reads and copies instruction
1593
newCode.putByte(Constants.LOOKUPSWITCH);
1594          while (newCode.length % 4 != 0) {
1595            newCode.putByte(0);
1596          }
1597          label = v + readInt(b, u); u += 4;
1598          newOffset = getNewOffset(allIndexes, allSizes, v, label);
1599          newCode.putInt(newOffset);
1600          j = readInt(b, u); u += 4;
1601          newCode.putInt(j);
1602          for ( ; j > 0; --j) {
1603            newCode.putInt(readInt(b, u)); u += 4;
1604            label = v + readInt(b, u); u += 4;
1605            newOffset = getNewOffset(allIndexes, allSizes, v, label);
1606            newCode.putInt(newOffset);
1607          }
1608          break;
1609        case ClassWriter.WIDE_INSN:
1610          opcode = b[u + 1] & 0xFF;
1611          if (opcode == Constants.IINC) {
1612            newCode.putByteArray(b, u, 6);
1613            u += 6;
1614          } else {
1615            newCode.putByteArray(b, u, 4);
1616            u += 4;
1617          }
1618          break;
1619        case ClassWriter.VAR_INSN:
1620        case ClassWriter.SBYTE_INSN:
1621        case ClassWriter.LDC_INSN:
1622          newCode.putByteArray(b, u, 2);
1623          u += 2;
1624          break;
1625        case ClassWriter.SHORT_INSN:
1626        case ClassWriter.LDCW_INSN:
1627        case ClassWriter.FIELDORMETH_INSN:
1628        case ClassWriter.TYPE_INSN:
1629        case ClassWriter.IINC_INSN:
1630          newCode.putByteArray(b, u, 3);
1631          u += 3;
1632          break;
1633        case ClassWriter.ITFMETH_INSN:
1634          newCode.putByteArray(b, u, 5);
1635          u += 5;
1636          break;
1637        // case MANA_INSN:
1638
default:
1639          newCode.putByteArray(b, u, 4);
1640          u += 4;
1641          break;
1642      }
1643    }
1644
1645    // updates the instructions addresses in the
1646
// catch, local var and line number tables
1647
if (catchTable != null) {
1648      b = catchTable.data;
1649      u = 0;
1650      while (u < catchTable.length) {
1651        writeShort(b, u, getNewOffset(
1652          allIndexes, allSizes, 0, readUnsignedShort(b, u)));
1653        writeShort(b, u + 2, getNewOffset(
1654          allIndexes, allSizes, 0, readUnsignedShort(b, u + 2)));
1655        writeShort(b, u + 4, getNewOffset(
1656          allIndexes, allSizes, 0, readUnsignedShort(b, u + 4)));
1657        u += 8;
1658      }
1659    }
1660    if (localVar != null) {
1661      b = localVar.data;
1662      u = 0;
1663      while (u < localVar.length) {
1664        label = readUnsignedShort(b, u);
1665        newOffset = getNewOffset(allIndexes, allSizes, 0, label);
1666        writeShort(b, u, newOffset);
1667        label += readUnsignedShort(b, u + 2);
1668        newOffset = getNewOffset(allIndexes, allSizes, 0, label) - newOffset;
1669        writeShort(b, u + 2, newOffset);
1670        u += 10;
1671      }
1672    }
1673    if (lineNumber != null) {
1674      b = lineNumber.data;
1675      u = 0;
1676      while (u < lineNumber.length) {
1677        writeShort(b, u, getNewOffset(
1678          allIndexes, allSizes, 0, readUnsignedShort(b, u)));
1679        u += 4;
1680      }
1681    }
1682    // updates the labels of the other attributes
1683
while (cattrs != null) {
1684      Label[] labels = cattrs.getLabels();
1685      if (labels != null) {
1686        for (i = labels.length - 1; i >= 0; --i) {
1687          if (!labels[i].resized) {
1688            labels[i].position =
1689              getNewOffset(allIndexes, allSizes, 0, labels[i].position);
1690            labels[i].resized = true;
1691          }
1692        }
1693      }
1694    }
1695
1696    // replaces old bytecodes with new ones
1697
code = newCode;
1698
1699    // returns the positions of the resized instructions
1700
return indexes;
1701  }
1702
1703  /**
1704   * Reads an unsigned short value in the given byte array.
1705   *
1706   * @param b a byte array.
1707   * @param index the start index of the value to be read.
1708   * @return the read value.
1709   */

1710
1711  static int readUnsignedShort (final byte[] b, final int index) {
1712    return ((b[index] & 0xFF) << 8) | (b[index + 1] & 0xFF);
1713  }
1714
1715  /**
1716   * Reads a signed short value in the given byte array.
1717   *
1718   * @param b a byte array.
1719   * @param index the start index of the value to be read.
1720   * @return the read value.
1721   */

1722
1723  static short readShort (final byte[] b, final int index) {
1724    return (short)(((b[index] & 0xFF) << 8) | (b[index + 1] & 0xFF));
1725  }
1726
1727  /**
1728   * Reads a signed int value in the given byte array.
1729   *
1730   * @param b a byte array.
1731   * @param index the start index of the value to be read.
1732   * @return the read value.
1733   */

1734
1735  static int readInt (final byte[] b, final int index) {
1736    return ((b[index] & 0xFF) << 24) |
1737           ((b[index + 1] & 0xFF) << 16) |
1738           ((b[index + 2] & 0xFF) << 8) |
1739           (b[index + 3] & 0xFF);
1740  }
1741
1742  /**
1743   * Writes a short value in the given byte array.
1744   *
1745   * @param b a byte array.
1746   * @param index where the first byte of the short value must be written.
1747   * @param s the value to be written in the given byte array.
1748   */

1749
1750  static void writeShort (final byte[] b, final int index, final int s) {
1751    b[index] = (byte)(s >>> 8);
1752    b[index + 1] = (byte)s;
1753  }
1754
1755  /**
1756   * Computes the future value of a bytecode offset.
1757   * <p>
1758   * Note: it is possible to have several entries for the same instruction
1759   * in the <tt>indexes</tt> and <tt>sizes</tt>: two entries (index=a,size=b)
1760   * and (index=a,size=b') are equivalent to a single entry (index=a,size=b+b').
1761   *
1762   * @param indexes current positions of the instructions to be resized. Each
1763   * instruction must be designated by the index of its <i>last</i> byte,
1764   * plus one (or, in other words, by the index of the <i>first</i> byte of
1765   * the <i>next</i> instruction).
1766   * @param sizes the number of bytes to be <i>added</i> to the above
1767   * instructions. More precisely, for each i < <tt>len</tt>,
1768   * <tt>sizes</tt>[i] bytes will be added at the end of the instruction
1769   * designated by <tt>indexes</tt>[i] or, if <tt>sizes</tt>[i] is
1770   * negative, the <i>last</i> |<tt>sizes[i]</tt>| bytes of the instruction
1771   * will be removed (the instruction size <i>must not</i> become negative
1772   * or null).
1773   * @param begin index of the first byte of the source instruction.
1774   * @param end index of the first byte of the target instruction.
1775   * @return the future value of the given bytecode offset.
1776   */

1777
1778  static int getNewOffset (
1779    final int[] indexes,
1780    final int[] sizes,
1781    final int begin,
1782    final int end)
1783  {
1784    int offset = end - begin;
1785    for (int i = 0; i < indexes.length; ++i) {
1786      if (begin < indexes[i] && indexes[i] <= end) { // forward jump
1787
offset += sizes[i];
1788      } else if (end < indexes[i] && indexes[i] <= begin) { // backward jump
1789
offset -= sizes[i];
1790      }
1791    }
1792    return offset;
1793  }
1794
1795  /**
1796   * Returns the current size of the bytecode of this method. This size just
1797   * includes the size of the bytecode instructions: it does not include the
1798   * size of the Exceptions, LocalVariableTable, LineNumberTable, Synthetic
1799   * and Deprecated attributes, if present.
1800   *
1801   * @return the current size of the bytecode of this method.
1802   */

1803
1804  public int getCodeSize () {
1805    return code.length;
1806  }
1807
1808  /**
1809   * Returns the current bytecode of this method. This bytecode only contains
1810   * the instructions: it does not include the Exceptions, LocalVariableTable,
1811   * LineNumberTable, Synthetic and Deprecated attributes, if present.
1812   *
1813   * @return the current bytecode of this method. The bytecode is contained
1814   * between the index 0 (inclusive) and the index {@link #getCodeSize
1815   * getCodeSize} (exclusive).
1816   */

1817
1818  public byte[] getCode () {
1819    return code.data;
1820  }
1821}
1822
Popular Tags