KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > objectweb > 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 org.objectweb.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     private 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      * The index of the constant pool item that contains the signature of this
75      * method.
76      */

77     private int signature;
78
79     /**
80      * Number of exceptions that can be thrown by this method.
81      */

82     private int exceptionCount;
83
84     /**
85      * The exceptions that can be thrown by this method. More precisely, this
86      * array contains the indexes of the constant pool items that contain the
87      * internal names of these exception classes.
88      */

89     private int[] exceptions;
90
91     /**
92      * The annotation default attribute of this method. May be <tt>null</tt>.
93      */

94     private ByteVector annd;
95
96     /**
97      * The runtime visible annotations of this method. May be <tt>null</tt>.
98      */

99     private AnnotationWriter anns;
100
101     /**
102      * The runtime invisible annotations of this method. May be <tt>null</tt>.
103      */

104     private AnnotationWriter ianns;
105
106     /**
107      * The runtime visible parameter annotations of this method. May be
108      * <tt>null</tt>.
109      */

110     private AnnotationWriter[] panns;
111
112     /**
113      * The runtime invisible parameter annotations of this method. May be
114      * <tt>null</tt>.
115      */

116     private AnnotationWriter[] ipanns;
117
118     /**
119      * The non standard attributes of the method.
120      */

121     private Attribute attrs;
122
123     /**
124      * The bytecode of this method.
125      */

126     private ByteVector code = new ByteVector();
127
128     /**
129      * Maximum stack size of this method.
130      */

131     private int maxStack;
132
133     /**
134      * Maximum number of local variables for this method.
135      */

136     private int maxLocals;
137
138     /**
139      * Number of entries in the catch table of this method.
140      */

141     private int catchCount;
142
143     /**
144      * The catch table of this method.
145      */

146     private ByteVector catchTable;
147
148     /**
149      * Number of entries in the LocalVariableTable attribute.
150      */

151     private int localVarCount;
152
153     /**
154      * The LocalVariableTable attribute.
155      */

156     private ByteVector localVar;
157
158     /**
159      * Number of entries in the LocalVariableTypeTable attribute.
160      */

161     private int localVarTypeCount;
162
163     /**
164      * The LocalVariableTypeTable attribute.
165      */

166     private ByteVector localVarType;
167
168     /**
169      * Number of entries in the LineNumberTable attribute.
170      */

171     private int lineNumberCount;
172
173     /**
174      * The LineNumberTable attribute.
175      */

176     private ByteVector lineNumber;
177
178     /**
179      * The non standard attributes of the method's code.
180      */

181     private Attribute cattrs;
182
183     /**
184      * Indicates if some jump instructions are too small and need to be resized.
185      */

186     private boolean resize;
187
188     /*
189      * Fields for the control flow graph analysis algorithm (used to compute the
190      * maximum stack size). A control flow graph contains one node per "basic
191      * block", and one edge per "jump" from one basic block to another. Each
192      * node (i.e., each basic block) is represented by the Label object that
193      * corresponds to the first instruction of this basic block. Each node also
194      * stores the list of its successors in the graph, as a linked list of Edge
195      * objects.
196      */

197
198     /**
199      * <tt>true</tt> if the maximum stack size and number of local variables
200      * must be automatically computed.
201      */

202     private final boolean computeMaxs;
203
204     /**
205      * The (relative) stack size after the last visited instruction. This size
206      * is relative to the beginning of the current basic block, i.e., the true
207      * stack size after the last visited instruction is equal to the {@link
208      * Label#beginStackSize beginStackSize} of the current basic block plus
209      * <tt>stackSize</tt>.
210      */

211     private int stackSize;
212
213     /**
214      * The (relative) maximum stack size after the last visited instruction.
215      * This size is relative to the beginning of the current basic block, i.e.,
216      * the true maximum stack size after the last visited instruction is equal
217      * to the {@link Label#beginStackSize beginStackSize} of the current basic
218      * block plus <tt>stackSize</tt>.
219      */

220     private int maxStackSize;
221
222     /**
223      * The current basic block. This block is the basic block to which the next
224      * instruction to be visited must be added.
225      */

226     private Label currentBlock;
227
228     /**
229      * The basic block stack used by the control flow analysis algorithm. This
230      * stack is represented by a linked list of {@link Label Label} objects,
231      * linked to each other by their {@link Label#next} field. This stack must
232      * not be confused with the JVM stack used to execute the JVM instructions!
233      */

234     private Label blockStack;
235
236     /**
237      * The stack size variation corresponding to each JVM instruction. This
238      * stack variation is equal to the size of the values produced by an
239      * instruction, minus the size of the values consumed by this instruction.
240      */

241     private final static int[] SIZE;
242
243     // ------------------------------------------------------------------------
244
// Static initializer
245
// ------------------------------------------------------------------------
246

247     /**
248      * Computes the stack size variation corresponding to each JVM instruction.
249      */

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

480     /**
481      * Constructs a new {@link MethodWriter}.
482      *
483      * @param cw the class writer in which the method must be added.
484      * @param access the method's access flags (see {@link Opcodes}).
485      * @param name the method's name.
486      * @param desc the method's descriptor (see {@link Type}).
487      * @param signature the method's signature. May be <tt>null</tt>.
488      * @param exceptions the internal names of the method's exceptions. May be
489      * <tt>null</tt>.
490      * @param computeMaxs <tt>true</tt> if the maximum stack size and number
491      * of local variables must be automatically computed.
492      */

