Source Code Cross Referenced for MethodWriter.java in  » Byte-Code » asm » org » objectweb » asm » Java Source Code / Java DocumentationJava Source Code and Java Documentation

Java Source Code / Java Documentation
1. 6.0 JDK Core
2. 6.0 JDK Modules
3. 6.0 JDK Modules com.sun
4. 6.0 JDK Modules com.sun.java
5. 6.0 JDK Modules sun
6. 6.0 JDK Platform
7. Ajax
8. Apache Harmony Java SE
9. Aspect oriented
10. Authentication Authorization
11. Blogger System
12. Build
13. Byte Code
14. Cache
15. Chart
16. Chat
17. Code Analyzer
18. Collaboration
19. Content Management System
20. Database Client
21. Database DBMS
22. Database JDBC Connection Pool
23. Database ORM
24. Development
25. EJB Server geronimo
26. EJB Server GlassFish
27. EJB Server JBoss 4.2.1
28. EJB Server resin 3.1.5
29. ERP CRM Financial
30. ESB
31. Forum
32. GIS
33. Graphic Library
34. Groupware
35. HTML Parser
36. IDE
37. IDE Eclipse
38. IDE Netbeans
39. Installer
40. Internationalization Localization
41. Inversion of Control
42. Issue Tracking
43. J2EE
44. JBoss
45. JMS
46. JMX
47. Library
48. Mail Clients
49. Net
50. Parser
51. PDF
52. Portal
53. Profiler
54. Project Management
55. Report
56. RSS RDF
57. Rule Engine
58. Science
59. Scripting
60. Search Engine
61. Security
62. Sevlet Container
63. Source Control
64. Swing Library
65. Template Engine
66. Test Coverage
67. Testing
68. UML
69. Web Crawler
70. Web Framework
71. Web Mail
72. Web Server
73. Web Services
74. Web Services apache cxf 2.0.1
75. Web Services AXIS2
76. Wiki Engine
77. Workflow Engines
78. XML
79. XML UI
Java
Java Tutorial
Java Open Source
Jar File Download
Java Articles
Java Products
Java by API
Photoshop Tutorials
Maya Tutorials
Flash Tutorials
3ds-Max Tutorials
Illustrator Tutorials
GIMP Tutorials
C# / C Sharp
C# / CSharp Tutorial
C# / CSharp Open Source
ASP.Net
ASP.NET Tutorial
JavaScript DHTML
JavaScript Tutorial
JavaScript Reference
HTML / CSS
HTML CSS Reference
C / ANSI-C
C Tutorial
C++
C++ Tutorial
Ruby
PHP
Python
Python Tutorial
Python Open Source
SQL Server / T-SQL
SQL Server / T-SQL Tutorial
Oracle PL / SQL
Oracle PL/SQL Tutorial
PostgreSQL
SQL / MySQL
MySQL Tutorial
VB.Net
VB.Net Tutorial
Flash / Flex / ActionScript
VBA / Excel / Access / Word
XML
XML Tutorial
Microsoft Office PowerPoint 2007 Tutorial
Microsoft Office Excel 2007 Tutorial
Microsoft Office Word 2007 Tutorial
Java Source Code / Java Documentation » Byte Code » asm » org.objectweb.asm 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


