KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > tc > 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 com.tc.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  */

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

1505    private int[] resizeInstructions(
1506        final int[] indexes,
1507        final int[] sizes,
1508        final int len)
1509    {
1510        byte[] b = code.data; // bytecode of the method
1511
int u, v, label; // indexes in b
1512
int i, j; // loop indexes
1513

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

1539        int[] allIndexes = new int[len]; // copy of indexes
1540
int[] allSizes = new int[len]; // copy of sizes
1541
boolean[] resize; // instructions to be resized
1542
int newOffset; // future offset of a jump instruction
1543

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

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

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

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

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

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

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

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

2011    static void getNewOffset(
2012        final int[] indexes,
2013        final int[] sizes,
2014        final Label label)
2015    {
2016        if (!label.resized) {
2017            label.position = getNewOffset(indexes, sizes, 0, label.position);
2018            label.resized = true;
2019        }
2020    }
2021}
2022
2023
Popular Tags