493     MethodWriter(
494         final ClassWriter cw,
495         final int access,
496         final String JavaDoc name,
497         final String JavaDoc desc,
498         final String JavaDoc signature,
499         final String JavaDoc[] exceptions,
500         final boolean computeMaxs)
501     {
502         if (cw.firstMethod == null) {
503             cw.firstMethod = this;
504         } else {
505             cw.lastMethod.next = this;
506         }
507         cw.lastMethod = this;
508         this.cw = cw;
509         this.access = access;
510         this.name = cw.newUTF8(name);
511         this.desc = cw.newUTF8(desc);
512         this.descriptor = desc;
513         if (signature != null) {
514             this.signature = cw.newUTF8(signature);
515         }
516         if (exceptions != null && exceptions.length > 0) {
517             exceptionCount = exceptions.length;
518             this.exceptions = new int[exceptionCount];
519             for (int i = 0; i < exceptionCount; ++i) {
520                 this.exceptions[i] = cw.newClass(exceptions[i]);
521             }
522         }
523         this.computeMaxs = computeMaxs;
524         if (computeMaxs) {
525             // updates maxLocals
526
int size = getArgumentsAndReturnSizes(desc) >> 2;
527             if ((access & Opcodes.ACC_STATIC) != 0) {
528                 --size;
529             }
530             maxLocals = size;
531             // pushes the first block onto the stack of blocks to be visited
532
currentBlock = new Label();
533             currentBlock.pushed = true;
534             blockStack = currentBlock;
535         }
536     }
537
538     // ------------------------------------------------------------------------
539
// Implementation of the MethodVisitor interface
540
// ------------------------------------------------------------------------
541

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

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

822             if (opcode == Opcodes.GOTO) {
823                 code.putByte(200); // GOTO_W
824
} else if (opcode == Opcodes.JSR) {
825                 code.putByte(201); // JSR_W
826
} else {
827                 code.putByte(opcode <= 166
828                         ? ((opcode + 1) ^ 1) - 1
829                         : opcode ^ 1);
830                 code.putShort(8); // jump offset
831
code.putByte(200); // GOTO_W
832
}
833             label.put(this, code, code.length - 1, true);
834         } else {
835             /*
836              * case of a backward jump with an offset >= -32768, or of a forward
837              * jump with, of course, an unknown offset. In these cases we store
838              * the offset in 2 bytes (which will be increased in
839              * resizeInstructions, if needed).
840              */

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

1060            Label stack = blockStack;
1061            while (stack != null) {
1062                // pops a block from the stack
1063
Label l = stack;
1064                stack = stack.next;
1065                // computes the true (non relative) max stack size of this block
1066
int start = l.beginStackSize;
1067                int blockMax = start + l.maxStackSize;
1068                // updates the global max stack size
1069
if (blockMax > max) {
1070                    max = blockMax;
1071                }
1072                // analyses the successors of the block
1073
Edge b = l.successors;
1074                while (b != null) {
1075                    l = b.successor;
1076                    // if this successor has not already been pushed onto the
1077
// stack...
1078
if (!l.pushed) {
1079                        // computes the true beginning stack size of this
1080
// successor block
1081
l.beginStackSize = start + b.stackSize;
1082                        // pushes this successor onto the stack
1083
l.pushed = true;
1084                        l.next = stack;
1085                        stack = l;
1086                    }
1087                    b = b.next;
1088                }
1089            }
1090            this.maxStack = max;
1091        } else {
1092            this.maxStack = maxStack;
1093            this.maxLocals = maxLocals;
1094        }
1095    }
1096
1097    public void visitEnd() {
1098    }
1099
1100    // ------------------------------------------------------------------------
1101
// Utility methods: control flow analysis algorithm
1102
// ------------------------------------------------------------------------
1103

1104    /**
1105     * Computes the size of the arguments and of the return value of a method.
1106     *
1107     * @param desc the descriptor of a method.
1108     * @return the size of the arguments of the method (plus one for the
1109     * implicit this argument), argSize, and the size of its return
1110     * value, retSize, packed into a single int i =
1111     * <tt>(argSize << 2) | retSize</tt> (argSize is therefore equal
1112     * to <tt>i >> 2</tt>, and retSize to <tt>i & 0x03</tt>).
1113     */

1114    private static int getArgumentsAndReturnSizes(final String JavaDoc desc) {
1115        int n = 1;
1116        int c = 1;
1117        while (true) {
1118            char car = desc.charAt(c++);
1119            if (car == ')') {
1120                car = desc.charAt(c);
1121                return n << 2
1122                        | (car == 'V' ? 0 : (car == 'D' || car == 'J' ? 2 : 1));
1123            } else if (car == 'L') {
1124                while (desc.charAt(c++) != ';') {
1125                }
1126                n += 1;
1127            } else if (car == '[') {
1128                while ((car = desc.charAt(c)) == '[') {
1129                    ++c;
1130                }
1131                if (car == 'D' || car == 'J') {
1132                    n -= 1;
1133                }
1134            } else if (car == 'D' || car == 'J') {
1135                n += 2;
1136            } else {
1137                n += 1;
1138            }
1139        }
1140    }
1141
1142    /**
1143     * Adds a successor to the {@link #currentBlock currentBlock} block.
1144     *
1145     * @param stackSize the current (relative) stack size in the current block.
1146     * @param successor the successor block to be added to the current block.
1147     */