0001:        /***
0002:         * ASM: a very small and fast Java bytecode manipulation framework
0003:         * Copyright (c) 2000-2007 INRIA, France Telecom
0004:         * All rights reserved.
0005:         *
0006:         * Redistribution and use in source and binary forms, with or without
0007:         * modification, are permitted provided that the following conditions
0008:         * are met:
0009:         * 1. Redistributions of source code must retain the above copyright
0010:         *    notice, this list of conditions and the following disclaimer.
0011:         * 2. Redistributions in binary form must reproduce the above copyright
0012:         *    notice, this list of conditions and the following disclaimer in the
0013:         *    documentation and/or other materials provided with the distribution.
0014:         * 3. Neither the name of the copyright holders nor the names of its
0015:         *    contributors may be used to endorse or promote products derived from
0016:         *    this software without specific prior written permission.
0017:         *
0018:         * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
0019:         * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
0020:         * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
0021:         * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
0022:         * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
0023:         * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
0024:         * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
0025:         * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
0026:         * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
0027:         * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
0028:         * THE POSSIBILITY OF SUCH DAMAGE.
0029:         */package org.objectweb.asm;
0030:
0031:        /**
0032:         * A {@link MethodVisitor} that generates methods in bytecode form. Each visit
0033:         * method of this class appends the bytecode corresponding to the visited
0034:         * instruction to a byte vector, in the order these methods are called.
0035:         * 
0036:         * @author Eric Bruneton
0037:         * @author Eugene Kuleshov
0038:         */
0039:        class MethodWriter implements  MethodVisitor {
0040:
0041:            /**
0042:             * Pseudo access flag used to denote constructors.
0043:             */
0044:            static final int ACC_CONSTRUCTOR = 262144;
0045:
0046:            /**
0047:             * Frame has exactly the same locals as the previous stack map frame and
0048:             * number of stack items is zero.
0049:             */
0050:            static final int SAME_FRAME = 0; // to 63 (0-3f)
0051:
0052:            /**
0053:             * Frame has exactly the same locals as the previous stack map frame and
0054:             * number of stack items is 1
0055:             */
0056:            static final int SAME_LOCALS_1_STACK_ITEM_FRAME = 64; // to 127 (40-7f)
0057:
0058:            /**
0059:             * Reserved for future use
0060:             */
0061:            static final int RESERVED = 128;
0062:
0063:            /**
0064:             * Frame has exactly the same locals as the previous stack map frame and
0065:             * number of stack items is 1. Offset is bigger then 63;
0066:             */
0067:            static final int SAME_LOCALS_1_STACK_ITEM_FRAME_EXTENDED = 247; // f7
0068:
0069:            /**
0070:             * Frame where current locals are the same as the locals in the previous
0071:             * frame, except that the k last locals are absent. The value of k is given
0072:             * by the formula 251-frame_type.
0073:             */
0074:            static final int CHOP_FRAME = 248; // to 250 (f8-fA)
0075:
0076:            /**
0077:             * Frame has exactly the same locals as the previous stack map frame and
0078:             * number of stack items is zero. Offset is bigger then 63;
0079:             */
0080:            static final int SAME_FRAME_EXTENDED = 251; // fb
0081:
0082:            /**
0083:             * Frame where current locals are the same as the locals in the previous
0084:             * frame, except that k additional locals are defined. The value of k is
0085:             * given by the formula frame_type-251.
0086:             */
0087:            static final int APPEND_FRAME = 252; // to 254 // fc-fe
0088:
0089:            /**
0090:             * Full frame
0091:             */
0092:            static final int FULL_FRAME = 255; // ff
0093:
0094:            /**
0095:             * Indicates that the stack map frames must be recomputed from scratch. In
0096:             * this case the maximum stack size and number of local variables is also
0097:             * recomputed from scratch.
0098:             * 
0099:             * @see #compute
0100:             */
0101:            private static final int FRAMES = 0;
0102:
0103:            /**
0104:             * Indicates that the maximum stack size and number of local variables must
0105:             * be automatically computed.
0106:             * 
0107:             * @see #compute
0108:             */
0109:            private static final int MAXS = 1;
0110:
0111:            /**
0112:             * Indicates that nothing must be automatically computed.
0113:             * 
0114:             * @see #compute
0115:             */
0116:            private static final int NOTHING = 2;
0117:
0118:            /**
0119:             * Next method writer (see {@link ClassWriter#firstMethod firstMethod}).
0120:             */
0121:            MethodWriter next;
0122:
0123:            /**
0124:             * The class writer to which this method must be added.
0125:             */
0126:            final ClassWriter cw;
0127:
0128:            /**
0129:             * Access flags of this method.
0130:             */
0131:            private int access;
0132:
0133:            /**
0134:             * The index of the constant pool item that contains the name of this
0135:             * method.
0136:             */
0137:            private final int name;
0138:
0139:            /**
0140:             * The index of the constant pool item that contains the descriptor of this
0141:             * method.
0142:             */
0143:            private final int desc;
0144:
0145:            /**
0146:             * The descriptor of this method.
0147:             */
0148:            private final String descriptor;
0149:
0150:            /**
0151:             * The signature of this method.
0152:             */
0153:            String signature;
0154:
0155:            /**
0156:             * If not zero, indicates that the code of this method must be copied from
0157:             * the ClassReader associated to this writer in <code>cw.cr</code>. More
0158:             * precisely, this field gives the index of the first byte to copied from
0159:             * <code>cw.cr.b</code>.
0160:             */
0161:            int classReaderOffset;
0162:
0163:            /**
0164:             * If not zero, indicates that the code of this method must be copied from
0165:             * the ClassReader associated to this writer in <code>cw.cr</code>. More
0166:             * precisely, this field gives the number of bytes to copied from
0167:             * <code>cw.cr.b</code>.
0168:             */
0169:            int classReaderLength;
0170:
0171:            /**
0172:             * Number of exceptions that can be thrown by this method.
0173:             */
0174:            int exceptionCount;
0175:
0176:            /**
0177:             * The exceptions that can be thrown by this method. More precisely, this
0178:             * array contains the indexes of the constant pool items that contain the
0179:             * internal names of these exception classes.
0180:             */
0181:            int[] exceptions;
0182:
0183:            /**
0184:             * The annotation default attribute of this method. May be <tt>null</tt>.
0185:             */
0186:            private ByteVector annd;
0187:
0188:            /**
0189:             * The runtime visible annotations of this method. May be <tt>null</tt>.
0190:             */
0191:            private AnnotationWriter anns;
0192:
0193:            /**
0194:             * The runtime invisible annotations of this method. May be <tt>null</tt>.
0195:             */
0196:            private AnnotationWriter ianns;
0197:
0198:            /**
0199:             * The runtime visible parameter annotations of this method. May be
0200:             * <tt>null</tt>.
0201:             */
0202:            private AnnotationWriter[] panns;
0203:
0204:            /**
0205:             * The runtime invisible parameter annotations of this method. May be
0206:             * <tt>null</tt>.
0207:             */
0208:            private AnnotationWriter[] ipanns;
0209:
0210:            /**
0211:             * The number of synthetic parameters of this method.
0212:             */
0213:            private int synthetics;
0214:
0215:            /**
0216:             * The non standard attributes of the method.
0217:             */
0218:            private Attribute attrs;
0219:
0220:            /**
0221:             * The bytecode of this method.
0222:             */
0223:            private ByteVector code = new ByteVector();
0224:
0225:            /**
0226:             * Maximum stack size of this method.
0227:             */
0228:            private int maxStack;
0229:
0230:            /**
0231:             * Maximum number of local variables for this method.
0232:             */
0233:            private int maxLocals;
0234:
0235:            /**
0236:             * Number of stack map frames in the StackMapTable attribute.
0237:             */
0238:            private int frameCount;
0239:
0240:            /**
0241:             * The StackMapTable attribute.
0242:             */
0243:            private ByteVector stackMap;
0244:
0245:            /**
0246:             * The offset of the last frame that was written in the StackMapTable
0247:             * attribute.
0248:             */
0249:            private int previousFrameOffset;
0250:
0251:            /**
0252:             * The last frame that was written in the StackMapTable attribute.
0253:             * 
0254:             * @see #frame
0255:             */
0256:            private int[] previousFrame;
0257:
0258:            /**
0259:             * Index of the next element to be added in {@link #frame}.
0260:             */
0261:            private int frameIndex;
0262:
0263:            /**
0264:             * The current stack map frame. The first element contains the offset of the
0265:             * instruction to which the frame corresponds, the second element is the
0266:             * number of locals and the third one is the number of stack elements. The
0267:             * local variables start at index 3 and are followed by the operand stack
0268:             * values. In summary frame[0] = offset, frame[1] = nLocal, frame[2] =
0269:             * nStack, frame[3] = nLocal. All types are encoded as integers, with the
0270:             * same format as the one used in {@link Label}, but limited to BASE types.
0271:             */
0272:            private int[] frame;
0273:
0274:            /**
0275:             * Number of elements in the exception handler list.
0276:             */
0277:            private int handlerCount;
0278:
0279:            /**
0280:             * The first element in the exception handler list.
0281:             */
0282:            private Handler firstHandler;
0283:
0284:            /**
0285:             * The last element in the exception handler list.
0286:             */
0287:            private Handler lastHandler;
0288:
0289:            /**
0290:             * Number of entries in the LocalVariableTable attribute.
0291:             */
0292:            private int localVarCount;
0293:
0294:            /**
0295:             * The LocalVariableTable attribute.
0296:             */
0297:            private ByteVector localVar;
0298:
0299:            /**
0300:             * Number of entries in the LocalVariableTypeTable attribute.
0301:             */
0302:            private int localVarTypeCount;
0303:
0304:            /**
0305:             * The LocalVariableTypeTable attribute.
0306:             */
0307:            private ByteVector localVarType;
0308:
0309:            /**
0310:             * Number of entries in the LineNumberTable attribute.
0311:             */
0312:            private int lineNumberCount;
0313:
0314:            /**
0315:             * The LineNumberTable attribute.
0316:             */
0317:            private ByteVector lineNumber;
0318:
0319:            /**
0320:             * The non standard attributes of the method's code.
0321:             */
0322:            private Attribute cattrs;
0323:
0324:            /**
0325:             * Indicates if some jump instructions are too small and need to be resized.
0326:             */
0327:            private boolean resize;
0328:
0329:            /**
0330:             * The number of subroutines in this method.
0331:             */
0332:            private int subroutines;
0333:
0334:            // ------------------------------------------------------------------------
0335:
0336:            /*
0337:             * Fields for the control flow graph analysis algorithm (used to compute the
0338:             * maximum stack size). A control flow graph contains one node per "basic
0339:             * block", and one edge per "jump" from one basic block to another. Each
0340:             * node (i.e., each basic block) is represented by the Label object that
0341:             * corresponds to the first instruction of this basic block. Each node also
0342:             * stores the list of its successors in the graph, as a linked list of Edge
0343:             * objects.
0344:             */
0345:
0346:            /**
0347:             * Indicates what must be automatically computed.
0348:             * 
0349:             * @see #FRAMES
0350:             * @see #MAXS
0351:             * @see #NOTHING
0352:             */
0353:            private final int compute;
0354:
0355:            /**
0356:             * A list of labels. This list is the list of basic blocks in the method,
0357:             * i.e. a list of Label objects linked to each other by their
0358:             * {@link Label#successor} field, in the order they are visited by
0359:             * {@link MethodVisitor#visitLabel}, and starting with the first basic block.
0360:             */
0361:            private Label labels;
0362:
0363:            /**
0364:             * The previous basic block.
0365:             */
0366:            private Label previousBlock;
0367:
0368:            /**
0369:             * The current basic block.
0370:             */
0371:            private Label currentBlock;
0372:
0373:            /**
0374:             * The (relative) stack size after the last visited instruction. This size
0375:             * is relative to the beginning of the current basic block, i.e., the true
0376:             * stack size after the last visited instruction is equal to the
0377:             * {@link Label#inputStackTop beginStackSize} of the current basic block
0378:             * plus <tt>stackSize</tt>.
0379:             */
0380:            private int stackSize;
0381:
0382:            /**
0383:             * The (relative) maximum stack size after the last visited instruction.
0384:             * This size is relative to the beginning of the current basic block, i.e.,
0385:             * the true maximum stack size after the last visited instruction is equal
0386:             * to the {@link Label#inputStackTop beginStackSize} of the current basic
0387:             * block plus <tt>stackSize</tt>.
0388:             */
0389:            private int maxStackSize;
0390:
0391:            // ------------------------------------------------------------------------
0392:            // Constructor
0393:            // ------------------------------------------------------------------------
0394:
0395:            /**
0396:             * Constructs a new {@link MethodWriter}.
0397:             * 
0398:             * @param cw the class writer in which the method must be added.
0399:             * @param access the method's access flags (see {@link Opcodes}).
0400:             * @param name the method's name.
0401:             * @param desc the method's descriptor (see {@link Type}).
0402:             * @param signature the method's signature. May be <tt>null</tt>.
0403:             * @param exceptions the internal names of the method's exceptions. May be
0404:             *        <tt>null</tt>.
0405:             * @param computeMaxs <tt>true</tt> if the maximum stack size and number
0406:             *        of local variables must be automatically computed.
0407:             * @param computeFrames <tt>true</tt> if the stack map tables must be
0408:             *        recomputed from scratch.
0409:             */
0410:            MethodWriter(final ClassWriter cw, final int access,
0411:                    final String name, final String desc,
0412:                    final String signature, final String[] exceptions,
0413:                    final boolean computeMaxs, final boolean computeFrames) {
0414:                if (cw.firstMethod == null) {
0415:                    cw.firstMethod = this ;
0416:                } else {
0417:                    cw.lastMethod.next = this ;
0418:                }
0419:                cw.lastMethod = this ;
0420:                this .cw = cw;
0421:                this .access = access;
0422:                this .name = cw.newUTF8(name);
0423:                this .desc = cw.newUTF8(desc);
0424:                this .descriptor = desc;
0425:                if (ClassReader.SIGNATURES) {
0426:                    this .signature = signature;
0427:                }
0428:                if (exceptions != null && exceptions.length > 0) {
0429:                    exceptionCount = exceptions.length;
0430:                    this .exceptions = new int[exceptionCount];
0431:                    for (int i = 0; i < exceptionCount; ++i) {
0432:                        this .exceptions[i] = cw.newClass(exceptions[i]);
0433:                    }
0434:                }
0435:                this .compute = computeFrames ? FRAMES : (computeMaxs ? MAXS
0436:                        : NOTHING);
0437:                if (computeMaxs || computeFrames) {
0438:                    if (computeFrames && "<init>".equals(name)) {
0439:                        this .access |= ACC_CONSTRUCTOR;
0440:                    }
0441:                    // updates maxLocals
0442:                    int size = getArgumentsAndReturnSizes(descriptor) >> 2;
0443:                    if ((access & Opcodes.ACC_STATIC) != 0) {
0444:                        --size;
0445:                    }
0446:                    maxLocals = size;
0447:                    // creates and visits the label for the first basic block
0448:                    labels = new Label();
0449:                    labels.status |= Label.PUSHED;
0450:                    visitLabel(labels);
0451:                }
0452:            }
0453:
0454:            // ------------------------------------------------------------------------
0455:            // Implementation of the MethodVisitor interface
0456:            // ------------------------------------------------------------------------
0457:
0458:            public AnnotationVisitor visitAnnotationDefault() {
0459:                if (!ClassReader.ANNOTATIONS) {
0460:                    return null;
0461:                }
0462:                annd = new ByteVector();
0463:                return new AnnotationWriter(cw, false, annd, null, 0);
0464:            }
0465:
0466:            public AnnotationVisitor visitAnnotation(final String desc,
0467:                    final boolean visible) {
0468:                if (!ClassReader.ANNOTATIONS) {
0469:                    return null;
0470:                }
0471:                ByteVector bv = new ByteVector();
0472:                // write type, and reserve space for values count
0473:                bv.putShort(cw.newUTF8(desc)).putShort(0);
0474:                AnnotationWriter aw = new AnnotationWriter(cw, true, bv, bv, 2);
0475:                if (visible) {
0476:                    aw.next = anns;
0477:                    anns = aw;
0478:                } else {
0479:                    aw.next = ianns;
0480:                    ianns = aw;
0481:                }
0482:                return aw;
0483:            }
0484:
0485:            public AnnotationVisitor visitParameterAnnotation(
0486:                    final int parameter, final String desc,
0487:                    final boolean visible) {
0488:                if (!ClassReader.ANNOTATIONS) {
0489:                    return null;
0490:                }
0491:                ByteVector bv = new ByteVector();
0492:                if ("Ljava/lang/Synthetic;".equals(desc)) {
0493:                    // workaround for a bug in javac with synthetic parameters
0494:                    // see ClassReader.readParameterAnnotations
0495:                    synthetics = Math.max(synthetics, parameter + 1);
0496:                    return new AnnotationWriter(cw, false, bv, null, 0);
0497:                }
0498:                // write type, and reserve space for values count
0499:                bv.putShort(cw.newUTF8(desc)).putShort(0);
0500:                AnnotationWriter aw = new AnnotationWriter(cw, true, bv, bv, 2);
0501:                if (visible) {
0502:                    if (panns == null) {
0503:                        panns = new AnnotationWriter[Type
0504:                                .getArgumentTypes(descriptor).length];
0505:                    }
0506:                    aw.next = panns[parameter];
0507:                    panns[parameter] = aw;
0508:                } else {
0509:                    if (ipanns == null) {
0510:                        ipanns = new AnnotationWriter[Type
0511:                                .getArgumentTypes(descriptor).length];
0512:                    }
0513:                    aw.next = ipanns[parameter];
0514:                    ipanns[parameter] = aw;
0515:                }
0516:                return aw;
0517:            }
0518:
0519:            public void visitAttribute(final Attribute attr) {
0520:                if (attr.isCodeAttribute()) {
0521:                    attr.next = cattrs;
0522:                    cattrs = attr;
0523:                } else {
0524:                    attr.next = attrs;
0525:                    attrs = attr;
0526:                }
0527:            }
0528:
0529:            public void visitCode() {
0530:            }
0531:
0532:            public void visitFrame(final int type, final int nLocal,
0533:                    final Object[] local, final int nStack, final Object[] stack) {
0534:                if (!ClassReader.FRAMES || compute == FRAMES) {
0535:                    return;
0536:                }
0537:
0538:                if (type == Opcodes.F_NEW) {
0539:                    startFrame(code.length, nLocal, nStack);
0540:                    for (int i = 0; i < nLocal; ++i) {
0541:                        if (local[i] instanceof  String) {
0542:                            frame[frameIndex++] = Frame.OBJECT
0543:                                    | cw.addType((String) local[i]);
0544:                        } else if (local[i] instanceof  Integer) {
0545:                            frame[frameIndex++] = ((Integer) local[i])
0546:                                    .intValue();
0547:                        } else {
0548:                            frame[frameIndex++] = Frame.UNINITIALIZED
0549:                                    | cw.addUninitializedType("",
0550:                                            ((Label) local[i]).position);
0551:                        }
0552:                    }
0553:                    for (int i = 0; i < nStack; ++i) {
0554:                        if (stack[i] instanceof  String) {
0555:                            frame[frameIndex++] = Frame.OBJECT
0556:                                    | cw.addType((String) stack[i]);
0557:                        } else if (stack[i] instanceof  Integer) {
0558:                            frame[frameIndex++] = ((Integer) stack[i])
0559:                                    .intValue();
0560:                        } else {
0561:                            frame[frameIndex++] = Frame.UNINITIALIZED
0562:                                    | cw.addUninitializedType("",
0563:                                            ((Label) stack[i]).position);
0564:                        }
0565:                    }
0566:                    endFrame();
0567:                } else {
0568:                    int delta;
0569:                    if (stackMap == null) {
0570:                        stackMap = new ByteVector();
0571:                        delta = code.length;
0572:                    } else {
0573:                        delta = code.length - previousFrameOffset - 1;
0574:                    }
0575:
0576:                    switch (type) {
0577:                    case Opcodes.F_FULL:
0578:                        stackMap.putByte(FULL_FRAME).putShort(delta).putShort(
0579:                                nLocal);
0580:                        for (int i = 0; i < nLocal; ++i) {
0581:                            writeFrameType(local[i]);
0582:                        }
0583:                        stackMap.putShort(nStack);
0584:                        for (int i = 0; i < nStack; ++i) {
0585:                            writeFrameType(stack[i]);
0586:                        }
0587:                        break;
0588:                    case Opcodes.F_APPEND:
0589:                        stackMap.putByte(SAME_FRAME_EXTENDED + nLocal)
0590:                                .putShort(delta);
0591:                        for (int i = 0; i < nLocal; ++i) {
0592:                            writeFrameType(local[i]);
0593:                        }
0594:                        break;
0595:                    case Opcodes.F_CHOP:
0596:                        stackMap.putByte(SAME_FRAME_EXTENDED - nLocal)
0597:                                .putShort(delta);
0598:                        break;
0599:                    case Opcodes.F_SAME:
0600:                        if (delta < 64) {
0601:                            stackMap.putByte(delta);
0602:                        } else {
0603:                            stackMap.putByte(SAME_FRAME_EXTENDED).putShort(
0604:                                    delta);
0605:                        }
0606:                        break;
0607:                    case Opcodes.F_SAME1:
0608:                        if (delta < 64) {
0609:                            stackMap.putByte(SAME_LOCALS_1_STACK_ITEM_FRAME
0610:                                    + delta);
0611:                        } else {
0612:                            stackMap.putByte(
0613:                                    SAME_LOCALS_1_STACK_ITEM_FRAME_EXTENDED)
0614:                                    .putShort(delta);
0615:                        }
0616:                        writeFrameType(stack[0]);
0617:                        break;
0618:                    }
0619:
0620:                    previousFrameOffset = code.length;
0621:                    ++frameCount;
0622:                }
0623:            }
0624:
0625:            public void visitInsn(final int opcode) {
0626:                // adds the instruction to the bytecode of the method
0627:                code.putByte(opcode);
0628:                // update currentBlock
0629:                // Label currentBlock = this.currentBlock;
0630:                if (currentBlock != null) {
0631:                    if (compute == FRAMES) {
0632:                        currentBlock.frame.execute(opcode, 0, null, null);
0633:                    } else {
0634:                        // updates current and max stack sizes
0635:                        int size = stackSize + Frame.SIZE[opcode];
0636:                        if (size > maxStackSize) {
0637:                            maxStackSize = size;
0638:                        }
0639:                        stackSize = size;
0640:                    }
0641:                    // if opcode == ATHROW or xRETURN, ends current block (no successor)
0642:                    if ((opcode >= Opcodes.IRETURN && opcode <= Opcodes.RETURN)
0643:                            || opcode == Opcodes.ATHROW) {
0644:                        noSuccessor();
0645:                    }
0646:                }
0647:            }
0648:
0649:            public void visitIntInsn(final int opcode, final int operand) {
0650:                // Label currentBlock = this.currentBlock;
0651:                if (currentBlock != null) {
0652:                    if (compute == FRAMES) {
0653:                        currentBlock.frame.execute(opcode, operand, null, null);
0654:                    } else if (opcode != Opcodes.NEWARRAY) {
0655:                        // updates current and max stack sizes only for NEWARRAY
0656:                        // (stack size variation = 0 for BIPUSH or SIPUSH)
0657:                        int size = stackSize + 1;
0658:                        if (size > maxStackSize) {
0659:                            maxStackSize = size;
0660:                        }
0661:                        stackSize = size;
0662:                    }
0663:                }
0664:                // adds the instruction to the bytecode of the method
0665:                if (opcode == Opcodes.SIPUSH) {
0666:                    code.put12(opcode, operand);
0667:                } else { // BIPUSH or NEWARRAY
0668:                    code.put11(opcode, operand);
0669:                }
0670:            }
0671:
0672:            public void visitVarInsn(final int opcode, final int var) {
0673:                // Label currentBlock = this.currentBlock;
0674:                if (currentBlock != null) {
0675:                    if (compute == FRAMES) {
0676:                        currentBlock.frame.execute(opcode, var, null, null);
0677:                    } else {
0678:                        // updates current and max stack sizes
0679:                        if (opcode == Opcodes.RET) {
0680:                            // no stack change, but end of current block (no successor)
0681:                            currentBlock.status |= Label.RET;
0682:                            // save 'stackSize' here for future use
0683:                            // (see {@link #findSubroutineSuccessors})
0684:                            currentBlock.inputStackTop = stackSize;
0685:                            noSuccessor();
0686:                        } else { // xLOAD or xSTORE
0687:                            int size = stackSize + Frame.SIZE[opcode];
0688:                            if (size > maxStackSize) {
0689:                                maxStackSize = size;
0690:                            }
0691:                            stackSize = size;
0692:                        }
0693:                    }
0694:                }
0695:                if (compute != NOTHING) {
0696:                    // updates max locals
0697:                    int n;
0698:                    if (opcode == Opcodes.LLOAD || opcode == Opcodes.DLOAD
0699:                            || opcode == Opcodes.LSTORE
0700:                            || opcode == Opcodes.DSTORE) {
0701:                        n = var + 2;
0702:                    } else {
0703:                        n = var + 1;
0704:                    }
0705:                    if (n > maxLocals) {
0706:                        maxLocals = n;
0707:                    }
0708:                }
0709:                // adds the instruction to the bytecode of the method
0710:                if (var < 4 && opcode != Opcodes.RET) {
0711:                    int opt;
0712:                    if (opcode < Opcodes.ISTORE) {
0713:                        /* ILOAD_0 */
0714:                        opt = 26 + ((opcode - Opcodes.ILOAD) << 2) + var;
0715:                    } else {
0716:                        /* ISTORE_0 */
0717:                        opt = 59 + ((opcode - Opcodes.ISTORE) << 2) + var;
0718:                    }
0719:                    code.putByte(opt);
0720:                } else if (var >= 256) {
0721:                    code.putByte(196 /* WIDE */).put12(opcode, var);
0722:                } else {
0723:                    code.put11(opcode, var);
0724:                }
0725:                if (opcode >= Opcodes.ISTORE && compute == FRAMES
0726:                        && handlerCount > 0) {
0727:                    visitLabel(new Label());
0728:                }
0729:            }
0730:
0731:            public void visitTypeInsn(final int opcode, final String type) {
0732:                Item i = cw.newClassItem(type);
0733:                // Label currentBlock = this.currentBlock;
0734:                if (currentBlock != null) {
0735:                    if (compute == FRAMES) {
0736:                        currentBlock.frame.execute(opcode, code.length, cw, i);
0737:                    } else if (opcode == Opcodes.NEW) {
0738:                        // updates current and max stack sizes only if opcode == NEW
0739:                        // (no stack change for ANEWARRAY, CHECKCAST, INSTANCEOF)
0740:                        int size = stackSize + 1;
0741:                        if (size > maxStackSize) {
0742:                            maxStackSize = size;
0743:                        }
0744:                        stackSize = size;
0745:                    }
0746:                }
0747:                // adds the instruction to the bytecode of the method
0748:                code.put12(opcode, i.index);
0749:            }
0750:
0751:            public void visitFieldInsn(final int opcode, final String owner,
0752:                    final String name, final String desc) {
0753:                Item i = cw.newFieldItem(owner, name, desc);
0754:                // Label currentBlock = this.currentBlock;
0755:                if (currentBlock != null) {
0756:                    if (compute == FRAMES) {
0757:                        currentBlock.frame.execute(opcode, 0, cw, i);
0758:                    } else {
0759:                        int size;
0760:                        // computes the stack size variation
0761:                        char c = desc.charAt(0);
0762:                        switch (opcode) {
0763:                        case Opcodes.GETSTATIC:
0764:                            size = stackSize + (c == 'D' || c == 'J' ? 2 : 1);
0765:                            break;
0766:                        case Opcodes.PUTSTATIC:
0767:                            size = stackSize + (c == 'D' || c == 'J' ? -2 : -1);
0768:                            break;
0769:                        case Opcodes.GETFIELD:
0770:                            size = stackSize + (c == 'D' || c == 'J' ? 1 : 0);
0771:                            break;
0772:                        // case Constants.PUTFIELD:
0773:                        default:
0774:                            size = stackSize + (c == 'D' || c == 'J' ? -3 : -2);
0775:                            break;
0776:                        }
0777:                        // updates current and max stack sizes
0778:                        if (size > maxStackSize) {
0779:                            maxStackSize = size;
0780:                        }
0781:                        stackSize = size;
0782:                    }
0783:                }
0784:                // adds the instruction to the bytecode of the method
0785:                code.put12(opcode, i.index);
0786:            }
0787:
0788:            public void visitMethodInsn(final int opcode, final String owner,
0789:                    final String name, final String desc) {
0790:                boolean itf = opcode == Opcodes.INVOKEINTERFACE;
0791:                Item i = cw.newMethodItem(owner, name, desc, itf);
0792:                int argSize = i.intVal;
0793:                // Label currentBlock = this.currentBlock;
0794:                if (currentBlock != null) {
0795:                    if (compute == FRAMES) {
0796:                        currentBlock.frame.execute(opcode, 0, cw, i);
0797:                    } else {
0798:                        /*
0799:                         * computes the stack size variation. In order not to recompute
0800:                         * several times this variation for the same Item, we use the
0801:                         * intVal field of this item to store this variation, once it
0802:                         * has been computed. More precisely this intVal field stores
0803:                         * the sizes of the arguments and of the return value
0804:                         * corresponding to desc.
0805:                         */
0806:                        if (argSize == 0) {
0807:                            // the above sizes have not been computed yet,
0808:                            // so we compute them...
0809:                            argSize = getArgumentsAndReturnSizes(desc);
0810:                            // ... and we save them in order
0811:                            // not to recompute them in the future
0812:                            i.intVal = argSize;
0813:                        }
0814:                        int size;
0815:                        if (opcode == Opcodes.INVOKESTATIC) {
0816:                            size = stackSize - (argSize >> 2)
0817:                                    + (argSize & 0x03) + 1;
0818:                        } else {
0819:                            size = stackSize - (argSize >> 2)
0820:                                    + (argSize & 0x03);
0821:                        }
0822:                        // updates current and max stack sizes
0823:                        if (size > maxStackSize) {
0824:                            maxStackSize = size;
0825:                        }
0826:                        stackSize = size;
0827:                    }
0828:                }
0829:                // adds the instruction to the bytecode of the method
0830:                if (itf) {
0831:                    if (argSize == 0) {
0832:                        argSize = getArgumentsAndReturnSizes(desc);
0833:                        i.intVal = argSize;
0834:                    }
0835:                    code.put12(Opcodes.INVOKEINTERFACE, i.index).put11(
0836:                            argSize >> 2, 0);
0837:                } else {
0838:                    code.put12(opcode, i.index);
0839:                }
0840:            }
0841:
0842:            public void visitJumpInsn(final int opcode, final Label label) {
0843:                Label nextInsn = null;
0844:                // Label currentBlock = this.currentBlock;
0845:                if (currentBlock != null) {
0846:                    if (compute == FRAMES) {
0847:                        currentBlock.frame.execute(opcode, 0, null, null);
0848:                        // 'label' is the target of a jump instruction
0849:                        label.getFirst().status |= Label.TARGET;
0850:                        // adds 'label' as a successor of this basic block
0851:                        addSuccessor(Edge.NORMAL, label);
0852:                        if (opcode != Opcodes.GOTO) {
0853:                            // creates a Label for the next basic block
0854:                            nextInsn = new Label();
0855:                        }
0856:                    } else {
0857:                        if (opcode == Opcodes.JSR) {
0858:                            if ((label.status & Label.SUBROUTINE) == 0) {
0859:                                label.status |= Label.SUBROUTINE;
0860:                                ++subroutines;
0861:                            }
0862:                            currentBlock.status |= Label.JSR;
0863:                            addSuccessor(stackSize + 1, label);
0864:                            // creates a Label for the next basic block
0865:                            nextInsn = new Label();
0866:                            /*
0867:                             * note that, by construction in this method, a JSR block
0868:                             * has at least two successors in the control flow graph:
0869:                             * the first one leads the next instruction after the JSR,
0870:                             * while the second one leads to the JSR target.
0871:                             */
0872:                        } else {
0873:                            // updates current stack size (max stack size unchanged
0874:                            // because stack size variation always negative in this
0875:                            // case)
0876:                            stackSize += Frame.SIZE[opcode];
0877:                            addSuccessor(stackSize, label);
0878:                        }
0879:                    }
0880:                }
0881:                // adds the instruction to the bytecode of the method
0882:                if ((label.status & Label.RESOLVED) != 0
0883:                        && label.position - code.length < Short.MIN_VALUE) {
0884:                    /*
0885:                     * case of a backward jump with an offset < -32768. In this case we
0886:                     * automatically replace GOTO with GOTO_W, JSR with JSR_W and IFxxx
0887:                     * <l> with IFNOTxxx <l'> GOTO_W <l>, where IFNOTxxx is the
0888:                     * "opposite" opcode of IFxxx (i.e., IFNE for IFEQ) and where <l'>
0889:                     * designates the instruction just after the GOTO_W.
0890:                     */
0891:                    if (opcode == Opcodes.GOTO) {
0892:                        code.putByte(200); // GOTO_W
0893:                    } else if (opcode == Opcodes.JSR) {
0894:                        code.putByte(201); // JSR_W
0895:                    } else {
0896:                        // if the IF instruction is transformed into IFNOT GOTO_W the
0897:                        // next instruction becomes the target of the IFNOT instruction
0898:                        if (nextInsn != null) {
0899:                            nextInsn.status |= Label.TARGET;
0900:                        }
0901:                        code.putByte(opcode <= 166 ? ((opcode + 1) ^ 1) - 1
0902:                                : opcode ^ 1);
0903:                        code.putShort(8); // jump offset
0904:                        code.putByte(200); // GOTO_W
0905:                    }
0906:                    label.put(this , code, code.length - 1, true);
0907:                } else {
0908:                    /*
0909:                     * case of a backward jump with an offset >= -32768, or of a forward
0910:                     * jump with, of course, an unknown offset. In these cases we store
0911:                     * the offset in 2 bytes (which will be increased in
0912:                     * resizeInstructions, if needed).
0913:                     */
0914:                    code.putByte(opcode);
0915:                    label.put(this , code, code.length - 1, false);
0916:                }
0917:                if (currentBlock != null) {
0918:                    if (nextInsn != null) {
0919:                        // if the jump instruction is not a GOTO, the next instruction
0920:                        // is also a successor of this instruction. Calling visitLabel
0921:                        // adds the label of this next instruction as a successor of the
0922:                        // current block, and starts a new basic block
0923:                        visitLabel(nextInsn);
0924:                    }
0925:                    if (opcode == Opcodes.GOTO) {
0926:                        noSuccessor();
0927:                    }
0928:                }
0929:            }
0930:
0931:            public void visitLabel(final Label label) {
0932:                // resolves previous forward references to label, if any
0933:                resize |= label.resolve(this , code.length, code.data);
0934:                // updates currentBlock
0935:                if ((label.status & Label.DEBUG) != 0) {
0936:                    return;
0937:                }
0938:                if (compute == FRAMES) {
0939:                    if (currentBlock != null) {
0940:                        if (label.position == currentBlock.position) {
0941:                            // successive labels, do not start a new basic block
0942:                            currentBlock.status |= (label.status & Label.TARGET);
0943:                            label.frame = currentBlock.frame;
0944:                            return;
0945:                        }
0946:                        // ends current block (with one new successor)
0947:                        addSuccessor(Edge.NORMAL, label);
0948:                    }
0949:                    // begins a new current block
0950:                    currentBlock = label;
0951:                    if (label.frame == null) {
0952:                        label.frame = new Frame();
0953:                        label.frame.owner = label;
0954:                    }
0955:                    // updates the basic block list
0956:                    if (previousBlock != null) {
0957:                        if (label.position == previousBlock.position) {
0958:                            previousBlock.status |= (label.status & Label.TARGET);
0959:                            label.frame = previousBlock.frame;
0960:                            currentBlock = previousBlock;
0961:                            return;
0962:                        }
0963:                        previousBlock.successor = label;
0964:                    }
0965:                    previousBlock = label;
0966:                } else if (compute == MAXS) {
0967:                    if (currentBlock != null) {
0968:                        // ends current block (with one new successor)
0969:                        currentBlock.outputStackMax = maxStackSize;
0970:                        addSuccessor(stackSize, label);
0971:                    }
0972:                    // begins a new current block
0973:                    currentBlock = label;
0974:                    // resets the relative current and max stack sizes
0975:                    stackSize = 0;
0976:                    maxStackSize = 0;
0977:                    // updates the basic block list
0978:                    if (previousBlock != null) {
0979:                        previousBlock.successor = label;
0980:                    }
0981:                    previousBlock = label;
0982:                }
0983:            }
0984:
0985:            public void visitLdcInsn(final Object cst) {
0986:                Item i = cw.newConstItem(cst);
0987:                // Label currentBlock = this.currentBlock;
0988:                if (currentBlock != null) {
0989:                    if (compute == FRAMES) {
0990:                        currentBlock.frame.execute(Opcodes.LDC, 0, cw, i);
0991:                    } else {
0992:                        int size;
0993:                        // computes the stack size variation
0994:                        if (i.type == ClassWriter.LONG
0995:                                || i.type == ClassWriter.DOUBLE) {
0996:                            size = stackSize + 2;
0997:                        } else {
0998:                            size = stackSize + 1;
0999:                        }
1000:                        // updates current and max stack sizes
1001:                        if (size > maxStackSize) {
1002:                            maxStackSize = size;
1003:                        }
1004:                        stackSize = size;
1005:                    }
1006:                }
1007:                // adds the instruction to the bytecode of the method
1008:                int index = i.index;
1009:                if (i.type == ClassWriter.LONG || i.type == ClassWriter.DOUBLE) {
1010:                    code.put12(20 /* LDC2_W */, index);
1011:                } else if (index >= 256) {
1012:                    code.put12(19 /* LDC_W */, index);
1013:                } else {
1014:                    code.put11(Opcodes.LDC, index);
1015:                }
1016:            }
1017:
1018:            public void visitIincInsn(final int var, final int increment) {
1019:                if (currentBlock != null) {
1020:                    if (compute == FRAMES) {
1021:                        currentBlock.frame.execute(Opcodes.IINC, var, null,
1022:                                null);
1023:                    }
1024:                }
1025:                if (compute != NOTHING) {
1026:                    // updates max locals
1027:                    int n = var + 1;
1028:                    if (n > maxLocals) {
1029:                        maxLocals = n;
1030:                    }
1031:                }
1032:                // adds the instruction to the bytecode of the method
1033:                if ((var > 255) || (increment > 127) || (increment < -128)) {
1034:                    code.putByte(196 /* WIDE */).put12(Opcodes.IINC, var)
1035:                            .putShort(increment);
1036:                } else {
1037:                    code.putByte(Opcodes.IINC).put11(var, increment);
1038:                }
1039:            }
1040:
1041:            public void visitTableSwitchInsn(final int min, final int max,
1042:                    final Label dflt, final Label[] labels) {
1043:                // adds the instruction to the bytecode of the method
1044:                int source = code.length;
1045:                code.putByte(Opcodes.TABLESWITCH);
1046:                code.length += (4 - code.length % 4) % 4;
1047:                dflt.put(this , code, source, true);
1048:                code.putInt(min).putInt(max);
1049:                for (int i = 0; i < labels.length; ++i) {
1050:                    labels[i].put(this , code, source, true);
1051:                }
1052:                // updates currentBlock
1053:                visitSwitchInsn(dflt, labels);
1054:            }
1055:
1056:            public void visitLookupSwitchInsn(final Label dflt,
1057:                    final int[] keys, final Label[] labels) {
1058:                // adds the instruction to the bytecode of the method
1059:                int source = code.length;
1060:                code.putByte(Opcodes.LOOKUPSWITCH);
1061:                code.length += (4 - code.length % 4) % 4;
1062:                dflt.put(this , code, source, true);
1063:                code.putInt(labels.length);
1064:                for (int i = 0; i < labels.length; ++i) {
1065:                    code.putInt(keys[i]);
1066:                    labels[i].put(this , code, source, true);
1067:                }
1068:                // updates currentBlock
1069:                visitSwitchInsn(dflt, labels);
1070:            }
1071:
1072:            private void visitSwitchInsn(final Label dflt, final Label[] labels) {
1073:                // Label currentBlock = this.currentBlock;
1074:                if (currentBlock != null) {
1075:                    if (compute == FRAMES) {
1076:                        currentBlock.frame.execute(Opcodes.LOOKUPSWITCH, 0,
1077:                                null, null);
1078:                        // adds current block successors
1079:                        addSuccessor(Edge.NORMAL, dflt);
1080:                        dflt.getFirst().status |= Label.TARGET;
1081:                        for (int i = 0; i < labels.length; ++i) {
1082:                            addSuccessor(Edge.NORMAL, labels[i]);
1083:                            labels[i].getFirst().status |= Label.TARGET;
1084:                        }
1085:                    } else {
1086:                        // updates current stack size (max stack size unchanged)
1087:                        --stackSize;
1088:                        // adds current block successors
1089:                        addSuccessor(stackSize, dflt);
1090:                        for (int i = 0; i < labels.length; ++i) {
1091:                            addSuccessor(stackSize, labels[i]);
1092:                        }
1093:                    }
1094:                    // ends current block
1095:                    noSuccessor();
1096:                }
1097:            }
1098:
1099:            public void visitMultiANewArrayInsn(final String desc,
1100:                    final int dims) {
1101:                Item i = cw.newClassItem(desc);
1102:                // Label currentBlock = this.currentBlock;
1103:                if (currentBlock != null) {
1104:                    if (compute == FRAMES) {
1105:                        currentBlock.frame.execute(Opcodes.MULTIANEWARRAY,
1106:                                dims, cw, i);
1107:                    } else {
1108:                        // updates current stack size (max stack size unchanged because
1109:                        // stack size variation always negative or null)
1110:                        stackSize += 1 - dims;
1111:                    }
1112:                }
1113:                // adds the instruction to the bytecode of the method
1114:                code.put12(Opcodes.MULTIANEWARRAY, i.index).putByte(dims);
1115:            }
1116:
1117:            public void visitTryCatchBlock(final Label start, final Label end,
1118:                    final Label handler, final String type) {
1119:                ++handlerCount;
1120:                Handler h = new Handler();
1121:                h.start = start;
1122:                h.end = end;
1123:                h.handler = handler;
1124:                h.desc = type;
1125:                h.type = type != null ? cw.newClass(type) : 0;
1126:                if (lastHandler == null) {
1127:                    firstHandler = h;
1128:                } else {
1129:                    lastHandler.next = h;
1130:                }
1131:                lastHandler = h;
1132:            }
1133:
1134:            public void visitLocalVariable(final String name,
1135:                    final String desc, final String signature,
1136:                    final Label start, final Label end, final int index) {
1137:                if (signature != null) {
1138:                    if (localVarType == null) {
1139:                        localVarType = new ByteVector();
1140:                    }
1141:                    ++localVarTypeCount;
1142:                    localVarType.putShort(start.position).putShort(
1143:                            end.position - start.position).putShort(
1144:                            cw.newUTF8(name)).putShort(cw.newUTF8(signature))
1145:                            .putShort(index);
1146:                }
1147:                if (localVar == null) {
1148:                    localVar = new ByteVector();
1149:                }
1150:                ++localVarCount;
1151:                localVar.putShort(start.position).putShort(
1152:                        end.position - start.position).putShort(
1153:                        cw.newUTF8(name)).putShort(cw.newUTF8(desc)).putShort(
1154:                        index);
1155:                if (compute != NOTHING) {
1156:                    // updates max locals
1157:                    char c = desc.charAt(0);
1158:                    int n = index + (c == 'J' || c == 'D' ? 2 : 1);
1159:                    if (n > maxLocals) {
1160:                        maxLocals = n;
1161:                    }
1162:                }
1163:            }
1164:
1165:            public void visitLineNumber(final int line, final Label start) {
1166:                if (lineNumber == null) {
1167:                    lineNumber = new ByteVector();
1168:                }
1169:                ++lineNumberCount;
1170:                lineNumber.putShort(start.position);
1171:                lineNumber.putShort(line);
1172:            }
1173:
1174:            public void visitMaxs(final int maxStack, final int maxLocals) {
1175:                if (ClassReader.FRAMES && compute == FRAMES) {
1176:                    // completes the control flow graph with exception handler blocks
1177:                    Handler handler = firstHandler;
1178:                    while (handler != null) {
1179:                        Label l = handler.start.getFirst();
1180:                        Label h = handler.handler.getFirst();
1181:                        Label e = handler.end.getFirst();
1182:                        // computes the kind of the edges to 'h'
1183:                        String t = handler.desc == null ? "java/lang/Throwable"
1184:                                : handler.desc;
1185:                        int kind = Frame.OBJECT | cw.addType(t);
1186:                        // h is an exception handler
1187:                        h.status |= Label.TARGET;
1188:                        // adds 'h' as a successor of labels between 'start' and 'end'
1189:                        while (l != e) {
1190:                            // creates an edge to 'h'
1191:                            Edge b = new Edge();
1192:                            b.info = kind;
1193:                            b.successor = h;
1194:                            // adds it to the successors of 'l'
1195:                            b.next = l.successors;
1196:                            l.successors = b;
1197:                            // goes to the next label
1198:                            l = l.successor;
1199:                        }
1200:                        handler = handler.next;
1201:                    }
1202:
1203:                    // creates and visits the first (implicit) frame
1204:                    Frame f = labels.frame;
1205:                    Type[] args = Type.getArgumentTypes(descriptor);
1206:                    f.initInputFrame(cw, access, args, this .maxLocals);
1207:                    visitFrame(f);
1208:
1209:                    /*
1210:                     * fix point algorithm: mark the first basic block as 'changed'
1211:                     * (i.e. put it in the 'changed' list) and, while there are changed
1212:                     * basic blocks, choose one, mark it as unchanged, and update its
1213:                     * successors (which can be changed in the process).
1214:                     */
1215:                    int max = 0;
1216:                    Label changed = labels;
1217:                    while (changed != null) {
1218:                        // removes a basic block from the list of changed basic blocks
1219:                        Label l = changed;
1220:                        changed = changed.next;
1221:                        l.next = null;
1222:                        f = l.frame;
1223:                        // a reachable jump target must be stored in the stack map
1224:                        if ((l.status & Label.TARGET) != 0) {
1225:                            l.status |= Label.STORE;
1226:                        }
1227:                        // all visited labels are reachable, by definition
1228:                        l.status |= Label.REACHABLE;
1229:                        // updates the (absolute) maximum stack size
1230:                        int blockMax = f.inputStack.length + l.outputStackMax;
1231:                        if (blockMax > max) {
1232:                            max = blockMax;
1233:                        }
1234:                        // updates the successors of the current basic block
1235:                        Edge e = l.successors;
1236:                        while (e != null) {
1237:                            Label n = e.successor.getFirst();
1238:                            boolean change = f.merge(cw, n.frame, e.info);
1239:                            if (change && n.next == null) {
1240:                                // if n has changed and is not already in the 'changed'
1241:                                // list, adds it to this list
1242:                                n.next = changed;
1243:                                changed = n;
1244:                            }
1245:                            e = e.next;
1246:                        }
1247:                    }
1248:                    this .maxStack = max;
1249:
1250:                    // visits all the frames that must be stored in the stack map
1251:                    Label l = labels;
1252:                    while (l != null) {
1253:                        f = l.frame;
1254:                        if ((l.status & Label.STORE) != 0) {
1255:                            visitFrame(f);
1256:                        }
1257:                        if ((l.status & Label.REACHABLE) == 0) {
1258:                            // finds start and end of dead basic block
1259:                            Label k = l.successor;
1260:                            int start = l.position;
1261:                            int end = (k == null ? code.length : k.position) - 1;
1262:                            // if non empty basic block
1263:                            if (end >= start) {
1264:                                // replaces instructions with NOP ... NOP ATHROW
1265:                                for (int i = start; i < end; ++i) {
1266:                                    code.data[i] = Opcodes.NOP;
1267:                                }
1268:                                code.data[end] = (byte) Opcodes.ATHROW;
1269:                                // emits a frame for this unreachable block
1270:                                startFrame(start, 0, 1);
1271:                                frame[frameIndex++] = Frame.OBJECT
1272:                                        | cw.addType("java/lang/Throwable");
1273:                                endFrame();
1274:                            }
1275:                        }
1276:                        l = l.successor;
1277:                    }
1278:                } else if (compute == MAXS) {
1279:                    // completes the control flow graph with exception handler blocks
1280:                    Handler handler = firstHandler;
1281:                    while (handler != null) {
1282:                        Label l = handler.start;
1283:                        Label h = handler.handler;
1284:                        Label e = handler.end;
1285:                        // adds 'h' as a successor of labels between 'start' and 'end'
1286:                        while (l != e) {
1287:                            // creates an edge to 'h'
1288:                            Edge b = new Edge();
1289:                            b.info = Edge.EXCEPTION;
1290:                            b.successor = h;
1291:                            // adds it to the successors of 'l'
1292:                            if ((l.status & Label.JSR) == 0) {
1293:                                b.next = l.successors;
1294:                                l.successors = b;
1295:                            } else {
1296:                                // if l is a JSR block, adds b after the first two edges
1297:                                // to preserve the hypothesis about JSR block successors
1298:                                // order (see {@link #visitJumpInsn})
1299:                                b.next = l.successors.next.next;
1300:                                l.successors.next.next = b;
1301:                            }
1302:                            // goes to the next label
1303:                            l = l.successor;
1304:                        }
1305:                        handler = handler.next;
1306:                    }
1307:
1308:                    if (subroutines > 0) {
1309:                        // completes the control flow graph with the RET successors
1310:                        /*
1311:                         * first step: finds the subroutines. This step determines, for
1312:                         * each basic block, to which subroutine(s) it belongs.
1313:                         */
1314:                        // finds the basic blocks that belong to the "main" subroutine
1315:                        int id = 0;
1316:                        labels.visitSubroutine(null, 1, subroutines);
1317:                        // finds the basic blocks that belong to the real subroutines
1318:                        Label l = labels;
1319:                        while (l != null) {
1320:                            if ((l.status & Label.JSR) != 0) {
1321:                                // the subroutine is defined by l's TARGET, not by l
1322:                                Label subroutine = l.successors.next.successor;
1323:                                // if this subroutine has not been visited yet...
1324:                                if ((subroutine.status & Label.VISITED) == 0) {
1325:                                    // ...assigns it a new id and finds its basic blocks
1326:                                    id += 1;
1327:                                    subroutine.visitSubroutine(null,
1328:                                            (id / 32L) << 32
1329:                                                    | (1L << (id % 32)),
1330:                                            subroutines);
1331:                                }
1332:                            }
1333:                            l = l.successor;
1334:                        }
1335:                        // second step: finds the successors of RET blocks
1336:                        l = labels;
1337:                        while (l != null) {
1338:                            if ((l.status & Label.JSR) != 0) {
1339:                                Label L = labels;
1340:                                while (L != null) {
1341:                                    L.status &= ~Label.VISITED;
1342:                                    L = L.successor;
1343:                                }
1344:                                // the subroutine is defined by l's TARGET, not by l
1345:                                Label subroutine = l.successors.next.successor;
1346:                                subroutine.visitSubroutine(l, 0, subroutines);
1347:                            }
1348:                            l = l.successor;
1349:                        }
1350:                    }
1351:
1352:                    /*
1353:                     * control flow analysis algorithm: while the block stack is not
1354:                     * empty, pop a block from this stack, update the max stack size,
1355:                     * compute the true (non relative) begin stack size of the
1356:                     * successors of this block, and push these successors onto the
1357:                     * stack (unless they have already been pushed onto the stack).
1358:                     * Note: by hypothesis, the {@link Label#inputStackTop} of the
1359:                     * blocks in the block stack are the true (non relative) beginning
1360:                     * stack sizes of these blocks.
1361:                     */
1362:                    int max = 0;
1363:                    Label stack = labels;
1364:                    while (stack != null) {
1365:                        // pops a block from the stack
1366:                        Label l = stack;
1367:                        stack = stack.next;
1368:                        // computes the true (non relative) max stack size of this block
1369:                        int start = l.inputStackTop;
1370:                        int blockMax = start + l.outputStackMax;
1371:                        // updates the global max stack size
1372:                        if (blockMax > max) {
1373:                            max = blockMax;
1374:                        }
1375:                        // analyzes the successors of the block
1376:                        Edge b = l.successors;
1377:                        if ((l.status & Label.JSR) != 0) {
1378:                            // ignores the first edge of JSR blocks (virtual successor)
1379:                            b = b.next;
1380:                        }
1381:                        while (b != null) {
1382:                            l = b.successor;
1383:                            // if this successor has not already been pushed...
1384:                            if ((l.status & Label.PUSHED) == 0) {
1385:                                // computes its true beginning stack size...
1386:                                l.inputStackTop = b.info == Edge.EXCEPTION ? 1
1387:                                        : start + b.info;
1388:                                // ...and pushes it onto the stack
1389:                                l.status |= Label.PUSHED;
1390:                                l.next = stack;
1391:                                stack = l;
1392:                            }
1393:                            b = b.next;
1394:                        }
1395:                    }
1396:                    this .maxStack = max;
1397:                } else {
1398:                    this .maxStack = maxStack;
1399:                    this .maxLocals = maxLocals;
1400:                }
1401:            }
1402:
1403:            public void visitEnd() {
1404:            }
1405:
1406:            // ------------------------------------------------------------------------
1407:            // Utility methods: control flow analysis algorithm
1408:            // ------------------------------------------------------------------------
1409:
1410:            /**
1411:             * Computes the size of the arguments and of the return value of a method.
1412:             * 
1413:             * @param desc the descriptor of a method.
1414:             * @return the size of the arguments of the method (plus one for the
1415:             *         implicit this argument), argSize, and the size of its return
1416:             *         value, retSize, packed into a single int i =
1417:             *         <tt>(argSize << 2) | retSize</tt> (argSize is therefore equal
1418:             *         to <tt>i >> 2</tt>, and retSize to <tt>i & 0x03</tt>).
1419:             */
1420:            static int getArgumentsAndReturnSizes(final String desc) {
1421:                int n = 1;
1422:                int c = 1;
1423:                while (true) {
1424:                    char car = desc.charAt(c++);
1425:                    if (car == ')') {
1426:                        car = desc.charAt(c);
1427:                        return n << 2
1428:                                | (car == 'V' ? 0
1429:                                        : (car == 'D' || car == 'J' ? 2 : 1));
1430:                    } else if (car == 'L') {
1431:                        while (desc.charAt(c++) != ';') {
1432:                        }
1433:                        n += 1;
1434:                    } else if (car == '[') {
1435:                        while ((car = desc.charAt(c)) == '[') {
1436:                            ++c;
1437:                        }
1438:                        if (car == 'D' || car == 'J') {
1439:                            n -= 1;
1440:                        }
1441:                    } else if (car == 'D' || car == 'J') {
1442:                        n += 2;
1443:                    } else {
1444:                        n += 1;
1445:                    }
1446:                }
1447:            }
1448:
1449:            /**
1450:             * Adds a successor to the {@link #currentBlock currentBlock} block.
1451:             * 
1452:             * @param info information about the control flow edge to be added.
1453:             * @param successor the successor block to be added to the current block.
1454:             */
1455:            private void addSuccessor(final int info, final Label successor) {
1456:                // creates and initializes an Edge object...
1457:                Edge b = new Edge();
1458:                b.info = info;
1459:                b.successor = successor;
1460:                // ...and adds it to the successor list of the currentBlock block
1461:                b.next = currentBlock.successors;
1462:                currentBlock.successors = b;
1463:            }
1464:
1465:            /**
1466:             * Ends the current basic block. This method must be used in the case where
1467:             * the current basic block does not have any successor.
1468:             */
1469:            private void noSuccessor() {
1470:                if (compute == FRAMES) {
1471:                    Label l = new Label();
1472:                    l.frame = new Frame();
1473:                    l.frame.owner = l;
1474:                    l.resolve(this , code.length, code.data);
1475:                    previousBlock.successor = l;
1476:                    previousBlock = l;
1477:                } else {
1478:                    currentBlock.outputStackMax = maxStackSize;
1479:                }
1480:                currentBlock = null;
1481:            }
1482:
1483:            // ------------------------------------------------------------------------
1484:            // Utility methods: stack map frames
1485:            // ------------------------------------------------------------------------
1486:
1487:            /**
1488:             * Visits a frame that has been computed from scratch.
1489:             * 
1490:             * @param f the frame that must be visited.
1491:             */
1492:            private void visitFrame(final Frame f) {
1493:                int i, t;
1494:                int nTop = 0;
1495:                int nLocal = 0;
1496:                int nStack = 0;
1497:                int[] locals = f.inputLocals;
1498:                int[] stacks = f.inputStack;
1499:                // computes the number of locals (ignores TOP types that are just after
1500:                // a LONG or a DOUBLE, and all trailing TOP types)
1501:                for (i = 0; i < locals.length; ++i) {
1502:                    t = locals[i];
1503:                    if (t == Frame.TOP) {
1504:                        ++nTop;
1505:                    } else {
1506:                        nLocal += nTop + 1;
1507:                        nTop = 0;
1508:                    }
1509:                    if (t == Frame.LONG || t == Frame.DOUBLE) {
1510:                        ++i;
1511:                    }
1512:                }
1513:                // computes the stack size (ignores TOP types that are just after
1514:                // a LONG or a DOUBLE)
1515:                for (i = 0; i < stacks.length; ++i) {
1516:                    t = stacks[i];
1517:                    ++nStack;
1518:                    if (t == Frame.LONG || t == Frame.DOUBLE) {
1519:                        ++i;
1520:                    }
1521:                }
1522:                // visits the frame and its content
1523:                startFrame(f.owner.position, nLocal, nStack);
1524:                for (i = 0; nLocal > 0; ++i, --nLocal) {
1525:                    t = locals[i];
1526:                    frame[frameIndex++] = t;
1527:                    if (t == Frame.LONG || t == Frame.DOUBLE) {
1528:                        ++i;
1529:                    }
1530:                }
1531:                for (i = 0; i < stacks.length; ++i) {
1532:                    t = stacks[i];
1533:                    frame[frameIndex++] = t;
1534:                    if (t == Frame.LONG || t == Frame.DOUBLE) {
1535:                        ++i;
1536:                    }
1537:                }
1538:                endFrame();
1539:            }
1540:
1541:            /**
1542:             * Starts the visit of a stack map frame.
1543:             * 
1544:             * @param offset the offset of the instruction to which the frame
1545:             *        corresponds.
1546:             * @param nLocal the number of local variables in the frame.
1547:             * @param nStack the number of stack elements in the frame.
1548:             */
1549:            private void startFrame(final int offset, final int nLocal,
1550:                    final int nStack) {
1551:                int n = 3 + nLocal + nStack;
1552:                if (frame == null || frame.length < n) {
1553:                    frame = new int[n];
1554:                }
1555:                frame[0] = offset;
1556:                frame[1] = nLocal;
1557:                frame[2] = nStack;
1558:                frameIndex = 3;
1559:            }
1560:
1561:            /**
1562:             * Checks if the visit of the current frame {@link #frame} is finished, and
1563:             * if yes, write it in the StackMapTable attribute.
1564:             */
1565:            private void endFrame() {
1566:                if (previousFrame != null) { // do not write the first frame
1567:                    if (stackMap == null) {
1568:                        stackMap = new ByteVector();
1569:                    }
1570:                    writeFrame();
1571:                    ++frameCount;
1572:                }
1573:                previousFrame = frame;
1574:                frame = null;
1575:            }
1576:
1577:            /**
1578:             * Compress and writes the current frame {@link #frame} in the StackMapTable
1579:             * attribute.
1580:             */
1581:            private void writeFrame() {
1582:                int clocalsSize = frame[1];
1583:                int cstackSize = frame[2];
1584:                if ((cw.version & 0xFFFF) < Opcodes.V1_6) {
1585:                    stackMap.putShort(frame[0]).putShort(clocalsSize);
1586:                    writeFrameTypes(3, 3 + clocalsSize);
1587:                    stackMap.putShort(cstackSize);
1588:                    writeFrameTypes(3 + clocalsSize, 3 + clocalsSize
1589:                            + cstackSize);
1590:                    return;
1591:                }
1592:                int localsSize = previousFrame[1];
1593:                int type = FULL_FRAME;
1594:                int k = 0;
1595:                int delta;
1596:                if (frameCount == 0) {
1597:                    delta = frame[0];
1598:                } else {
1599:                    delta = frame[0] - previousFrame[0] - 1;
1600:                }
1601:                if (cstackSize == 0) {
1602:                    k = clocalsSize - localsSize;
1603:                    switch (k) {
1604:                    case -3:
1605:                    case -2:
1606:                    case -1:
1607:                        type = CHOP_FRAME;
1608:                        localsSize = clocalsSize;
1609:                        break;
1610:                    case 0:
1611:                        type = delta < 64 ? SAME_FRAME : SAME_FRAME_EXTENDED;
1612:                        break;
1613:                    case 1:
1614:                    case 2:
1615:                    case 3:
1616:                        type = APPEND_FRAME;
1617:                        break;
1618:                    }
1619:                } else if (clocalsSize == localsSize && cstackSize == 1) {
1620:                    type = delta < 63 ? SAME_LOCALS_1_STACK_ITEM_FRAME
1621:                            : SAME_LOCALS_1_STACK_ITEM_FRAME_EXTENDED;
1622:                }
1623:                if (type != FULL_FRAME) {
1624:                    // verify if locals are the same
1625:                    int l = 3;
1626:                    for (int j = 0; j < localsSize; j++) {
1627:                        if (frame[l] != previousFrame[l]) {
1628:                            type = FULL_FRAME;
1629:                            break;
1630:                        }
1631:                        l++;
1632:                    }
1633:                }
1634:                switch (type) {
1635:                case SAME_FRAME:
1636:                    stackMap.putByte(delta);
1637:                    break;
1638:                case SAME_LOCALS_1_STACK_ITEM_FRAME:
1639:                    stackMap.putByte(SAME_LOCALS_1_STACK_ITEM_FRAME + delta);
1640:                    writeFrameTypes(3 + clocalsSize, 4 + clocalsSize);
1641:                    break;
1642:                case SAME_LOCALS_1_STACK_ITEM_FRAME_EXTENDED:
1643:                    stackMap.putByte(SAME_LOCALS_1_STACK_ITEM_FRAME_EXTENDED)
1644:                            .putShort(delta);
1645:                    writeFrameTypes(3 + clocalsSize, 4 + clocalsSize);
1646:                    break;
1647:                case SAME_FRAME_EXTENDED:
1648:                    stackMap.putByte(SAME_FRAME_EXTENDED).putShort(delta);
1649:                    break;
1650:                case CHOP_FRAME:
1651:                    stackMap.putByte(SAME_FRAME_EXTENDED + k).putShort(delta);
1652:                    break;
1653:                case APPEND_FRAME:
1654:                    stackMap.putByte(SAME_FRAME_EXTENDED + k).putShort(delta);
1655:                    writeFrameTypes(3 + localsSize, 3 + clocalsSize);
1656:                    break;
1657:                // case FULL_FRAME:
1658:                default:
1659:                    stackMap.putByte(FULL_FRAME).putShort(delta).putShort(
1660:                            clocalsSize);
1661:                    writeFrameTypes(3, 3 + clocalsSize);
1662:                    stackMap.putShort(cstackSize);
1663:                    writeFrameTypes(3 + clocalsSize, 3 + clocalsSize
1664:                            + cstackSize);
1665:                }
1666:            }
1667:
1668:            /**
1669:             * Writes some types of the current frame {@link #frame} into the
1670:             * StackMapTableAttribute. This method converts types from the format used
1671:             * in {@link Label} to the format used in StackMapTable attributes. In
1672:             * particular, it converts type table indexes to constant pool indexes.
1673:             * 
1674:             * @param start index of the first type in {@link #frame} to write.
1675:             * @param end index of last type in {@link #frame} to write (exclusive).
1676:             */
1677:            private void writeFrameTypes(final int start, final int end) {
1678:                for (int i = start; i < end; ++i) {
1679:                    int t = frame[i];
1680:                    int d = t & Frame.DIM;
1681:                    if (d == 0) {
1682:                        int v = t & Frame.BASE_VALUE;
1683:                        switch (t & Frame.BASE_KIND) {
1684:                        case Frame.OBJECT:
1685:                            stackMap.putByte(7).putShort(
1686:                                    cw.newClass(cw.typeTable[v].strVal1));
1687:                            break;
1688:                        case Frame.UNINITIALIZED:
1689:                            stackMap.putByte(8)
1690:                                    .putShort(cw.typeTable[v].intVal);
1691:                            break;
1692:                        default:
1693:                            stackMap.putByte(v);
1694:                        }
1695:                    } else {
1696:                        StringBuffer buf = new StringBuffer();
1697:                        d >>= 28;
1698:                        while (d-- > 0) {
1699:                            buf.append('[');
1700:                        }
1701:                        if ((t & Frame.BASE_KIND) == Frame.OBJECT) {
1702:                            buf.append('L');
1703:                            buf
1704:                                    .append(cw.typeTable[t & Frame.BASE_VALUE].strVal1);
1705:                            buf.append(';');
1706:                        } else {
1707:                            switch (t & 0xF) {
1708:                            case 1:
1709:                                buf.append('I');
1710:                                break;
1711:                            case 2:
1712:                                buf.append('F');
1713:                                break;
1714:                            case 3:
1715:                                buf.append('D');
1716:                                break;
1717:                            case 9:
1718:                                buf.append('Z');
1719:                                break;
1720:                            case 10:
1721:                                buf.append('B');
1722:                                break;
1723:                            case 11:
1724:                                buf.append('C');
1725:                                break;
1726:                            case 12:
1727:                                buf.append('S');
1728:                                break;
1729:                            default:
1730:                                buf.append('J');
1731:                            }
1732:                        }
1733:                        stackMap.putByte(7).putShort(
1734:                                cw.newClass(buf.toString()));
1735:                    }
1736:                }
1737:            }
1738:
1739:            private void writeFrameType(final Object type) {
1740:                if (type instanceof  String) {
1741:                    stackMap.putByte(7).putShort(cw.newClass((String) type));
1742:                } else if (type instanceof  Integer) {
1743:                    stackMap.putByte(((Integer) type).intValue());
1744:                } else {
1745:                    stackMap.putByte(8).putShort(((Label) type).position);
1746:                }
1747:            }
1748:
1749:            // ------------------------------------------------------------------------
1750:            // Utility methods: dump bytecode array
1751:            // ------------------------------------------------------------------------
1752:
1753:            /**
1754:             * Returns the size of the bytecode of this method.
1755:             * 
1756:             * @return the size of the bytecode of this method.
1757:             */
1758:            final int getSize() {
1759:                if (classReaderOffset != 0) {
1760:                    return 6 + classReaderLength;
1761:                }
1762:                if (resize) {
1763:                    // replaces the temporary jump opcodes introduced by Label.resolve.
1764:                    if (ClassReader.RESIZE) {
1765:                        resizeInstructions();
1766:                    } else {
1767:                        throw new RuntimeException("Method code too large!");
1768:                    }
1769:                }
1770:                int size = 8;
1771:                if (code.length > 0) {
1772:                    cw.newUTF8("Code");
1773:                    size += 18 + code.length + 8 * handlerCount;
1774:                    if (localVar != null) {
1775:                        cw.newUTF8("LocalVariableTable");
1776:                        size += 8 + localVar.length;
1777:                    }
1778:                    if (localVarType != null) {
1779:                        cw.newUTF8("LocalVariableTypeTable");
1780:                        size += 8 + localVarType.length;
1781:                    }
1782:                    if (lineNumber != null) {
1783:                        cw.newUTF8("LineNumberTable");
1784:                        size += 8 + lineNumber.length;
1785:                    }
1786:                    if (stackMap != null) {
1787:                        boolean zip = (cw.version & 0xFFFF) >= Opcodes.V1_6;
1788:                        cw.newUTF8(zip ? "StackMapTable" : "StackMap");
1789:                        size += 8 + stackMap.length;
1790:                    }
1791:                    if (cattrs != null) {
1792:                        size += cattrs.getSize(cw, code.data, code.length,
1793:                                maxStack, maxLocals);
1794:                    }
1795:                }
1796:                if (exceptionCount > 0) {
1797:                    cw.newUTF8("Exceptions");
1798:                    size += 8 + 2 * exceptionCount;
1799:                }
1800:                if ((access & Opcodes.ACC_SYNTHETIC) != 0
1801:                        && (cw.version & 0xffff) < Opcodes.V1_5) {
1802:                    cw.newUTF8("Synthetic");
1803:                    size += 6;
1804:                }
1805:                if ((access & Opcodes.ACC_DEPRECATED) != 0) {
1806:                    cw.newUTF8("Deprecated");
1807:                    size += 6;
1808:                }
1809:                if (ClassReader.SIGNATURES && signature != null) {
1810:                    cw.newUTF8("Signature");
1811:                    cw.newUTF8(signature);
1812:                    size += 8;
1813:                }
1814:                if (ClassReader.ANNOTATIONS && annd != null) {
1815:                    cw.newUTF8("AnnotationDefault");
1816:                    size += 6 + annd.length;
1817:                }
1818:                if (ClassReader.ANNOTATIONS && anns != null) {
1819:                    cw.newUTF8("RuntimeVisibleAnnotations");
1820:                    size += 8 + anns.getSize();
1821:                }
1822:                if (ClassReader.ANNOTATIONS && ianns != null) {
1823:                    cw.newUTF8("RuntimeInvisibleAnnotations");
1824:                    size += 8 + ianns.getSize();
1825:                }
1826:                if (ClassReader.ANNOTATIONS && panns != null) {
1827:                    cw.newUTF8("RuntimeVisibleParameterAnnotations");
1828:                    size += 7 + 2 * (panns.length - synthetics);
1829:                    for (int i = panns.length - 1; i >= synthetics; --i) {
1830:                        size += panns[i] == null ? 0 : panns[i].getSize();
1831:                    }
1832:                }
1833:                if (ClassReader.ANNOTATIONS && ipanns != null) {
1834:                    cw.newUTF8("RuntimeInvisibleParameterAnnotations");
1835:                    size += 7 + 2 * (ipanns.length - synthetics);
1836:                    for (int i = ipanns.length - 1; i >= synthetics; --i) {
1837:                        size += ipanns[i] == null ? 0 : ipanns[i].getSize();
1838:                    }
1839:                }
1840:                if (attrs != null) {
1841:                    size += attrs.getSize(cw, null, 0, -1, -1);
1842:                }
1843:                return size;
1844:            }
1845:
1846:            /**
1847:             * Puts the bytecode of this method in the given byte vector.
1848:             * 
1849:             * @param out the byte vector into which the bytecode of this method must be
1850:             *        copied.
1851:             */
1852:            final void put(final ByteVector out) {
1853:                out.putShort(access).putShort(name).putShort(desc);
1854:                if (classReaderOffset != 0) {
1855:                    out.putByteArray(cw.cr.b, classReaderOffset,
1856:                            classReaderLength);
1857:                    return;
1858:                }
1859:                int attributeCount = 0;
1860:                if (code.length > 0) {
1861:                    ++attributeCount;
1862:                }
1863:                if (exceptionCount > 0) {
1864:                    ++attributeCount;
1865:                }
1866:                if ((access & Opcodes.ACC_SYNTHETIC) != 0
1867:                        && (cw.version & 0xffff) < Opcodes.V1_5) {
1868:                    ++attributeCount;
1869:                }
1870:                if ((access & Opcodes.ACC_DEPRECATED) != 0) {
1871:                    ++attributeCount;
1872:                }
1873:                if (ClassReader.SIGNATURES && signature != null) {
1874:                    ++attributeCount;
1875:                }
1876:                if (ClassReader.ANNOTATIONS && annd != null) {
1877:                    ++attributeCount;
1878:                }
1879:                if (ClassReader.ANNOTATIONS && anns != null) {
1880:                    ++attributeCount;
1881:                }
1882:                if (ClassReader.ANNOTATIONS && ianns != null) {
1883:                    ++attributeCount;
1884:                }
1885:                if (ClassReader.ANNOTATIONS && panns != null) {
1886:                    ++attributeCount;
1887:                }
1888:                if (ClassReader.ANNOTATIONS && ipanns != null) {
1889:                    ++attributeCount;
1890:                }
1891:                if (attrs != null) {
1892:                    attributeCount += attrs.getCount();
1893:                }
1894:                out.putShort(attributeCount);
1895:                if (code.length > 0) {
1896:                    int size = 12 + code.length + 8 * handlerCount;
1897:                    if (localVar != null) {
1898:                        size += 8 + localVar.length;
1899:                    }
1900:                    if (localVarType != null) {
1901:                        size += 8 + localVarType.length;
1902:                    }
1903:                    if (lineNumber != null) {
1904:                        size += 8 + lineNumber.length;
1905:                    }
1906:                    if (stackMap != null) {
1907:                        size += 8 + stackMap.length;
1908:                    }
1909:                    if (cattrs != null) {
1910:                        size += cattrs.getSize(cw, code.data, code.length,
1911:                                maxStack, maxLocals);
1912:                    }
1913:                    out.putShort(cw.newUTF8("Code")).putInt(size);
1914:                    out.putShort(maxStack).putShort(maxLocals);
1915:                    out.putInt(code.length).putByteArray(code.data, 0,
1916:                            code.length);
1917:                    out.putShort(handlerCount);
1918:                    if (handlerCount > 0) {
1919:                        Handler h = firstHandler;
1920:                        while (h != null) {
1921:                            out.putShort(h.start.position).putShort(
1922:                                    h.end.position)
1923:                                    .putShort(h.handler.position).putShort(
1924:                                            h.type);
1925:                            h = h.next;
1926:                        }
1927:                    }
1928:                    attributeCount = 0;
1929:                    if (localVar != null) {
1930:                        ++attributeCount;
1931:                    }
1932:                    if (localVarType != null) {
1933:                        ++attributeCount;
1934:                    }
1935:                    if (lineNumber != null) {
1936:                        ++attributeCount;
1937:                    }
1938:                    if (stackMap != null) {
1939:                        ++attributeCount;
1940:                    }
1941:                    if (cattrs != null) {
1942:                        attributeCount += cattrs.getCount();
1943:                    }
1944:                    out.putShort(attributeCount);
1945:                    if (localVar != null) {
1946:                        out.putShort(cw.newUTF8("LocalVariableTable"));
1947:                        out.putInt(localVar.length + 2).putShort(localVarCount);
1948:                        out.putByteArray(localVar.data, 0, localVar.length);
1949:                    }
1950:                    if (localVarType != null) {
1951:                        out.putShort(cw.newUTF8("LocalVariableTypeTable"));
1952:                        out.putInt(localVarType.length + 2).putShort(
1953:                                localVarTypeCount);
1954:                        out.putByteArray(localVarType.data, 0,
1955:                                localVarType.length);
1956:                    }
1957:                    if (lineNumber != null) {
1958:                        out.putShort(cw.newUTF8("LineNumberTable"));
1959:                        out.putInt(lineNumber.length + 2).putShort(
1960:                                lineNumberCount);
1961:                        out.putByteArray(lineNumber.data, 0, lineNumber.length);
1962:                    }
1963:                    if (stackMap != null) {
1964:                        boolean zip = (cw.version & 0xFFFF) >= Opcodes.V1_6;
1965:                        out.putShort(cw.newUTF8(zip ? "StackMapTable"
1966:                                : "StackMap"));
1967:                        out.putInt(stackMap.length + 2).putShort(frameCount);
1968:                        out.putByteArray(stackMap.data, 0, stackMap.length);
1969:                    }
1970:                    if (cattrs != null) {
1971:                        cattrs.put(cw, code.data, code.length, maxLocals,
1972:                                maxStack, out);
1973:                    }
1974:                }
1975:                if (exceptionCount > 0) {
1976:                    out.putShort(cw.newUTF8("Exceptions")).putInt(
1977:                            2 * exceptionCount + 2);
1978:                    out.putShort(exceptionCount);
1979:                    for (int i = 0; i < exceptionCount; ++i) {
1980:                        out.putShort(exceptions[i]);
1981:                    }
1982:                }
1983:                if ((access & Opcodes.ACC_SYNTHETIC) != 0
1984:                        && (cw.version & 0xffff) < Opcodes.V1_5) {
1985:                    out.putShort(cw.newUTF8("Synthetic")).putInt(0);
1986:                }
1987:                if ((access & Opcodes.ACC_DEPRECATED) != 0) {
1988:                    out.putShort(cw.newUTF8("Deprecated")).putInt(0);
1989:                }
1990:                if (ClassReader.SIGNATURES && signature != null) {
1991:                    out.putShort(cw.newUTF8("Signature")).putInt(2).putShort(
1992:                            cw.newUTF8(signature));
1993:                }
1994:                if (ClassReader.ANNOTATIONS && annd != null) {
1995:                    out.putShort(cw.newUTF8("AnnotationDefault"));
1996:                    out.putInt(annd.length);
1997:                    out.putByteArray(annd.data, 0, annd.length);
1998:                }
1999:                if (ClassReader.ANNOTATIONS && anns != null) {
2000:                    out.putShort(cw.newUTF8("RuntimeVisibleAnnotations"));
2001:                    anns.put(out);
2002:                }
2003:                if (ClassReader.ANNOTATIONS && ianns != null) {
2004:                    out.putShort(cw.newUTF8("RuntimeInvisibleAnnotations"));
2005:                    ianns.put(out);
2006:                }
2007:                if (ClassReader.ANNOTATIONS && panns != null) {
2008:                    out.putShort(cw
2009:                            .newUTF8("RuntimeVisibleParameterAnnotations"));
2010:                    AnnotationWriter.put(panns, synthetics, out);
2011:                }
2012:                if (ClassReader.ANNOTATIONS && ipanns != null) {
2013:                    out.putShort(cw
2014:                            .newUTF8("RuntimeInvisibleParameterAnnotations"));
2015:                    AnnotationWriter.put(ipanns, synthetics, out);
2016:                }
2017:                if (attrs != null) {
2018:                    attrs.put(cw, null, 0, -1, -1, out);
2019:                }
2020:            }
2021:
2022:            // ------------------------------------------------------------------------
2023:            // Utility methods: instruction resizing (used to handle GOTO_W and JSR_W)
2024:            // ------------------------------------------------------------------------
2025:
2026:            /**
2027:             * Resizes and replaces the temporary instructions inserted by
2028:             * {@link Label#resolve} for wide forward jumps, while keeping jump offsets
2029:             * and instruction addresses consistent. This may require to resize other
2030:             * existing instructions, or even to introduce new instructions: for
2031:             * example, increasing the size of an instruction by 2 at the middle of a
2032:             * method can increases the offset of an IFEQ instruction from 32766 to
2033:             * 32768, in which case IFEQ 32766 must be replaced with IFNEQ 8 GOTO_W
2034:             * 32765. This, in turn, may require to increase the size of another jump
2035:             * instruction, and so on... All these operations are handled automatically
2036:             * by this method. <p> <i>This method must be called after all the method
2037:             * that is being built has been visited</i>. In particular, the
2038:             * {@link Label Label} objects used to construct the method are no longer
2039:             * valid after this method has been called.
2040:             */
2041:            private void resizeInstructions() {
2042:                byte[] b = code.data; // bytecode of the method
2043:                int u, v, label; // indexes in b
2044:                int i, j; // loop indexes
2045:                /*
2046:                 * 1st step: As explained above, resizing an instruction may require to
2047:                 * resize another one, which may require to resize yet another one, and
2048:                 * so on. The first step of the algorithm consists in finding all the
2049:                 * instructions that need to be resized, without modifying the code.
2050:                 * This is done by the following "fix point" algorithm:
2051:                 * 
2052:                 * Parse the code to find the jump instructions whose offset will need
2053:                 * more than 2 bytes to be stored (the future offset is computed from
2054:                 * the current offset and from the number of bytes that will be inserted
2055:                 * or removed between the source and target instructions). For each such
2056:                 * instruction, adds an entry in (a copy of) the indexes and sizes
2057:                 * arrays (if this has not already been done in a previous iteration!).
2058:                 * 
2059:                 * If at least one entry has been added during the previous step, go
2060:                 * back to the beginning, otherwise stop.
2061:                 * 
2062:                 * In fact the real algorithm is complicated by the fact that the size
2063:                 * of TABLESWITCH and LOOKUPSWITCH instructions depends on their
2064:                 * position in the bytecode (because of padding). In order to ensure the
2065:                 * convergence of the algorithm, the number of bytes to be added or
2066:                 * removed from these instructions is over estimated during the previous
2067:                 * loop, and computed exactly only after the loop is finished (this
2068:                 * requires another pass to parse the bytecode of the method).
2069:                 */
2070:                int[] allIndexes = new int[0]; // copy of indexes
2071:                int[] allSizes = new int[0]; // copy of sizes
2072:                boolean[] resize; // instructions to be resized
2073:                int newOffset; // future offset of a jump instruction
2074:
2075:                resize = new boolean[code.length];
2076:
2077:                // 3 = loop again, 2 = loop ended, 1 = last pass, 0 = done
2078:                int state = 3;
2079:                do {
2080:                    if (state == 3) {
2081:                        state = 2;
2082:                    }
2083:                    u = 0;
2084:                    while (u < b.length) {
2085:                        int opcode = b[u] & 0xFF; // opcode of current instruction
2086:                        int insert = 0; // bytes to be added after this instruction
2087:
2088:                        switch (ClassWriter.TYPE[opcode]) {
2089:                        case ClassWriter.NOARG_INSN:
2090:                        case ClassWriter.IMPLVAR_INSN:
2091:                            u += 1;
2092:                            break;
2093:                        case ClassWriter.LABEL_INSN:
2094:                            if (opcode > 201) {
2095:                                // converts temporary opcodes 202 to 217, 218 and
2096:                                // 219 to IFEQ ... JSR (inclusive), IFNULL and
2097:                                // IFNONNULL
2098:                                opcode = opcode < 218 ? opcode - 49
2099:                                        : opcode - 20;
2100:                                label = u + readUnsignedShort(b, u + 1);
2101:                            } else {
2102:                                label = u + readShort(b, u + 1);
2103:                            }
2104:                            newOffset = getNewOffset(allIndexes, allSizes, u,
2105:                                    label);
2106:                            if (newOffset < Short.MIN_VALUE
2107:                                    || newOffset > Short.MAX_VALUE) {
2108:                                if (!resize[u]) {
2109:                                    if (opcode == Opcodes.GOTO
2110:                                            || opcode == Opcodes.JSR) {
2111:                                        // two additional bytes will be required to
2112:                                        // replace this GOTO or JSR instruction with
2113:                                        // a GOTO_W or a JSR_W
2114:                                        insert = 2;
2115:                                    } else {
2116:                                        // five additional bytes will be required to
2117:                                        // replace this IFxxx <l> instruction with
2118:                                        // IFNOTxxx <l'> GOTO_W <l>, where IFNOTxxx
2119:                                        // is the "opposite" opcode of IFxxx (i.e.,
2120:                                        // IFNE for IFEQ) and where <l'> designates
2121:                                        // the instruction just after the GOTO_W.
2122:                                        insert = 5;
2123:                                    }
2124:                                    resize[u] = true;
2125:                                }
2126:                            }
2127:                            u += 3;
2128:                            break;
2129:                        case ClassWriter.LABELW_INSN:
2130:                            u += 5;
2131:                            break;
2132:                        case ClassWriter.TABL_INSN:
2133:                            if (state == 1) {
2134:                                // true number of bytes to be added (or removed)
2135:                                // from this instruction = (future number of padding
2136:                                // bytes - current number of padding byte) -
2137:                                // previously over estimated variation =
2138:                                // = ((3 - newOffset%4) - (3 - u%4)) - u%4
2139:                                // = (-newOffset%4 + u%4) - u%4
2140:                                // = -(newOffset & 3)
2141:                                newOffset = getNewOffset(allIndexes, allSizes,
2142:                                        0, u);
2143:                                insert = -(newOffset & 3);
2144:                            } else if (!resize[u]) {
2145:                                // over estimation of the number of bytes to be
2146:                                // added to this instruction = 3 - current number
2147:                                // of padding bytes = 3 - (3 - u%4) = u%4 = u & 3
2148:                                insert = u & 3;
2149:                                resize[u] = true;
2150:                            }
2151:                            // skips instruction
2152:                            u = u + 4 - (u & 3);
2153:                            u += 4 * (readInt(b, u + 8) - readInt(b, u + 4) + 1) + 12;
2154:                            break;
2155:                        case ClassWriter.LOOK_INSN:
2156:                            if (state == 1) {
2157:                                // like TABL_INSN
2158:                                newOffset = getNewOffset(allIndexes, allSizes,
2159:                                        0, u);
2160:                                insert = -(newOffset & 3);
2161:                            } else if (!resize[u]) {
2162:                                // like TABL_INSN
2163:                                insert = u & 3;
2164:                                resize[u] = true;
2165:                            }
2166:                            // skips instruction
2167:                            u = u + 4 - (u & 3);
2168:                            u += 8 * readInt(b, u + 4) + 8;
2169:                            break;
2170:                        case ClassWriter.WIDE_INSN:
2171:                            opcode = b[u + 1] & 0xFF;
2172:                            if (opcode == Opcodes.IINC) {
2173:                                u += 6;
2174:                            } else {
2175:                                u += 4;
2176:                            }
2177:                            break;
2178:                        case ClassWriter.VAR_INSN:
2179:                        case ClassWriter.SBYTE_INSN:
2180:                        case ClassWriter.LDC_INSN:
2181:                            u += 2;
2182:                            break;
2183:                        case ClassWriter.SHORT_INSN:
2184:                        case ClassWriter.LDCW_INSN:
2185:                        case ClassWriter.FIELDORMETH_INSN:
2186:                        case ClassWriter.TYPE_INSN:
2187:                        case ClassWriter.IINC_INSN:
2188:                            u += 3;
2189:                            break;
2190:                        case ClassWriter.ITFMETH_INSN:
2191:                            u += 5;
2192:                            break;
2193:                        // case ClassWriter.MANA_INSN:
2194:                        default:
2195:                            u += 4;
2196:                            break;
2197:                        }
2198:                        if (insert != 0) {
2199:                            // adds a new (u, insert) entry in the allIndexes and
2200:                            // allSizes arrays
2201:                            int[] newIndexes = new int[allIndexes.length + 1];
2202:                            int[] newSizes = new int[allSizes.length + 1];
2203:                            System.arraycopy(allIndexes, 0, newIndexes, 0,
2204:                                    allIndexes.length);
2205:                            System.arraycopy(allSizes, 0, newSizes, 0,
2206:                                    allSizes.length);
2207:                            newIndexes[allIndexes.length] = u;
2208:                            newSizes[allSizes.length] = insert;
2209:                            allIndexes = newIndexes;
2210:                            allSizes = newSizes;
2211:                            if (insert > 0) {
2212:                                state = 3;
2213:                            }
2214:                        }
2215:                    }
2216:                    if (state < 3) {
2217:                        --state;
2218:                    }
2219:                } while (state != 0);
2220:
2221:                // 2nd step:
2222:                // copies the bytecode of the method into a new bytevector, updates the
2223:                // offsets, and inserts (or removes) bytes as requested.
2224:
2225:                ByteVector newCode = new ByteVector(code.length);
2226:
2227:                u = 0;
2228:                while (u < code.length) {
2229:                    int opcode = b[u] & 0xFF;
2230:                    switch (ClassWriter.TYPE[opcode]) {
2231:                    case ClassWriter.NOARG_INSN:
2232:                    case ClassWriter.IMPLVAR_INSN:
2233:                        newCode.putByte(opcode);
2234:                        u += 1;
2235:                        break;
2236:                    case ClassWriter.LABEL_INSN:
2237:                        if (opcode > 201) {
2238:                            // changes temporary opcodes 202 to 217 (inclusive), 218
2239:                            // and 219 to IFEQ ... JSR (inclusive), IFNULL and
2240:                            // IFNONNULL
2241:                            opcode = opcode < 218 ? opcode - 49 : opcode - 20;
2242:                            label = u + readUnsignedShort(b, u + 1);
2243:                        } else {
2244:                            label = u + readShort(b, u + 1);
2245:                        }
2246:                        newOffset = getNewOffset(allIndexes, allSizes, u, label);
2247:                        if (resize[u]) {
2248:                            // replaces GOTO with GOTO_W, JSR with JSR_W and IFxxx
2249:                            // <l> with IFNOTxxx <l'> GOTO_W <l>, where IFNOTxxx is
2250:                            // the "opposite" opcode of IFxxx (i.e., IFNE for IFEQ)
2251:                            // and where <l'> designates the instruction just after
2252:                            // the GOTO_W.
2253:                            if (opcode == Opcodes.GOTO) {
2254:                                newCode.putByte(200); // GOTO_W
2255:                            } else if (opcode == Opcodes.JSR) {
2256:                                newCode.putByte(201); // JSR_W
2257:                            } else {
2258:                                newCode
2259:                                        .putByte(opcode <= 166 ? ((opcode + 1) ^ 1) - 1
2260:                                                : opcode ^ 1);
2261:                                newCode.putShort(8); // jump offset
2262:                                newCode.putByte(200); // GOTO_W
2263:                                // newOffset now computed from start of GOTO_W
2264:                                newOffset -= 3;
2265:                            }
2266:                            newCode.putInt(newOffset);
2267:                        } else {
2268:                            newCode.putByte(opcode);
2269:                            newCode.putShort(newOffset);
2270:                        }
2271:                        u += 3;
2272:                        break;
2273:                    case ClassWriter.LABELW_INSN:
2274:                        label = u + readInt(b, u + 1);
2275:                        newOffset = getNewOffset(allIndexes, allSizes, u, label);
2276:                        newCode.putByte(opcode);
2277:                        newCode.putInt(newOffset);
2278:                        u += 5;
2279:                        break;
2280:                    case ClassWriter.TABL_INSN:
2281:                        // skips 0 to 3 padding bytes
2282:                        v = u;
2283:                        u = u + 4 - (v & 3);
2284:                        // reads and copies instruction
2285:                        newCode.putByte(Opcodes.TABLESWITCH);
2286:                        newCode.length += (4 - newCode.length % 4) % 4;
2287:                        label = v + readInt(b, u);
2288:                        u += 4;
2289:                        newOffset = getNewOffset(allIndexes, allSizes, v, label);
2290:                        newCode.putInt(newOffset);
2291:                        j = readInt(b, u);
2292:                        u += 4;
2293:                        newCode.putInt(j);
2294:                        j = readInt(b, u) - j + 1;
2295:                        u += 4;
2296:                        newCode.putInt(readInt(b, u - 4));
2297:                        for (; j > 0; --j) {
2298:                            label = v + readInt(b, u);
2299:                            u += 4;
2300:                            newOffset = getNewOffset(allIndexes, allSizes, v,
2301:                                    label);
2302:                            newCode.putInt(newOffset);
2303:                        }
2304:                        break;
2305:                    case ClassWriter.LOOK_INSN:
2306:                        // skips 0 to 3 padding bytes
2307:                        v = u;
2308:                        u = u + 4 - (v & 3);
2309:                        // reads and copies instruction
2310:                        newCode.putByte(Opcodes.LOOKUPSWITCH);
2311:                        newCode.length += (4 - newCode.length % 4) % 4;
2312:                        label = v + readInt(b, u);
2313:                        u += 4;
2314:                        newOffset = getNewOffset(allIndexes, allSizes, v, label);
2315:                        newCode.putInt(newOffset);
2316:                        j = readInt(b, u);
2317:                        u += 4;
2318:                        newCode.putInt(j);
2319:                        for (; j > 0; --j) {
2320:                            newCode.putInt(readInt(b, u));
2321:                            u += 4;
2322:                            label = v + readInt(b, u);
2323:                            u += 4;
2324:                            newOffset = getNewOffset(allIndexes, allSizes, v,
2325:                                    label);
2326:                            newCode.putInt(newOffset);
2327:                        }
2328:                        break;
2329:                    case ClassWriter.WIDE_INSN:
2330:                        opcode = b[u + 1] & 0xFF;
2331:                        if (opcode == Opcodes.IINC) {
2332:                            newCode.putByteArray(b, u, 6);
2333:                            u += 6;
2334:                        } else {
2335:                            newCode.putByteArray(b, u, 4);
2336:                            u += 4;
2337:                        }
2338:                        break;
2339:                    case ClassWriter.VAR_INSN:
2340:                    case ClassWriter.SBYTE_INSN:
2341:                    case ClassWriter.LDC_INSN:
2342:                        newCode.putByteArray(b, u, 2);
2343:                        u += 2;
2344:                        break;
2345:                    case ClassWriter.SHORT_INSN:
2346:                    case ClassWriter.LDCW_INSN:
2347:                    case ClassWriter.FIELDORMETH_INSN:
2348:                    case ClassWriter.TYPE_INSN:
2349:                    case ClassWriter.IINC_INSN:
2350:                        newCode.putByteArray(b, u, 3);
2351:                        u += 3;
2352:                        break;
2353:                    case ClassWriter.ITFMETH_INSN:
2354:                        newCode.putByteArray(b, u, 5);
2355:                        u += 5;
2356:                        break;
2357:                    // case MANA_INSN:
2358:                    default:
2359:                        newCode.putByteArray(b, u, 4);
2360:                        u += 4;
2361:                        break;
2362:                    }
2363:                }
2364:
2365:                // recomputes the stack map frames
2366:                if (frameCount > 0) {
2367:                    if (compute == FRAMES) {
2368:                        frameCount = 0;
2369:                        stackMap = null;
2370:                        previousFrame = null;
2371:                        frame = null;
2372:                        Frame f = new Frame();
2373:                        f.owner = labels;
2374:                        Type[] args = Type.getArgumentTypes(descriptor);
2375:                        f.initInputFrame(cw, access, args, maxLocals);
2376:                        visitFrame(f);
2377:                        Label l = labels;
2378:                        while (l != null) {
2379:                            /*
2380:                             * here we need the original label position. getNewOffset
2381:                             * must therefore never have been called for this label.
2382:                             */
2383:                            u = l.position - 3;
2384:                            if ((l.status & Label.STORE) != 0
2385:                                    || (u >= 0 && resize[u])) {
2386:                                getNewOffset(allIndexes, allSizes, l);
2387:                                // TODO update offsets in UNINITIALIZED values
2388:                                visitFrame(l.frame);
2389:                            }
2390:                            l = l.successor;
2391:                        }
2392:                    } else {
2393:                        /*
2394:                         * Resizing an existing stack map frame table is really hard.
2395:                         * Not only the table must be parsed to update the offets, but
2396:                         * new frames may be needed for jump instructions that were
2397:                         * inserted by this method. And updating the offsets or
2398:                         * inserting frames can change the format of the following
2399:                         * frames, in case of packed frames. In practice the whole table
2400:                         * must be recomputed. For this the frames are marked as
2401:                         * potentially invalid. This will cause the whole class to be
2402:                         * reread and rewritten with the COMPUTE_FRAMES option (see the
2403:                         * ClassWriter.toByteArray method). This is not very efficient
2404:                         * but is much easier and requires much less code than any other
2405:                         * method I can think of.
2406:                         */
2407:                        cw.invalidFrames = true;
2408:                    }
2409:                }
2410:                // updates the exception handler block labels
2411:                Handler h = firstHandler;
2412:                while (h != null) {
2413:                    getNewOffset(allIndexes, allSizes, h.start);
2414:                    getNewOffset(allIndexes, allSizes, h.end);
2415:                    getNewOffset(allIndexes, allSizes, h.handler);
2416:                    h = h.next;
2417:                }
2418:                // updates the instructions addresses in the
2419:                // local var and line number tables
2420:                for (i = 0; i < 2; ++i) {
2421:                    ByteVector bv = i == 0 ? localVar : localVarType;
2422:                    if (bv != null) {
2423:                        b = bv.data;
2424:                        u = 0;
2425:                        while (u < bv.length) {
2426:                            label = readUnsignedShort(b, u);
2427:                            newOffset = getNewOffset(allIndexes, allSizes, 0,
2428:                                    label);
2429:                            writeShort(b, u, newOffset);
2430:                            label += readUnsignedShort(b, u + 2);
2431:                            newOffset = getNewOffset(allIndexes, allSizes, 0,
2432:                                    label)
2433:                                    - newOffset;
2434:                            writeShort(b, u + 2, newOffset);
2435:                            u += 10;
2436:                        }
2437:                    }
2438:                }
2439:                if (lineNumber != null) {
2440:                    b = lineNumber.data;
2441:                    u = 0;
2442:                    while (u < lineNumber.length) {
2443:                        writeShort(b, u, getNewOffset(allIndexes, allSizes, 0,
2444:                                readUnsignedShort(b, u)));
2445:                        u += 4;
2446:                    }
2447:                }
2448:                // updates the labels of the other attributes
2449:                Attribute attr = cattrs;
2450:                while (attr != null) {
2451:                    Label[] labels = attr.getLabels();
2452:                    if (labels != null) {
2453:                        for (i = labels.length - 1; i >= 0; --i) {
2454:                            getNewOffset(allIndexes, allSizes, labels[i]);
2455:                        }
2456:                    }
2457:                    attr = attr.next;
2458:                }
2459:
2460:                // replaces old bytecodes with new ones
2461:                code = newCode;
2462:            }
2463:
2464:            /**
2465:             * Reads an unsigned short value in the given byte array.
2466:             * 
2467:             * @param b a byte array.
2468:             * @param index the start index of the value to be read.
2469:             * @return the read value.
2470:             */
2471:            static int readUnsignedShort(final byte[] b, final int index) {
2472:                return ((b[index] & 0xFF) << 8) | (b[index + 1] & 0xFF);
2473:            }
2474:
2475:            /**
2476:             * Reads a signed short value in the given byte array.
2477:             * 
2478:             * @param b a byte array.
2479:             * @param index the start index of the value to be read.
2480:             * @return the read value.
2481:             */
2482:            static short readShort(final byte[] b, final int index) {
2483:                return (short) (((b[index] & 0xFF) << 8) | (b[index + 1] & 0xFF));
2484:            }
2485:
2486:            /**
2487:             * Reads a signed int value in the given byte array.
2488:             * 
2489:             * @param b a byte array.
2490:             * @param index the start index of the value to be read.
2491:             * @return the read value.
2492:             */
2493:            static int readInt(final byte[] b, final int index) {
2494:                return ((b[index] & 0xFF) << 24)
2495:                        | ((b[index + 1] & 0xFF) << 16)
2496:                        | ((b[index + 2] & 0xFF) << 8) | (b[index + 3] & 0xFF);
2497:            }
2498:
2499:            /**
2500:             * Writes a short value in the given byte array.
2501:             * 
2502:             * @param b a byte array.
2503:             * @param index where the first byte of the short value must be written.
2504:             * @param s the value to be written in the given byte array.
2505:             */
2506:            static void writeShort(final byte[] b, final int index, final int s) {
2507:                b[index] = (byte) (s >>> 8);
2508:                b[index + 1] = (byte) s;
2509:            }
2510:
2511:            /**
2512:             * Computes the future value of a bytecode offset. <p> Note: it is possible
2513:             * to have several entries for the same instruction in the <tt>indexes</tt>
2514:             * and <tt>sizes</tt>: two entries (index=a,size=b) and (index=a,size=b')
2515:             * are equivalent to a single entry (index=a,size=b+b').
2516:             * 
2517:             * @param indexes current positions of the instructions to be resized. Each
2518:             *        instruction must be designated by the index of its <i>last</i>
2519:             *        byte, plus one (or, in other words, by the index of the <i>first</i>
2520:             *        byte of the <i>next</i> instruction).
2521:             * @param sizes the number of bytes to be <i>added</i> to the above
2522:             *        instructions. More precisely, for each i < <tt>len</tt>,
2523:             *        <tt>sizes</tt>[i] bytes will be added at the end of the
2524:             *        instruction designated by <tt>indexes</tt>[i] or, if
2525:             *        <tt>sizes</tt>[i] is negative, the <i>last</i> |<tt>sizes[i]</tt>|
2526:             *        bytes of the instruction will be removed (the instruction size
2527:             *        <i>must not</i> become negative or null).
2528:             * @param begin index of the first byte of the source instruction.
2529:             * @param end index of the first byte of the target instruction.
2530:             * @return the future value of the given bytecode offset.
2531:             */
2532:            static int getNewOffset(final int[] indexes, final int[] sizes,
2533:                    final int begin, final int end) {
2534:                int offset = end - begin;
2535:                for (int i = 0; i < indexes.length; ++i) {
2536:                    if (begin < indexes[i] && indexes[i] <= end) {
2537:                        // forward jump
2538:                        offset += sizes[i];
2539:                    } else if (end < indexes[i] && indexes[i] <= begin) {
2540:                        // backward jump
2541:                        offset -= sizes[i];
2542:                    }
2543:                }
2544:                return offset;
2545:            }
2546:
2547:            /**
2548:             * Updates the offset of the given label.
2549:             * 
2550:             * @param indexes current positions of the instructions to be resized. Each
2551:             *        instruction must be designated by the index of its <i>last</i>
2552:             *        byte, plus one (or, in other words, by the index of the <i>first</i>
2553:             *        byte of the <i>next</i> instruction).
2554:             * @param sizes the number of bytes to be <i>added</i> to the above
2555:             *        instructions. More precisely, for each i < <tt>len</tt>,
2556:             *        <tt>sizes</tt>[i] bytes will be added at the end of the
2557:             *        instruction designated by <tt>indexes</tt>[i] or, if
2558:             *        <tt>sizes</tt>[i] is negative, the <i>last</i> |<tt>sizes[i]</tt>|
2559:             *        bytes of the instruction will be removed (the instruction size
2560:             *        <i>must not</i> become negative or null).
2561:             * @param label the label whose offset must be updated.
2562:             */
2563:            static void getNewOffset(final int[] indexes, final int[] sizes,
2564:                    final Label label) {
2565:                if ((label.status & Label.RESIZED) == 0) {
2566:                    label.position = getNewOffset(indexes, sizes, 0,
2567:                            label.position);
2568:                    label.status |= Label.RESIZED;
2569:                }
2570:            }
2571:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.