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  * @author Eugene Kuleshov
39  */
40 class MethodWriter implements MethodVisitor {
41 
42     /**
43      * Next method writer (see {@link ClassWriter#firstMethod firstMethod}).
44      */
45     MethodWriter next;
46 
47     /**
48      * The class writer to which this method must be added.
49      */
50     ClassWriter cw;
51 
52     /**
53      * Access flags of this method.
54      */
55     private int access;
56 
57     /**
58      * The index of the constant pool item that contains the name of this
59      * method.
60      */
61     private int name;
62 
63     /**
64      * The index of the constant pool item that contains the descriptor of this
65      * method.
66      */
67     private int desc;
68 
69     /**
70      * The descriptor of this method.
71      */
72     private String descriptor;
73 
74     /**
75      * If not zero, indicates that the code of this method must be copied from
76      * the ClassReader associated to this writer in <code>cw.cr</code>. More
77      * precisely, this field gives the index of the first byte to copied from
78      * <code>cw.cr.b</code>.
79      */
80     int classReaderOffset;
81 
82     /**
83      * If not zero, indicates that the code of this method must be copied from
84      * the ClassReader associated to this writer in <code>cw.cr</code>. More
85      * precisely, this field gives the number of bytes to copied from
86      * <code>cw.cr.b</code>.
87      */
88     int classReaderLength;
89 
90     /**
91      * The signature of this method.
92      */
93     String signature;
94 
95     /**
96      * Number of exceptions that can be thrown by this method.
97      */
98     int exceptionCount;
99 
100     /**
101      * The exceptions that can be thrown by this method. More precisely, this
102      * array contains the indexes of the constant pool items that contain the
103      * internal names of these exception classes.
104      */
105     int[] exceptions;
106 
107     /**
108      * The annotation default attribute of this method. May be <tt>null</tt>.
109      */
110     private ByteVector annd;
111 
112     /**
113      * The runtime visible annotations of this method. May be <tt>null</tt>.
114      */
115     private AnnotationWriter anns;
116 
117     /**
118      * The runtime invisible annotations of this method. May be <tt>null</tt>.
119      */
120     private AnnotationWriter ianns;
121 
122     /**
123      * The runtime visible parameter annotations of this method. May be
124      * <tt>null</tt>.
125      */
126     private AnnotationWriter[] panns;
127 
128     /**
129      * The runtime invisible parameter annotations of this method. May be
130      * <tt>null</tt>.
131      */
132     private AnnotationWriter[] ipanns;
133 
134     /**
135      * The non standard attributes of the method.
136      */
137     private Attribute attrs;
138 
139     /**
140      * The bytecode of this method.
141      */
142     private ByteVector code = new ByteVector();
143 
144     /**
145      * Maximum stack size of this method.
146      */
147     private int maxStack;
148 
149     /**
150      * Maximum number of local variables for this method.
151      */
152     private int maxLocals;
153 
154     /**
155      * Number of entries in the catch table of this method.
156      */
157     private int catchCount;
158 
159     /**
160      * The catch table of this method.
161      */
162     private Handler catchTable;
163 
164     /**
165      * The last element in the catchTable handler list.
166      */
167     private Handler lastHandler;
168 
169     /**
170      * Number of entries in the LocalVariableTable attribute.
171      */
172     private int localVarCount;
173 
174     /**
175      * The LocalVariableTable attribute.
176      */
177     private ByteVector localVar;
178 
179     /**
180      * Number of entries in the LocalVariableTypeTable attribute.
181      */
182     private int localVarTypeCount;
183 
184     /**
185      * The LocalVariableTypeTable attribute.
186      */
187     private ByteVector localVarType;
188 
189     /**
190      * Number of entries in the LineNumberTable attribute.
191      */
192     private int lineNumberCount;
193 
194     /**
195      * The LineNumberTable attribute.
196      */
197     private ByteVector lineNumber;
198 
199     /**
200      * The non standard attributes of the method's code.
201      */
202     private Attribute cattrs;
203 
204     /**
205      * Indicates if some jump instructions are too small and need to be resized.
206      */
207     private boolean resize;
208 
209     /*
210      * Fields for the control flow graph analysis algorithm (used to compute the
211      * maximum stack size). A control flow graph contains one node per "basic
212      * block", and one edge per "jump" from one basic block to another. Each
213      * node (i.e., each basic block) is represented by the Label object that
214      * corresponds to the first instruction of this basic block. Each node also
215      * stores the list of its successors in the graph, as a linked list of Edge
216      * objects.
217      */
218 
219     /**
220      * <tt>true</tt> if the maximum stack size and number of local variables
221      * must be automatically computed.
222      */
223     private final boolean computeMaxs;
224 
225     /**
226      * The (relative) stack size after the last visited instruction. This size
227      * is relative to the beginning of the current basic block, i.e., the true
228      * stack size after the last visited instruction is equal to the {@link
229      * Label#beginStackSize beginStackSize} of the current basic block plus
230      * <tt>stackSize</tt>.
231      */
232     private int stackSize;
233 
234     /**
235      * The (relative) maximum stack size after the last visited instruction.
236      * This size is relative to the beginning of the current basic block, i.e.,
237      * the true maximum stack size after the last visited instruction is equal
238      * to the {@link Label#beginStackSize beginStackSize} of the current basic
239      * block plus <tt>stackSize</tt>.
240      */
241     private int maxStackSize;
242 
243     /**
244      * The current basic block. This block is the basic block to which the next
245      * instruction to be visited must be added.
246      */
247     private Label currentBlock;
248 
249     /**
250      * The basic block stack used by the control flow analysis algorithm. This
251      * stack is represented by a linked list of {@link Label Label} objects,
252      * linked to each other by their {@link Label#next} field. This stack must
253      * not be confused with the JVM stack used to execute the JVM instructions!
254      */
255     private Label blockStack;
256 
257     /**
258      * The stack size variation corresponding to each JVM instruction. This
259      * stack variation is equal to the size of the values produced by an
260      * instruction, minus the size of the values consumed by this instruction.
261      */
262     private final static int[] SIZE;
263 
264     // ------------------------------------------------------------------------
265     // Static initializer
266     // ------------------------------------------------------------------------
267 
268     /**
269      * Computes the stack size variation corresponding to each JVM instruction.
270      */
271     static {
272         int i;
273         int[] b = new int[202];
274         String s = "EFFFFFFFFGGFFFGGFFFEEFGFGFEEEEEEEEEEEEEEEEEEEEDEDEDDDDD"
275                 + "CDCDEEEEEEEEEEEEEEEEEEEEBABABBBBDCFFFGGGEDCDCDCDCDCDCDCDCD"
276                 + "CDCEEEEDDDDDDDCDCDCEFEFDDEEFFDEDEEEBDDBBDDDDDDCCCCCCCCEFED"
277                 + "DDCDCDEEEEEEEEEEFEEEEEEDDEEDDEE";
278         for (i = 0; i < b.length; ++i) {
279             b[i] = s.charAt(i) - 'E';
280         }
281         SIZE = b;
282 
283         // code to generate the above string
284         //
285         // int NA = 0; // not applicable (unused opcode or variable size opcode)
286         //
287         // b = new int[] {
288         // 0, //NOP, // visitInsn
289         // 1, //ACONST_NULL, // -
290         // 1, //ICONST_M1, // -
291         // 1, //ICONST_0, // -
292         // 1, //ICONST_1, // -
293         // 1, //ICONST_2, // -
294         // 1, //ICONST_3, // -
295         // 1, //ICONST_4, // -
296         // 1, //ICONST_5, // -
297         // 2, //LCONST_0, // -
298         // 2, //LCONST_1, // -
299         // 1, //FCONST_0, // -
300         // 1, //FCONST_1, // -
301         // 1, //FCONST_2, // -
302         // 2, //DCONST_0, // -
303         // 2, //DCONST_1, // -
304         // 1, //BIPUSH, // visitIntInsn
305         // 1, //SIPUSH, // -
306         // 1, //LDC, // visitLdcInsn
307         // NA, //LDC_W, // -
308         // NA, //LDC2_W, // -
309         // 1, //ILOAD, // visitVarInsn
310         // 2, //LLOAD, // -
311         // 1, //FLOAD, // -
312         // 2, //DLOAD, // -
313         // 1, //ALOAD, // -
314         // NA, //ILOAD_0, // -
315         // NA, //ILOAD_1, // -
316         // NA, //ILOAD_2, // -
317         // NA, //ILOAD_3, // -
318         // NA, //LLOAD_0, // -
319         // NA, //LLOAD_1, // -
320         // NA, //LLOAD_2, // -
321         // NA, //LLOAD_3, // -
322         // NA, //FLOAD_0, // -
323         // NA, //FLOAD_1, // -
324         // NA, //FLOAD_2, // -
325         // NA, //FLOAD_3, // -
326         // NA, //DLOAD_0, // -
327         // NA, //DLOAD_1, // -
328         // NA, //DLOAD_2, // -
329         // NA, //DLOAD_3, // -
330         // NA, //ALOAD_0, // -
331         // NA, //ALOAD_1, // -
332         // NA, //ALOAD_2, // -
333         // NA, //ALOAD_3, // -
334         // -1, //IALOAD, // visitInsn
335         // 0, //LALOAD, // -
336         // -1, //FALOAD, // -
337         // 0, //DALOAD, // -
338         // -1, //AALOAD, // -
339         // -1, //BALOAD, // -
340         // -1, //CALOAD, // -
341         // -1, //SALOAD, // -
342         // -1, //ISTORE, // visitVarInsn
343         // -2, //LSTORE, // -
344         // -1, //FSTORE, // -
345         // -2, //DSTORE, // -
346         // -1, //ASTORE, // -
347         // NA, //ISTORE_0, // -
348         // NA, //ISTORE_1, // -
349         // NA, //ISTORE_2, // -
350         // NA, //ISTORE_3, // -
351         // NA, //LSTORE_0, // -
352         // NA, //LSTORE_1, // -
353         // NA, //LSTORE_2, // -
354         // NA, //LSTORE_3, // -
355         // NA, //FSTORE_0, // -
356         // NA, //FSTORE_1, // -
357         // NA, //FSTORE_2, // -
358         // NA, //FSTORE_3, // -
359         // NA, //DSTORE_0, // -
360         // NA, //DSTORE_1, // -
361         // NA, //DSTORE_2, // -
362         // NA, //DSTORE_3, // -
363         // NA, //ASTORE_0, // -
364         // NA, //ASTORE_1, // -
365         // NA, //ASTORE_2, // -
366         // NA, //ASTORE_3, // -
367         // -3, //IASTORE, // visitInsn
368         // -4, //LASTORE, // -
369         // -3, //FASTORE, // -
370         // -4, //DASTORE, // -
371         // -3, //AASTORE, // -
372         // -3, //BASTORE, // -
373         // -3, //CASTORE, // -
374         // -3, //SASTORE, // -
375         // -1, //POP, // -
376         // -2, //POP2, // -
377         // 1, //DUP, // -
378         // 1, //DUP_X1, // -
379         // 1, //DUP_X2, // -
380         // 2, //DUP2, // -
381         // 2, //DUP2_X1, // -
382         // 2, //DUP2_X2, // -
383         // 0, //SWAP, // -
384         // -1, //IADD, // -
385         // -2, //LADD, // -
386         // -1, //FADD, // -
387         // -2, //DADD, // -
388         // -1, //ISUB, // -
389         // -2, //LSUB, // -
390         // -1, //FSUB, // -
391         // -2, //DSUB, // -
392         // -1, //IMUL, // -
393         // -2, //LMUL, // -
394         // -1, //FMUL, // -
395         // -2, //DMUL, // -
396         // -1, //IDIV, // -
397         // -2, //LDIV, // -
398         // -1, //FDIV, // -
399         // -2, //DDIV, // -
400         // -1, //IREM, // -
401         // -2, //LREM, // -
402         // -1, //FREM, // -
403         // -2, //DREM, // -
404         // 0, //INEG, // -
405         // 0, //LNEG, // -
406         // 0, //FNEG, // -
407         // 0, //DNEG, // -
408         // -1, //ISHL, // -
409         // -1, //LSHL, // -
410         // -1, //ISHR, // -
411         // -1, //LSHR, // -
412         // -1, //IUSHR, // -
413         // -1, //LUSHR, // -
414         // -1, //IAND, // -
415         // -2, //LAND, // -
416         // -1, //IOR, // -
417         // -2, //LOR, // -
418         // -1, //IXOR, // -
419         // -2, //LXOR, // -
420         // 0, //IINC, // visitIincInsn
421         // 1, //I2L, // visitInsn
422         // 0, //I2F, // -
423         // 1, //I2D, // -
424         // -1, //L2I, // -
425         // -1, //L2F, // -
426         // 0, //L2D, // -
427         // 0, //F2I, // -
428         // 1, //F2L, // -
429         // 1, //F2D, // -
430         // -1, //D2I, // -
431         // 0, //D2L, // -
432         // -1, //D2F, // -
433         // 0, //I2B, // -
434         // 0, //I2C, // -
435         // 0, //I2S, // -
436         // -3, //LCMP, // -
437         // -1, //FCMPL, // -
438         // -1, //FCMPG, // -
439         // -3, //DCMPL, // -
440         // -3, //DCMPG, // -
441         // -1, //IFEQ, // visitJumpInsn
442         // -1, //IFNE, // -
443         // -1, //IFLT, // -
444         // -1, //IFGE, // -
445         // -1, //IFGT, // -
446         // -1, //IFLE, // -
447         // -2, //IF_ICMPEQ, // -
448         // -2, //IF_ICMPNE, // -
449         // -2, //IF_ICMPLT, // -
450         // -2, //IF_ICMPGE, // -
451         // -2, //IF_ICMPGT, // -
452         // -2, //IF_ICMPLE, // -
453         // -2, //IF_ACMPEQ, // -
454         // -2, //IF_ACMPNE, // -
455         // 0, //GOTO, // -
456         // 1, //JSR, // -
457         // 0, //RET, // visitVarInsn
458         // -1, //TABLESWITCH, // visiTableSwitchInsn
459         // -1, //LOOKUPSWITCH, // visitLookupSwitch
460         // -1, //IRETURN, // visitInsn
461         // -2, //LRETURN, // -
462         // -1, //FRETURN, // -
463         // -2, //DRETURN, // -
464         // -1, //ARETURN, // -
465         // 0, //RETURN, // -
466         // NA, //GETSTATIC, // visitFieldInsn
467         // NA, //PUTSTATIC, // -
468         // NA, //GETFIELD, // -
469         // NA, //PUTFIELD, // -
470         // NA, //INVOKEVIRTUAL, // visitMethodInsn
471         // NA, //INVOKESPECIAL, // -
472         // NA, //INVOKESTATIC, // -
473         // NA, //INVOKEINTERFACE, // -
474         // NA, //UNUSED, // NOT VISITED
475         // 1, //NEW, // visitTypeInsn
476         // 0, //NEWARRAY, // visitIntInsn
477         // 0, //ANEWARRAY, // visitTypeInsn
478         // 0, //ARRAYLENGTH, // visitInsn
479         // NA, //ATHROW, // -
480         // 0, //CHECKCAST, // visitTypeInsn
481         // 0, //INSTANCEOF, // -
482         // -1, //MONITORENTER, // visitInsn
483         // -1, //MONITOREXIT, // -
484         // NA, //WIDE, // NOT VISITED
485         // NA, //MULTIANEWARRAY, // visitMultiANewArrayInsn
486         // -1, //IFNULL, // visitJumpInsn
487         // -1, //IFNONNULL, // -
488         // NA, //GOTO_W, // -
489         // NA, //JSR_W, // -
490         // };
491         // for (i = 0; i < b.length; ++i) {
492         // System.err.print((char)('E' + b[i]));
493         // }
494         // System.err.println();
495     }
496 
497     // ------------------------------------------------------------------------
498     // Constructor
499     // ------------------------------------------------------------------------
500 
501     /**
502      * Constructs a new {@link MethodWriter}.
503      *
504      * @param cw the class writer in which the method must be added.
505      * @param access the method's access flags (see {@link Opcodes}).
506      * @param name the method's name.
507      * @param desc the method's descriptor (see {@link Type}).
508      * @param signature the method's signature. May be <tt>null</tt>.
509      * @param exceptions the internal names of the method's exceptions. May be
510      *        <tt>null</tt>.
511      * @param computeMaxs <tt>true</tt> if the maximum stack size and number
512      *        of local variables must be automatically computed.
513      */
MethodWriter( final ClassWriter cw, final int access, final String name, final String desc, final String signature, final String[] exceptions, final boolean computeMaxs)514     MethodWriter(
515         final ClassWriter cw,
516         final int access,
517         final String name,
518         final String desc,
519         final String signature,
520         final String[] exceptions,
521         final boolean computeMaxs)
522     {
523         if (cw.firstMethod == null) {
524             cw.firstMethod = this;
525         } else {
526             cw.lastMethod.next = this;
527         }
528         cw.lastMethod = this;
529         this.cw = cw;
530         this.access = access;
531         this.name = cw.newUTF8(name);
532         this.desc = cw.newUTF8(desc);
533         this.descriptor = desc;
534         this.signature = signature;
535         if (exceptions != null && exceptions.length > 0) {
536             exceptionCount = exceptions.length;
537             this.exceptions = new int[exceptionCount];
538             for (int i = 0; i < exceptionCount; ++i) {
539                 this.exceptions[i] = cw.newClass(exceptions[i]);
540             }
541         }
542         this.computeMaxs = computeMaxs;
543         if (computeMaxs) {
544             // updates maxLocals
545             int size = getArgumentsAndReturnSizes(desc) >> 2;
546             if ((access & Opcodes.ACC_STATIC) != 0) {
547                 --size;
548             }
549             maxLocals = size;
550             // pushes the first block onto the stack of blocks to be visited
551             currentBlock = new Label();
552             currentBlock.pushed = true;
553             blockStack = currentBlock;
554         }
555     }
556 
557     // ------------------------------------------------------------------------
558     // Implementation of the MethodVisitor interface
559     // ------------------------------------------------------------------------
560 
visitAnnotationDefault()561     public AnnotationVisitor visitAnnotationDefault() {
562         annd = new ByteVector();
563         return new AnnotationWriter(cw, false, annd, null, 0);
564     }
565 
visitAnnotation( final String desc, final boolean visible)566     public AnnotationVisitor visitAnnotation(
567         final String desc,
568         final boolean visible)
569     {
570         ByteVector bv = new ByteVector();
571         // write type, and reserve space for values count
572         bv.putShort(cw.newUTF8(desc)).putShort(0);
573         AnnotationWriter aw = new AnnotationWriter(cw, true, bv, bv, 2);
574         if (visible) {
575             aw.next = anns;
576             anns = aw;
577         } else {
578             aw.next = ianns;
579             ianns = aw;
580         }
581         return aw;
582     }
583 
visitParameterAnnotation( final int parameter, final String desc, final boolean visible)584     public AnnotationVisitor visitParameterAnnotation(
585         final int parameter,
586         final String desc,
587         final boolean visible)
588     {
589         ByteVector bv = new ByteVector();
590         // write type, and reserve space for values count
591         bv.putShort(cw.newUTF8(desc)).putShort(0);
592         AnnotationWriter aw = new AnnotationWriter(cw, true, bv, bv, 2);
593         if (visible) {
594             if (panns == null) {
595                 panns = new AnnotationWriter[Type.getArgumentTypes(descriptor).length];
596             }
597             aw.next = panns[parameter];
598             panns[parameter] = aw;
599         } else {
600             if (ipanns == null) {
601                 ipanns = new AnnotationWriter[Type.getArgumentTypes(descriptor).length];
602             }
603             aw.next = ipanns[parameter];
604             ipanns[parameter] = aw;
605         }
606         return aw;
607     }
608 
visitAttribute(final Attribute attr)609     public void visitAttribute(final Attribute attr) {
610         if (attr.isCodeAttribute()) {
611             attr.next = cattrs;
612             cattrs = attr;
613         } else {
614             attr.next = attrs;
615             attrs = attr;
616         }
617     }
618 
visitCode()619     public void visitCode() {
620     }
621 
visitInsn(final int opcode)622     public void visitInsn(final int opcode) {
623         if (computeMaxs) {
624             // updates current and max stack sizes
625             int size = stackSize + SIZE[opcode];
626             if (size > maxStackSize) {
627                 maxStackSize = size;
628             }
629             stackSize = size;
630             // if opcode == ATHROW or xRETURN, ends current block (no successor)
631             if ((opcode >= Opcodes.IRETURN && opcode <= Opcodes.RETURN)
632                     || opcode == Opcodes.ATHROW)
633             {
634                 if (currentBlock != null) {
635                     currentBlock.maxStackSize = maxStackSize;
636                     currentBlock = null;
637                 }
638             }
639         }
640         // adds the instruction to the bytecode of the method
641         code.putByte(opcode);
642     }
643 
visitIntInsn(final int opcode, final int operand)644     public void visitIntInsn(final int opcode, final int operand) {
645         if (computeMaxs && opcode != Opcodes.NEWARRAY) {
646             // updates current and max stack sizes only if opcode == NEWARRAY
647             // (stack size variation = 0 for BIPUSH or SIPUSH)
648             int size = stackSize + 1;
649             if (size > maxStackSize) {
650                 maxStackSize = size;
651             }
652             stackSize = size;
653         }
654         // adds the instruction to the bytecode of the method
655         if (opcode == Opcodes.SIPUSH) {
656             code.put12(opcode, operand);
657         } else { // BIPUSH or NEWARRAY
658             code.put11(opcode, operand);
659         }
660     }
661 
visitVarInsn(final int opcode, final int var)662     public void visitVarInsn(final int opcode, final int var) {
663         if (computeMaxs) {
664             // updates current and max stack sizes
665             if (opcode == Opcodes.RET) {
666                 // no stack change, but end of current block (no successor)
667                 if (currentBlock != null) {
668                     currentBlock.maxStackSize = maxStackSize;
669                     currentBlock = null;
670                 }
671             } else { // xLOAD or xSTORE
672                 int size = stackSize + SIZE[opcode];
673                 if (size > maxStackSize) {
674                     maxStackSize = size;
675                 }
676                 stackSize = size;
677             }
678             // updates max locals
679             int n;
680             if (opcode == Opcodes.LLOAD || opcode == Opcodes.DLOAD
681                     || opcode == Opcodes.LSTORE || opcode == Opcodes.DSTORE)
682             {
683                 n = var + 2;
684             } else {
685                 n = var + 1;
686             }
687             if (n > maxLocals) {
688                 maxLocals = n;
689             }
690         }
691         // adds the instruction to the bytecode of the method
692         if (var < 4 && opcode != Opcodes.RET) {
693             int opt;
694             if (opcode < Opcodes.ISTORE) {
695                 /* ILOAD_0 */
696                 opt = 26 + ((opcode - Opcodes.ILOAD) << 2) + var;
697             } else {
698                 /* ISTORE_0 */
699                 opt = 59 + ((opcode - Opcodes.ISTORE) << 2) + var;
700             }
701             code.putByte(opt);
702         } else if (var >= 256) {
703             code.putByte(196 /* WIDE */).put12(opcode, var);
704         } else {
705             code.put11(opcode, var);
706         }
707     }
708 
visitTypeInsn(final int opcode, final String desc)709     public void visitTypeInsn(final int opcode, final String desc) {
710         if (computeMaxs && opcode == Opcodes.NEW) {
711             // updates current and max stack sizes only if opcode == NEW
712             // (stack size variation = 0 for ANEWARRAY, CHECKCAST, INSTANCEOF)
713             int size = stackSize + 1;
714             if (size > maxStackSize) {
715                 maxStackSize = size;
716             }
717             stackSize = size;
718         }
719         // adds the instruction to the bytecode of the method
720         code.put12(opcode, cw.newClass(desc));
721     }
722 
visitFieldInsn( final int opcode, final String owner, final String name, final String desc)723     public void visitFieldInsn(
724         final int opcode,
725         final String owner,
726         final String name,
727         final String desc)
728     {
729         if (computeMaxs) {
730             int size;
731             // computes the stack size variation
732             char c = desc.charAt(0);
733             switch (opcode) {
734                 case Opcodes.GETSTATIC:
735                     size = stackSize + (c == 'D' || c == 'J' ? 2 : 1);
736                     break;
737                 case Opcodes.PUTSTATIC:
738                     size = stackSize + (c == 'D' || c == 'J' ? -2 : -1);
739                     break;
740                 case Opcodes.GETFIELD:
741                     size = stackSize + (c == 'D' || c == 'J' ? 1 : 0);
742                     break;
743                 // case Constants.PUTFIELD:
744                 default:
745                     size = stackSize + (c == 'D' || c == 'J' ? -3 : -2);
746                     break;
747             }
748             // updates current and max stack sizes
749             if (size > maxStackSize) {
750                 maxStackSize = size;
751             }
752             stackSize = size;
753         }
754         // adds the instruction to the bytecode of the method
755         code.put12(opcode, cw.newField(owner, name, desc));
756     }
757 
visitMethodInsn( final int opcode, final String owner, final String name, final String desc)758     public void visitMethodInsn(
759         final int opcode,
760         final String owner,
761         final String name,
762         final String desc)
763     {
764         boolean itf = opcode == Opcodes.INVOKEINTERFACE;
765         Item i = cw.newMethodItem(owner, name, desc, itf);
766         int argSize = i.intVal;
767         if (computeMaxs) {
768             /*
769              * computes the stack size variation. In order not to recompute
770              * several times this variation for the same Item, we use the intVal
771              * field of this item to store this variation, once it has been
772              * computed. More precisely this intVal field stores the sizes of
773              * the arguments and of the return value corresponding to desc.
774              */
775             if (argSize == 0) {
776                 // the above sizes have not been computed yet, so we compute
777                 // them...
778                 argSize = getArgumentsAndReturnSizes(desc);
779                 // ... and we save them in order not to recompute them in the
780                 // future
781                 i.intVal = argSize;
782             }
783             int size;
784             if (opcode == Opcodes.INVOKESTATIC) {
785                 size = stackSize - (argSize >> 2) + (argSize & 0x03) + 1;
786             } else {
787                 size = stackSize - (argSize >> 2) + (argSize & 0x03);
788             }
789             // updates current and max stack sizes
790             if (size > maxStackSize) {
791                 maxStackSize = size;
792             }
793             stackSize = size;
794         }
795         // adds the instruction to the bytecode of the method
796         if (itf) {
797             if (!computeMaxs) {
798                 if (argSize == 0) {
799                     argSize = getArgumentsAndReturnSizes(desc);
800                     i.intVal = argSize;
801                 }
802             }
803             code.put12(Opcodes.INVOKEINTERFACE, i.index).put11(argSize >> 2, 0);
804         } else {
805             code.put12(opcode, i.index);
806         }
807     }
808 
visitJumpInsn(final int opcode, final Label label)809     public void visitJumpInsn(final int opcode, final Label label) {
810         if (computeMaxs) {
811             if (opcode == Opcodes.GOTO) {
812                 // no stack change, but end of current block (with one new
813                 // successor)
814                 if (currentBlock != null) {
815                     currentBlock.maxStackSize = maxStackSize;
816                     addSuccessor(stackSize, label);
817                     currentBlock = null;
818                 }
819             } else if (opcode == Opcodes.JSR) {
820                 if (currentBlock != null) {
821                     addSuccessor(stackSize + 1, label);
822                 }
823             } else {
824                 // updates current stack size (max stack size unchanged because
825                 // stack size variation always negative in this case)
826                 stackSize += SIZE[opcode];
827                 if (currentBlock != null) {
828                     addSuccessor(stackSize, label);
829                 }
830             }
831         }
832         // adds the instruction to the bytecode of the method
833         if (label.resolved && label.position - code.length < Short.MIN_VALUE) {
834             /*
835              * case of a backward jump with an offset < -32768. In this case we
836              * automatically replace GOTO with GOTO_W, JSR with JSR_W and IFxxx
837              * <l> with IFNOTxxx <l'> GOTO_W <l>, where IFNOTxxx is the
838              * "opposite" opcode of IFxxx (i.e., IFNE for IFEQ) and where <l'>
839              * designates the instruction just after the GOTO_W.
840              */
841             if (opcode == Opcodes.GOTO) {
842                 code.putByte(200); // GOTO_W
843             } else if (opcode == Opcodes.JSR) {
844                 code.putByte(201); // JSR_W
845             } else {
846                 code.putByte(opcode <= 166
847                         ? ((opcode + 1) ^ 1) - 1
848                         : opcode ^ 1);
849                 code.putShort(8); // jump offset
850                 code.putByte(200); // GOTO_W
851             }
852             label.put(this, code, code.length - 1, true);
853         } else {
854             /*
855              * case of a backward jump with an offset >= -32768, or of a forward
856              * jump with, of course, an unknown offset. In these cases we store
857              * the offset in 2 bytes (which will be increased in
858              * resizeInstructions, if needed).
859              */
860             code.putByte(opcode);
861             label.put(this, code, code.length - 1, false);
862         }
863     }
864 
visitLabel(final Label label)865     public void visitLabel(final Label label) {
866         if (computeMaxs) {
867             if (currentBlock != null) {
868                 // ends current block (with one new successor)
869                 currentBlock.maxStackSize = maxStackSize;
870                 addSuccessor(stackSize, label);
871             }
872             // begins a new current block,
873             // resets the relative current and max stack sizes
874             currentBlock = label;
875             stackSize = 0;
876             maxStackSize = 0;
877         }
878         // resolves previous forward references to label, if any
879         resize |= label.resolve(this, code.length, code.data);
880     }
881 
visitLdcInsn(final Object cst)882     public void visitLdcInsn(final Object cst) {
883         Item i = cw.newConstItem(cst);
884         if (computeMaxs) {
885             int size;
886             // computes the stack size variation
887             if (i.type == ClassWriter.LONG || i.type == ClassWriter.DOUBLE) {
888                 size = stackSize + 2;
889             } else {
890                 size = stackSize + 1;
891             }
892             // updates current and max stack sizes
893             if (size > maxStackSize) {
894                 maxStackSize = size;
895             }
896             stackSize = size;
897         }
898         // adds the instruction to the bytecode of the method
899         int index = i.index;
900         if (i.type == ClassWriter.LONG || i.type == ClassWriter.DOUBLE) {
901             code.put12(20 /* LDC2_W */, index);
902         } else if (index >= 256) {
903             code.put12(19 /* LDC_W */, index);
904         } else {
905             code.put11(Opcodes.LDC, index);
906         }
907     }
908 
visitIincInsn(final int var, final int increment)909     public void visitIincInsn(final int var, final int increment) {
910         if (computeMaxs) {
911             // updates max locals only (no stack change)
912             int n = var + 1;
913             if (n > maxLocals) {
914                 maxLocals = n;
915             }
916         }
917         // adds the instruction to the bytecode of the method
918         if ((var > 255) || (increment > 127) || (increment < -128)) {
919             code.putByte(196 /* WIDE */)
920                     .put12(Opcodes.IINC, var)
921                     .putShort(increment);
922         } else {
923             code.putByte(Opcodes.IINC).put11(var, increment);
924         }
925     }
926 
visitTableSwitchInsn( final int min, final int max, final Label dflt, final Label labels[])927     public void visitTableSwitchInsn(
928         final int min,
929         final int max,
930         final Label dflt,
931         final Label labels[])
932     {
933         if (computeMaxs) {
934             // updates current stack size (max stack size unchanged)
935             --stackSize;
936             // ends current block (with many new successors)
937             if (currentBlock != null) {
938                 currentBlock.maxStackSize = maxStackSize;
939                 addSuccessor(stackSize, dflt);
940                 for (int i = 0; i < labels.length; ++i) {
941                     addSuccessor(stackSize, labels[i]);
942                 }
943                 currentBlock = null;
944             }
945         }
946         // adds the instruction to the bytecode of the method
947         int source = code.length;
948         code.putByte(Opcodes.TABLESWITCH);
949         while (code.length % 4 != 0) {
950             code.putByte(0);
951         }
952         dflt.put(this, code, source, true);
953         code.putInt(min).putInt(max);
954         for (int i = 0; i < labels.length; ++i) {
955             labels[i].put(this, code, source, true);
956         }
957     }
958 
visitLookupSwitchInsn( final Label dflt, final int keys[], final Label labels[])959     public void visitLookupSwitchInsn(
960         final Label dflt,
961         final int keys[],
962         final Label labels[])
963     {
964         if (computeMaxs) {
965             // updates current stack size (max stack size unchanged)
966             --stackSize;
967             // ends current block (with many new successors)
968             if (currentBlock != null) {
969                 currentBlock.maxStackSize = maxStackSize;
970                 addSuccessor(stackSize, dflt);
971                 for (int i = 0; i < labels.length; ++i) {
972                     addSuccessor(stackSize, labels[i]);
973                 }
974                 currentBlock = null;
975             }
976         }
977         // adds the instruction to the bytecode of the method
978         int source = code.length;
979         code.putByte(Opcodes.LOOKUPSWITCH);
980         while (code.length % 4 != 0) {
981             code.putByte(0);
982         }
983         dflt.put(this, code, source, true);
984         code.putInt(labels.length);
985         for (int i = 0; i < labels.length; ++i) {
986             code.putInt(keys[i]);
987             labels[i].put(this, code, source, true);
988         }
989     }
990 
visitMultiANewArrayInsn(final String desc, final int dims)991     public void visitMultiANewArrayInsn(final String desc, final int dims) {
992         if (computeMaxs) {
993             // updates current stack size (max stack size unchanged because
994             // stack size variation always negative or null)
995             stackSize += 1 - dims;
996         }
997         // adds the instruction to the bytecode of the method
998         code.put12(Opcodes.MULTIANEWARRAY, cw.newClass(desc)).putByte(dims);
999     }
1000 
visitTryCatchBlock( final Label start, final Label end, final Label handler, final String type)1001     public void visitTryCatchBlock(
1002         final Label start,
1003         final Label end,
1004         final Label handler,
1005         final String type)
1006     {
1007         if (computeMaxs) {
1008             // pushes handler block onto the stack of blocks to be visited
1009             if (!handler.pushed) {
1010                 handler.beginStackSize = 1;
1011                 handler.pushed = true;
1012                 handler.next = blockStack;
1013                 blockStack = handler;
1014             }
1015         }
1016         ++catchCount;
1017         Handler h = new Handler();
1018         h.start = start;
1019         h.end = end;
1020         h.handler = handler;
1021         h.desc = type;
1022         h.type = type != null ? cw.newClass(type) : 0;
1023         if (lastHandler == null) {
1024             catchTable = h;
1025         } else {
1026             lastHandler.next = h;
1027         }
1028         lastHandler = h;
1029     }
1030 
visitLocalVariable( final String name, final String desc, final String signature, final Label start, final Label end, final int index)1031     public void visitLocalVariable(
1032         final String name,
1033         final String desc,
1034         final String signature,
1035         final Label start,
1036         final Label end,
1037         final int index)
1038     {
1039         if (signature != null) {
1040             if (localVarType == null) {
1041                 localVarType = new ByteVector();
1042             }
1043             ++localVarTypeCount;
1044             localVarType.putShort(start.position)
1045                     .putShort(end.position - start.position)
1046                     .putShort(cw.newUTF8(name))
1047                     .putShort(cw.newUTF8(signature))
1048                     .putShort(index);
1049         }
1050         if (localVar == null) {
1051             localVar = new ByteVector();
1052         }
1053         ++localVarCount;
1054         localVar.putShort(start.position)
1055                 .putShort(end.position - start.position)
1056                 .putShort(cw.newUTF8(name))
1057                 .putShort(cw.newUTF8(desc))
1058                 .putShort(index);
1059 
1060         if(computeMaxs) {
1061             // updates max locals
1062             char c = desc.charAt(0);
1063             int n = index + ( c=='L' || c=='D' ? 2 : 1);
1064             if (n > maxLocals) {
1065                 maxLocals = n;
1066             }
1067         }
1068     }
1069 
visitLineNumber(final int line, final Label start)1070     public void visitLineNumber(final int line, final Label start) {
1071         if (lineNumber == null) {
1072             lineNumber = new ByteVector();
1073         }
1074         ++lineNumberCount;
1075         lineNumber.putShort(start.position);
1076         lineNumber.putShort(line);
1077     }
1078 
visitMaxs(final int maxStack, final int maxLocals)1079     public void visitMaxs(final int maxStack, final int maxLocals) {
1080         if (computeMaxs) {
1081             // true (non relative) max stack size
1082             int max = 0;
1083             /*
1084              * control flow analysis algorithm: while the block stack is not
1085              * empty, pop a block from this stack, update the max stack size,
1086              * compute the true (non relative) begin stack size of the
1087              * successors of this block, and push these successors onto the
1088              * stack (unless they have already been pushed onto the stack).
1089              * Note: by hypothesis, the {@link Label#beginStackSize} of the
1090              * blocks in the block stack are the true (non relative) beginning
1091              * stack sizes of these blocks.
1092              */
1093             Label stack = blockStack;
1094             while (stack != null) {
1095                 // pops a block from the stack
1096                 Label l = stack;
1097                 stack = stack.next;
1098                 // computes the true (non relative) max stack size of this block
1099                 int start = l.beginStackSize;
1100                 int blockMax = start + l.maxStackSize;
1101                 // updates the global max stack size
1102                 if (blockMax > max) {
1103                     max = blockMax;
1104                 }
1105                 // analyses the successors of the block
1106                 Edge b = l.successors;
1107                 while (b != null) {
1108                     l = b.successor;
1109                     // if this successor has not already been pushed onto the
1110                     // stack...
1111                     if (!l.pushed) {
1112                         // computes the true beginning stack size of this
1113                         // successor block
1114                         l.beginStackSize = start + b.stackSize;
1115                         // pushes this successor onto the stack
1116                         l.pushed = true;
1117                         l.next = stack;
1118                         stack = l;
1119                     }
1120                     b = b.next;
1121                 }
1122             }
1123             this.maxStack = max;
1124         } else {
1125             this.maxStack = maxStack;
1126             this.maxLocals = maxLocals;
1127         }
1128     }
1129 
visitEnd()1130     public void visitEnd() {
1131     }
1132 
1133     // ------------------------------------------------------------------------
1134     // Utility methods: control flow analysis algorithm
1135     // ------------------------------------------------------------------------
1136 
1137     /**
1138      * Computes the size of the arguments and of the return value of a method.
1139      *
1140      * @param desc the descriptor of a method.
1141      * @return the size of the arguments of the method (plus one for the
1142      *         implicit this argument), argSize, and the size of its return
1143      *         value, retSize, packed into a single int i =
1144      *         <tt>(argSize << 2) | retSize</tt> (argSize is therefore equal
1145      *         to <tt>i >> 2</tt>, and retSize to <tt>i & 0x03</tt>).
1146      */
getArgumentsAndReturnSizes(final String desc)1147     private static int getArgumentsAndReturnSizes(final String desc) {
1148         int n = 1;
1149         int c = 1;
1150         while (true) {
1151             char car = desc.charAt(c++);
1152             if (car == ')') {
1153                 car = desc.charAt(c);
1154                 return n << 2
1155                         | (car == 'V' ? 0 : (car == 'D' || car == 'J' ? 2 : 1));
1156             } else if (car == 'L') {
1157                 while (desc.charAt(c++) != ';') {
1158                 }
1159                 n += 1;
1160             } else if (car == '[') {
1161                 while ((car = desc.charAt(c)) == '[') {
1162                     ++c;
1163                 }
1164                 if (car == 'D' || car == 'J') {
1165                     n -= 1;
1166                 }
1167             } else if (car == 'D' || car == 'J') {
1168                 n += 2;
1169             } else {
1170                 n += 1;
1171             }
1172         }
1173     }
1174 
1175     /**
1176      * Adds a successor to the {@link #currentBlock currentBlock} block.
1177      *
1178      * @param stackSize the current (relative) stack size in the current block.
1179      * @param successor the successor block to be added to the current block.
1180      */
addSuccessor(final int stackSize, final Label successor)1181     private void addSuccessor(final int stackSize, final Label successor) {
1182         Edge b = new Edge();
1183         // initializes the previous Edge object...
1184         b.stackSize = stackSize;
1185         b.successor = successor;
1186         // ...and adds it to the successor list of the currentBlock block
1187         b.next = currentBlock.successors;
1188         currentBlock.successors = b;
1189     }
1190 
1191     // ------------------------------------------------------------------------
1192     // Utility methods: dump bytecode array
1193     // ------------------------------------------------------------------------
1194 
1195     /**
1196      * Returns the size of the bytecode of this method.
1197      *
1198      * @return the size of the bytecode of this method.
1199      */
getSize()1200     final int getSize() {
1201         if (classReaderOffset != 0) {
1202             return 6 + classReaderLength;
1203         }
1204         if (resize) {
1205             // replaces the temporary jump opcodes introduced by Label.resolve.
1206             resizeInstructions(new int[0], new int[0], 0);
1207         }
1208         int size = 8;
1209         if (code.length > 0) {
1210             cw.newUTF8("Code");
1211             size += 18 + code.length + 8 * catchCount;
1212             if (localVar != null) {
1213                 cw.newUTF8("LocalVariableTable");
1214                 size += 8 + localVar.length;
1215             }
1216             if (localVarType != null) {
1217                 cw.newUTF8("LocalVariableTypeTable");
1218                 size += 8 + localVarType.length;
1219             }
1220             if (lineNumber != null) {
1221                 cw.newUTF8("LineNumberTable");
1222                 size += 8 + lineNumber.length;
1223             }
1224             if (cattrs != null) {
1225                 size += cattrs.getSize(cw,
1226                         code.data,
1227                         code.length,
1228                         maxStack,
1229                         maxLocals);
1230             }
1231         }
1232         if (exceptionCount > 0) {
1233             cw.newUTF8("Exceptions");
1234             size += 8 + 2 * exceptionCount;
1235         }
1236         if ((access & Opcodes.ACC_SYNTHETIC) != 0
1237                 && (cw.version & 0xffff) < Opcodes.V1_5)
1238         {
1239             cw.newUTF8("Synthetic");
1240             size += 6;
1241         }
1242         if ((access & Opcodes.ACC_DEPRECATED) != 0) {
1243             cw.newUTF8("Deprecated");
1244             size += 6;
1245         }
1246         if (cw.version == Opcodes.V1_4) {
1247             if ((access & Opcodes.ACC_VARARGS) != 0) {
1248                 cw.newUTF8("Varargs");
1249                 size += 6;
1250             }
1251             if ((access & Opcodes.ACC_BRIDGE) != 0) {
1252                 cw.newUTF8("Bridge");
1253                 size += 6;
1254             }
1255         }
1256         if (signature != null) {
1257             cw.newUTF8("Signature");
1258             cw.newUTF8(signature);
1259             size += 8;
1260         }
1261         if (annd != null) {
1262             cw.newUTF8("AnnotationDefault");
1263             size += 6 + annd.length;
1264         }
1265         if (anns != null) {
1266             cw.newUTF8("RuntimeVisibleAnnotations");
1267             size += 8 + anns.getSize();
1268         }
1269         if (ianns != null) {
1270             cw.newUTF8("RuntimeInvisibleAnnotations");
1271             size += 8 + ianns.getSize();
1272         }
1273         if (panns != null) {
1274             cw.newUTF8("RuntimeVisibleParameterAnnotations");
1275             size += 7 + 2 * panns.length;
1276             for (int i = panns.length - 1; i >= 0; --i) {
1277                 size += panns[i] == null ? 0 : panns[i].getSize();
1278             }
1279         }
1280         if (ipanns != null) {
1281             cw.newUTF8("RuntimeInvisibleParameterAnnotations");
1282             size += 7 + 2 * ipanns.length;
1283             for (int i = ipanns.length - 1; i >= 0; --i) {
1284                 size += ipanns[i] == null ? 0 : ipanns[i].getSize();
1285             }
1286         }
1287         if (attrs != null) {
1288             size += attrs.getSize(cw, null, 0, -1, -1);
1289         }
1290         return size;
1291     }
1292 
1293     /**
1294      * Puts the bytecode of this method in the given byte vector.
1295      *
1296      * @param out the byte vector into which the bytecode of this method must be
1297      *        copied.
1298      */
put(final ByteVector out)1299     final void put(final ByteVector out) {
1300         out.putShort(access).putShort(name).putShort(desc);
1301         if (classReaderOffset != 0) {
1302             out.putByteArray(cw.cr.b, classReaderOffset, classReaderLength);
1303             return;
1304         }
1305         int attributeCount = 0;
1306         if (code.length > 0) {
1307             ++attributeCount;
1308         }
1309         if (exceptionCount > 0) {
1310             ++attributeCount;
1311         }
1312         if ((access & Opcodes.ACC_SYNTHETIC) != 0
1313                 && (cw.version & 0xffff) < Opcodes.V1_5)
1314         {
1315             ++attributeCount;
1316         }
1317         if ((access & Opcodes.ACC_DEPRECATED) != 0) {
1318             ++attributeCount;
1319         }
1320         if (cw.version == Opcodes.V1_4) {
1321             if ((access & Opcodes.ACC_VARARGS) != 0) {
1322                 ++attributeCount;
1323             }
1324             if ((access & Opcodes.ACC_BRIDGE) != 0) {
1325                 ++attributeCount;
1326             }
1327         }
1328         if (signature != null) {
1329             ++attributeCount;
1330         }
1331         if (annd != null) {
1332             ++attributeCount;
1333         }
1334         if (anns != null) {
1335             ++attributeCount;
1336         }
1337         if (ianns != null) {
1338             ++attributeCount;
1339         }
1340         if (panns != null) {
1341             ++attributeCount;
1342         }
1343         if (ipanns != null) {
1344             ++attributeCount;
1345         }
1346         if (attrs != null) {
1347             attributeCount += attrs.getCount();
1348         }
1349         out.putShort(attributeCount);
1350         if (code.length > 0) {
1351             int size = 12 + code.length + 8 * catchCount;
1352             if (localVar != null) {
1353                 size += 8 + localVar.length;
1354             }
1355             if (localVarType != null) {
1356                 size += 8 + localVarType.length;
1357             }
1358             if (lineNumber != null) {
1359                 size += 8 + lineNumber.length;
1360             }
1361             if (cattrs != null) {
1362                 size += cattrs.getSize(cw,
1363                         code.data,
1364                         code.length,
1365                         maxStack,
1366                         maxLocals);
1367             }
1368             out.putShort(cw.newUTF8("Code")).putInt(size);
1369             out.putShort(maxStack).putShort(maxLocals);
1370             out.putInt(code.length).putByteArray(code.data, 0, code.length);
1371             out.putShort(catchCount);
1372             if (catchCount > 0) {
1373                 Handler h = catchTable;
1374                 while (h != null) {
1375                     out.putShort(h.start.position)
1376                             .putShort(h.end.position)
1377                             .putShort(h.handler.position)
1378                             .putShort(h.type);
1379                     h = h.next;
1380                 }
1381             }
1382             attributeCount = 0;
1383             if (localVar != null) {
1384                 ++attributeCount;
1385             }
1386             if (localVarType != null) {
1387                 ++attributeCount;
1388             }
1389             if (lineNumber != null) {
1390                 ++attributeCount;
1391             }
1392             if (cattrs != null) {
1393                 attributeCount += cattrs.getCount();
1394             }
1395             out.putShort(attributeCount);
1396             if (localVar != null) {
1397                 out.putShort(cw.newUTF8("LocalVariableTable"));
1398                 out.putInt(localVar.length + 2).putShort(localVarCount);
1399                 out.putByteArray(localVar.data, 0, localVar.length);
1400             }
1401             if (localVarType != null) {
1402                 out.putShort(cw.newUTF8("LocalVariableTypeTable"));
1403                 out.putInt(localVarType.length + 2).putShort(localVarTypeCount);
1404                 out.putByteArray(localVarType.data, 0, localVarType.length);
1405             }
1406             if (lineNumber != null) {
1407                 out.putShort(cw.newUTF8("LineNumberTable"));
1408                 out.putInt(lineNumber.length + 2).putShort(lineNumberCount);
1409                 out.putByteArray(lineNumber.data, 0, lineNumber.length);
1410             }
1411             if (cattrs != null) {
1412                 cattrs.put(cw, code.data, code.length, maxLocals, maxStack, out);
1413             }
1414         }
1415         if (exceptionCount > 0) {
1416             out.putShort(cw.newUTF8("Exceptions"))
1417                     .putInt(2 * exceptionCount + 2);
1418             out.putShort(exceptionCount);
1419             for (int i = 0; i < exceptionCount; ++i) {
1420                 out.putShort(exceptions[i]);
1421             }
1422         }
1423         if ((access & Opcodes.ACC_SYNTHETIC) != 0
1424                 && (cw.version & 0xffff) < Opcodes.V1_5)
1425         {
1426             out.putShort(cw.newUTF8("Synthetic")).putInt(0);
1427         }
1428         if ((access & Opcodes.ACC_DEPRECATED) != 0) {
1429             out.putShort(cw.newUTF8("Deprecated")).putInt(0);
1430         }
1431         if (cw.version == Opcodes.V1_4) {
1432             if ((access & Opcodes.ACC_VARARGS) != 0) {
1433                 out.putShort(cw.newUTF8("Varargs")).putInt(0);
1434             }
1435             if ((access & Opcodes.ACC_BRIDGE) != 0) {
1436                 out.putShort(cw.newUTF8("Bridge")).putInt(0);
1437             }
1438         }
1439         if (signature != null) {
1440             out.putShort(cw.newUTF8("Signature"))
1441                     .putInt(2)
1442                     .putShort(cw.newUTF8(signature));
1443         }
1444         if (annd != null) {
1445             out.putShort(cw.newUTF8("AnnotationDefault"));
1446             out.putInt(annd.length);
1447             out.putByteArray(annd.data, 0, annd.length);
1448         }
1449         if (anns != null) {
1450             out.putShort(cw.newUTF8("RuntimeVisibleAnnotations"));
1451             anns.put(out);
1452         }
1453         if (ianns != null) {
1454             out.putShort(cw.newUTF8("RuntimeInvisibleAnnotations"));
1455             ianns.put(out);
1456         }
1457         if (panns != null) {
1458             out.putShort(cw.newUTF8("RuntimeVisibleParameterAnnotations"));
1459             AnnotationWriter.put(panns, out);
1460         }
1461         if (ipanns != null) {
1462             out.putShort(cw.newUTF8("RuntimeInvisibleParameterAnnotations"));
1463             AnnotationWriter.put(ipanns, out);
1464         }
1465         if (attrs != null) {
1466             attrs.put(cw, null, 0, -1, -1, out);
1467         }
1468     }
1469 
1470     // ------------------------------------------------------------------------
1471     // Utility methods: instruction resizing (used to handle GOTO_W and JSR_W)
1472     // ------------------------------------------------------------------------
1473 
1474     /**
1475      * Resizes the designated instructions, while keeping jump offsets and
1476      * instruction addresses consistent. This may require to resize other
1477      * existing instructions, or even to introduce new instructions: for
1478      * example, increasing the size of an instruction by 2 at the middle of a
1479      * method can increases the offset of an IFEQ instruction from 32766 to
1480      * 32768, in which case IFEQ 32766 must be replaced with IFNEQ 8 GOTO_W
1481      * 32765. This, in turn, may require to increase the size of another jump
1482      * instruction, and so on... All these operations are handled automatically
1483      * by this method. <p> <i>This method must be called after all the method
1484      * that is being built has been visited</i>. In particular, the
1485      * {@link Label Label} objects used to construct the method are no longer
1486      * valid after this method has been called.
1487      *
1488      * @param indexes current positions of the instructions to be resized. Each
1489      *        instruction must be designated by the index of its <i>last</i>
1490      *        byte, plus one (or, in other words, by the index of the <i>first</i>
1491      *        byte of the <i>next</i> instruction).
1492      * @param sizes the number of bytes to be <i>added</i> to the above
1493      *        instructions. More precisely, for each i &lt; <tt>len</tt>,
1494      *        <tt>sizes</tt>[i] bytes will be added at the end of the
1495      *        instruction designated by <tt>indexes</tt>[i] or, if
1496      *        <tt>sizes</tt>[i] is negative, the <i>last</i> |<tt>sizes[i]</tt>|
1497      *        bytes of the instruction will be removed (the instruction size
1498      *        <i>must not</i> become negative or null). The gaps introduced by
1499      *        this method must be filled in "manually" in {@link #code code}
1500      *        method.
1501      * @param len the number of instruction to be resized. Must be smaller than
1502      *        or equal to <tt>indexes</tt>.length and <tt>sizes</tt>.length.
1503      * @return the <tt>indexes</tt> array, which now contains the new
1504      *         positions of the resized instructions (designated as above).
1505      */
resizeInstructions( final int[] indexes, final int[] sizes, final int len)1506     private int[] resizeInstructions(
1507         final int[] indexes,
1508         final int[] sizes,
1509         final int len)
1510     {
1511         byte[] b = code.data; // bytecode of the method
1512         int u, v, label; // indexes in b
1513         int i, j; // loop indexes
1514 
1515         /*
1516          * 1st step: As explained above, resizing an instruction may require to
1517          * resize another one, which may require to resize yet another one, and
1518          * so on. The first step of the algorithm consists in finding all the
1519          * instructions that need to be resized, without modifying the code.
1520          * This is done by the following "fix point" algorithm:
1521          *
1522          * Parse the code to find the jump instructions whose offset will need
1523          * more than 2 bytes to be stored (the future offset is computed from
1524          * the current offset and from the number of bytes that will be inserted
1525          * or removed between the source and target instructions). For each such
1526          * instruction, adds an entry in (a copy of) the indexes and sizes
1527          * arrays (if this has not already been done in a previous iteration!).
1528          *
1529          * If at least one entry has been added during the previous step, go
1530          * back to the beginning, otherwise stop.
1531          *
1532          * In fact the real algorithm is complicated by the fact that the size
1533          * of TABLESWITCH and LOOKUPSWITCH instructions depends on their
1534          * position in the bytecode (because of padding). In order to ensure the
1535          * convergence of the algorithm, the number of bytes to be added or
1536          * removed from these instructions is over estimated during the previous
1537          * loop, and computed exactly only after the loop is finished (this
1538          * requires another pass to parse the bytecode of the method).
1539          */
1540         int[] allIndexes = new int[len]; // copy of indexes
1541         int[] allSizes = new int[len]; // copy of sizes
1542         boolean[] resize; // instructions to be resized
1543         int newOffset; // future offset of a jump instruction
1544 
1545         System.arraycopy(indexes, 0, allIndexes, 0, len);
1546         System.arraycopy(sizes, 0, allSizes, 0, len);
1547         resize = new boolean[code.length];
1548 
1549         // 3 = loop again, 2 = loop ended, 1 = last pass, 0 = done
1550         int state = 3;
1551         do {
1552             if (state == 3) {
1553                 state = 2;
1554             }
1555             u = 0;
1556             while (u < b.length) {
1557                 int opcode = b[u] & 0xFF; // opcode of current instruction
1558                 int insert = 0; // bytes to be added after this instruction
1559 
1560                 switch (ClassWriter.TYPE[opcode]) {
1561                     case ClassWriter.NOARG_INSN:
1562                     case ClassWriter.IMPLVAR_INSN:
1563                         u += 1;
1564                         break;
1565                     case ClassWriter.LABEL_INSN:
1566                         if (opcode > 201) {
1567                             // converts temporary opcodes 202 to 217, 218 and
1568                             // 219 to IFEQ ... JSR (inclusive), IFNULL and
1569                             // IFNONNULL
1570                             opcode = opcode < 218 ? opcode - 49 : opcode - 20;
1571                             label = u + readUnsignedShort(b, u + 1);
1572                         } else {
1573                             label = u + readShort(b, u + 1);
1574                         }
1575                         newOffset = getNewOffset(allIndexes, allSizes, u, label);
1576                         if (newOffset < Short.MIN_VALUE
1577                                 || newOffset > Short.MAX_VALUE)
1578                         {
1579                             if (!resize[u]) {
1580                                 if (opcode == Opcodes.GOTO
1581                                         || opcode == Opcodes.JSR)
1582                                 {
1583                                     // two additional bytes will be required to
1584                                     // replace this GOTO or JSR instruction with
1585                                     // a GOTO_W or a JSR_W
1586                                     insert = 2;
1587                                 } else {
1588                                     // five additional bytes will be required to
1589                                     // replace this IFxxx <l> instruction with
1590                                     // IFNOTxxx <l'> GOTO_W <l>, where IFNOTxxx
1591                                     // is the "opposite" opcode of IFxxx (i.e.,
1592                                     // IFNE for IFEQ) and where <l'> designates
1593                                     // the instruction just after the GOTO_W.
1594                                     insert = 5;
1595                                 }
1596                                 resize[u] = true;
1597                             }
1598                         }
1599                         u += 3;
1600                         break;
1601                     case ClassWriter.LABELW_INSN:
1602                         u += 5;
1603                         break;
1604                     case ClassWriter.TABL_INSN:
1605                         if (state == 1) {
1606                             // true number of bytes to be added (or removed)
1607                             // from this instruction = (future number of padding
1608                             // bytes - current number of padding byte) -
1609                             // previously over estimated variation =
1610                             // = ((3 - newOffset%4) - (3 - u%4)) - u%4
1611                             // = (-newOffset%4 + u%4) - u%4
1612                             // = -(newOffset & 3)
1613                             newOffset = getNewOffset(allIndexes, allSizes, 0, u);
1614                             insert = -(newOffset & 3);
1615                         } else if (!resize[u]) {
1616                             // over estimation of the number of bytes to be
1617                             // added to this instruction = 3 - current number
1618                             // of padding bytes = 3 - (3 - u%4) = u%4 = u & 3
1619                             insert = u & 3;
1620                             resize[u] = true;
1621                         }
1622                         // skips instruction
1623                         u = u + 4 - (u & 3);
1624                         u += 4 * (readInt(b, u + 8) - readInt(b, u + 4) + 1) + 12;
1625                         break;
1626                     case ClassWriter.LOOK_INSN:
1627                         if (state == 1) {
1628                             // like TABL_INSN
1629                             newOffset = getNewOffset(allIndexes, allSizes, 0, u);
1630                             insert = -(newOffset & 3);
1631                         } else if (!resize[u]) {
1632                             // like TABL_INSN
1633                             insert = u & 3;
1634                             resize[u] = true;
1635                         }
1636                         // skips instruction
1637                         u = u + 4 - (u & 3);
1638                         u += 8 * readInt(b, u + 4) + 8;
1639                         break;
1640                     case ClassWriter.WIDE_INSN:
1641                         opcode = b[u + 1] & 0xFF;
1642                         if (opcode == Opcodes.IINC) {
1643                             u += 6;
1644                         } else {
1645                             u += 4;
1646                         }
1647                         break;
1648                     case ClassWriter.VAR_INSN:
1649                     case ClassWriter.SBYTE_INSN:
1650                     case ClassWriter.LDC_INSN:
1651                         u += 2;
1652                         break;
1653                     case ClassWriter.SHORT_INSN:
1654                     case ClassWriter.LDCW_INSN:
1655                     case ClassWriter.FIELDORMETH_INSN:
1656                     case ClassWriter.TYPE_INSN:
1657                     case ClassWriter.IINC_INSN:
1658                         u += 3;
1659                         break;
1660                     case ClassWriter.ITFMETH_INSN:
1661                         u += 5;
1662                         break;
1663                     // case ClassWriter.MANA_INSN:
1664                     default:
1665                         u += 4;
1666                         break;
1667                 }
1668                 if (insert != 0) {
1669                     // adds a new (u, insert) entry in the allIndexes and
1670                     // allSizes arrays
1671                     int[] newIndexes = new int[allIndexes.length + 1];
1672                     int[] newSizes = new int[allSizes.length + 1];
1673                     System.arraycopy(allIndexes,
1674                             0,
1675                             newIndexes,
1676                             0,
1677                             allIndexes.length);
1678                     System.arraycopy(allSizes, 0, newSizes, 0, allSizes.length);
1679                     newIndexes[allIndexes.length] = u;
1680                     newSizes[allSizes.length] = insert;
1681                     allIndexes = newIndexes;
1682                     allSizes = newSizes;
1683                     if (insert > 0) {
1684                         state = 3;
1685                     }
1686                 }
1687             }
1688             if (state < 3) {
1689                 --state;
1690             }
1691         } while (state != 0);
1692 
1693         // 2nd step:
1694         // copies the bytecode of the method into a new bytevector, updates the
1695         // offsets, and inserts (or removes) bytes as requested.
1696 
1697         ByteVector newCode = new ByteVector(code.length);
1698 
1699         u = 0;
1700         while (u < code.length) {
1701             for (i = allIndexes.length - 1; i >= 0; --i) {
1702                 if (allIndexes[i] == u) {
1703                     if (i < len) {
1704                         if (sizes[i] > 0) {
1705                             newCode.putByteArray(null, 0, sizes[i]);
1706                         } else {
1707                             newCode.length += sizes[i];
1708                         }
1709                         indexes[i] = newCode.length;
1710                     }
1711                 }
1712             }
1713             int opcode = b[u] & 0xFF;
1714             switch (ClassWriter.TYPE[opcode]) {
1715                 case ClassWriter.NOARG_INSN:
1716                 case ClassWriter.IMPLVAR_INSN:
1717                     newCode.putByte(opcode);
1718                     u += 1;
1719                     break;
1720                 case ClassWriter.LABEL_INSN:
1721                     if (opcode > 201) {
1722                         // changes temporary opcodes 202 to 217 (inclusive), 218
1723                         // and 219 to IFEQ ... JSR (inclusive), IFNULL and
1724                         // IFNONNULL
1725                         opcode = opcode < 218 ? opcode - 49 : opcode - 20;
1726                         label = u + readUnsignedShort(b, u + 1);
1727                     } else {
1728                         label = u + readShort(b, u + 1);
1729                     }
1730                     newOffset = getNewOffset(allIndexes, allSizes, u, label);
1731                     if (resize[u]) {
1732                         // replaces GOTO with GOTO_W, JSR with JSR_W and IFxxx
1733                         // <l> with IFNOTxxx <l'> GOTO_W <l>, where IFNOTxxx is
1734                         // the "opposite" opcode of IFxxx (i.e., IFNE for IFEQ)
1735                         // and where <l'> designates the instruction just after
1736                         // the GOTO_W.
1737                         if (opcode == Opcodes.GOTO) {
1738                             newCode.putByte(200); // GOTO_W
1739                         } else if (opcode == Opcodes.JSR) {
1740                             newCode.putByte(201); // JSR_W
1741                         } else {
1742                             newCode.putByte(opcode <= 166
1743                                     ? ((opcode + 1) ^ 1) - 1
1744                                     : opcode ^ 1);
1745                             newCode.putShort(8); // jump offset
1746                             newCode.putByte(200); // GOTO_W
1747                             // newOffset now computed from start of GOTO_W
1748                             newOffset -= 3;
1749                         }
1750                         newCode.putInt(newOffset);
1751                     } else {
1752                         newCode.putByte(opcode);
1753                         newCode.putShort(newOffset);
1754                     }
1755                     u += 3;
1756                     break;
1757                 case ClassWriter.LABELW_INSN:
1758                     label = u + readInt(b, u + 1);
1759                     newOffset = getNewOffset(allIndexes, allSizes, u, label);
1760                     newCode.putByte(opcode);
1761                     newCode.putInt(newOffset);
1762                     u += 5;
1763                     break;
1764                 case ClassWriter.TABL_INSN:
1765                     // skips 0 to 3 padding bytes
1766                     v = u;
1767                     u = u + 4 - (v & 3);
1768                     // reads and copies instruction
1769                     newCode.putByte(Opcodes.TABLESWITCH);
1770                     while (newCode.length % 4 != 0) {
1771                         newCode.putByte(0);
1772                     }
1773                     label = v + readInt(b, u);
1774                     u += 4;
1775                     newOffset = getNewOffset(allIndexes, allSizes, v, label);
1776                     newCode.putInt(newOffset);
1777                     j = readInt(b, u);
1778                     u += 4;
1779                     newCode.putInt(j);
1780                     j = readInt(b, u) - j + 1;
1781                     u += 4;
1782                     newCode.putInt(readInt(b, u - 4));
1783                     for (; j > 0; --j) {
1784                         label = v + readInt(b, u);
1785                         u += 4;
1786                         newOffset = getNewOffset(allIndexes, allSizes, v, label);
1787                         newCode.putInt(newOffset);
1788                     }
1789                     break;
1790                 case ClassWriter.LOOK_INSN:
1791                     // skips 0 to 3 padding bytes
1792                     v = u;
1793                     u = u + 4 - (v & 3);
1794                     // reads and copies instruction
1795                     newCode.putByte(Opcodes.LOOKUPSWITCH);
1796                     while (newCode.length % 4 != 0) {
1797                         newCode.putByte(0);
1798                     }
1799                     label = v + readInt(b, u);
1800                     u += 4;
1801                     newOffset = getNewOffset(allIndexes, allSizes, v, label);
1802                     newCode.putInt(newOffset);
1803                     j = readInt(b, u);
1804                     u += 4;
1805                     newCode.putInt(j);
1806                     for (; j > 0; --j) {
1807                         newCode.putInt(readInt(b, u));
1808                         u += 4;
1809                         label = v + readInt(b, u);
1810                         u += 4;
1811                         newOffset = getNewOffset(allIndexes, allSizes, v, label);
1812                         newCode.putInt(newOffset);
1813                     }
1814                     break;
1815                 case ClassWriter.WIDE_INSN:
1816                     opcode = b[u + 1] & 0xFF;
1817                     if (opcode == Opcodes.IINC) {
1818                         newCode.putByteArray(b, u, 6);
1819                         u += 6;
1820                     } else {
1821                         newCode.putByteArray(b, u, 4);
1822                         u += 4;
1823                     }
1824                     break;
1825                 case ClassWriter.VAR_INSN:
1826                 case ClassWriter.SBYTE_INSN:
1827                 case ClassWriter.LDC_INSN:
1828                     newCode.putByteArray(b, u, 2);
1829                     u += 2;
1830                     break;
1831                 case ClassWriter.SHORT_INSN:
1832                 case ClassWriter.LDCW_INSN:
1833                 case ClassWriter.FIELDORMETH_INSN:
1834                 case ClassWriter.TYPE_INSN:
1835                 case ClassWriter.IINC_INSN:
1836                     newCode.putByteArray(b, u, 3);
1837                     u += 3;
1838                     break;
1839                 case ClassWriter.ITFMETH_INSN:
1840                     newCode.putByteArray(b, u, 5);
1841                     u += 5;
1842                     break;
1843                 // case MANA_INSN:
1844                 default:
1845                     newCode.putByteArray(b, u, 4);
1846                     u += 4;
1847                     break;
1848             }
1849         }
1850 
1851         // updates the exception handler block labels
1852         Handler h = catchTable;
1853         while (h != null) {
1854             getNewOffset(allIndexes, allSizes, h.start);
1855             getNewOffset(allIndexes, allSizes, h.end);
1856             getNewOffset(allIndexes, allSizes, h.handler);
1857             h = h.next;
1858         }
1859         for (i = 0; i < 2; ++i) {
1860             ByteVector bv = i == 0 ? localVar : localVarType;
1861             if (bv != null) {
1862                 b = bv.data;
1863                 u = 0;
1864                 while (u < bv.length) {
1865                     label = readUnsignedShort(b, u);
1866                     newOffset = getNewOffset(allIndexes, allSizes, 0, label);
1867                     writeShort(b, u, newOffset);
1868                     label += readUnsignedShort(b, u + 2);
1869                     newOffset = getNewOffset(allIndexes, allSizes, 0, label)
1870                             - newOffset;
1871                     writeShort(b, u + 2, newOffset);
1872                     u += 10;
1873                 }
1874             }
1875         }
1876         if (lineNumber != null) {
1877             b = lineNumber.data;
1878             u = 0;
1879             while (u < lineNumber.length) {
1880                 writeShort(b, u, getNewOffset(allIndexes,
1881                         allSizes,
1882                         0,
1883                         readUnsignedShort(b, u)));
1884                 u += 4;
1885             }
1886         }
1887         // updates the labels of the other attributes
1888         while (cattrs != null) {
1889             Label[] labels = cattrs.getLabels();
1890             if (labels != null) {
1891                 for (i = labels.length - 1; i >= 0; --i) {
1892                     if (!labels[i].resized) {
1893                         labels[i].position = getNewOffset(allIndexes,
1894                                 allSizes,
1895                                 0,
1896                                 labels[i].position);
1897                         labels[i].resized = true;
1898                     }
1899                 }
1900             }
1901         }
1902 
1903         // replaces old bytecodes with new ones
1904         code = newCode;
1905 
1906         // returns the positions of the resized instructions
1907         return indexes;
1908     }
1909 
1910     /**
1911      * Reads an unsigned short value in the given byte array.
1912      *
1913      * @param b a byte array.
1914      * @param index the start index of the value to be read.
1915      * @return the read value.
1916      */
readUnsignedShort(final byte[] b, final int index)1917     static int readUnsignedShort(final byte[] b, final int index) {
1918         return ((b[index] & 0xFF) << 8) | (b[index + 1] & 0xFF);
1919     }
1920 
1921     /**
1922      * Reads a signed short value in the given byte array.
1923      *
1924      * @param b a byte array.
1925      * @param index the start index of the value to be read.
1926      * @return the read value.
1927      */
readShort(final byte[] b, final int index)1928     static short readShort(final byte[] b, final int index) {
1929         return (short) (((b[index] & 0xFF) << 8) | (b[index + 1] & 0xFF));
1930     }
1931 
1932     /**
1933      * Reads a signed int value in the given byte array.
1934      *
1935      * @param b a byte array.
1936      * @param index the start index of the value to be read.
1937      * @return the read value.
1938      */
readInt(final byte[] b, final int index)1939     static int readInt(final byte[] b, final int index) {
1940         return ((b[index] & 0xFF) << 24) | ((b[index + 1] & 0xFF) << 16)
1941                 | ((b[index + 2] & 0xFF) << 8) | (b[index + 3] & 0xFF);
1942     }
1943 
1944     /**
1945      * Writes a short value in the given byte array.
1946      *
1947      * @param b a byte array.
1948      * @param index where the first byte of the short value must be written.
1949      * @param s the value to be written in the given byte array.
1950      */
writeShort(final byte[] b, final int index, final int s)1951     static void writeShort(final byte[] b, final int index, final int s) {
1952         b[index] = (byte) (s >>> 8);
1953         b[index + 1] = (byte) s;
1954     }
1955 
1956     /**
1957      * Computes the future value of a bytecode offset. <p> Note: it is possible
1958      * to have several entries for the same instruction in the <tt>indexes</tt>
1959      * and <tt>sizes</tt>: two entries (index=a,size=b) and (index=a,size=b')
1960      * are equivalent to a single entry (index=a,size=b+b').
1961      *
1962      * @param indexes current positions of the instructions to be resized. Each
1963      *        instruction must be designated by the index of its <i>last</i>
1964      *        byte, plus one (or, in other words, by the index of the <i>first</i>
1965      *        byte of the <i>next</i> instruction).
1966      * @param sizes the number of bytes to be <i>added</i> to the above
1967      *        instructions. More precisely, for each i < <tt>len</tt>,
1968      *        <tt>sizes</tt>[i] bytes will be added at the end of the
1969      *        instruction designated by <tt>indexes</tt>[i] or, if
1970      *        <tt>sizes</tt>[i] is negative, the <i>last</i> |<tt>sizes[i]</tt>|
1971      *        bytes of the instruction will be removed (the instruction size
1972      *        <i>must not</i> become negative or null).
1973      * @param begin index of the first byte of the source instruction.
1974      * @param end index of the first byte of the target instruction.
1975      * @return the future value of the given bytecode offset.
1976      */
getNewOffset( final int[] indexes, final int[] sizes, final int begin, final int end)1977     static int getNewOffset(
1978         final int[] indexes,
1979         final int[] sizes,
1980         final int begin,
1981         final int end)
1982     {
1983         int offset = end - begin;
1984         for (int i = 0; i < indexes.length; ++i) {
1985             if (begin < indexes[i] && indexes[i] <= end) {
1986                 // forward jump
1987                 offset += sizes[i];
1988             } else if (end < indexes[i] && indexes[i] <= begin) {
1989                 // backward jump
1990                 offset -= sizes[i];
1991             }
1992         }
1993         return offset;
1994     }
1995 
1996     /**
1997      * Updates the offset of the given label.
1998      *
1999      * @param indexes current positions of the instructions to be resized. Each
2000      *        instruction must be designated by the index of its <i>last</i>
2001      *        byte, plus one (or, in other words, by the index of the <i>first</i>
2002      *        byte of the <i>next</i> instruction).
2003      * @param sizes the number of bytes to be <i>added</i> to the above
2004      *        instructions. More precisely, for each i < <tt>len</tt>,
2005      *        <tt>sizes</tt>[i] bytes will be added at the end of the
2006      *        instruction designated by <tt>indexes</tt>[i] or, if
2007      *        <tt>sizes</tt>[i] is negative, the <i>last</i> |<tt>sizes[i]</tt>|
2008      *        bytes of the instruction will be removed (the instruction size
2009      *        <i>must not</i> become negative or null).
2010      * @param label the label whose offset must be updated.
2011      */
getNewOffset( final int[] indexes, final int[] sizes, final Label label)2012     static void getNewOffset(
2013         final int[] indexes,
2014         final int[] sizes,
2015         final Label label)
2016     {
2017         if (!label.resized) {
2018             label.position = getNewOffset(indexes, sizes, 0, label.position);
2019             label.resized = true;
2020         }
2021     }
2022 }
2023