1148    private void addSuccessor(final int stackSize, final Label successor) {
1149        Edge b = new Edge();
1150        // initializes the previous Edge object...
1151
b.stackSize = stackSize;
1152        b.successor = successor;
1153        // ...and adds it to the successor list of the currentBlock block
1154
b.next = currentBlock.successors;
1155        currentBlock.successors = b;
1156    }
1157
1158    // ------------------------------------------------------------------------
1159
// Utility methods: dump bytecode array
1160
// ------------------------------------------------------------------------
1161

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

1167    final int getSize() {
1168        if (resize) {
1169            // replaces the temporary jump opcodes introduced by Label.resolve.
1170
resizeInstructions(new int[0], new int[0], 0);
1171        }
1172        int size = 8;
1173        if (code.length > 0) {
1174            cw.newUTF8("Code");
1175            size += 18 + code.length + 8 * catchCount;
1176            if (localVar != null) {
1177                cw.newUTF8("LocalVariableTable");
1178                size += 8 + localVar.length;
1179            }
1180            if (localVarType != null) {
1181                cw.newUTF8("LocalVariableTypeTable");
1182                size += 8 + localVarType.length;
1183            }
1184            if (lineNumber != null) {
1185                cw.newUTF8("LineNumberTable");
1186                size += 8 + lineNumber.length;
1187            }
1188            if (cattrs != null) {
1189                size += cattrs.getSize(cw,
1190                        code.data,
1191                        code.length,
1192                        maxStack,
1193                        maxLocals);
1194            }
1195        }
1196        if (exceptionCount > 0) {
1197            cw.newUTF8("Exceptions");
1198            size += 8 + 2 * exceptionCount;
1199        }
1200        if ((access & Opcodes.ACC_SYNTHETIC) != 0
1201                && (cw.version & 0xffff) < Opcodes.V1_5)
1202        {
1203            cw.newUTF8("Synthetic");
1204            size += 6;
1205        }
1206        if ((access & Opcodes.ACC_DEPRECATED) != 0) {
1207            cw.newUTF8("Deprecated");
1208            size += 6;
1209        }
1210        if (cw.version == Opcodes.V1_4) {
1211            if ((access & Opcodes.ACC_VARARGS) != 0) {
1212                cw.newUTF8("Varargs");
1213                size += 6;
1214            }
1215            if ((access & Opcodes.ACC_BRIDGE) != 0) {
1216                cw.newUTF8("Bridge");
1217                size += 6;
1218            }
1219        }
1220        if (signature != 0) {
1221            cw.newUTF8("Signature");
1222            size += 8;
1223        }
1224        if (annd != null) {
1225            cw.newUTF8("AnnotationDefault");
1226            size += 6 + annd.length;
1227        }
1228        if (anns != null) {
1229            cw.newUTF8("RuntimeVisibleAnnotations");
1230            size += 8 + anns.getSize();
1231        }
1232        if (ianns != null) {
1233            cw.newUTF8("RuntimeInvisibleAnnotations");
1234            size += 8 + ianns.getSize();
1235        }
1236        if (panns != null) {
1237            cw.newUTF8("RuntimeVisibleParameterAnnotations");
1238            size += 7 + 2 * panns.length;
1239            for (int i = panns.length - 1; i >= 0; --i) {
1240                size += panns[i] == null ? 0 : panns[i].getSize();
1241            }
1242        }
1243        if (ipanns != null) {
1244            cw.newUTF8("RuntimeInvisibleParameterAnnotations");
1245            size += 7 + 2 * ipanns.length;
1246            for (int i = ipanns.length - 1; i >= 0; --i) {
1247                size += ipanns[i] == null ? 0 : ipanns[i].getSize();
1248            }
1249        }
1250        if (attrs != null) {
1251            size += attrs.getSize(cw, null, 0, -1, -1);
1252        }
1253        return size;
1254    }
1255
1256    /**
1257     * Puts the bytecode of this method in the given byte vector.
1258     *
1259     * @param out the byte vector into which the bytecode of this method must be
1260     * copied.
1261     */

