KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > net > sf > retrotranslator > runtime > asm > MethodWriter


1 /***
2  * ASM: a very small and fast Java bytecode manipulation framework
3  * Copyright (c) 2000-2005 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 package net.sf.retrotranslator.runtime.asm;
31
32 /**
33  * A {@link MethodVisitor} that generates methods in bytecode form. Each visit
34  * method of this class appends the bytecode corresponding to the visited
35  * instruction to a byte vector, in the order these methods are called.
36  *
37  * @author Eric Bruneton
38  * @author Eugene Kuleshov
39  */

40 class MethodWriter implements MethodVisitor {
41
42     /**
43      * Next method writer (see {@link ClassWriter#firstMethod firstMethod}).
44      */

45     MethodWriter next;
46
47     /**
48      * The class writer to which this method must be added.
49      */

50     ClassWriter cw;
51
52     /**
53      * Access flags of this method.
54      */

55     private int access;
56
57     /**
58      * The index of the constant pool item that contains the name of this
59      * method.
60      */

61     private int name;
62
63     /**
64      * The index of the constant pool item that contains the descriptor of this
65      * method.
66      */

67     private int desc;
68
69     /**
70      * The descriptor of this method.
71      */

72     private String JavaDoc descriptor;
73
74     /**
75      * If not zero, indicates that the code of this method must be copied from
76      * the ClassReader associated to this writer in <code>cw.cr</code>. More
77      * precisely, this field gives the index of the first byte to copied from
78      * <code>cw.cr.b</code>.
79      */

80     int classReaderOffset;
81
82     /**
83      * If not zero, indicates that the code of this method must be copied from
84      * the ClassReader associated to this writer in <code>cw.cr</code>. More
85      * precisely, this field gives the number of bytes to copied from
86      * <code>cw.cr.b</code>.
87      */

88     int classReaderLength;
89
90     /**
91      * The signature of this method.
92      */

93     String JavaDoc signature;
94
95     /**
96      * Number of exceptions that can be thrown by this method.
97      */

98     int exceptionCount;
99
100     /**
101      * The exceptions that can be thrown by this method. More precisely, this
102      * array contains the indexes of the constant pool items that contain the
103      * internal names of these exception classes.
104      */

105     int[] exceptions;
106
107     /**
108      * The annotation default attribute of this method. May be <tt>null</tt>.
109      */

110     private ByteVector annd;
111
112     /**
113      * The runtime visible annotations of this method. May be <tt>null</tt>.
114      */

115     private AnnotationWriter anns;
116
117     /**
118      * The runtime invisible annotations of this method. May be <tt>null</tt>.
119      */

120     private AnnotationWriter ianns;
121
122     /**
123      * The runtime visible parameter annotations of this method. May be
124      * <tt>null</tt>.
125      */

126     private AnnotationWriter[] panns;
127
128     /**
129      * The runtime invisible parameter annotations of this method. May be
130      * <tt>null</tt>.
131      */

132     private AnnotationWriter[] ipanns;
133
134     /**
135      * The non standard attributes of the method.
136      */

137     private Attribute attrs;
138
139     /**
140      * The bytecode of this method.
141      */

142     private ByteVector code = new ByteVector();
143
144     /**
145      * Maximum stack size of this method.
146      */

147     private int maxStack;
148
149     /**
150      * Maximum number of local variables for this method.
151      */

152     private int maxLocals;
153
154     /**
155      * Number of entries in the catch table of this method.
156      */

157     private int catchCount;
158
159     /**
160      * The catch table of this method.
161      */

162     private Handler catchTable;
163
164     /**
165      * The last element in the catchTable handler list.
166      */

167     private Handler lastHandler;
168
169     /**
170      * Number of entries in the LocalVariableTable attribute.
171      */

172     private int localVarCount;
173
174     /**
175      * The LocalVariableTable attribute.
176      */

177     private ByteVector localVar;
178
179     /**
180      * Number of entries in the LocalVariableTypeTable attribute.
181      */

182     private int localVarTypeCount;
183
184     /**
185      * The LocalVariableTypeTable attribute.
186      */

187     private ByteVector localVarType;
188
189     /**
190      * Number of entries in the LineNumberTable attribute.
191      */

192     private int lineNumberCount;
193
194     /**
195      * The LineNumberTable attribute.
196      */

197     private ByteVector lineNumber;
198
199     /**
200      * The non standard attributes of the method's code.
201      */

202     private Attribute cattrs;
203
204     /**
205      * Indicates if some jump instructions are too small and need to be resized.
206      */

207     private boolean resize;
208
209     /*
210      * Fields for the control flow graph analysis algorithm (used to compute the
211      * maximum stack size). A control flow graph contains one node per "basic
212      * block", and one edge per "jump" from one basic block to another. Each
213      * node (i.e., each basic block) is represented by the Label object that
214      * corresponds to the first instruction of this basic block. Each node also
215      * stores the list of its successors in the graph, as a linked list of Edge
216      * objects.
217      */

218
219     /**
220      * <tt>true</tt> if the maximum stack size and number of local variables
221      * must be automatically computed.
222      */

223     private final boolean computeMaxs;
224
225     /**
226      * The (relative) stack size after the last visited instruction. This size
227      * is relative to the beginning of the current basic block, i.e., the true
228      * stack size after the last visited instruction is equal to the {@link
229      * Label#beginStackSize beginStackSize} of the current basic block plus
230      * <tt>stackSize</tt>.
231      */

232     private int stackSize;
233
234     /**
235      * The (relative) maximum stack size after the last visited instruction.
236      * This size is relative to the beginning of the current basic block, i.e.,
237      * the true maximum stack size after the last visited instruction is equal
238      * to the {@link Label#beginStackSize beginStackSize} of the current basic
239      * block plus <tt>stackSize</tt>.
240      */

241     private int maxStackSize;
242
243     /**
244      * The current basic block. This block is the basic block to which the next
245      * instruction to be visited must be added.
246      */

247     private Label currentBlock;
248
249     /**
250      * The basic block stack used by the control flow analysis algorithm. This
251      * stack is represented by a linked list of {@link Label Label} objects,
252      * linked to each other by their {@link Label#next} field. This stack must
253      * not be confused with the JVM stack used to execute the JVM instructions!
254      */

255     private Label blockStack;
256
257     /**
258      * The stack size variation corresponding to each JVM instruction. This
259      * stack variation is equal to the size of the values produced by an
260      * instruction, minus the size of the values consumed by this instruction.
261      */

262     private final static int[] SIZE;
263
264     // ------------------------------------------------------------------------
265
// Static initializer
266
// ------------------------------------------------------------------------
267

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

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

501     /**
502      * Constructs a new {@link MethodWriter}.
503      *
504      * @param cw the class writer in which the method must be added.
505      * @param access the method's access flags (see {@link Opcodes}).
506      * @param name the method's name.
507      * @param desc the method's descriptor (see {@link Type}).
508      * @param signature the method's signature. May be <tt>null</tt>.
509      * @param exceptions the internal names of the method's exceptions. May be
510      * <tt>null</tt>.
511      * @param computeMaxs <tt>true</tt> if the maximum stack size and number
512      * of local variables must be automatically computed.
513      */

514     MethodWriter(
515         final ClassWriter cw,
516         final int access,
517         final String JavaDoc name,
518         final String JavaDoc desc,
519         final String JavaDoc signature,
520         final String JavaDoc[] exceptions,
521         final boolean computeMaxs)
522     {
523         if (cw.firstMethod == null) {
524             cw.firstMethod = this;
525         } else {
526             cw.lastMethod.next = this;
527         }
528         cw.lastMethod = this;
529         this.cw = cw;
530         this.access = access;
531         this.name = cw.newUTF8(name);
532         this.desc = cw.newUTF8(desc);
533         this.descriptor = desc;
534         this.signature = signature;
535         if (exceptions != null && exceptions.length > 0) {
536             exceptionCount = exceptions.length;
537             this.exceptions = new int[exceptionCount];
538             for (int i = 0; i < exceptionCount; ++i) {
539                 this.exceptions[i] = cw.newClass(exceptions[i]);
540             }
541         }
542         this.computeMaxs = computeMaxs;
543         if (computeMaxs) {
544             // updates maxLocals
545
int size = getArgumentsAndReturnSizes(desc) >> 2;
546             if ((access & Opcodes.ACC_STATIC) != 0) {
547                 --size;
548             }
549             maxLocals = size;
550             // pushes the first block onto the stack of blocks to be visited
551
currentBlock = new Label();
552             currentBlock.pushed = true;
553             blockStack = currentBlock;
554         }
555     }
556
557     // ------------------------------------------------------------------------
558
// Implementation of the MethodVisitor interface
559
// ------------------------------------------------------------------------
560

561     public AnnotationVisitor visitAnnotationDefault() {
562         annd = new ByteVector();
563         return new AnnotationWriter(cw, false, annd, null, 0);
564     }
565
566     public AnnotationVisitor visitAnnotation(
567         final String JavaDoc desc,
568         final boolean visible)
569     {
570         ByteVector bv = new ByteVector();
571         // write type, and reserve space for values count
572
bv.putShort(cw.newUTF8(desc)).putShort(0);
573         AnnotationWriter aw = new AnnotationWriter(cw, true, bv, bv, 2);
574         if (visible) {
575             aw.next = anns;
576             anns = aw;
577         } else {
578             aw.next = ianns;
579             ianns = aw;
580         }
581         return aw;
582     }
583
584     public AnnotationVisitor visitParameterAnnotation(
585         final int parameter,
586         final String JavaDoc desc,
587         final boolean visible)
588     {
589         ByteVector bv = new ByteVector();
590         // write type, and reserve space for values count
591
bv.putShort(cw.newUTF8(desc)).putShort(0);
592         AnnotationWriter aw = new AnnotationWriter(cw, true, bv, bv, 2);
593         if (visible) {
594             if (panns == null) {
595                 panns = new AnnotationWriter[Type.getArgumentTypes(descriptor).length];
596             }
597             aw.next = panns[parameter];
598             panns[parameter] = aw;
599         } else {
600             if (ipanns == null) {
601                 ipanns = new AnnotationWriter[Type.getArgumentTypes(descriptor).length];
602             }
603             aw.next = ipanns[parameter];
604             ipanns[parameter] = aw;
605         }
606         return aw;
607     }
608
609     public void visitAttribute(final Attribute attr) {
610         if (attr.isCodeAttribute()) {
611             attr.next = cattrs;
612             cattrs = attr;
613         } else {
614             attr.next = attrs;
615             attrs = attr;
616         }
617     }
618
619     public void visitCode() {
620     }
621
622     public void visitInsn(final int opcode) {
623         if (computeMaxs) {
624             // updates current and max stack sizes
625
int size = stackSize + SIZE[opcode];
626             if (size > maxStackSize) {
627                 maxStackSize = size;
628             }
629             stackSize = size;
630             // if opcode == ATHROW or xRETURN, ends current block (no successor)
631
if ((opcode >= Opcodes.IRETURN && opcode <= Opcodes.RETURN)
632                     || opcode == Opcodes.ATHROW)
633             {
634                 if (currentBlock != null) {
635                     currentBlock.maxStackSize = maxStackSize;
636                     currentBlock = null;
637                 }
638             }
639         }
640         // adds the instruction to the bytecode of the method
641
code.putByte(opcode);
642     }
643
644     public void visitIntInsn(final int opcode, final int operand) {
645         if (computeMaxs && opcode != Opcodes.NEWARRAY) {
646             // updates current and max stack sizes only if opcode == NEWARRAY
647
// (stack size variation = 0 for BIPUSH or SIPUSH)
648
int size = stackSize + 1;
649             if (size > maxStackSize) {
650                 maxStackSize = size;
651             }
652             stackSize = size;
653         }
654         // adds the instruction to the bytecode of the method
655
if (opcode == Opcodes.SIPUSH) {
656             code.put12(opcode, operand);
657         } else { // BIPUSH or NEWARRAY
658
code.put11(opcode, operand);
659         }
660     }
661
662     public void visitVarInsn(final int opcode, final int var) {
663         if (computeMaxs) {
664             // updates current and max stack sizes
665
if (opcode == Opcodes.RET) {
666                 // no stack change, but end of current block (no successor)
667
if (currentBlock != null) {
668                     currentBlock.maxStackSize = maxStackSize;
669                     currentBlock = null;
670                 }
671             } else { // xLOAD or xSTORE
672
int size = stackSize + SIZE[opcode];
673                 if (size > maxStackSize) {
674                     maxStackSize = size;
675                 }
676                 stackSize = size;
677             }
678             // updates max locals
679
int n;
680             if (opcode == Opcodes.LLOAD || opcode == Opcodes.DLOAD
681                     || opcode == Opcodes.LSTORE || opcode == Opcodes.DSTORE)
682             {
683                 n = var + 2;
684             } else {
685                 n = var + 1;
686             }
687             if (n > maxLocals) {
688                 maxLocals = n;
689             }
690         }
691         // adds the instruction to the bytecode of the method
692
if (var < 4 && opcode != Opcodes.RET) {
693             int opt;
694             if (opcode < Opcodes.ISTORE) {
695                 /* ILOAD_0 */
696                 opt = 26 + ((opcode - Opcodes.ILOAD) << 2) + var;
697             } else {
698                 /* ISTORE_0 */
699                 opt = 59 + ((opcode - Opcodes.ISTORE) << 2) + var;
700             }
701             code.putByte(opt);
702         } else if (var >= 256) {
703             code.putByte(196 /* WIDE */).put12(opcode, var);
704         } else {
705             code.put11(opcode, var);
706         }
707     }
708
709     public void visitTypeInsn(final int opcode, final String JavaDoc desc) {
710         if (computeMaxs && opcode == Opcodes.NEW) {
711             // updates current and max stack sizes only if opcode == NEW
712
// (stack size variation = 0 for ANEWARRAY, CHECKCAST, INSTANCEOF)
713
int size = stackSize + 1;
714             if (size > maxStackSize) {
715                 maxStackSize = size;
716             }
717             stackSize = size;
718         }
719         // adds the instruction to the bytecode of the method
720
code.put12(opcode, cw.newClass(desc));
721     }
722
723     public void visitFieldInsn(
724         final int opcode,
725         final String JavaDoc owner,
726         final String JavaDoc name,
727         final String JavaDoc desc)
728     {
729         if (computeMaxs) {
730             int size;
731             // computes the stack size variation
732
char c = desc.charAt(0);
733             switch (opcode) {
734                 case Opcodes.GETSTATIC:
735                     size = stackSize + (c == 'D' || c == 'J' ? 2 : 1);
736                     break;
737                 case Opcodes.PUTSTATIC:
738                     size = stackSize + (c == 'D' || c == 'J' ? -2 : -1);
739                     break;
740                 case Opcodes.GETFIELD:
741                     size = stackSize + (c == 'D' || c == 'J' ? 1 : 0);
742                     break;
743                 // case Constants.PUTFIELD:
744
default:
745                     size = stackSize + (c == 'D' || c == 'J' ? -3 : -2);
746                     break;
747             }
748             // updates current and max stack sizes
749
if (size > maxStackSize) {
750                 maxStackSize = size;
751             }
752             stackSize = size;
753         }
754         // adds the instruction to the bytecode of the method
755
code.put12(opcode, cw.newField(owner, name, desc));
756     }
757
758     public void visitMethodInsn(
759         final int opcode,
760         final String JavaDoc owner,
761         final String JavaDoc name,
762         final String JavaDoc desc)
763     {
764         boolean itf = opcode == Opcodes.INVOKEINTERFACE;
765         Item i = cw.newMethodItem(owner, name, desc, itf);
766         int argSize = i.intVal;
767         if (computeMaxs) {
768             /*
769              * computes the stack size variation. In order not to recompute
770              * several times this variation for the same Item, we use the intVal
771              * field of this item to store this variation, once it has been
772              * computed. More precisely this intVal field stores the sizes of
773              * the arguments and of the return value corresponding to desc.
774              */

775             if (argSize == 0) {
776                 // the above sizes have not been computed yet, so we compute
777
// them...
778
argSize = getArgumentsAndReturnSizes(desc);
779                 // ... and we save them in order not to recompute them in the
780
// future
781
i.intVal = argSize;
782             }
783             int size;
784             if (opcode == Opcodes.INVOKESTATIC) {
785                 size = stackSize - (argSize >> 2) + (argSize & 0x03) + 1;
786             } else {
787                 size = stackSize - (argSize >> 2) + (argSize & 0x03);
788             }
789             // updates current and max stack sizes
790
if (size > maxStackSize) {
791                 maxStackSize = size;
792             }
793             stackSize = size;
794         }
795         // adds the instruction to the bytecode of the method
796
if (itf) {
797             if (!computeMaxs) {
798                 if (argSize == 0) {
799                     argSize = getArgumentsAndReturnSizes(desc);
800                     i.intVal = argSize;
801                 }
802             }
803             code.put12(Opcodes.INVOKEINTERFACE, i.index).put11(argSize >> 2, 0);
804         } else {
805             code.put12(opcode, i.index);
806         }
807     }
808
809     public void visitJumpInsn(final int opcode, final Label label) {
810         if (computeMaxs) {
811             if (opcode == Opcodes.GOTO) {
812                 // no stack change, but end of current block (with one new
813
// successor)
814
if (currentBlock != null) {
815                     currentBlock.maxStackSize = maxStackSize;
816                     addSuccessor(stackSize, label);
817                     currentBlock = null;
818                 }
819             } else if (opcode == Opcodes.JSR) {
820                 if (currentBlock != null) {
821                     addSuccessor(stackSize + 1, label);
822                 }
823             } else {
824                 // updates current stack size (max stack size unchanged because
825
// stack size variation always negative in this case)
826
stackSize += SIZE[opcode];
827                 if (currentBlock != null) {
828                     addSuccessor(stackSize, label);
829                 }
830             }
831         }
832         // adds the instruction to the bytecode of the method
833
if (label.resolved && label.position - code.length < Short.MIN_VALUE) {
834             /*
835              * case of a backward jump with an offset < -32768. In this case we
836              * automatically replace GOTO with GOTO_W, JSR with JSR_W and IFxxx
837              * <l> with IFNOTxxx <l'> GOTO_W <l>, where IFNOTxxx is the
838              * "opposite" opcode of IFxxx (i.e., IFNE for IFEQ) and where <l'>
839              * designates the instruction just after the GOTO_W.
840              */

841             if (opcode == Opcodes.GOTO) {
842                 code.putByte(200); // GOTO_W
843
} else if (opcode == Opcodes.JSR) {
844                 code.putByte(201); // JSR_W
845
} else {
846                 code.putByte(opcode <= 166
847                         ? ((opcode + 1) ^ 1) - 1
848                         : opcode ^ 1);
849                 code.putShort(8); // jump offset
850
code.putByte(200); // GOTO_W
851
}
852             label.put(this, code, code.length - 1, true);
853         } else {
854             /*
855              * case of a backward jump with an offset >= -32768, or of a forward
856              * jump with, of course, an unknown offset. In these cases we store
857              * the offset in 2 bytes (which will be increased in
858              * resizeInstructions, if needed).
859              */

860             code.putByte(opcode);
861             label.put(this, code, code.length - 1, false);
862         }
863     }
864
865     public void visitLabel(final Label label) {
866         if (computeMaxs) {
867             if (currentBlock != null) {
868                 // ends current block (with one new successor)
869
currentBlock.maxStackSize = maxStackSize;
870                 addSuccessor(stackSize, label);
871             }
872             // begins a new current block,
873
// resets the relative current and max stack sizes
874
currentBlock = label;
875             stackSize = 0;
876             maxStackSize = 0;
877         }
878         // resolves previous forward references to label, if any
879
resize |= label.resolve(this, code.length, code.data);
880     }
881
882     public void visitLdcInsn(final Object JavaDoc cst) {
883         Item i = cw.newConstItem(cst);
884         if (computeMaxs) {
885             int size;
886             // computes the stack size variation
887
if (i.type == ClassWriter.LONG || i.type == ClassWriter.DOUBLE) {
888                 size = stackSize + 2;
889             } else {
890                 size = stackSize + 1;
891             }
892             // updates current and max stack sizes
893
if (size > maxStackSize) {
894                 maxStackSize = size;
895             }
896             stackSize = size;
897         }
898         // adds the instruction to the bytecode of the method
899
int index = i.index;
900         if (i.type == ClassWriter.LONG || i.type == ClassWriter.DOUBLE) {
901             code.put12(20 /* LDC2_W */, index);
902         } else if (index >= 256) {
903             code.put12(19 /* LDC_W */, index);
904         } else {
905             code.put11(Opcodes.LDC, index);
906         }
907     }
908
909     public void visitIincInsn(final int var, final int increment) {
910         if (computeMaxs) {
911             // updates max locals only (no stack change)
912
int n = var + 1;
913             if (n > maxLocals) {
914                 maxLocals = n;
915             }
916         }
917         // adds the instruction to the bytecode of the method
918
if ((var > 255) || (increment > 127) || (increment < -128)) {
919             code.putByte(196 /* WIDE */)
920                     .put12(Opcodes.IINC, var)
921                     .putShort(increment);
922         } else {
923             code.putByte(Opcodes.IINC).put11(var, increment);
924         }
925     }
926
927     public void visitTableSwitchInsn(
928         final int min,
929         final int max,
930         final Label dflt,
931         final Label labels[])
932     {
933         if (computeMaxs) {
934             // updates current stack size (max stack size unchanged)
935
--stackSize;
936             // ends current block (with many new successors)
937
if (currentBlock != null) {
938                 currentBlock.maxStackSize = maxStackSize;
939                 addSuccessor(stackSize, dflt);
940                 for (int i = 0; i < labels.length; ++i) {
941                     addSuccessor(stackSize, labels[i]);
942                 }
943                 currentBlock = null;
944             }
945         }
946         // adds the instruction to the bytecode of the method
947
int source = code.length;
948         code.putByte(Opcodes.TABLESWITCH);
949         while (code.length % 4 != 0) {
950             code.putByte(0);
951         }
952         dflt.put(this, code, source, true);
953         code.putInt(min).putInt(max);
954         for (int i = 0; i < labels.length; ++i) {
955             labels[i].put(this, code, source, true);
956         }
957     }
958
959     public void visitLookupSwitchInsn(
960         final Label dflt,
961         final int keys[],
962         final Label labels[])
963     {
964         if (computeMaxs) {
965             // updates current stack size (max stack size unchanged)
966
--stackSize;
967             // ends current block (with many new successors)
968
if (currentBlock != null) {
969                 currentBlock.maxStackSize = maxStackSize;
970                 addSuccessor(stackSize, dflt);
971                 for (int i = 0; i < labels.length; ++i) {
972                     addSuccessor(stackSize, labels[i]);
973                 }
974                 currentBlock = null;
975             }
976         }
977         // adds the instruction to the bytecode of the method
978
int source = code.length;
979         code.putByte(Opcodes.LOOKUPSWITCH);
980         while (code.length % 4 != 0) {
981             code.putByte(0);
982         }
983         dflt.put(this, code, source, true);
984         code.putInt(labels.length);
985         for (int i = 0; i < labels.length; ++i) {
986             code.putInt(keys[i]);
987             labels[i].put(this, code, source, true);
988         }
989     }
990
991     public void visitMultiANewArrayInsn(final String JavaDoc desc, final int dims) {
992         if (computeMaxs) {
993             // updates current stack size (max stack size unchanged because
994
// stack size variation always negative or null)
995
stackSize += 1 - dims;
996         }
997         // adds the instruction to the bytecode of the method
998
code.put12(Opcodes.MULTIANEWARRAY, cw.newClass(desc)).putByte(dims);
999     }
1000
1001    public void visitTryCatchBlock(
1002        final Label start,
1003        final Label end,
1004        final Label handler,
1005        final String JavaDoc type)
1006    {
1007        if (computeMaxs) {
1008            // pushes handler block onto the stack of blocks to be visited
1009
if (!handler.pushed) {
1010                handler.beginStackSize = 1;
1011                handler.pushed = true;
1012                handler.next = blockStack;
1013                blockStack = handler;
1014            }
1015        }
1016        ++catchCount;
1017        Handler h = new Handler();
1018        h.start = start;
1019        h.end = end;
1020        h.handler = handler;
1021        h.desc = type;
1022        h.type = type != null ? cw.newClass(type) : 0;
1023        if (lastHandler == null) {
1024            catchTable = h;
1025        } else {
1026            lastHandler.next = h;
1027        }
1028        lastHandler = h;
1029    }
1030
1031    public void visitLocalVariable(
1032        final String JavaDoc name,
1033        final String JavaDoc desc,
1034        final String JavaDoc signature,
1035        final Label start,
1036        final Label end,
1037        final int index)
1038    {
1039        if (signature != null) {
1040            if (localVarType == null) {
1041                localVarType = new ByteVector();
1042            }
1043            ++localVarTypeCount;
1044            localVarType.putShort(start.position)
1045                    .putShort(end.position - start.position)
1046                    .putShort(cw.newUTF8(name))
1047                    .putShort(cw.newUTF8(signature))
1048                    .putShort(index);
1049        }
1050        if (localVar == null) {
1051            localVar = new ByteVector();
1052        }
1053        ++localVarCount;
1054        localVar.putShort(start.position)
1055                .putShort(end.position - start.position)
1056                .putShort(cw.newUTF8(name))
1057                .putShort(cw.newUTF8(desc))
1058                .putShort(index);
1059        
1060        if(computeMaxs) {
1061            // updates max locals
1062
char c = desc.charAt(0);
1063            int n = index + ( c=='L' || c=='D' ? 2 : 1);
1064            if (n > maxLocals) {
1065                maxLocals = n;
1066            }
1067        }
1068    }
1069
1070    public void visitLineNumber(final int line, final Label start) {
1071        if (lineNumber == null) {
1072            lineNumber = new ByteVector();
1073        }
1074        ++lineNumberCount;
1075        lineNumber.putShort(start.position);
1076        lineNumber.putShort(line);
1077    }
1078
1079    public void visitMaxs(final int maxStack, final int maxLocals) {
1080        if (computeMaxs) {
1081            // true (non relative) max stack size
1082
int max = 0;
1083            /*
1084             * control flow analysis algorithm: while the block stack is not
1085             * empty, pop a block from this stack, update the max stack size,
1086             * compute the true (non relative) begin stack size of the
1087             * successors of this block, and push these successors onto the
1088             * stack (unless they have already been pushed onto the stack).
1089             * Note: by hypothesis, the {@link Label#beginStackSize} of the
1090             * blocks in the block stack are the true (non relative) beginning
1091             * stack sizes of these blocks.
1092             */

1093            Label stack = blockStack;
1094            while (stack != null) {
1095                // pops a block from the stack
1096
Label l = stack;
1097                stack = stack.next;
1098                // computes the true (non relative) max stack size of this block
1099
int start = l.beginStackSize;
1100                int blockMax = start + l.maxStackSize;
1101                // updates the global max stack size
1102
if (blockMax > max) {
1103                    max = blockMax;
1104                }
1105                // analyses the successors of the block
1106
Edge b = l.successors;
1107                while (b != null) {
1108                    l = b.successor;
1109                    // if this successor has not already been pushed onto the
1110
// stack...
1111
if (!l.pushed) {
1112                        // computes the true beginning stack size of this
1113
// successor block
1114
l.beginStackSize = start + b.stackSize;
1115                        // pushes this successor onto the stack
1116
l.pushed = true;
1117                        l.next = stack;
1118                        stack = l;
1119                    }
1120                    b = b.next;
1121                }
1122            }
1123            this.maxStack = max;
1124        } else {
1125            this.maxStack = maxStack;
1126            this.maxLocals = maxLocals;
1127        }
1128    }
1129
1130    public void visitEnd() {
1131    }
1132
1133    // ------------------------------------------------------------------------
1134
// Utility methods: control flow analysis algorithm
1135
// ------------------------------------------------------------------------
1136

1137    /**
1138     * Computes the size of the arguments and of the return value of a method.
1139     *
1140     * @param desc the descriptor of a method.
1141     * @return the size of the arguments of the method (plus one for the
1142     * implicit this argument), argSize, and the size of its return
1143     * value, retSize, packed into a single int i =
1144     * <tt>(argSize << 2) | retSize</tt> (argSize is therefore equal
1145     * to <tt>i >> 2</tt>, and retSize to <tt>i & 0x03</tt>).
1146     */

1147    private static int getArgumentsAndReturnSizes(final String JavaDoc desc) {
1148        int n = 1;
1149        int c = 1;
1150        while (true) {
1151            char car = desc.charAt(c++);
1152            if (car == ')') {
1153                car = desc.charAt(c);
1154                return n << 2
1155                        | (car == 'V' ? 0 : (car == 'D' || car == 'J' ? 2 : 1));
1156            } else if (car == 'L') {
1157                while (desc.charAt(c++) != ';') {
1158                }
1159                n += 1;
1160            } else if (car == '[') {
1161                while ((car = desc.charAt(c)) == '[') {
1162                    ++c;
1163                }
1164                if (car == 'D' || car == 'J') {
1165                    n -= 1;
1166                }
1167            } else if (car == 'D' || car == 'J') {
1168                n += 2;
1169            } else {
1170                n += 1;
1171            }
1172        }
1173    }
1174
1175    /**
1176     * Adds a successor to the {@link #currentBlock currentBlock} block.
1177     *
1178     * @param stackSize the current (relative) stack size in the current block.
1179     * @param successor the successor block to be added to the current block.
1180     */

1181    private void addSuccessor(final int stackSize, final Label successor) {
1182        Edge b = new Edge();
1183        // initializes the previous Edge object...
1184
b.stackSize = stackSize;
1185        b.successor = successor;
1186        // ...and adds it to the successor list of the currentBlock block
1187
b.next = currentBlock.successors;
1188        currentBlock.successors = b;
1189    }
1190
1191    // ------------------------------------------------------------------------
1192
// Utility methods: dump bytecode array
1193
// ------------------------------------------------------------------------
1194

1195    /**
1196     * Returns the size of the bytecode of this method.
1197     *
1198     * @return the size of the bytecode of this method.
1199     */

1200    final int getSize() {
1201        if (classReaderOffset != 0) {
1202            return 6 + classReaderLength;
1203        }
1204        if (resize) {
1205            // replaces the temporary jump opcodes introduced by Label.resolve.
1206
resizeInstructions(new int[0], new int[0], 0);
1207        }
1208        int size = 8;
1209        if (code.length > 0) {
1210            cw.newUTF8("Code");
1211            size += 18 + code.length + 8 * catchCount;
1212            if (localVar != null) {
1213                cw.newUTF8("LocalVariableTable");
1214                size += 8 + localVar.length;
1215            }
1216            if (localVarType != null) {
1217                cw.newUTF8("LocalVariableTypeTable");
1218                size += 8 + localVarType.length;
1219            }
1220            if (lineNumber != null) {
1221                cw.newUTF8("LineNumberTable");
1222                size += 8 + lineNumber.length;
1223            }
1224            if (cattrs != null) {
1225                size += cattrs.getSize(cw,
1226                        code.data,
1227                        code.length,
1228                        maxStack,
1229                        maxLocals);
1230            }
1231        }
1232        if (exceptionCount > 0) {
1233            cw.newUTF8("Exceptions");
1234            size += 8 + 2 * exceptionCount;
1235        }
1236        if ((access & Opcodes.ACC_SYNTHETIC) != 0
1237                && (cw.version & 0xffff) < Opcodes.V1_5)
1238        {
1239            cw.newUTF8("Synthetic");
1240            size += 6;
1241        }
1242        if ((access & Opcodes.ACC_DEPRECATED) != 0) {
1243            cw.newUTF8("Deprecated");
1244            size += 6;
1245        }
1246        if (cw.version == Opcodes.V1_4) {
1247            if ((access & Opcodes.ACC_VARARGS) != 0) {
1248                cw.newUTF8("Varargs");
1249                size += 6;
1250            }
1251            if ((access & Opcodes.ACC_BRIDGE) != 0) {
1252                cw.newUTF8("Bridge");
1253                size += 6;
1254            }
1255        }
1256        if (signature != null) {
1257            cw.newUTF8("Signature");
1258            cw.newUTF8(signature);
1259            size += 8;
1260        }
1261        if (annd != null) {
1262            cw.newUTF8("AnnotationDefault");
1263            size += 6 + annd.length;
1264        }
1265        if (anns != null) {
1266            cw.newUTF8("RuntimeVisibleAnnotations");
1267            size += 8 + anns.getSize();
1268        }
1269        if (ianns != null) {
1270            cw.newUTF8("RuntimeInvisibleAnnotations");
1271            size += 8 + ianns.getSize();
1272        }
1273        if (panns != null) {
1274            cw.newUTF8("RuntimeVisibleParameterAnnotations");
1275            size += 7 + 2 * panns.length;
1276            for (int i = panns.length - 1; i >= 0; --i) {
1277                size += panns[i] == null ? 0 : panns[i].getSize();
1278            }
1279        }
1280        if (ipanns != null) {
1281            cw.newUTF8("RuntimeInvisibleParameterAnnotations");
1282            size += 7 + 2 * ipanns.length;
1283            for (int i = ipanns.length - 1; i >= 0; --i) {
1284                size += ipanns[i] == null ? 0 : ipanns[i].getSize();
1285            }
1286        }
1287        if (attrs != null) {
1288            size += attrs.getSize(cw, null, 0, -1, -1);
1289        }
1290        return size;
1291    }
1292
1293    /**
1294     * Puts the bytecode of this method in the given byte vector.
1295     *
1296     * @param out the byte vector into which the bytecode of this method must be
1297     * @param dropTigerFlags
1298     */

1299    final void put(final ByteVector out, boolean dropTigerFlags) {
1300        int modifiers = access;
1301        if (dropTigerFlags) {
1302            modifiers &= ~(Opcodes.ACC_SYNTHETIC | Opcodes.ACC_VARARGS | Opcodes.ACC_BRIDGE);
1303        }
1304        out.putShort(modifiers).putShort(name).putShort(desc);
1305        if (classReaderOffset != 0) {
1306            out.putByteArray(cw.cr.b, classReaderOffset, classReaderLength);
1307            return;
1308        }
1309        int attributeCount = 0;
1310        if (code.length > 0) {
1311            ++attributeCount;
1312        }
1313        if (exceptionCount > 0) {
1314            ++attributeCount;
1315        }
1316        if ((access & Opcodes.ACC_SYNTHETIC) != 0
1317                && (cw.version & 0xffff) < Opcodes.V1_5)
1318        {
1319            ++attributeCount;
1320        }
1321        if ((access & Opcodes.ACC_DEPRECATED) != 0) {
1322            ++attributeCount;
1323        }
1324        if (cw.version == Opcodes.V1_4) {
1325            if ((access & Opcodes.ACC_VARARGS) != 0) {
1326                ++attributeCount;
1327            }
1328            if ((access & Opcodes.ACC_BRIDGE) != 0) {
1329                ++attributeCount;
1330            }
1331        }
1332        if (signature != null) {
1333            ++attributeCount;
1334        }
1335        if (annd != null) {
1336            ++attributeCount;
1337        }
1338        if (anns != null) {
1339            ++attributeCount;
1340        }
1341        if (ianns != null) {
1342            ++attributeCount;
1343        }
1344        if (panns != null) {
1345            ++attributeCount;
1346        }
1347        if (ipanns != null) {
1348            ++attributeCount;
1349        }
1350        if (attrs != null) {
1351            attributeCount += attrs.getCount();
1352        }
1353        out.putShort(attributeCount);
1354        if (code.length > 0) {
1355            int size = 12 + code.length + 8 * catchCount;
1356            if (localVar != null) {
1357                size += 8 + localVar.length;
1358            }
1359            if (localVarType != null) {
1360                size += 8 + localVarType.length;
1361            }
1362            if (lineNumber != null) {
1363                size += 8 + lineNumber.length;
1364            }
1365            if (cattrs != null) {
1366                size += cattrs.getSize(cw,
1367                        code.data,
1368                        code.length,
1369                        maxStack,
1370                        maxLocals);
1371            }
1372            out.putShort(cw.newUTF8("Code")).putInt(size);
1373            out.putShort(maxStack).putShort(maxLocals);
1374            out.putInt(code.length).putByteArray(code.data, 0, code.length);
1375            out.putShort(catchCount);
1376            if (catchCount > 0) {
1377                Handler h = catchTable;
1378                while (h != null) {
1379                    out.putShort(h.start.position)
1380                            .putShort(h.end.position)
1381                            .putShort(h.handler.position)
1382                            .putShort(h.type);
1383                    h = h.next;
1384                }
1385            }
1386            attributeCount = 0;
1387            if (localVar != null) {
1388                ++attributeCount;
1389            }
1390            if (localVarType != null) {
1391                ++attributeCount;
1392            }
1393            if (lineNumber != null) {
1394                ++attributeCount;
1395            }
1396            if (cattrs != null) {
1397                attributeCount += cattrs.getCount();
1398            }
1399            out.putShort(attributeCount);
1400            if (localVar != null) {
1401                out.putShort(cw.newUTF8("LocalVariableTable"));
1402                out.putInt(localVar.length + 2).putShort(localVarCount);
1403                out.putByteArray(localVar.data, 0, localVar.length);
1404            }
1405            if (localVarType != null) {
1406                out.putShort(cw.newUTF8("LocalVariableTypeTable"));
1407                out.putInt(localVarType.length + 2).putShort(localVarTypeCount);
1408                out.putByteArray(localVarType.data, 0, localVarType.length);
1409            }
1410            if (lineNumber != null) {
1411                out.putShort(cw.newUTF8("LineNumberTable"));
1412                out.putInt(lineNumber.length + 2).putShort(lineNumberCount);
1413                out.putByteArray(lineNumber.data, 0, lineNumber.length);
1414            }
1415            if (cattrs != null) {
1416                cattrs.put(cw, code.data, code.length, maxLocals, maxStack, out);
1417            }
1418        }
1419        if (exceptionCount > 0) {
1420            out.putShort(cw.newUTF8("Exceptions"))
1421                    .putInt(2 * exceptionCount + 2);
1422            out.putShort(exceptionCount);
1423            for (int i = 0; i < exceptionCount; ++i) {
1424                out.putShort(exceptions[i]);
1425            }
1426        }
1427        if ((access & Opcodes.ACC_SYNTHETIC) != 0
1428                && (cw.version & 0xffff) < Opcodes.V1_5)
1429        {
1430            out.putShort(cw.newUTF8("Synthetic")).putInt(0);
1431        }
1432        if ((access & Opcodes.ACC_DEPRECATED) != 0) {
1433            out.putShort(cw.newUTF8("Deprecated")).putInt(0);
1434        }
1435        if (cw.version == Opcodes.V1_4) {
1436            if ((access & Opcodes.ACC_VARARGS) != 0) {
1437                out.putShort(cw.newUTF8("Varargs")).putInt(0);
1438            }
1439            if ((access & Opcodes.ACC_BRIDGE) != 0) {
1440                out.putShort(cw.newUTF8("Bridge")).putInt(0);
1441            }
1442        }
1443        if (signature != null) {
1444            out.putShort(cw.newUTF8("Signature"))
1445                    .putInt(2)
1446                    .putShort(cw.newUTF8(signature));
1447        }
1448        if (annd != null) {
1449            out.putShort(cw.newUTF8("AnnotationDefault"));
1450            out.putInt(annd.length);
1451            out.putByteArray(annd.data, 0, annd.length);
1452        }
1453        if (anns != null) {
1454            out.putShort(cw.newUTF8("RuntimeVisibleAnnotations"));
1455            anns.put(out);
1456        }
1457        if (ianns != null) {
1458            out.putShort(cw.newUTF8("RuntimeInvisibleAnnotations"));
1459            ianns.put(out);
1460        }
1461        if (panns != null) {
1462            out.putShort(cw.newUTF8("RuntimeVisibleParameterAnnotations"));
1463            AnnotationWriter.put(panns, out);
1464        }
1465        if (ipanns != null) {
1466            out.putShort(cw.newUTF8("RuntimeInvisibleParameterAnnotations"));
1467            AnnotationWriter.put(ipanns, out);
1468        }
1469        if (attrs != null) {
1470            attrs.put(cw, null, 0, -1, -1, out);
1471        }
1472    }
1473
1474    // ------------------------------------------------------------------------
1475
// Utility methods: instruction resizing (used to handle GOTO_W and JSR_W)
1476
// ------------------------------------------------------------------------
1477

1478    /**
1479     * Resizes the designated instructions, while keeping jump offsets and
1480     * instruction addresses consistent. This may require to resize other
1481     * existing instructions, or even to introduce new instructions: for
1482     * example, increasing the size of an instruction by 2 at the middle of a
1483     * method can increases the offset of an IFEQ instruction from 32766 to
1484     * 32768, in which case IFEQ 32766 must be replaced with IFNEQ 8 GOTO_W
1485     * 32765. This, in turn, may require to increase the size of another jump
1486     * instruction, and so on... All these operations are handled automatically
1487     * by this method. <p> <i>This method must be called after all the method
1488     * that is being built has been visited</i>. In particular, the
1489     * {@link Label Label} objects used to construct the method are no longer
1490     * valid after this method has been called.
1491     *
1492     * @param indexes current positions of the instructions to be resized. Each
1493     * instruction must be designated by the index of its <i>last</i>
1494     * byte, plus one (or, in other words, by the index of the <i>first</i>
1495     * byte of the <i>next</i> instruction).
1496     * @param sizes the number of bytes to be <i>added</i> to the above
1497     * instructions. More precisely, for each i &lt; <tt>len</tt>,
1498     * <tt>sizes</tt>[i] bytes will be added at the end of the
1499     * instruction designated by <tt>indexes</tt>[i] or, if
1500     * <tt>sizes</tt>[i] is negative, the <i>last</i> |<tt>sizes[i]</tt>|
1501     * bytes of the instruction will be removed (the instruction size
1502     * <i>must not</i> become negative or null). The gaps introduced by
1503     * this method must be filled in "manually" in {@link #code code}
1504     * method.
1505     * @param len the number of instruction to be resized. Must be smaller than
1506     * or equal to <tt>indexes</tt>.length and <tt>sizes</tt>.length.
1507     * @return the <tt>indexes</tt> array, which now contains the new
1508     * positions of the resized instructions (designated as above).
1509     */

1510    private int[] resizeInstructions(
1511        final int[] indexes,
1512        final int[] sizes,
1513        final int len)
1514    {
1515        byte[] b = code.data; // bytecode of the method
1516
int u, v, label; // indexes in b
1517
int i, j; // loop indexes
1518

1519        /*
1520         * 1st step: As explained above, resizing an instruction may require to
1521         * resize another one, which may require to resize yet another one, and
1522         * so on. The first step of the algorithm consists in finding all the
1523         * instructions that need to be resized, without modifying the code.
1524         * This is done by the following "fix point" algorithm:
1525         *
1526         * Parse the code to find the jump instructions whose offset will need
1527         * more than 2 bytes to be stored (the future offset is computed from
1528         * the current offset and from the number of bytes that will be inserted
1529         * or removed between the source and target instructions). For each such
1530         * instruction, adds an entry in (a copy of) the indexes and sizes
1531         * arrays (if this has not already been done in a previous iteration!).
1532         *
1533         * If at least one entry has been added during the previous step, go
1534         * back to the beginning, otherwise stop.
1535         *
1536         * In fact the real algorithm is complicated by the fact that the size
1537         * of TABLESWITCH and LOOKUPSWITCH instructions depends on their
1538         * position in the bytecode (because of padding). In order to ensure the
1539         * convergence of the algorithm, the number of bytes to be added or
1540         * removed from these instructions is over estimated during the previous
1541         * loop, and computed exactly only after the loop is finished (this
1542         * requires another pass to parse the bytecode of the method).
1543         */

1544        int[] allIndexes = new int[len]; // copy of indexes
1545
int[] allSizes = new int[len]; // copy of sizes
1546
boolean[] resize; // instructions to be resized
1547
int newOffset; // future offset of a jump instruction
1548

1549        System.arraycopy(indexes, 0, allIndexes, 0, len);
1550        System.arraycopy(sizes, 0, allSizes, 0, len);
1551        resize = new boolean[code.length];
1552
1553        // 3 = loop again, 2 = loop ended, 1 = last pass, 0 = done
1554
int state = 3;
1555        do {
1556            if (state == 3) {
1557                state = 2;
1558            }
1559            u = 0;
1560            while (u < b.length) {
1561                int opcode = b[u] & 0xFF; // opcode of current instruction
1562
int insert = 0; // bytes to be added after this instruction
1563

1564                switch (ClassWriter.TYPE[opcode]) {
1565                    case ClassWriter.NOARG_INSN:
1566                    case ClassWriter.IMPLVAR_INSN:
1567                        u += 1;
1568                        break;
1569                    case ClassWriter.LABEL_INSN:
1570                        if (opcode > 201) {
1571                            // converts temporary opcodes 202 to 217, 218 and
1572
// 219 to IFEQ ... JSR (inclusive), IFNULL and
1573
// IFNONNULL
1574
opcode = opcode < 218 ? opcode - 49 : opcode - 20;
1575                            label = u + readUnsignedShort(b, u + 1);
1576                        } else {
1577                            label = u + readShort(b, u + 1);
1578                        }
1579                        newOffset = getNewOffset(allIndexes, allSizes, u, label);
1580                        if (newOffset < Short.MIN_VALUE
1581                                || newOffset > Short.MAX_VALUE)
1582                        {
1583                            if (!resize[u]) {
1584                                if (opcode == Opcodes.GOTO
1585                                        || opcode == Opcodes.JSR)
1586                                {
1587                                    // two additional bytes will be required to
1588
// replace this GOTO or JSR instruction with
1589
// a GOTO_W or a JSR_W
1590
insert = 2;
1591                                } else {
1592                                    // five additional bytes will be required to
1593
// replace this IFxxx <l> instruction with
1594
// IFNOTxxx <l'> GOTO_W <l>, where IFNOTxxx
1595
// is the "opposite" opcode of IFxxx (i.e.,
1596
// IFNE for IFEQ) and where <l'> designates
1597
// the instruction just after the GOTO_W.
1598
insert = 5;
1599                                }
1600                                resize[u] = true;
1601                            }
1602                        }
1603                        u += 3;
1604                        break;
1605                    case ClassWriter.LABELW_INSN:
1606                        u += 5;
1607                        break;
1608                    case ClassWriter.TABL_INSN:
1609                        if (state == 1) {
1610                            // true number of bytes to be added (or removed)
1611
// from this instruction = (future number of padding
1612
// bytes - current number of padding byte) -
1613
// previously over estimated variation =
1614
// = ((3 - newOffset%4) - (3 - u%4)) - u%4
1615
// = (-newOffset%4 + u%4) - u%4
1616
// = -(newOffset & 3)
1617
newOffset = getNewOffset(allIndexes, allSizes, 0, u);
1618                            insert = -(newOffset & 3);
1619                        } else if (!resize[u]) {
1620                            // over estimation of the number of bytes to be
1621
// added to this instruction = 3 - current number
1622
// of padding bytes = 3 - (3 - u%4) = u%4 = u & 3
1623
insert = u & 3;
1624                            resize[u] = true;
1625                        }
1626                        // skips instruction
1627
u = u + 4 - (u & 3);
1628                        u += 4 * (readInt(b, u + 8) - readInt(b, u + 4) + 1) + 12;
1629                        break;
1630                    case ClassWriter.LOOK_INSN:
1631                        if (state == 1) {
1632                            // like TABL_INSN
1633
newOffset = getNewOffset(allIndexes, allSizes, 0, u);
1634                            insert = -(newOffset & 3);
1635                        } else if (!resize[u]) {
1636                            // like TABL_INSN
1637
insert = u & 3;
1638                            resize[u] = true;
1639                        }
1640                        // skips instruction
1641
u = u + 4 - (u & 3);
1642                        u += 8 * readInt(b, u + 4) + 8;
1643                        break;
1644                    case ClassWriter.WIDE_INSN:
1645                        opcode = b[u + 1] & 0xFF;
1646                        if (opcode == Opcodes.IINC) {
1647                            u += 6;
1648                        } else {
1649                            u += 4;
1650                        }
1651                        break;
1652                    case ClassWriter.VAR_INSN:
1653                    case ClassWriter.SBYTE_INSN:
1654                    case ClassWriter.LDC_INSN:
1655                        u += 2;
1656                        break;
1657                    case ClassWriter.SHORT_INSN:
1658                    case ClassWriter.LDCW_INSN:
1659                    case ClassWriter.FIELDORMETH_INSN:
1660                    case ClassWriter.TYPE_INSN:
1661                    case ClassWriter.IINC_INSN:
1662                        u += 3;
1663                        break;
1664                    case ClassWriter.ITFMETH_INSN:
1665                        u += 5;
1666                        break;
1667                    // case ClassWriter.MANA_INSN:
1668
default:
1669                        u += 4;
1670                        break;
1671                }
1672                if (insert != 0) {
1673                    // adds a new (u, insert) entry in the allIndexes and
1674
// allSizes arrays
1675
int[] newIndexes = new int[allIndexes.length + 1];
1676                    int[] newSizes = new int[allSizes.length + 1];
1677                    System.arraycopy(allIndexes,
1678                            0,
1679                            newIndexes,
1680                            0,
1681                            allIndexes.length);
1682                    System.arraycopy(allSizes, 0, newSizes, 0, allSizes.length);
1683                    newIndexes[allIndexes.length] = u;
1684                    newSizes[allSizes.length] = insert;
1685                    allIndexes = newIndexes;
1686                    allSizes = newSizes;
1687                    if (insert > 0) {
1688                        state = 3;
1689                    }
1690                }
1691            }
1692            if (state < 3) {
1693                --state;
1694            }
1695        } while (state != 0);
1696
1697        // 2nd step:
1698
// copies the bytecode of the method into a new bytevector, updates the
1699
// offsets, and inserts (or removes) bytes as requested.
1700

1701        ByteVector newCode = new ByteVector(code.length);
1702
1703        u = 0;
1704        while (u < code.length) {
1705            for (i = allIndexes.length - 1; i >= 0; --i) {
1706                if (allIndexes[i] == u) {
1707                    if (i < len) {
1708                        if (sizes[i] > 0) {
1709                            newCode.putByteArray(null, 0, sizes[i]);
1710                        } else {
1711                            newCode.length += sizes[i];
1712                        }
1713                        indexes[i] = newCode.length;
1714                    }
1715                }
1716            }
1717            int opcode = b[u] & 0xFF;
1718            switch (ClassWriter.TYPE[opcode]) {
1719                case ClassWriter.NOARG_INSN:
1720                case ClassWriter.IMPLVAR_INSN:
1721                    newCode.putByte(opcode);
1722                    u += 1;
1723                    break;
1724                case ClassWriter.LABEL_INSN:
1725                    if (opcode > 201) {
1726                        // changes temporary opcodes 202 to 217 (inclusive), 218
1727
// and 219 to IFEQ ... JSR (inclusive), IFNULL and
1728
// IFNONNULL
1729
opcode = opcode < 218 ? opcode - 49 : opcode - 20;
1730                        label = u + readUnsignedShort(b, u + 1);
1731                    } else {
1732                        label = u + readShort(b, u + 1);
1733                    }
1734                    newOffset = getNewOffset(allIndexes, allSizes, u, label);
1735                    if (resize[u]) {
1736                        // replaces GOTO with GOTO_W, JSR with JSR_W and IFxxx
1737
// <l> with IFNOTxxx <l'> GOTO_W <l>, where IFNOTxxx is
1738
// the "opposite" opcode of IFxxx (i.e., IFNE for IFEQ)
1739
// and where <l'> designates the instruction just after
1740
// the GOTO_W.
1741
if (opcode == Opcodes.GOTO) {
1742                            newCode.putByte(200); // GOTO_W
1743
} else if (opcode == Opcodes.JSR) {
1744                            newCode.putByte(201); // JSR_W
1745
} else {
1746                            newCode.putByte(opcode <= 166
1747                                    ? ((opcode + 1) ^ 1) - 1
1748                                    : opcode ^ 1);
1749                            newCode.putShort(8); // jump offset
1750
newCode.putByte(200); // GOTO_W
1751
// newOffset now computed from start of GOTO_W
1752
newOffset -= 3;
1753                        }
1754                        newCode.putInt(newOffset);
1755                    } else {
1756                        newCode.putByte(opcode);
1757                        newCode.putShort(newOffset);
1758                    }
1759                    u += 3;
1760                    break;
1761                case ClassWriter.LABELW_INSN:
1762                    label = u + readInt(b, u + 1);
1763                    newOffset = getNewOffset(allIndexes, allSizes, u, label);
1764                    newCode.putByte(opcode);
1765                    newCode.putInt(newOffset);
1766                    u += 5;
1767                    break;
1768                case ClassWriter.TABL_INSN:
1769                    // skips 0 to 3 padding bytes
1770
v = u;
1771                    u = u + 4 - (v & 3);
1772                    // reads and copies instruction
1773
newCode.putByte(Opcodes.TABLESWITCH);
1774                    while (newCode.length % 4 != 0) {
1775                        newCode.putByte(0);
1776                    }
1777                    label = v + readInt(b, u);
1778                    u += 4;
1779                    newOffset = getNewOffset(allIndexes, allSizes, v, label);
1780                    newCode.putInt(newOffset);
1781                    j = readInt(b, u);
1782                    u += 4;
1783                    newCode.putInt(j);
1784                    j = readInt(b, u) - j + 1;
1785                    u += 4;
1786                    newCode.putInt(readInt(b, u - 4));
1787                    for (; j > 0; --j) {
1788                        label = v + readInt(b, u);
1789                        u += 4;
1790                        newOffset = getNewOffset(allIndexes, allSizes, v, label);
1791                        newCode.putInt(newOffset);
1792                    }
1793                    break;
1794                case ClassWriter.LOOK_INSN:
1795                    // skips 0 to 3 padding bytes
1796
v = u;
1797                    u = u + 4 - (v & 3);
1798                    // reads and copies instruction
1799
newCode.putByte(Opcodes.LOOKUPSWITCH);
1800                    while (newCode.length % 4 != 0) {
1801                        newCode.putByte(0);
1802                    }
1803                    label = v + readInt(b, u);
1804                    u += 4;
1805                    newOffset = getNewOffset(allIndexes, allSizes, v, label);
1806                    newCode.putInt(newOffset);
1807                    j = readInt(b, u);
1808                    u += 4;
1809                    newCode.putInt(j);
1810                    for (; j > 0; --j) {
1811                        newCode.putInt(readInt(b, u));
1812                        u += 4;
1813                        label = v + readInt(b, u);
1814                        u += 4;
1815                        newOffset = getNewOffset(allIndexes, allSizes, v, label);
1816                        newCode.putInt(newOffset);
1817                    }
1818                    break;
1819                case ClassWriter.WIDE_INSN:
1820                    opcode = b[u + 1] & 0xFF;
1821                    if (opcode == Opcodes.IINC) {
1822                        newCode.putByteArray(b, u, 6);
1823                        u += 6;
1824                    } else {
1825                        newCode.putByteArray(b, u, 4);
1826                        u += 4;
1827                    }
1828                    break;
1829                case ClassWriter.VAR_INSN:
1830                case ClassWriter.SBYTE_INSN:
1831                case ClassWriter.LDC_INSN:
1832                    newCode.putByteArray(b, u, 2);
1833                    u += 2;
1834                    break;
1835                case ClassWriter.SHORT_INSN:
1836                case ClassWriter.LDCW_INSN:
1837                case ClassWriter.FIELDORMETH_INSN:
1838                case ClassWriter.TYPE_INSN:
1839                case ClassWriter.IINC_INSN:
1840                    newCode.putByteArray(b, u, 3);
1841                    u += 3;
1842                    break;
1843                case ClassWriter.ITFMETH_INSN:
1844                    newCode.putByteArray(b, u, 5);
1845                    u += 5;
1846                    break;
1847                // case MANA_INSN:
1848
default:
1849                    newCode.putByteArray(b, u, 4);
1850                    u += 4;
1851                    break;
1852            }
1853        }
1854
1855        // updates the exception handler block labels
1856
Handler h = catchTable;
1857        while (h != null) {
1858            getNewOffset(allIndexes, allSizes, h.start);
1859            getNewOffset(allIndexes, allSizes, h.end);
1860            getNewOffset(allIndexes, allSizes, h.handler);
1861            h = h.next;
1862        }
1863        for (i = 0; i < 2; ++i) {
1864            ByteVector bv = i == 0 ? localVar : localVarType;
1865            if (bv != null) {
1866                b = bv.data;
1867                u = 0;
1868                while (u < bv.length) {
1869                    label = readUnsignedShort(b, u);
1870                    newOffset = getNewOffset(allIndexes, allSizes, 0, label);
1871                    writeShort(b, u, newOffset);
1872                    label += readUnsignedShort(b, u + 2);
1873                    newOffset = getNewOffset(allIndexes, allSizes, 0, label)
1874                            - newOffset;
1875                    writeShort(b, u + 2, newOffset);
1876                    u += 10;
1877                }
1878            }
1879        }
1880        if (lineNumber != null) {
1881            b = lineNumber.data;
1882            u = 0;
1883            while (u < lineNumber.length) {
1884                writeShort(b, u, getNewOffset(allIndexes,
1885                        allSizes,
1886                        0,
1887                        readUnsignedShort(b, u)));
1888                u += 4;
1889            }
1890        }
1891        // updates the labels of the other attributes
1892
while (cattrs != null) {
1893            Label[] labels = cattrs.getLabels();
1894            if (labels != null) {
1895                for (i = labels.length - 1; i >= 0; --i) {
1896                    if (!labels[i].resized) {
1897                        labels[i].position = getNewOffset(allIndexes,
1898                                allSizes,
1899                                0,
1900                                labels[i].position);
1901                        labels[i].resized = true;
1902                    }
1903                }
1904            }
1905        }
1906
1907        // replaces old bytecodes with new ones
1908
code = newCode;
1909
1910        // returns the positions of the resized instructions
1911
return indexes;
1912    }
1913
1914    /**
1915     * Reads an unsigned short value in the given byte array.
1916     *
1917     * @param b a byte array.
1918     * @param index the start index of the value to be read.
1919     * @return the read value.
1920     */

1921    static int readUnsignedShort(final byte[] b, final int index) {
1922        return ((b[index] & 0xFF) << 8) | (b[index + 1] & 0xFF);
1923    }
1924
1925    /**
1926     * Reads a signed short value in the given byte array.
1927     *
1928     * @param b a byte array.
1929     * @param index the start index of the value to be read.
1930     * @return the read value.
1931     */

1932    static short readShort(final byte[] b, final int index) {
1933        return (short) (((b[index] & 0xFF) << 8) | (b[index + 1] & 0xFF));
1934    }
1935
1936    /**
1937     * Reads a signed int value in the given byte array.
1938     *
1939     * @param b a byte array.
1940     * @param index the start index of the value to be read.
1941     * @return the read value.
1942     */

1943    static int readInt(final byte[] b, final int index) {
1944        return ((b[index] & 0xFF) << 24) | ((b[index + 1] & 0xFF) << 16)
1945                | ((b[index + 2] & 0xFF) << 8) | (b[index + 3] & 0xFF);
1946    }
1947
1948    /**
1949     * Writes a short value in the given byte array.
1950     *
1951     * @param b a byte array.
1952     * @param index where the first byte of the short value must be written.
1953     * @param s the value to be written in the given byte array.
1954     */

1955    static void writeShort(final byte[] b, final int index, final int s) {
1956        b[index] = (byte) (s >>> 8);
1957        b[index + 1] = (byte) s;
1958    }
1959
1960    /**
1961     * Computes the future value of a bytecode offset. <p> Note: it is possible
1962     * to have several entries for the same instruction in the <tt>indexes</tt>
1963     * and <tt>sizes</tt>: two entries (index=a,size=b) and (index=a,size=b')
1964     * are equivalent to a single entry (index=a,size=b+b').
1965     *
1966     * @param indexes current positions of the instructions to be resized. Each
1967     * instruction must be designated by the index of its <i>last</i>
1968     * byte, plus one (or, in other words, by the index of the <i>first</i>
1969     * byte of the <i>next</i> instruction).
1970     * @param sizes the number of bytes to be <i>added</i> to the above
1971     * instructions. More precisely, for each i < <tt>len</tt>,
1972     * <tt>sizes</tt>[i] bytes will be added at the end of the
1973     * instruction designated by <tt>indexes</tt>[i] or, if
1974     * <tt>sizes</tt>[i] is negative, the <i>last</i> |<tt>sizes[i]</tt>|
1975     * bytes of the instruction will be removed (the instruction size
1976     * <i>must not</i> become negative or null).
1977     * @param begin index of the first byte of the source instruction.
1978     * @param end index of the first byte of the target instruction.
1979     * @return the future value of the given bytecode offset.
1980     */

1981    static int getNewOffset(
1982        final int[] indexes,
1983        final int[] sizes,
1984        final int begin,
1985        final int end)
1986    {
1987        int offset = end - begin;
1988        for (int i = 0; i < indexes.length; ++i) {
1989            if (begin < indexes[i] && indexes[i] <= end) {
1990                // forward jump
1991
offset += sizes[i];
1992            } else if (end < indexes[i] && indexes[i] <= begin) {
1993                // backward jump
1994
offset -= sizes[i];
1995            }
1996        }
1997        return offset;
1998    }
1999    
2000    /**
2001     * Updates the offset of the given label.
2002     *
2003     * @param indexes current positions of the instructions to be resized. Each
2004     * instruction must be designated by the index of its <i>last</i>
2005     * byte, plus one (or, in other words, by the index of the <i>first</i>
2006     * byte of the <i>next</i> instruction).
2007     * @param sizes the number of bytes to be <i>added</i> to the above
2008     * instructions. More precisely, for each i < <tt>len</tt>,
2009     * <tt>sizes</tt>[i] bytes will be added at the end of the
2010     * instruction designated by <tt>indexes</tt>[i] or, if
2011     * <tt>sizes</tt>[i] is negative, the <i>last</i> |<tt>sizes[i]</tt>|
2012     * bytes of the instruction will be removed (the instruction size
2013     * <i>must not</i> become negative or null).
2014     * @param label the label whose offset must be updated.
2015     */

2016    static void getNewOffset(
2017        final int[] indexes,
2018        final int[] sizes,
2019        final Label label)
2020    {
2021        if (!label.resized) {
2022            label.position = getNewOffset(indexes, sizes, 0, label.position);
2023            label.resized = true;
2024        }
2025    }
2026}
2027
Popular Tags