1262    final void put(final ByteVector out) {
1263        out.putShort(access).putShort(name).putShort(desc);
1264        int attributeCount = 0;
1265        if (code.length > 0) {
1266            ++attributeCount;
1267        }
1268        if (exceptionCount > 0) {
1269            ++attributeCount;
1270        }
1271        if ((access & Opcodes.ACC_SYNTHETIC) != 0
1272                && (cw.version & 0xffff) < Opcodes.V1_5)
1273        {
1274            ++attributeCount;
1275        }
1276        if ((access & Opcodes.ACC_DEPRECATED) != 0) {
1277            ++attributeCount;
1278        }
1279        if (cw.version == Opcodes.V1_4) {
1280            if ((access & Opcodes.ACC_VARARGS) != 0) {
1281                ++attributeCount;
1282            }
1283            if ((access & Opcodes.ACC_BRIDGE) != 0) {
1284                ++attributeCount;
1285            }
1286        }
1287        if (signature != 0) {
1288            ++attributeCount;
1289        }
1290        if (annd != null) {
1291            ++attributeCount;
1292        }
1293        if (anns != null) {
1294            ++attributeCount;
1295        }
1296        if (ianns != null) {
1297            ++attributeCount;
1298        }
1299        if (panns != null) {
1300            ++attributeCount;
1301        }
1302        if (ipanns != null) {
1303            ++attributeCount;
1304        }
1305        if (attrs != null) {
1306            attributeCount += attrs.getCount();
1307        }
1308        out.putShort(attributeCount);
1309        if (code.length > 0) {
1310            int size = 12 + code.length + 8 * catchCount;
1311            if (localVar != null) {
1312                size += 8 + localVar.length;
1313            }
1314            if (localVarType != null) {
1315                size += 8 + localVarType.length;
1316            }
1317            if (lineNumber != null) {
1318                size += 8 + lineNumber.length;
1319            }
1320            if (cattrs != null) {
1321                size += cattrs.getSize(cw,
1322                        code.data,
1323                        code.length,
1324                        maxStack,
1325                        maxLocals);
1326            }
1327            out.putShort(cw.newUTF8("Code")).putInt(size);
1328            out.putShort(maxStack).putShort(maxLocals);
1329            out.putInt(code.length).putByteArray(code.data, 0, code.length);
1330            out.putShort(catchCount);
1331            if (catchCount > 0) {
1332                out.putByteArray(catchTable.data, 0, catchTable.length);
1333            }
1334            attributeCount = 0;
1335            if (localVar != null) {
1336                ++attributeCount;
1337            }
1338            if (localVarType != null) {
1339                ++attributeCount;
1340            }
1341            if (lineNumber != null) {
1342                ++attributeCount;
1343            }
1344            if (cattrs != null) {
1345                attributeCount += cattrs.getCount();
1346            }
1347            out.putShort(attributeCount);
1348            if (localVar != null) {
1349                out.putShort(cw.newUTF8("LocalVariableTable"));
1350                out.putInt(localVar.length + 2).putShort(localVarCount);
1351                out.putByteArray(localVar.data, 0, localVar.length);
1352            }
1353            if (localVarType != null) {
1354                out.putShort(cw.newUTF8("LocalVariableTypeTable"));
1355                out.putInt(localVarType.length + 2).putShort(localVarTypeCount);
1356                out.putByteArray(localVarType.data, 0, localVarType.length);
1357            }
1358            if (lineNumber != null) {
1359                out.putShort(cw.newUTF8("LineNumberTable"));
1360                out.putInt(lineNumber.length + 2).putShort(lineNumberCount);
1361                out.putByteArray(lineNumber.data, 0, lineNumber.length);
1362            }
1363            if (cattrs != null) {
1364                cattrs.put(cw, code.data, code.length, maxLocals, maxStack, out);
1365            }
1366        }
1367        if (exceptionCount > 0) {
1368            out.putShort(cw.newUTF8("Exceptions"))
1369                    .putInt(2 * exceptionCount + 2);
1370            out.putShort(exceptionCount);
1371            for (int i = 0; i < exceptionCount; ++i) {
1372                out.putShort(exceptions[i]);
1373            }
1374        }
1375        if ((access & Opcodes.ACC_SYNTHETIC) != 0
1376                && (cw.version & 0xffff) < Opcodes.V1_5)
1377        {
1378            out.putShort(cw.newUTF8("Synthetic")).putInt(0);
1379        }
1380        if ((access & Opcodes.ACC_DEPRECATED) != 0) {
1381            out.putShort(cw.newUTF8("Deprecated")).putInt(0);
1382        }
1383        if (cw.version == Opcodes.V1_4) {
1384            if ((access & Opcodes.ACC_VARARGS) != 0) {
1385                out.putShort(cw.newUTF8("Varargs")).putInt(0);
1386            }
1387            if ((access & Opcodes.ACC_BRIDGE) != 0) {
1388                out.putShort(cw.newUTF8("Bridge")).putInt(0);
1389            }
1390        }
1391        if (signature != 0) {
1392            out.putShort(cw.newUTF8("Signature")).putInt(2).putShort(signature);
1393        }
1394        if (annd != null) {
1395            out.putShort(cw.newUTF8("AnnotationDefault"));
1396            out.putInt(annd.length);
1397            out.putByteArray(annd.data, 0, annd.length);
1398        }
1399        if (anns != null) {
1400            out.putShort(cw.newUTF8("RuntimeVisibleAnnotations"));
1401            anns.put(out);
1402        }
1403        if (ianns != null) {
1404            out.putShort(cw.newUTF8("RuntimeInvisibleAnnotations"));
1405            ianns.put(out);
1406        }
1407        if (panns != null) {
1408            out.putShort(cw.newUTF8("RuntimeVisibleParameterAnnotations"));
1409            AnnotationWriter.put(panns, out);
1410        }
1411        if (ipanns != null) {
1412            out.putShort(cw.newUTF8("RuntimeInvisibleParameterAnnotations"));
1413            AnnotationWriter.put(ipanns, out);
1414        }
1415        if (attrs != null) {
1416            attrs.put(cw, null, 0, -1, -1, out);
1417        }
1418    }
1419
1420    // ------------------------------------------------------------------------
1421
// Utility methods: instruction resizing (used to handle GOTO_W and JSR_W)
1422
// ------------------------------------------------------------------------
1423

1424    /**
1425     * Resizes the designated instructions, while keeping jump offsets and
1426     * instruction addresses consistent. This may require to resize other
1427     * existing instructions, or even to introduce new instructions: for
1428     * example, increasing the size of an instruction by 2 at the middle of a
1429     * method can increases the offset of an IFEQ instruction from 32766 to
1430     * 32768, in which case IFEQ 32766 must be replaced with IFNEQ 8 GOTO_W
1431     * 32765. This, in turn, may require to increase the size of another jump
1432     * instruction, and so on... All these operations are handled automatically
1433     * by this method. <p> <i>This method must be called after all the method
1434     * that is being built has been visited</i>. In particular, the
1435     * {@link Label Label} objects used to construct the method are no longer
1436     * valid after this method has been called.
1437     *
1438     * @param indexes current positions of the instructions to be resized. Each
1439     * instruction must be designated by the index of its <i>last</i>
1440     * byte, plus one (or, in other words, by the index of the <i>first</i>
1441     * byte of the <i>next</i> instruction).
1442     * @param sizes the number of bytes to be <i>added</i> to the above
1443     * instructions. More precisely, for each i &lt; <tt>len</tt>,
1444     * <tt>sizes</tt>[i] bytes will be added at the end of the
1445     * instruction designated by <tt>indexes</tt>[i] or, if
1446     * <tt>sizes</tt>[i] is negative, the <i>last</i> |<tt>sizes[i]</tt>|
1447     * bytes of the instruction will be removed (the instruction size
1448     * <i>must not</i> become negative or null). The gaps introduced by
1449     * this method must be filled in "manually" in {@link #code code}
1450     * method.
1451     * @param len the number of instruction to be resized. Must be smaller than
1452     * or equal to <tt>indexes</tt>.length and <tt>sizes</tt>.length.
1453     * @return the <tt>indexes</tt> array, which now contains the new
1454     * positions of the resized instructions (designated as above).
1455     */

1456    private int[] resizeInstructions(
1457        final int[] indexes,
1458        final int[] sizes,
1459        final int len)
1460    {
1461        byte[] b = code.data; // bytecode of the method
1462
int u, v, label; // indexes in b
1463
int i, j; // loop indexes
1464

1465        /*
1466         * 1st step: As explained above, resizing an instruction may require to
1467         * resize another one, which may require to resize yet another one, and
1468         * so on. The first step of the algorithm consists in finding all the
1469         * instructions that need to be resized, without modifying the code.
1470         * This is done by the following "fix point" algorithm:
1471         *
1472         * Parse the code to find the jump instructions whose offset will need
1473         * more than 2 bytes to be stored (the future offset is computed from
1474         * the current offset and from the number of bytes that will be inserted
1475         * or removed between the source and target instructions). For each such
1476         * instruction, adds an entry in (a copy of) the indexes and sizes
1477         * arrays (if this has not already been done in a previous iteration!).
1478         *
1479         * If at least one entry has been added during the previous step, go
1480         * back to the beginning, otherwise stop.
1481         *
1482         * In fact the real algorithm is complicated by the fact that the size
1483         * of TABLESWITCH and LOOKUPSWITCH instructions depends on their
1484         * position in the bytecode (because of padding). In order to ensure the
1485         * convergence of the algorithm, the number of bytes to be added or
1486         * removed from these instructions is over estimated during the previous
1487         * loop, and computed exactly only after the loop is finished (this
1488         * requires another pass to parse the bytecode of the method).
1489         */
int[] allIndexes = new int[len]; // copy of indexes
1490
int[] allSizes = new int[len]; // copy of sizes
1491
boolean[] resize; // instructions to be resized
1492
int newOffset; // future offset of a jump instruction
1493

1494        System.arraycopy(indexes, 0, allIndexes, 0, len);
1495        System.arraycopy(sizes, 0, allSizes, 0, len);
1496        resize = new boolean[code.length];
1497
1498        int state = 3; // 3 = loop again, 2 = loop ended, 1 = last pass, 0 =
1499
// done
1500
do {
1501            if (state == 3) {
1502                state = 2;
1503            }
1504            u = 0;
1505            while (u < b.length) {
1506                int opcode = b[u] & 0xFF; // opcode of current instruction
1507
int insert = 0; // bytes to be added after this instruction
1508

1509                switch (ClassWriter.TYPE[opcode]) {
1510                    case ClassWriter.NOARG_INSN:
1511                    case ClassWriter.IMPLVAR_INSN:
1512                        u += 1;
1513                        break;
1514                    case ClassWriter.LABEL_INSN:
1515                        if (opcode > 201) {
1516                            // converts temporary opcodes 202 to 217, 218 and
1517
// 219 to IFEQ ... JSR (inclusive), IFNULL and
1518
// IFNONNULL
1519
opcode = opcode < 218 ? opcode - 49 : opcode - 20;
1520                            label = u + readUnsignedShort(b, u + 1);
1521                        } else {
1522                            label = u + readShort(b, u + 1);
1523                        }
1524                        newOffset = getNewOffset(allIndexes, allSizes, u, label);
1525                        if (newOffset < Short.MIN_VALUE
1526                                || newOffset > Short.MAX_VALUE)
1527                        {
1528                            if (!resize[u]) {
1529                                if (opcode == Opcodes.GOTO
1530                                        || opcode == Opcodes.JSR)
1531                                {
1532                                    // two additional bytes will be required to
1533
// replace this GOTO or JSR instruction with
1534
// a GOTO_W or a JSR_W
1535
insert = 2;
1536                                } else {
1537                                    // five additional bytes will be required to
1538
// replace this IFxxx <l> instruction with
1539
// IFNOTxxx <l'> GOTO_W <l>, where IFNOTxxx
1540
// is the "opposite" opcode of IFxxx (i.e.,
1541
// IFNE for IFEQ) and where <l'> designates
1542
// the instruction just after the GOTO_W.
1543
insert = 5;
1544                                }
1545                                resize[u] = true;
1546                            }
1547                        }
1548                        u += 3;
1549                        break;
1550                    case ClassWriter.LABELW_INSN:
1551                        u += 5;
1552                        break;
1553                    case ClassWriter.TABL_INSN:
1554                        if (state == 1) {
1555                            // true number of bytes to be added (or removed)
1556
// from this instruction = (future number of padding
1557
// bytes - current number of padding byte) -
1558
// previously over estimated variation =
1559
// = ((3 - newOffset%4) - (3 - u%4)) - u%4
1560
// = (-newOffset%4 + u%4) - u%4
1561
// = -(newOffset & 3)
1562
newOffset = getNewOffset(allIndexes, allSizes, 0, u);
1563                            insert = -(newOffset & 3);
1564                        } else if (!resize[u]) {
1565                            // over estimation of the number of bytes to be
1566
// added to this instruction = 3 - current number
1567
// of padding bytes = 3 - (3 - u%4) = u%4 = u & 3
1568
insert = u & 3;
1569                            resize[u] = true;
1570                        }
1571                        // skips instruction
1572
u = u + 4 - (u & 3);
1573                        u += 4 * (readInt(b, u + 8) - readInt(b, u + 4) + 1) + 12;
1574                        break;
1575                    case ClassWriter.LOOK_INSN:
1576                        if (state == 1) {
1577                            // like TABL_INSN
1578
newOffset = getNewOffset(allIndexes, allSizes, 0, u);
1579                            insert = -(newOffset & 3);
1580                        } else if (!resize[u]) {
1581                            // like TABL_INSN
1582
insert = u & 3;
1583                            resize[u] = true;
1584                        }
1585                        // skips instruction
1586
u = u + 4 - (u & 3);
1587                        u += 8 * readInt(b, u + 4) + 8;
1588                        break;
1589                    case ClassWriter.WIDE_INSN:
1590                        opcode = b[u + 1] & 0xFF;
1591                        if (opcode == Opcodes.IINC) {
1592                            u += 6;
1593                        } else {
1594                            u += 4;
1595                        }
1596                        break;
1597                    case ClassWriter.VAR_INSN:
1598                    case ClassWriter.SBYTE_INSN:
1599                    case ClassWriter.LDC_INSN:
1600                        u += 2;
1601                        break;
1602                    case ClassWriter.SHORT_INSN:
1603                    case ClassWriter.LDCW_INSN:
1604                    case ClassWriter.FIELDORMETH_INSN:
1605                    case ClassWriter.TYPE_INSN:
1606                    case ClassWriter.IINC_INSN:
1607                        u += 3;
1608                        break;
1609                    case ClassWriter.ITFMETH_INSN:
1610                        u += 5;
1611                        break;
1612                    // case ClassWriter.MANA_INSN:
1613
default:
1614                        u += 4;
1615                        break;
1616                }
1617                if (insert != 0) {
1618                    // adds a new (u, insert) entry in the allIndexes and
1619
// allSizes arrays
1620
int[] newIndexes = new int[allIndexes.length + 1];
1621                    int[] newSizes = new int[allSizes.length + 1];
1622                    System.arraycopy(allIndexes,
1623                            0,
1624                            newIndexes,
1625                            0,
1626                            allIndexes.length);
1627                    System.arraycopy(allSizes, 0, newSizes, 0, allSizes.length);
1628                    newIndexes[allIndexes.length] = u;
1629                    newSizes[allSizes.length] = insert;
1630                    allIndexes = newIndexes;
1631                    allSizes = newSizes;
1632                    if (insert > 0) {
1633                        state = 3;
1634                    }
1635                }
1636            }
1637            if (state < 3) {
1638                --state;
1639            }
1640        } while (state != 0);
1641
1642        // 2nd step:
1643
// copies the bytecode of the method into a new bytevector, updates the
1644
// offsets, and inserts (or removes) bytes as requested.
1645

1646        ByteVector newCode = new ByteVector(code.length);
1647
1648        u = 0;
1649        while (u < code.length) {
1650            for (i = allIndexes.length - 1; i >= 0; --i) {
1651                if (allIndexes[i] == u) {
1652                    if (i < len) {
1653                        if (sizes[i] > 0) {
1654                            newCode.putByteArray(null, 0, sizes[i]);
1655                        } else {
1656                            newCode.length += sizes[i];
1657                        }
1658                        indexes[i] = newCode.length;
1659                    }
1660                }
1661            }
1662            int opcode = b[u] & 0xFF;
1663            switch (ClassWriter.TYPE[opcode]) {
1664                case ClassWriter.NOARG_INSN:
1665                case ClassWriter.IMPLVAR_INSN:
1666                    newCode.putByte(opcode);
1667                    u += 1;
1668                    break;
1669                case ClassWriter.LABEL_INSN:
1670                    if (opcode > 201) {
1671                        // changes temporary opcodes 202 to 217 (inclusive), 218
1672
// and 219 to IFEQ ... JSR (inclusive), IFNULL and
1673
// IFNONNULL
1674
opcode = opcode < 218 ? opcode - 49 : opcode - 20;
1675                        label = u + readUnsignedShort(b, u + 1);
1676                    } else {
1677                        label = u + readShort(b, u + 1);
1678                    }
1679                    newOffset = getNewOffset(allIndexes, allSizes, u, label);
1680                    if (resize[u]) {
1681                        // replaces GOTO with GOTO_W, JSR with JSR_W and IFxxx
1682
// <l> with IFNOTxxx <l'> GOTO_W <l>, where IFNOTxxx is
1683
// the "opposite" opcode of IFxxx (i.e., IFNE for IFEQ)
1684
// and where <l'> designates the instruction just after
1685
// the GOTO_W.
1686
if (opcode == Opcodes.GOTO) {
1687                            newCode.putByte(200); // GOTO_W
1688
} else if (opcode == Opcodes.JSR) {
1689                            newCode.putByte(201); // JSR_W
1690
} else {
1691                            newCode.putByte(opcode <= 166
1692                                    ? ((opcode + 1) ^ 1) - 1
1693                                    : opcode ^ 1);
1694                            newCode.putShort(8); // jump offset
1695
newCode.putByte(200); // GOTO_W
1696
// newOffset now computed from start of GOTO_W
1697
newOffset -= 3;
1698                        }
1699                        newCode.putInt(newOffset);
1700                    } else {
1701                        newCode.putByte(opcode);
1702                        newCode.putShort(newOffset);
1703                    }
1704                    u += 3;
1705                    break;
1706                case ClassWriter.LABELW_INSN:
1707                    label = u + readInt(b, u + 1);
1708                    newOffset = getNewOffset(allIndexes, allSizes, u, label);
1709                    newCode.putByte(opcode);
1710                    newCode.putInt(newOffset);
1711                    u += 5;
1712                    break;
1713                case ClassWriter.TABL_INSN:
1714                    // skips 0 to 3 padding bytes
1715
v = u;
1716                    u = u + 4 - (v & 3);
1717                    // reads and copies instruction
1718
newCode.putByte(Opcodes.TABLESWITCH);
1719                    while (newCode.length % 4 != 0) {
1720                        newCode.putByte(0);
1721                    }
1722                    label = v + readInt(b, u);
1723                    u += 4;
1724                    newOffset = getNewOffset(allIndexes, allSizes, v, label);
1725                    newCode.putInt(newOffset);
1726                    j = readInt(b, u);
1727                    u += 4;
1728                    newCode.putInt(j);
1729                    j = readInt(b, u) - j + 1;
1730                    u += 4;
1731                    newCode.putInt(readInt(b, u - 4));
1732                    for (; j > 0; --j) {
1733                        label = v + readInt(b, u);
1734                        u += 4;
1735                        newOffset = getNewOffset(allIndexes, allSizes, v, label);
1736                        newCode.putInt(newOffset);
1737                    }
1738                    break;
1739                case ClassWriter.LOOK_INSN:
1740                    // skips 0 to 3 padding bytes
1741
v = u;
1742                    u = u + 4 - (v & 3);
1743                    // reads and copies instruction
1744
newCode.putByte(Opcodes.LOOKUPSWITCH);
1745                    while (newCode.length % 4 != 0) {
1746                        newCode.putByte(0);
1747                    }
1748                    label = v + readInt(b, u);
1749                    u += 4;
1750                    newOffset = getNewOffset(allIndexes, allSizes, v, label);
1751                    newCode.putInt(newOffset);
1752                    j = readInt(b, u);
1753                    u += 4;
1754                    newCode.putInt(j);
1755                    for (; j > 0; --j) {
1756                        newCode.putInt(readInt(b, u));
1757                        u += 4;
1758                        label = v + readInt(b, u);
1759                        u += 4;
1760                        newOffset = getNewOffset(allIndexes, allSizes, v, label);
1761                        newCode.putInt(newOffset);
1762                    }
1763                    break;
1764                case ClassWriter.WIDE_INSN:
1765                    opcode = b[u + 1] & 0xFF;
1766                    if (opcode == Opcodes.IINC) {
1767                        newCode.putByteArray(b, u, 6);
1768                        u += 6;
1769                    } else {
1770                        newCode.putByteArray(b, u, 4);
1771                        u += 4;
1772                    }
1773                    break;
1774                case ClassWriter.VAR_INSN:
1775                case ClassWriter.SBYTE_INSN:
1776                case ClassWriter.LDC_INSN:
1777                    newCode.putByteArray(b, u, 2);
1778                    u += 2;
1779                    break;
1780                case ClassWriter.SHORT_INSN:
1781                case ClassWriter.LDCW_INSN:
1782                case ClassWriter.FIELDORMETH_INSN:
1783                case ClassWriter.TYPE_INSN:
1784                case ClassWriter.IINC_INSN:
1785                    newCode.putByteArray(b, u, 3);
1786                    u += 3;
1787                    break;
1788                case ClassWriter.ITFMETH_INSN:
1789                    newCode.putByteArray(b, u, 5);
1790                    u += 5;
1791                    break;
1792                // case MANA_INSN:
1793
default:
1794                    newCode.putByteArray(b, u, 4);
1795                    u += 4;
1796                    break;
1797            }
1798        }
1799
1800        // updates the instructions addresses in the
1801
// catch, local var and line number tables
1802
if (catchTable != null) {
1803            b = catchTable.data;
1804            u = 0;
1805            while (u < catchTable.length) {
1806                writeShort(b, u, getNewOffset(allIndexes,
1807                        allSizes,
1808                        0,
1809                        readUnsignedShort(b, u)));
1810                writeShort(b, u + 2, getNewOffset(allIndexes,
1811                        allSizes,
1812                        0,
1813                        readUnsignedShort(b, u + 2)));
1814                writeShort(b, u + 4, getNewOffset(allIndexes,
1815                        allSizes,
1816                        0,
1817                        readUnsignedShort(b, u + 4)));
1818                u += 8;
1819            }
1820        }
1821        for (i = 0; i < 2; ++i) {
1822            ByteVector bv = i == 0 ? localVar : localVarType;
1823            if (bv != null) {
1824                b = bv.data;
1825                u = 0;
1826                while (u < bv.length) {
1827                    label = readUnsignedShort(b, u);
1828                    newOffset = getNewOffset(allIndexes, allSizes, 0, label);
1829                    writeShort(b, u, newOffset);
1830                    label += readUnsignedShort(b, u + 2);
1831                    newOffset = getNewOffset(allIndexes, allSizes, 0, label)
1832                            - newOffset;
1833                    writeShort(b, u + 2, newOffset);
1834                    u += 10;
1835                }
1836            }
1837        }
1838        if (lineNumber != null) {
1839            b = lineNumber.data;
1840            u = 0;
1841            while (u < lineNumber.length) {
1842                writeShort(b, u, getNewOffset(allIndexes,
1843                        allSizes,
1844                        0,
1845                        readUnsignedShort(b, u)));
1846                u += 4;
1847            }
1848        }
1849        // updates the labels of the other attributes
1850
while (cattrs != null) {
1851            Label[] labels = cattrs.getLabels();
1852            if (labels != null) {
1853                for (i = labels.length - 1; i >= 0; --i) {
1854                    if (!labels[i].resized) {
1855                        labels[i].position = getNewOffset(allIndexes,
1856                                allSizes,
1857                                0,
1858                                labels[i].position);
1859                        labels[i].resized = true;
1860                    }
1861                }
1862            }
1863        }
1864
1865        // replaces old bytecodes with new ones
1866
code = newCode;
1867
1868        // returns the positions of the resized instructions
1869
return indexes;
1870    }
1871
1872    /**
1873     * Reads an unsigned short value in the given byte array.
1874     *
1875     * @param b a byte array.
1876     * @param index the start index of the value to be read.
1877     * @return the read value.
1878     */

1879    static int readUnsignedShort(final byte[] b, final int index) {
1880        return ((b[index] & 0xFF) << 8) | (b[index + 1] & 0xFF);
1881    }
1882
1883    /**
1884     * Reads a signed short value in the given byte array.
1885     *
1886     * @param b a byte array.
1887     * @param index the start index of the value to be read.
1888     * @return the read value.
1889     */

1890    static short readShort(final byte[] b, final int index) {
1891        return (short) (((b[index] & 0xFF) << 8) | (b[index + 1] & 0xFF));
1892    }
1893
1894    /**
1895     * Reads a signed int value in the given byte array.
1896     *
1897     * @param b a byte array.
1898     * @param index the start index of the value to be read.
1899     * @return the read value.
1900     */

1901    static int readInt(final byte[] b, final int index) {
1902        return ((b[index] & 0xFF) << 24) | ((b[index + 1] & 0xFF) << 16)
1903                | ((b[index + 2] & 0xFF) << 8) | (b[index + 3] & 0xFF);
1904    }
1905
1906    /**
1907     * Writes a short value in the given byte array.
1908     *
1909     * @param b a byte array.
1910     * @param index where the first byte of the short value must be written.
1911     * @param s the value to be written in the given byte array.
1912     */

1913    static void writeShort(final byte[] b, final int index, final int s) {
1914        b[index] = (byte) (s >>> 8);
1915        b[index + 1] = (byte) s;
1916    }
1917
1918    /**
1919     * Computes the future value of a bytecode offset. <p> Note: it is possible
1920     * to have several entries for the same instruction in the <tt>indexes</tt>
1921     * and <tt>sizes</tt>: two entries (index=a,size=b) and (index=a,size=b')
1922     * are equivalent to a single entry (index=a,size=b+b').
1923     *
1924     * @param indexes current positions of the instructions to be resized. Each
1925     * instruction must be designated by the index of its <i>last</i>
1926     * byte, plus one (or, in other words, by the index of the <i>first</i>
1927     * byte of the <i>next</i> instruction).
1928     * @param sizes the number of bytes to be <i>added</i> to the above
1929     * instructions. More precisely, for each i < <tt>len</tt>,
1930     * <tt>sizes</tt>[i] bytes will be added at the end of the
1931     * instruction designated by <tt>indexes</tt>[i] or, if
1932     * <tt>sizes</tt>[i] is negative, the <i>last</i> |<tt>sizes[i]</tt>|
1933     * bytes of the instruction will be removed (the instruction size
1934     * <i>must not</i> become negative or null).
1935     * @param begin index of the first byte of the source instruction.
1936     * @param end index of the first byte of the target instruction.
1937     * @return the future value of the given bytecode offset.
1938     */

1939    static int getNewOffset(
1940        final int[] indexes,
1941        final int[] sizes,
1942        final int begin,
1943        final int end)
1944    {
1945        int offset = end - begin;
1946        for (int i = 0; i < indexes.length; ++i) {
1947            if (begin < indexes[i] && indexes[i] <= end) { // forward jump
1948
offset += sizes[i];
1949            } else if (end < indexes[i] && indexes[i] <= begin) { // backward
1950
// jump
1951
offset -= sizes[i];
1952            }
1953        }
1954        return offset;
1955    }
1956}
1957
Popular Tags