Source Code Cross Referenced for MethodWriter.java in  » Rule-Engine » drolls-Rule-Engine » org » drools » 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 » Rule Engine » drolls Rule Engine » org.drools.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-2005 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.drools.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:         */
0038:        class MethodWriter implements  MethodVisitor {
0039:
0040:            /**
0041:             * Next method writer (see {@link ClassWriter#firstMethod firstMethod}).
0042:             */
0043:            MethodWriter next;
0044:
0045:            /**
0046:             * The class writer to which this method must be added.
0047:             */
0048:            ClassWriter cw;
0049:
0050:            /**
0051:             * Access flags of this method.
0052:             */
0053:            private int access;
0054:
0055:            /**
0056:             * The index of the constant pool item that contains the name of this
0057:             * method.
0058:             */
0059:            private int name;
0060:
0061:            /**
0062:             * The index of the constant pool item that contains the descriptor of this
0063:             * method.
0064:             */
0065:            private int desc;
0066:
0067:            /**
0068:             * The descriptor of this method.
0069:             */
0070:            private String descriptor;
0071:
0072:            /**
0073:             * If not zero, indicates that the code of this method must be copied from
0074:             * the ClassReader associated to this writer in <code>cw.cr</code>. More
0075:             * precisely, this field gives the index of the first byte to copied from
0076:             * <code>cw.cr.b</code>.
0077:             */
0078:            int classReaderOffset;
0079:
0080:            /**
0081:             * If not zero, indicates that the code of this method must be copied from
0082:             * the ClassReader associated to this writer in <code>cw.cr</code>. More
0083:             * precisely, this field gives the number of bytes to copied from
0084:             * <code>cw.cr.b</code>.
0085:             */
0086:            int classReaderLength;
0087:
0088:            /**
0089:             * The signature of this method.
0090:             */
0091:            String signature;
0092:
0093:            /**
0094:             * Number of exceptions that can be thrown by this method.
0095:             */
0096:            int exceptionCount;
0097:
0098:            /**
0099:             * The exceptions that can be thrown by this method. More precisely, this
0100:             * array contains the indexes of the constant pool items that contain the
0101:             * internal names of these exception classes.
0102:             */
0103:            int[] exceptions;
0104:
0105:            /**
0106:             * The annotation default attribute of this method. May be <tt>null</tt>.
0107:             */
0108:            private ByteVector annd;
0109:
0110:            /**
0111:             * The runtime visible annotations of this method. May be <tt>null</tt>.
0112:             */
0113:            private AnnotationWriter anns;
0114:
0115:            /**
0116:             * The runtime invisible annotations of this method. May be <tt>null</tt>.
0117:             */
0118:            private AnnotationWriter ianns;
0119:
0120:            /**
0121:             * The runtime visible parameter annotations of this method. May be
0122:             * <tt>null</tt>.
0123:             */
0124:            private AnnotationWriter[] panns;
0125:
0126:            /**
0127:             * The runtime invisible parameter annotations of this method. May be
0128:             * <tt>null</tt>.
0129:             */
0130:            private AnnotationWriter[] ipanns;
0131:
0132:            /**
0133:             * The non standard attributes of the method.
0134:             */
0135:            private Attribute attrs;
0136:
0137:            /**
0138:             * The bytecode of this method.
0139:             */
0140:            private ByteVector code = new ByteVector();
0141:
0142:            /**
0143:             * Maximum stack size of this method.
0144:             */
0145:            private int maxStack;
0146:
0147:            /**
0148:             * Maximum number of local variables for this method.
0149:             */
0150:            private int maxLocals;
0151:
0152:            /**
0153:             * Number of entries in the catch table of this method.
0154:             */
0155:            private int catchCount;
0156:
0157:            /**
0158:             * The catch table of this method.
0159:             */
0160:            private Handler catchTable;
0161:
0162:            /**
0163:             * The last element in the catchTable handler list.
0164:             */
0165:            private Handler lastHandler;
0166:
0167:            /**
0168:             * Number of entries in the LocalVariableTable attribute.
0169:             */
0170:            private int localVarCount;
0171:
0172:            /**
0173:             * The LocalVariableTable attribute.
0174:             */
0175:            private ByteVector localVar;
0176:
0177:            /**
0178:             * Number of entries in the LocalVariableTypeTable attribute.
0179:             */
0180:            private int localVarTypeCount;
0181:
0182:            /**
0183:             * The LocalVariableTypeTable attribute.
0184:             */
0185:            private ByteVector localVarType;
0186:
0187:            /**
0188:             * Number of entries in the LineNumberTable attribute.
0189:             */
0190:            private int lineNumberCount;
0191:
0192:            /**
0193:             * The LineNumberTable attribute.
0194:             */
0195:            private ByteVector lineNumber;
0196:
0197:            /**
0198:             * The non standard attributes of the method's code.
0199:             */
0200:            private Attribute cattrs;
0201:
0202:            /**
0203:             * Indicates if some jump instructions are too small and need to be resized.
0204:             */
0205:            private boolean resize;
0206:
0207:            /*
0208:             * Fields for the control flow graph analysis algorithm (used to compute the
0209:             * maximum stack size). A control flow graph contains one node per "basic
0210:             * block", and one edge per "jump" from one basic block to another. Each
0211:             * node (i.e., each basic block) is represented by the Label object that
0212:             * corresponds to the first instruction of this basic block. Each node also
0213:             * stores the list of its successors in the graph, as a linked list of Edge
0214:             * objects.
0215:             */
0216:
0217:            /**
0218:             * <tt>true</tt> if the maximum stack size and number of local variables
0219:             * must be automatically computed.
0220:             */
0221:            private final boolean computeMaxs;
0222:
0223:            /**
0224:             * The (relative) stack size after the last visited instruction. This size
0225:             * is relative to the beginning of the current basic block, i.e., the true
0226:             * stack size after the last visited instruction is equal to the {@link
0227:             * Label#beginStackSize beginStackSize} of the current basic block plus
0228:             * <tt>stackSize</tt>.
0229:             */
0230:            private int stackSize;
0231:
0232:            /**
0233:             * The (relative) maximum stack size after the last visited instruction.
0234:             * This size is relative to the beginning of the current basic block, i.e.,
0235:             * the true maximum stack size after the last visited instruction is equal
0236:             * to the {@link Label#beginStackSize beginStackSize} of the current basic
0237:             * block plus <tt>stackSize</tt>.
0238:             */
0239:            private int maxStackSize;
0240:
0241:            /**
0242:             * The current basic block. This block is the basic block to which the next
0243:             * instruction to be visited must be added.
0244:             */
0245:            private Label currentBlock;
0246:
0247:            /**
0248:             * The basic block stack used by the control flow analysis algorithm. This
0249:             * stack is represented by a linked list of {@link Label Label} objects,
0250:             * linked to each other by their {@link Label#next} field. This stack must
0251:             * not be confused with the JVM stack used to execute the JVM instructions!
0252:             */
0253:            private Label blockStack;
0254:
0255:            /**
0256:             * The stack size variation corresponding to each JVM instruction. This
0257:             * stack variation is equal to the size of the values produced by an
0258:             * instruction, minus the size of the values consumed by this instruction.
0259:             */
0260:            private final static int[] SIZE;
0261:
0262:            // ------------------------------------------------------------------------
0263:            // Static initializer
0264:            // ------------------------------------------------------------------------
0265:
0266:            /**
0267:             * Computes the stack size variation corresponding to each JVM instruction.
0268:             */
0269:            static {
0270:                int i;
0271:                final int[] b = new int[202];
0272:                final String s = "EFFFFFFFFGGFFFGGFFFEEFGFGFEEEEEEEEEEEEEEEEEEEEDEDEDDDDD"
0273:                        + "CDCDEEEEEEEEEEEEEEEEEEEEBABABBBBDCFFFGGGEDCDCDCDCDCDCDCDCD"
0274:                        + "CDCEEEEDDDDDDDCDCDCEFEFDDEEFFDEDEEEBDDBBDDDDDDCCCCCCCCEFED"
0275:                        + "DDCDCDEEEEEEEEEEFEEEEEEDDEEDDEE";
0276:                for (i = 0; i < b.length; ++i) {
0277:                    b[i] = s.charAt(i) - 'E';
0278:                }
0279:                SIZE = b;
0280:
0281:                // code to generate the above string
0282:                //
0283:                // int NA = 0; // not applicable (unused opcode or variable size opcode)
0284:                //
0285:                // b = new int[] {
0286:                // 0, //NOP, // visitInsn
0287:                // 1, //ACONST_NULL, // -
0288:                // 1, //ICONST_M1, // -
0289:                // 1, //ICONST_0, // -
0290:                // 1, //ICONST_1, // -
0291:                // 1, //ICONST_2, // -
0292:                // 1, //ICONST_3, // -
0293:                // 1, //ICONST_4, // -
0294:                // 1, //ICONST_5, // -
0295:                // 2, //LCONST_0, // -
0296:                // 2, //LCONST_1, // -
0297:                // 1, //FCONST_0, // -
0298:                // 1, //FCONST_1, // -
0299:                // 1, //FCONST_2, // -
0300:                // 2, //DCONST_0, // -
0301:                // 2, //DCONST_1, // -
0302:                // 1, //BIPUSH, // visitIntInsn
0303:                // 1, //SIPUSH, // -
0304:                // 1, //LDC, // visitLdcInsn
0305:                // NA, //LDC_W, // -
0306:                // NA, //LDC2_W, // -
0307:                // 1, //ILOAD, // visitVarInsn
0308:                // 2, //LLOAD, // -
0309:                // 1, //FLOAD, // -
0310:                // 2, //DLOAD, // -
0311:                // 1, //ALOAD, // -
0312:                // NA, //ILOAD_0, // -
0313:                // NA, //ILOAD_1, // -
0314:                // NA, //ILOAD_2, // -
0315:                // NA, //ILOAD_3, // -
0316:                // NA, //LLOAD_0, // -
0317:                // NA, //LLOAD_1, // -
0318:                // NA, //LLOAD_2, // -
0319:                // NA, //LLOAD_3, // -
0320:                // NA, //FLOAD_0, // -
0321:                // NA, //FLOAD_1, // -
0322:                // NA, //FLOAD_2, // -
0323:                // NA, //FLOAD_3, // -
0324:                // NA, //DLOAD_0, // -
0325:                // NA, //DLOAD_1, // -
0326:                // NA, //DLOAD_2, // -
0327:                // NA, //DLOAD_3, // -
0328:                // NA, //ALOAD_0, // -
0329:                // NA, //ALOAD_1, // -
0330:                // NA, //ALOAD_2, // -
0331:                // NA, //ALOAD_3, // -
0332:                // -1, //IALOAD, // visitInsn
0333:                // 0, //LALOAD, // -
0334:                // -1, //FALOAD, // -
0335:                // 0, //DALOAD, // -
0336:                // -1, //AALOAD, // -
0337:                // -1, //BALOAD, // -
0338:                // -1, //CALOAD, // -
0339:                // -1, //SALOAD, // -
0340:                // -1, //ISTORE, // visitVarInsn
0341:                // -2, //LSTORE, // -
0342:                // -1, //FSTORE, // -
0343:                // -2, //DSTORE, // -
0344:                // -1, //ASTORE, // -
0345:                // NA, //ISTORE_0, // -
0346:                // NA, //ISTORE_1, // -
0347:                // NA, //ISTORE_2, // -
0348:                // NA, //ISTORE_3, // -
0349:                // NA, //LSTORE_0, // -
0350:                // NA, //LSTORE_1, // -
0351:                // NA, //LSTORE_2, // -
0352:                // NA, //LSTORE_3, // -
0353:                // NA, //FSTORE_0, // -
0354:                // NA, //FSTORE_1, // -
0355:                // NA, //FSTORE_2, // -
0356:                // NA, //FSTORE_3, // -
0357:                // NA, //DSTORE_0, // -
0358:                // NA, //DSTORE_1, // -
0359:                // NA, //DSTORE_2, // -
0360:                // NA, //DSTORE_3, // -
0361:                // NA, //ASTORE_0, // -
0362:                // NA, //ASTORE_1, // -
0363:                // NA, //ASTORE_2, // -
0364:                // NA, //ASTORE_3, // -
0365:                // -3, //IASTORE, // visitInsn
0366:                // -4, //LASTORE, // -
0367:                // -3, //FASTORE, // -
0368:                // -4, //DASTORE, // -
0369:                // -3, //AASTORE, // -
0370:                // -3, //BASTORE, // -
0371:                // -3, //CASTORE, // -
0372:                // -3, //SASTORE, // -
0373:                // -1, //POP, // -
0374:                // -2, //POP2, // -
0375:                // 1, //DUP, // -
0376:                // 1, //DUP_X1, // -
0377:                // 1, //DUP_X2, // -
0378:                // 2, //DUP2, // -
0379:                // 2, //DUP2_X1, // -
0380:                // 2, //DUP2_X2, // -
0381:                // 0, //SWAP, // -
0382:                // -1, //IADD, // -
0383:                // -2, //LADD, // -
0384:                // -1, //FADD, // -
0385:                // -2, //DADD, // -
0386:                // -1, //ISUB, // -
0387:                // -2, //LSUB, // -
0388:                // -1, //FSUB, // -
0389:                // -2, //DSUB, // -
0390:                // -1, //IMUL, // -
0391:                // -2, //LMUL, // -
0392:                // -1, //FMUL, // -
0393:                // -2, //DMUL, // -
0394:                // -1, //IDIV, // -
0395:                // -2, //LDIV, // -
0396:                // -1, //FDIV, // -
0397:                // -2, //DDIV, // -
0398:                // -1, //IREM, // -
0399:                // -2, //LREM, // -
0400:                // -1, //FREM, // -
0401:                // -2, //DREM, // -
0402:                // 0, //INEG, // -
0403:                // 0, //LNEG, // -
0404:                // 0, //FNEG, // -
0405:                // 0, //DNEG, // -
0406:                // -1, //ISHL, // -
0407:                // -1, //LSHL, // -
0408:                // -1, //ISHR, // -
0409:                // -1, //LSHR, // -
0410:                // -1, //IUSHR, // -
0411:                // -1, //LUSHR, // -
0412:                // -1, //IAND, // -
0413:                // -2, //LAND, // -
0414:                // -1, //IOR, // -
0415:                // -2, //LOR, // -
0416:                // -1, //IXOR, // -
0417:                // -2, //LXOR, // -
0418:                // 0, //IINC, // visitIincInsn
0419:                // 1, //I2L, // visitInsn
0420:                // 0, //I2F, // -
0421:                // 1, //I2D, // -
0422:                // -1, //L2I, // -
0423:                // -1, //L2F, // -
0424:                // 0, //L2D, // -
0425:                // 0, //F2I, // -
0426:                // 1, //F2L, // -
0427:                // 1, //F2D, // -
0428:                // -1, //D2I, // -
0429:                // 0, //D2L, // -
0430:                // -1, //D2F, // -
0431:                // 0, //I2B, // -
0432:                // 0, //I2C, // -
0433:                // 0, //I2S, // -
0434:                // -3, //LCMP, // -
0435:                // -1, //FCMPL, // -
0436:                // -1, //FCMPG, // -
0437:                // -3, //DCMPL, // -
0438:                // -3, //DCMPG, // -
0439:                // -1, //IFEQ, // visitJumpInsn
0440:                // -1, //IFNE, // -
0441:                // -1, //IFLT, // -
0442:                // -1, //IFGE, // -
0443:                // -1, //IFGT, // -
0444:                // -1, //IFLE, // -
0445:                // -2, //IF_ICMPEQ, // -
0446:                // -2, //IF_ICMPNE, // -
0447:                // -2, //IF_ICMPLT, // -
0448:                // -2, //IF_ICMPGE, // -
0449:                // -2, //IF_ICMPGT, // -
0450:                // -2, //IF_ICMPLE, // -
0451:                // -2, //IF_ACMPEQ, // -
0452:                // -2, //IF_ACMPNE, // -
0453:                // 0, //GOTO, // -
0454:                // 1, //JSR, // -
0455:                // 0, //RET, // visitVarInsn
0456:                // -1, //TABLESWITCH, // visiTableSwitchInsn
0457:                // -1, //LOOKUPSWITCH, // visitLookupSwitch
0458:                // -1, //IRETURN, // visitInsn
0459:                // -2, //LRETURN, // -
0460:                // -1, //FRETURN, // -
0461:                // -2, //DRETURN, // -
0462:                // -1, //ARETURN, // -
0463:                // 0, //RETURN, // -
0464:                // NA, //GETSTATIC, // visitFieldInsn
0465:                // NA, //PUTSTATIC, // -
0466:                // NA, //GETFIELD, // -
0467:                // NA, //PUTFIELD, // -
0468:                // NA, //INVOKEVIRTUAL, // visitMethodInsn
0469:                // NA, //INVOKESPECIAL, // -
0470:                // NA, //INVOKESTATIC, // -
0471:                // NA, //INVOKEINTERFACE, // -
0472:                // NA, //UNUSED, // NOT VISITED
0473:                // 1, //NEW, // visitTypeInsn
0474:                // 0, //NEWARRAY, // visitIntInsn
0475:                // 0, //ANEWARRAY, // visitTypeInsn
0476:                // 0, //ARRAYLENGTH, // visitInsn
0477:                // NA, //ATHROW, // -
0478:                // 0, //CHECKCAST, // visitTypeInsn
0479:                // 0, //INSTANCEOF, // -
0480:                // -1, //MONITORENTER, // visitInsn
0481:                // -1, //MONITOREXIT, // -
0482:                // NA, //WIDE, // NOT VISITED
0483:                // NA, //MULTIANEWARRAY, // visitMultiANewArrayInsn
0484:                // -1, //IFNULL, // visitJumpInsn
0485:                // -1, //IFNONNULL, // -
0486:                // NA, //GOTO_W, // -
0487:                // NA, //JSR_W, // -
0488:                // };
0489:                // for (i = 0; i < b.length; ++i) {
0490:                // System.err.print((char)('E' + b[i]));
0491:                // }
0492:                // System.err.println();
0493:            }
0494:
0495:            // ------------------------------------------------------------------------
0496:            // Constructor
0497:            // ------------------------------------------------------------------------
0498:
0499:            /**
0500:             * Constructs a new {@link MethodWriter}.
0501:             * 
0502:             * @param cw the class writer in which the method must be added.
0503:             * @param access the method's access flags (see {@link Opcodes}).
0504:             * @param name the method's name.
0505:             * @param desc the method's descriptor (see {@link Type}).
0506:             * @param signature the method's signature. May be <tt>null</tt>.
0507:             * @param exceptions the internal names of the method's exceptions. May be
0508:             *        <tt>null</tt>.
0509:             * @param computeMaxs <tt>true</tt> if the maximum stack size and number
0510:             *        of local variables must be automatically computed.
0511:             */
0512:            MethodWriter(final ClassWriter cw, final int access,
0513:                    final String name, final String desc,
0514:                    final String signature, final String[] exceptions,
0515:                    final boolean computeMaxs) {
0516:                if (cw.firstMethod == null) {
0517:                    cw.firstMethod = this ;
0518:                } else {
0519:                    cw.lastMethod.next = this ;
0520:                }
0521:                cw.lastMethod = this ;
0522:                this .cw = cw;
0523:                this .access = access;
0524:                this .name = cw.newUTF8(name);
0525:                this .desc = cw.newUTF8(desc);
0526:                this .descriptor = desc;
0527:                this .signature = signature;
0528:                if (exceptions != null && exceptions.length > 0) {
0529:                    this .exceptionCount = exceptions.length;
0530:                    this .exceptions = new int[this .exceptionCount];
0531:                    for (int i = 0; i < this .exceptionCount; ++i) {
0532:                        this .exceptions[i] = cw.newClass(exceptions[i]);
0533:                    }
0534:                }
0535:                this .computeMaxs = computeMaxs;
0536:                if (computeMaxs) {
0537:                    // updates maxLocals
0538:                    int size = getArgumentsAndReturnSizes(desc) >> 2;
0539:                    if ((access & Opcodes.ACC_STATIC) != 0) {
0540:                        --size;
0541:                    }
0542:                    this .maxLocals = size;
0543:                    // pushes the first block onto the stack of blocks to be visited
0544:                    this .currentBlock = new Label();
0545:                    this .currentBlock.pushed = true;
0546:                    this .blockStack = this .currentBlock;
0547:                }
0548:            }
0549:
0550:            // ------------------------------------------------------------------------
0551:            // Implementation of the MethodVisitor interface
0552:            // ------------------------------------------------------------------------
0553:
0554:            public AnnotationVisitor visitAnnotationDefault() {
0555:                this .annd = new ByteVector();
0556:                return new AnnotationWriter(this .cw, false, this .annd, null, 0);
0557:            }
0558:
0559:            public AnnotationVisitor visitAnnotation(final String desc,
0560:                    final boolean visible) {
0561:                final ByteVector bv = new ByteVector();
0562:                // write type, and reserve space for values count
0563:                bv.putShort(this .cw.newUTF8(desc)).putShort(0);
0564:                final AnnotationWriter aw = new AnnotationWriter(this .cw, true,
0565:                        bv, bv, 2);
0566:                if (visible) {
0567:                    aw.next = this .anns;
0568:                    this .anns = aw;
0569:                } else {
0570:                    aw.next = this .ianns;
0571:                    this .ianns = aw;
0572:                }
0573:                return aw;
0574:            }
0575:
0576:            public AnnotationVisitor visitParameterAnnotation(
0577:                    final int parameter, final String desc,
0578:                    final boolean visible) {
0579:                final ByteVector bv = new ByteVector();
0580:                // write type, and reserve space for values count
0581:                bv.putShort(this .cw.newUTF8(desc)).putShort(0);
0582:                final AnnotationWriter aw = new AnnotationWriter(this .cw, true,
0583:                        bv, bv, 2);
0584:                if (visible) {
0585:                    if (this .panns == null) {
0586:                        this .panns = new AnnotationWriter[Type
0587:                                .getArgumentTypes(this .descriptor).length];
0588:                    }
0589:                    aw.next = this .panns[parameter];
0590:                    this .panns[parameter] = aw;
0591:                } else {
0592:                    if (this .ipanns == null) {
0593:                        this .ipanns = new AnnotationWriter[Type
0594:                                .getArgumentTypes(this .descriptor).length];
0595:                    }
0596:                    aw.next = this .ipanns[parameter];
0597:                    this .ipanns[parameter] = aw;
0598:                }
0599:                return aw;
0600:            }
0601:
0602:            public void visitAttribute(final Attribute attr) {
0603:                if (attr.isCodeAttribute()) {
0604:                    attr.next = this .cattrs;
0605:                    this .cattrs = attr;
0606:                } else {
0607:                    attr.next = this .attrs;
0608:                    this .attrs = attr;
0609:                }
0610:            }
0611:
0612:            public void visitCode() {
0613:            }
0614:
0615:            public void visitInsn(final int opcode) {
0616:                if (this .computeMaxs) {
0617:                    // updates current and min stack sizes
0618:                    final int size = this .stackSize + MethodWriter.SIZE[opcode];
0619:                    if (size > this .maxStackSize) {
0620:                        this .maxStackSize = size;
0621:                    }
0622:                    this .stackSize = size;
0623:                    // if opcode == ATHROW or xRETURN, ends current block (no successor)
0624:                    if ((opcode >= Opcodes.IRETURN && opcode <= Opcodes.RETURN)
0625:                            || opcode == Opcodes.ATHROW) {
0626:                        if (this .currentBlock != null) {
0627:                            this .currentBlock.maxStackSize = this .maxStackSize;
0628:                            this .currentBlock = null;
0629:                        }
0630:                    }
0631:                }
0632:                // adds the instruction to the bytecode of the method
0633:                this .code.putByte(opcode);
0634:            }
0635:
0636:            public void visitIntInsn(final int opcode, final int operand) {
0637:                if (this .computeMaxs && opcode != Opcodes.NEWARRAY) {
0638:                    // updates current and min stack sizes only if opcode == NEWARRAY
0639:                    // (stack size variation = 0 for BIPUSH or SIPUSH)
0640:                    final int size = this .stackSize + 1;
0641:                    if (size > this .maxStackSize) {
0642:                        this .maxStackSize = size;
0643:                    }
0644:                    this .stackSize = size;
0645:                }
0646:                // adds the instruction to the bytecode of the method
0647:                if (opcode == Opcodes.SIPUSH) {
0648:                    this .code.put12(opcode, operand);
0649:                } else { // BIPUSH or NEWARRAY
0650:                    this .code.put11(opcode, operand);
0651:                }
0652:            }
0653:
0654:            public void visitVarInsn(final int opcode, final int var) {
0655:                if (this .computeMaxs) {
0656:                    // updates current and min stack sizes
0657:                    if (opcode == Opcodes.RET) {
0658:                        // no stack change, but end of current block (no successor)
0659:                        if (this .currentBlock != null) {
0660:                            this .currentBlock.maxStackSize = this .maxStackSize;
0661:                            this .currentBlock = null;
0662:                        }
0663:                    } else { // xLOAD or xSTORE
0664:                        final int size = this .stackSize
0665:                                + MethodWriter.SIZE[opcode];
0666:                        if (size > this .maxStackSize) {
0667:                            this .maxStackSize = size;
0668:                        }
0669:                        this .stackSize = size;
0670:                    }
0671:                    // updates min locals
0672:                    int n;
0673:                    if (opcode == Opcodes.LLOAD || opcode == Opcodes.DLOAD
0674:                            || opcode == Opcodes.LSTORE
0675:                            || opcode == Opcodes.DSTORE) {
0676:                        n = var + 2;
0677:                    } else {
0678:                        n = var + 1;
0679:                    }
0680:                    if (n > this .maxLocals) {
0681:                        this .maxLocals = n;
0682:                    }
0683:                }
0684:                // adds the instruction to the bytecode of the method
0685:                if (var < 4 && opcode != Opcodes.RET) {
0686:                    int opt;
0687:                    if (opcode < Opcodes.ISTORE) {
0688:                        /* ILOAD_0 */
0689:                        opt = 26 + ((opcode - Opcodes.ILOAD) << 2) + var;
0690:                    } else {
0691:                        /* ISTORE_0 */
0692:                        opt = 59 + ((opcode - Opcodes.ISTORE) << 2) + var;
0693:                    }
0694:                    this .code.putByte(opt);
0695:                } else if (var >= 256) {
0696:                    this .code.putByte(196 /* WIDE */).put12(opcode, var);
0697:                } else {
0698:                    this .code.put11(opcode, var);
0699:                }
0700:            }
0701:
0702:            public void visitTypeInsn(final int opcode, final String desc) {
0703:                if (this .computeMaxs && opcode == Opcodes.NEW) {
0704:                    // updates current and min stack sizes only if opcode == NEW
0705:                    // (stack size variation = 0 for ANEWARRAY, CHECKCAST, INSTANCEOF)
0706:                    final int size = this .stackSize + 1;
0707:                    if (size > this .maxStackSize) {
0708:                        this .maxStackSize = size;
0709:                    }
0710:                    this .stackSize = size;
0711:                }
0712:                // adds the instruction to the bytecode of the method
0713:                this .code.put12(opcode, this .cw.newClass(desc));
0714:            }
0715:
0716:            public void visitFieldInsn(final int opcode, final String owner,
0717:                    final String name, final String desc) {
0718:                if (this .computeMaxs) {
0719:                    int size;
0720:                    // computes the stack size variation
0721:                    final char c = desc.charAt(0);
0722:                    switch (opcode) {
0723:                    case Opcodes.GETSTATIC:
0724:                        size = this .stackSize + (c == 'D' || c == 'J' ? 2 : 1);
0725:                        break;
0726:                    case Opcodes.PUTSTATIC:
0727:                        size = this .stackSize
0728:                                + (c == 'D' || c == 'J' ? -2 : -1);
0729:                        break;
0730:                    case Opcodes.GETFIELD:
0731:                        size = this .stackSize + (c == 'D' || c == 'J' ? 1 : 0);
0732:                        break;
0733:                    // case Constants.PUTFIELD:
0734:                    default:
0735:                        size = this .stackSize
0736:                                + (c == 'D' || c == 'J' ? -3 : -2);
0737:                        break;
0738:                    }
0739:                    // updates current and min stack sizes
0740:                    if (size > this .maxStackSize) {
0741:                        this .maxStackSize = size;
0742:                    }
0743:                    this .stackSize = size;
0744:                }
0745:                // adds the instruction to the bytecode of the method
0746:                this .code.put12(opcode, this .cw.newField(owner, name, desc));
0747:            }
0748:
0749:            public void visitMethodInsn(final int opcode, final String owner,
0750:                    final String name, final String desc) {
0751:                final boolean itf = opcode == Opcodes.INVOKEINTERFACE;
0752:                final Item i = this .cw.newMethodItem(owner, name, desc, itf);
0753:                int argSize = i.intVal;
0754:                if (this .computeMaxs) {
0755:                    /*
0756:                     * computes the stack size variation. In order not to recompute
0757:                     * several times this variation for the same Item, we use the intVal
0758:                     * field of this item to store this variation, once it has been
0759:                     * computed. More precisely this intVal field stores the sizes of
0760:                     * the arguments and of the return value corresponding to desc.
0761:                     */
0762:                    if (argSize == 0) {
0763:                        // the above sizes have not been computed yet, so we compute
0764:                        // them...
0765:                        argSize = getArgumentsAndReturnSizes(desc);
0766:                        // ... and we save them in order not to recompute them in the
0767:                        // future
0768:                        i.intVal = argSize;
0769:                    }
0770:                    int size;
0771:                    if (opcode == Opcodes.INVOKESTATIC) {
0772:                        size = this .stackSize - (argSize >> 2)
0773:                                + (argSize & 0x03) + 1;
0774:                    } else {
0775:                        size = this .stackSize - (argSize >> 2)
0776:                                + (argSize & 0x03);
0777:                    }
0778:                    // updates current and min stack sizes
0779:                    if (size > this .maxStackSize) {
0780:                        this .maxStackSize = size;
0781:                    }
0782:                    this .stackSize = size;
0783:                }
0784:                // adds the instruction to the bytecode of the method
0785:                if (itf) {
0786:                    if (!this .computeMaxs) {
0787:                        if (argSize == 0) {
0788:                            argSize = getArgumentsAndReturnSizes(desc);
0789:                            i.intVal = argSize;
0790:                        }
0791:                    }
0792:                    this .code.put12(Opcodes.INVOKEINTERFACE, i.index).put11(
0793:                            argSize >> 2, 0);
0794:                } else {
0795:                    this .code.put12(opcode, i.index);
0796:                }
0797:            }
0798:
0799:            public void visitJumpInsn(final int opcode, final Label label) {
0800:                if (this .computeMaxs) {
0801:                    if (opcode == Opcodes.GOTO) {
0802:                        // no stack change, but end of current block (with one new
0803:                        // successor)
0804:                        if (this .currentBlock != null) {
0805:                            this .currentBlock.maxStackSize = this .maxStackSize;
0806:                            addSuccessor(this .stackSize, label);
0807:                            this .currentBlock = null;
0808:                        }
0809:                    } else if (opcode == Opcodes.JSR) {
0810:                        if (this .currentBlock != null) {
0811:                            addSuccessor(this .stackSize + 1, label);
0812:                        }
0813:                    } else {
0814:                        // updates current stack size (min stack size unchanged because
0815:                        // stack size variation always negative in this case)
0816:                        this .stackSize += MethodWriter.SIZE[opcode];
0817:                        if (this .currentBlock != null) {
0818:                            addSuccessor(this .stackSize, label);
0819:                        }
0820:                    }
0821:                }
0822:                // adds the instruction to the bytecode of the method
0823:                if (label.resolved
0824:                        && label.position - this .code.length < Short.MIN_VALUE) {
0825:                    /*
0826:                     * case of a backward jump with an offset < -32768. In this case we
0827:                     * automatically replace GOTO with GOTO_W, JSR with JSR_W and IFxxx
0828:                     * <l> with IFNOTxxx <l'> GOTO_W <l>, where IFNOTxxx is the
0829:                     * "opposite" opcode of IFxxx (i.e., IFNE for IFEQ) and where <l'>
0830:                     * designates the instruction just after the GOTO_W.
0831:                     */
0832:                    if (opcode == Opcodes.GOTO) {
0833:                        this .code.putByte(200); // GOTO_W
0834:                    } else if (opcode == Opcodes.JSR) {
0835:                        this .code.putByte(201); // JSR_W
0836:                    } else {
0837:                        this .code
0838:                                .putByte(opcode <= 166 ? ((opcode + 1) ^ 1) - 1
0839:                                        : opcode ^ 1);
0840:                        this .code.putShort(8); // jump offset
0841:                        this .code.putByte(200); // GOTO_W
0842:                    }
0843:                    label.put(this , this .code, this .code.length - 1, true);
0844:                } else {
0845:                    /*
0846:                     * case of a backward jump with an offset >= -32768, or of a forward
0847:                     * jump with, of course, an unknown offset. In these cases we store
0848:                     * the offset in 2 bytes (which will be increased in
0849:                     * resizeInstructions, if needed).
0850:                     */
0851:                    this .code.putByte(opcode);
0852:                    label.put(this , this .code, this .code.length - 1, false);
0853:                }
0854:            }
0855:
0856:            public void visitLabel(final Label label) {
0857:                if (this .computeMaxs) {
0858:                    if (this .currentBlock != null) {
0859:                        // ends current block (with one new successor)
0860:                        this .currentBlock.maxStackSize = this .maxStackSize;
0861:                        addSuccessor(this .stackSize, label);
0862:                    }
0863:                    // begins a new current block,
0864:                    // resets the relative current and min stack sizes
0865:                    this .currentBlock = label;
0866:                    this .stackSize = 0;
0867:                    this .maxStackSize = 0;
0868:                }
0869:                // resolves previous forward references to label, if any
0870:                this .resize |= label.resolve(this , this .code.length,
0871:                        this .code.data);
0872:            }
0873:
0874:            public void visitLdcInsn(final Object cst) {
0875:                final Item i = this .cw.newConstItem(cst);
0876:                if (this .computeMaxs) {
0877:                    int size;
0878:                    // computes the stack size variation
0879:                    if (i.type == ClassWriter.LONG
0880:                            || i.type == ClassWriter.DOUBLE) {
0881:                        size = this .stackSize + 2;
0882:                    } else {
0883:                        size = this .stackSize + 1;
0884:                    }
0885:                    // updates current and min stack sizes
0886:                    if (size > this .maxStackSize) {
0887:                        this .maxStackSize = size;
0888:                    }
0889:                    this .stackSize = size;
0890:                }
0891:                // adds the instruction to the bytecode of the method
0892:                final int index = i.index;
0893:                if (i.type == ClassWriter.LONG || i.type == ClassWriter.DOUBLE) {
0894:                    this .code.put12(20 /* LDC2_W */, index);
0895:                } else if (index >= 256) {
0896:                    this .code.put12(19 /* LDC_W */, index);
0897:                } else {
0898:                    this .code.put11(Opcodes.LDC, index);
0899:                }
0900:            }
0901:
0902:            public void visitIincInsn(final int var, final int increment) {
0903:                if (this .computeMaxs) {
0904:                    // updates min locals only (no stack change)
0905:                    final int n = var + 1;
0906:                    if (n > this .maxLocals) {
0907:                        this .maxLocals = n;
0908:                    }
0909:                }
0910:                // adds the instruction to the bytecode of the method
0911:                if ((var > 255) || (increment > 127) || (increment < -128)) {
0912:                    this .code.putByte(196 /* WIDE */).put12(Opcodes.IINC, var)
0913:                            .putShort(increment);
0914:                } else {
0915:                    this .code.putByte(Opcodes.IINC).put11(var, increment);
0916:                }
0917:            }
0918:
0919:            public void visitTableSwitchInsn(final int min, final int max,
0920:                    final Label dflt, final Label labels[]) {
0921:                if (this .computeMaxs) {
0922:                    // updates current stack size (min stack size unchanged)
0923:                    --this .stackSize;
0924:                    // ends current block (with many new successors)
0925:                    if (this .currentBlock != null) {
0926:                        this .currentBlock.maxStackSize = this .maxStackSize;
0927:                        addSuccessor(this .stackSize, dflt);
0928:                        for (int i = 0; i < labels.length; ++i) {
0929:                            addSuccessor(this .stackSize, labels[i]);
0930:                        }
0931:                        this .currentBlock = null;
0932:                    }
0933:                }
0934:                // adds the instruction to the bytecode of the method
0935:                final int source = this .code.length;
0936:                this .code.putByte(Opcodes.TABLESWITCH);
0937:                while (this .code.length % 4 != 0) {
0938:                    this .code.putByte(0);
0939:                }
0940:                dflt.put(this , this .code, source, true);
0941:                this .code.putInt(min).putInt(max);
0942:                for (int i = 0; i < labels.length; ++i) {
0943:                    labels[i].put(this , this .code, source, true);
0944:                }
0945:            }
0946:
0947:            public void visitLookupSwitchInsn(final Label dflt,
0948:                    final int keys[], final Label labels[]) {
0949:                if (this .computeMaxs) {
0950:                    // updates current stack size (min stack size unchanged)
0951:                    --this .stackSize;
0952:                    // ends current block (with many new successors)
0953:                    if (this .currentBlock != null) {
0954:                        this .currentBlock.maxStackSize = this .maxStackSize;
0955:                        addSuccessor(this .stackSize, dflt);
0956:                        for (int i = 0; i < labels.length; ++i) {
0957:                            addSuccessor(this .stackSize, labels[i]);
0958:                        }
0959:                        this .currentBlock = null;
0960:                    }
0961:                }
0962:                // adds the instruction to the bytecode of the method
0963:                final int source = this .code.length;
0964:                this .code.putByte(Opcodes.LOOKUPSWITCH);
0965:                while (this .code.length % 4 != 0) {
0966:                    this .code.putByte(0);
0967:                }
0968:                dflt.put(this , this .code, source, true);
0969:                this .code.putInt(labels.length);
0970:                for (int i = 0; i < labels.length; ++i) {
0971:                    this .code.putInt(keys[i]);
0972:                    labels[i].put(this , this .code, source, true);
0973:                }
0974:            }
0975:
0976:            public void visitMultiANewArrayInsn(final String desc,
0977:                    final int dims) {
0978:                if (this .computeMaxs) {
0979:                    // updates current stack size (min stack size unchanged because
0980:                    // stack size variation always negative or null)
0981:                    this .stackSize += 1 - dims;
0982:                }
0983:                // adds the instruction to the bytecode of the method
0984:                this .code.put12(Opcodes.MULTIANEWARRAY, this .cw.newClass(desc))
0985:                        .putByte(dims);
0986:            }
0987:
0988:            public void visitTryCatchBlock(final Label start, final Label end,
0989:                    final Label handler, final String type) {
0990:                if (this .computeMaxs) {
0991:                    // pushes handler block onto the stack of blocks to be visited
0992:                    if (!handler.pushed) {
0993:                        handler.beginStackSize = 1;
0994:                        handler.pushed = true;
0995:                        handler.next = this .blockStack;
0996:                        this .blockStack = handler;
0997:                    }
0998:                }
0999:                ++this .catchCount;
1000:                final Handler h = new Handler();
1001:                h.start = start;
1002:                h.end = end;
1003:                h.handler = handler;
1004:                h.desc = type;
1005:                h.type = type != null ? this .cw.newClass(type) : 0;
1006:                if (this .lastHandler == null) {
1007:                    this .catchTable = h;
1008:                } else {
1009:                    this .lastHandler.next = h;
1010:                }
1011:                this .lastHandler = h;
1012:            }
1013:
1014:            public void visitLocalVariable(final String name,
1015:                    final String desc, final String signature,
1016:                    final Label start, final Label end, final int index) {
1017:                if (signature != null) {
1018:                    if (this .localVarType == null) {
1019:                        this .localVarType = new ByteVector();
1020:                    }
1021:                    ++this .localVarTypeCount;
1022:                    this .localVarType.putShort(start.position).putShort(
1023:                            end.position - start.position).putShort(
1024:                            this .cw.newUTF8(name)).putShort(
1025:                            this .cw.newUTF8(signature)).putShort(index);
1026:                }
1027:                if (this .localVar == null) {
1028:                    this .localVar = new ByteVector();
1029:                }
1030:                ++this .localVarCount;
1031:                this .localVar.putShort(start.position).putShort(
1032:                        end.position - start.position).putShort(
1033:                        this .cw.newUTF8(name)).putShort(this .cw.newUTF8(desc))
1034:                        .putShort(index);
1035:            }
1036:
1037:            public void visitLineNumber(final int line, final Label start) {
1038:                if (this .lineNumber == null) {
1039:                    this .lineNumber = new ByteVector();
1040:                }
1041:                ++this .lineNumberCount;
1042:                this .lineNumber.putShort(start.position);
1043:                this .lineNumber.putShort(line);
1044:            }
1045:
1046:            public void visitMaxs(final int maxStack, final int maxLocals) {
1047:                if (this .computeMaxs) {
1048:                    // true (non relative) min stack size
1049:                    int max = 0;
1050:                    /*
1051:                     * control flow analysis algorithm: while the block stack is not
1052:                     * empty, pop a block from this stack, update the min stack size,
1053:                     * compute the true (non relative) begin stack size of the
1054:                     * successors of this block, and push these successors onto the
1055:                     * stack (unless they have already been pushed onto the stack).
1056:                     * Note: by hypothesis, the {@link Label#beginStackSize} of the
1057:                     * blocks in the block stack are the true (non relative) beginning
1058:                     * stack sizes of these blocks.
1059:                     */
1060:                    Label stack = this .blockStack;
1061:                    while (stack != null) {
1062:                        // pops a block from the stack
1063:                        Label l = stack;
1064:                        stack = stack.next;
1065:                        // computes the true (non relative) min stack size of this block
1066:                        final int start = l.beginStackSize;
1067:                        final int blockMax = start + l.maxStackSize;
1068:                        // updates the global min stack size
1069:                        if (blockMax > max) {
1070:                            max = blockMax;
1071:                        }
1072:                        // analyses the successors of the block
1073:                        Edge b = l.successors;
1074:                        while (b != null) {
1075:                            l = b.successor;
1076:                            // if this successor has not already been pushed onto the
1077:                            // stack...
1078:                            if (!l.pushed) {
1079:                                // computes the true beginning stack size of this
1080:                                // successor block
1081:                                l.beginStackSize = start + b.stackSize;
1082:                                // pushes this successor onto the stack
1083:                                l.pushed = true;
1084:                                l.next = stack;
1085:                                stack = l;
1086:                            }
1087:                            b = b.next;
1088:                        }
1089:                    }
1090:                    this .maxStack = max;
1091:                } else {
1092:                    this .maxStack = maxStack;
1093:                    this .maxLocals = maxLocals;
1094:                }
1095:            }
1096:
1097:            public void visitEnd() {
1098:            }
1099:
1100:            // ------------------------------------------------------------------------
1101:            // Utility methods: control flow analysis algorithm
1102:            // ------------------------------------------------------------------------
1103:
1104:            /**
1105:             * Computes the size of the arguments and of the return value of a method.
1106:             * 
1107:             * @param desc the descriptor of a method.
1108:             * @return the size of the arguments of the method (plus one for the
1109:             *         implicit this argument), argSize, and the size of its return
1110:             *         value, retSize, packed into a single int i =
1111:             *         <tt>(argSize << 2) | retSize</tt> (argSize is therefore equal
1112:             *         to <tt>i >> 2</tt>, and retSize to <tt>i & 0x03</tt>).
1113:             */
1114:            private static int getArgumentsAndReturnSizes(final String desc) {
1115:                int n = 1;
1116:                int c = 1;
1117:                while (true) {
1118:                    char car = desc.charAt(c++);
1119:                    if (car == ')') {
1120:                        car = desc.charAt(c);
1121:                        return n << 2
1122:                                | (car == 'V' ? 0
1123:                                        : (car == 'D' || car == 'J' ? 2 : 1));
1124:                    } else if (car == 'L') {
1125:                        while (desc.charAt(c++) != ';') {
1126:                        }
1127:                        n += 1;
1128:                    } else if (car == '[') {
1129:                        while ((car = desc.charAt(c)) == '[') {
1130:                            ++c;
1131:                        }
1132:                        if (car == 'D' || car == 'J') {
1133:                            n -= 1;
1134:                        }
1135:                    } else if (car == 'D' || car == 'J') {
1136:                        n += 2;
1137:                    } else {
1138:                        n += 1;
1139:                    }
1140:                }
1141:            }
1142:
1143:            /**
1144:             * Adds a successor to the {@link #currentBlock currentBlock} block.
1145:             * 
1146:             * @param stackSize the current (relative) stack size in the current block.
1147:             * @param successor the successor block to be added to the current block.
1148:             */
1149:            private void addSuccessor(final int stackSize, final Label successor) {
1150:                final Edge b = new Edge();
1151:                // initializes the previous Edge object...
1152:                b.stackSize = stackSize;
1153:                b.successor = successor;
1154:                // ...and adds it to the successor list of the currentBlock block
1155:                b.next = this .currentBlock.successors;
1156:                this .currentBlock.successors = b;
1157:            }
1158:
1159:            // ------------------------------------------------------------------------
1160:            // Utility methods: dump bytecode array
1161:            // ------------------------------------------------------------------------
1162:
1163:            /**
1164:             * Returns the size of the bytecode of this method.
1165:             * 
1166:             * @return the size of the bytecode of this method.
1167:             */
1168:            final int getSize() {
1169:                if (this .classReaderOffset != 0) {
1170:                    return 6 + this .classReaderLength;
1171:                }
1172:                if (this .resize) {
1173:                    // replaces the temporary jump opcodes introduced by Label.resolve.
1174:                    resizeInstructions(new int[0], new int[0], 0);
1175:                }
1176:                int size = 8;
1177:                if (this .code.length > 0) {
1178:                    this .cw.newUTF8("Code");
1179:                    size += 18 + this .code.length + 8 * this .catchCount;
1180:                    if (this .localVar != null) {
1181:                        this .cw.newUTF8("LocalVariableTable");
1182:                        size += 8 + this .localVar.length;
1183:                    }
1184:                    if (this .localVarType != null) {
1185:                        this .cw.newUTF8("LocalVariableTypeTable");
1186:                        size += 8 + this .localVarType.length;
1187:                    }
1188:                    if (this .lineNumber != null) {
1189:                        this .cw.newUTF8("LineNumberTable");
1190:                        size += 8 + this .lineNumber.length;
1191:                    }
1192:                    if (this .cattrs != null) {
1193:                        size += this .cattrs
1194:                                .getSize(this .cw, this .code.data,
1195:                                        this .code.length, this .maxStack,
1196:                                        this .maxLocals);
1197:                    }
1198:                }
1199:                if (this .exceptionCount > 0) {
1200:                    this .cw.newUTF8("Exceptions");
1201:                    size += 8 + 2 * this .exceptionCount;
1202:                }
1203:                if ((this .access & Opcodes.ACC_SYNTHETIC) != 0
1204:                        && (this .cw.version & 0xffff) < Opcodes.V1_5) {
1205:                    this .cw.newUTF8("Synthetic");
1206:                    size += 6;
1207:                }
1208:                if ((this .access & Opcodes.ACC_DEPRECATED) != 0) {
1209:                    this .cw.newUTF8("Deprecated");
1210:                    size += 6;
1211:                }
1212:                if (this .cw.version == Opcodes.V1_4) {
1213:                    if ((this .access & Opcodes.ACC_VARARGS) != 0) {
1214:                        this .cw.newUTF8("Varargs");
1215:                        size += 6;
1216:                    }
1217:                    if ((this .access & Opcodes.ACC_BRIDGE) != 0) {
1218:                        this .cw.newUTF8("Bridge");
1219:                        size += 6;
1220:                    }
1221:                }
1222:                if (this .signature != null) {
1223:                    this .cw.newUTF8("Signature");
1224:                    this .cw.newUTF8(this .signature);
1225:                    size += 8;
1226:                }
1227:                if (this .annd != null) {
1228:                    this .cw.newUTF8("AnnotationDefault");
1229:                    size += 6 + this .annd.length;
1230:                }
1231:                if (this .anns != null) {
1232:                    this .cw.newUTF8("RuntimeVisibleAnnotations");
1233:                    size += 8 + this .anns.getSize();
1234:                }
1235:                if (this .ianns != null) {
1236:                    this .cw.newUTF8("RuntimeInvisibleAnnotations");
1237:                    size += 8 + this .ianns.getSize();
1238:                }
1239:                if (this .panns != null) {
1240:                    this .cw.newUTF8("RuntimeVisibleParameterAnnotations");
1241:                    size += 7 + 2 * this .panns.length;
1242:                    for (int i = this .panns.length - 1; i >= 0; --i) {
1243:                        size += this .panns[i] == null ? 0 : this .panns[i]
1244:                                .getSize();
1245:                    }
1246:                }
1247:                if (this .ipanns != null) {
1248:                    this .cw.newUTF8("RuntimeInvisibleParameterAnnotations");
1249:                    size += 7 + 2 * this .ipanns.length;
1250:                    for (int i = this .ipanns.length - 1; i >= 0; --i) {
1251:                        size += this .ipanns[i] == null ? 0 : this .ipanns[i]
1252:                                .getSize();
1253:                    }
1254:                }
1255:                if (this .attrs != null) {
1256:                    size += this .attrs.getSize(this .cw, null, 0, -1, -1);
1257:                }
1258:                return size;
1259:            }
1260:
1261:            /**
1262:             * Puts the bytecode of this method in the given byte vector.
1263:             * 
1264:             * @param out the byte vector into which the bytecode of this method must be
1265:             *        copied.
1266:             */
1267:            final void put(final ByteVector out) {
1268:                out.putShort(this .access).putShort(this .name).putShort(
1269:                        this .desc);
1270:                if (this .classReaderOffset != 0) {
1271:                    out.putByteArray(this .cw.cr.b, this .classReaderOffset,
1272:                            this .classReaderLength);
1273:                    return;
1274:                }
1275:                int attributeCount = 0;
1276:                if (this .code.length > 0) {
1277:                    ++attributeCount;
1278:                }
1279:                if (this .exceptionCount > 0) {
1280:                    ++attributeCount;
1281:                }
1282:                if ((this .access & Opcodes.ACC_SYNTHETIC) != 0
1283:                        && (this .cw.version & 0xffff) < Opcodes.V1_5) {
1284:                    ++attributeCount;
1285:                }
1286:                if ((this .access & Opcodes.ACC_DEPRECATED) != 0) {
1287:                    ++attributeCount;
1288:                }
1289:                if (this .cw.version == Opcodes.V1_4) {
1290:                    if ((this .access & Opcodes.ACC_VARARGS) != 0) {
1291:                        ++attributeCount;
1292:                    }
1293:                    if ((this .access & Opcodes.ACC_BRIDGE) != 0) {
1294:                        ++attributeCount;
1295:                    }
1296:                }
1297:                if (this .signature != null) {
1298:                    ++attributeCount;
1299:                }
1300:                if (this .annd != null) {
1301:                    ++attributeCount;
1302:                }
1303:                if (this .anns != null) {
1304:                    ++attributeCount;
1305:                }
1306:                if (this .ianns != null) {
1307:                    ++attributeCount;
1308:                }
1309:                if (this .panns != null) {
1310:                    ++attributeCount;
1311:                }
1312:                if (this .ipanns != null) {
1313:                    ++attributeCount;
1314:                }
1315:                if (this .attrs != null) {
1316:                    attributeCount += this .attrs.getCount();
1317:                }
1318:                out.putShort(attributeCount);
1319:                if (this .code.length > 0) {
1320:                    int size = 12 + this .code.length + 8 * this .catchCount;
1321:                    if (this .localVar != null) {
1322:                        size += 8 + this .localVar.length;
1323:                    }
1324:                    if (this .localVarType != null) {
1325:                        size += 8 + this .localVarType.length;
1326:                    }
1327:                    if (this .lineNumber != null) {
1328:                        size += 8 + this .lineNumber.length;
1329:                    }
1330:                    if (this .cattrs != null) {
1331:                        size += this .cattrs
1332:                                .getSize(this .cw, this .code.data,
1333:                                        this .code.length, this .maxStack,
1334:                                        this .maxLocals);
1335:                    }
1336:                    out.putShort(this .cw.newUTF8("Code")).putInt(size);
1337:                    out.putShort(this .maxStack).putShort(this .maxLocals);
1338:                    out.putInt(this .code.length).putByteArray(this .code.data,
1339:                            0, this .code.length);
1340:                    out.putShort(this .catchCount);
1341:                    if (this .catchCount > 0) {
1342:                        Handler h = this .catchTable;
1343:                        while (h != null) {
1344:                            out.putShort(h.start.position).putShort(
1345:                                    h.end.position)
1346:                                    .putShort(h.handler.position).putShort(
1347:                                            h.type);
1348:                            h = h.next;
1349:                        }
1350:                    }
1351:                    attributeCount = 0;
1352:                    if (this .localVar != null) {
1353:                        ++attributeCount;
1354:                    }
1355:                    if (this .localVarType != null) {
1356:                        ++attributeCount;
1357:                    }
1358:                    if (this .lineNumber != null) {
1359:                        ++attributeCount;
1360:                    }
1361:                    if (this .cattrs != null) {
1362:                        attributeCount += this .cattrs.getCount();
1363:                    }
1364:                    out.putShort(attributeCount);
1365:                    if (this .localVar != null) {
1366:                        out.putShort(this .cw.newUTF8("LocalVariableTable"));
1367:                        out.putInt(this .localVar.length + 2).putShort(
1368:                                this .localVarCount);
1369:                        out.putByteArray(this .localVar.data, 0,
1370:                                this .localVar.length);
1371:                    }
1372:                    if (this .localVarType != null) {
1373:                        out.putShort(this .cw.newUTF8("LocalVariableTypeTable"));
1374:                        out.putInt(this .localVarType.length + 2).putShort(
1375:                                this .localVarTypeCount);
1376:                        out.putByteArray(this .localVarType.data, 0,
1377:                                this .localVarType.length);
1378:                    }
1379:                    if (this .lineNumber != null) {
1380:                        out.putShort(this .cw.newUTF8("LineNumberTable"));
1381:                        out.putInt(this .lineNumber.length + 2).putShort(
1382:                                this .lineNumberCount);
1383:                        out.putByteArray(this .lineNumber.data, 0,
1384:                                this .lineNumber.length);
1385:                    }
1386:                    if (this .cattrs != null) {
1387:                        this .cattrs.put(this .cw, this .code.data,
1388:                                this .code.length, this .maxLocals,
1389:                                this .maxStack, out);
1390:                    }
1391:                }
1392:                if (this .exceptionCount > 0) {
1393:                    out.putShort(this .cw.newUTF8("Exceptions")).putInt(
1394:                            2 * this .exceptionCount + 2);
1395:                    out.putShort(this .exceptionCount);
1396:                    for (int i = 0; i < this .exceptionCount; ++i) {
1397:                        out.putShort(this .exceptions[i]);
1398:                    }
1399:                }
1400:                if ((this .access & Opcodes.ACC_SYNTHETIC) != 0
1401:                        && (this .cw.version & 0xffff) < Opcodes.V1_5) {
1402:                    out.putShort(this .cw.newUTF8("Synthetic")).putInt(0);
1403:                }
1404:                if ((this .access & Opcodes.ACC_DEPRECATED) != 0) {
1405:                    out.putShort(this .cw.newUTF8("Deprecated")).putInt(0);
1406:                }
1407:                if (this .cw.version == Opcodes.V1_4) {
1408:                    if ((this .access & Opcodes.ACC_VARARGS) != 0) {
1409:                        out.putShort(this .cw.newUTF8("Varargs")).putInt(0);
1410:                    }
1411:                    if ((this .access & Opcodes.ACC_BRIDGE) != 0) {
1412:                        out.putShort(this .cw.newUTF8("Bridge")).putInt(0);
1413:                    }
1414:                }
1415:                if (this .signature != null) {
1416:                    out.putShort(this .cw.newUTF8("Signature")).putInt(2)
1417:                            .putShort(this .cw.newUTF8(this .signature));
1418:                }
1419:                if (this .annd != null) {
1420:                    out.putShort(this .cw.newUTF8("AnnotationDefault"));
1421:                    out.putInt(this .annd.length);
1422:                    out.putByteArray(this .annd.data, 0, this .annd.length);
1423:                }
1424:                if (this .anns != null) {
1425:                    out.putShort(this .cw.newUTF8("RuntimeVisibleAnnotations"));
1426:                    this .anns.put(out);
1427:                }
1428:                if (this .ianns != null) {
1429:                    out
1430:                            .putShort(this .cw
1431:                                    .newUTF8("RuntimeInvisibleAnnotations"));
1432:                    this .ianns.put(out);
1433:                }
1434:                if (this .panns != null) {
1435:                    out.putShort(this .cw
1436:                            .newUTF8("RuntimeVisibleParameterAnnotations"));
1437:                    AnnotationWriter.put(this .panns, out);
1438:                }
1439:                if (this .ipanns != null) {
1440:                    out.putShort(this .cw
1441:                            .newUTF8("RuntimeInvisibleParameterAnnotations"));
1442:                    AnnotationWriter.put(this .ipanns, out);
1443:                }
1444:                if (this .attrs != null) {
1445:                    this .attrs.put(this .cw, null, 0, -1, -1, out);
1446:                }
1447:            }
1448:
1449:            // ------------------------------------------------------------------------
1450:            // Utility methods: instruction resizing (used to handle GOTO_W and JSR_W)
1451:            // ------------------------------------------------------------------------
1452:
1453:            /**
1454:             * Resizes the designated instructions, while keeping jump offsets and
1455:             * instruction addresses consistent. This may require to resize other
1456:             * existing instructions, or even to introduce new instructions: for
1457:             * example, increasing the size of an instruction by 2 at the middle of a
1458:             * method can increases the offset of an IFEQ instruction from 32766 to
1459:             * 32768, in which case IFEQ 32766 must be replaced with IFNEQ 8 GOTO_W
1460:             * 32765. This, in turn, may require to increase the size of another jump
1461:             * instruction, and so on... All these operations are handled automatically
1462:             * by this method. <p> <i>This method must be called after all the method
1463:             * that is being built has been visited</i>. In particular, the
1464:             * {@link Label Label} objects used to construct the method are no longer
1465:             * valid after this method has been called.
1466:             * 
1467:             * @param indexes current positions of the instructions to be resized. Each
1468:             *        instruction must be designated by the index of its <i>last</i>
1469:             *        byte, plus one (or, in other words, by the index of the <i>first</i>
1470:             *        byte of the <i>next</i> instruction).
1471:             * @param sizes the number of bytes to be <i>added</i> to the above
1472:             *        instructions. More precisely, for each i &lt; <tt>len</tt>,
1473:             *        <tt>sizes</tt>[i] bytes will be added at the end of the
1474:             *        instruction designated by <tt>indexes</tt>[i] or, if
1475:             *        <tt>sizes</tt>[i] is negative, the <i>last</i> |<tt>sizes[i]</tt>|
1476:             *        bytes of the instruction will be removed (the instruction size
1477:             *        <i>must not</i> become negative or null). The gaps introduced by
1478:             *        this method must be filled in "manually" in {@link #code code}
1479:             *        method.
1480:             * @param len the number of instruction to be resized. Must be smaller than
1481:             *        or equal to <tt>indexes</tt>.length and <tt>sizes</tt>.length.
1482:             * @return the <tt>indexes</tt> array, which now contains the new
1483:             *         positions of the resized instructions (designated as above).
1484:             */
1485:            private int[] resizeInstructions(final int[] indexes,
1486:                    final int[] sizes, final int len) {
1487:                byte[] b = this .code.data; // bytecode of the method
1488:                int u, v, label; // indexes in b
1489:                int i, j; // loop indexes
1490:
1491:                /*
1492:                 * 1st step: As explained above, resizing an instruction may require to
1493:                 * resize another one, which may require to resize yet another one, and
1494:                 * so on. The first step of the algorithm consists in finding all the
1495:                 * instructions that need to be resized, without modifying the code.
1496:                 * This is done by the following "fix point" algorithm:
1497:                 * 
1498:                 * Parse the code to find the jump instructions whose offset will need
1499:                 * more than 2 bytes to be stored (the future offset is computed from
1500:                 * the current offset and from the number of bytes that will be inserted
1501:                 * or removed between the source and target instructions). For each such
1502:                 * instruction, adds an entry in (a copy of) the indexes and sizes
1503:                 * arrays (if this has not already been done in a previous iteration!).
1504:                 * 
1505:                 * If at least one entry has been added during the previous step, go
1506:                 * back to the beginning, otherwise stop.
1507:                 * 
1508:                 * In fact the real algorithm is complicated by the fact that the size
1509:                 * of TABLESWITCH and LOOKUPSWITCH instructions depends on their
1510:                 * position in the bytecode (because of padding). In order to ensure the
1511:                 * convergence of the algorithm, the number of bytes to be added or
1512:                 * removed from these instructions is over estimated during the previous
1513:                 * loop, and computed exactly only after the loop is finished (this
1514:                 * requires another pass to parse the bytecode of the method).
1515:                 */
1516:                int[] allIndexes = new int[len]; // copy of indexes
1517:                int[] allSizes = new int[len]; // copy of sizes
1518:                boolean[] resize; // instructions to be resized
1519:                int newOffset; // future offset of a jump instruction
1520:
1521:                System.arraycopy(indexes, 0, allIndexes, 0, len);
1522:                System.arraycopy(sizes, 0, allSizes, 0, len);
1523:                resize = new boolean[this .code.length];
1524:
1525:                // 3 = loop again, 2 = loop ended, 1 = last pass, 0 = done
1526:                int state = 3;
1527:                do {
1528:                    if (state == 3) {
1529:                        state = 2;
1530:                    }
1531:                    u = 0;
1532:                    while (u < b.length) {
1533:                        int opcode = b[u] & 0xFF; // opcode of current instruction
1534:                        int insert = 0; // bytes to be added after this instruction
1535:
1536:                        switch (ClassWriter.TYPE[opcode]) {
1537:                        case ClassWriter.NOARG_INSN:
1538:                        case ClassWriter.IMPLVAR_INSN:
1539:                            u += 1;
1540:                            break;
1541:                        case ClassWriter.LABEL_INSN:
1542:                            if (opcode > 201) {
1543:                                // converts temporary opcodes 202 to 217, 218 and
1544:                                // 219 to IFEQ ... JSR (inclusive), IFNULL and
1545:                                // IFNONNULL
1546:                                opcode = opcode < 218 ? opcode - 49
1547:                                        : opcode - 20;
1548:                                label = u + readUnsignedShort(b, u + 1);
1549:                            } else {
1550:                                label = u + readShort(b, u + 1);
1551:                            }
1552:                            newOffset = getNewOffset(allIndexes, allSizes, u,
1553:                                    label);
1554:                            if (newOffset < Short.MIN_VALUE
1555:                                    || newOffset > Short.MAX_VALUE) {
1556:                                if (!resize[u]) {
1557:                                    if (opcode == Opcodes.GOTO
1558:                                            || opcode == Opcodes.JSR) {
1559:                                        // two additional bytes will be required to
1560:                                        // replace this GOTO or JSR instruction with
1561:                                        // a GOTO_W or a JSR_W
1562:                                        insert = 2;
1563:                                    } else {
1564:                                        // five additional bytes will be required to
1565:                                        // replace this IFxxx <l> instruction with
1566:                                        // IFNOTxxx <l'> GOTO_W <l>, where IFNOTxxx
1567:                                        // is the "opposite" opcode of IFxxx (i.e.,
1568:                                        // IFNE for IFEQ) and where <l'> designates
1569:                                        // the instruction just after the GOTO_W.
1570:                                        insert = 5;
1571:                                    }
1572:                                    resize[u] = true;
1573:                                }
1574:                            }
1575:                            u += 3;
1576:                            break;
1577:                        case ClassWriter.LABELW_INSN:
1578:                            u += 5;
1579:                            break;
1580:                        case ClassWriter.TABL_INSN:
1581:                            if (state == 1) {
1582:                                // true number of bytes to be added (or removed)
1583:                                // from this instruction = (future number of padding
1584:                                // bytes - current number of padding byte) -
1585:                                // previously over estimated variation =
1586:                                // = ((3 - newOffset%4) - (3 - u%4)) - u%4
1587:                                // = (-newOffset%4 + u%4) - u%4
1588:                                // = -(newOffset & 3)
1589:                                newOffset = getNewOffset(allIndexes, allSizes,
1590:                                        0, u);
1591:                                insert = -(newOffset & 3);
1592:                            } else if (!resize[u]) {
1593:                                // over estimation of the number of bytes to be
1594:                                // added to this instruction = 3 - current number
1595:                                // of padding bytes = 3 - (3 - u%4) = u%4 = u & 3
1596:                                insert = u & 3;
1597:                                resize[u] = true;
1598:                            }
1599:                            // skips instruction
1600:                            u = u + 4 - (u & 3);
1601:                            u += 4 * (readInt(b, u + 8) - readInt(b, u + 4) + 1) + 12;
1602:                            break;
1603:                        case ClassWriter.LOOK_INSN:
1604:                            if (state == 1) {
1605:                                // like TABL_INSN
1606:                                newOffset = getNewOffset(allIndexes, allSizes,
1607:                                        0, u);
1608:                                insert = -(newOffset & 3);
1609:                            } else if (!resize[u]) {
1610:                                // like TABL_INSN
1611:                                insert = u & 3;
1612:                                resize[u] = true;
1613:                            }
1614:                            // skips instruction
1615:                            u = u + 4 - (u & 3);
1616:                            u += 8 * readInt(b, u + 4) + 8;
1617:                            break;
1618:                        case ClassWriter.WIDE_INSN:
1619:                            opcode = b[u + 1] & 0xFF;
1620:                            if (opcode == Opcodes.IINC) {
1621:                                u += 6;
1622:                            } else {
1623:                                u += 4;
1624:                            }
1625:                            break;
1626:                        case ClassWriter.VAR_INSN:
1627:                        case ClassWriter.SBYTE_INSN:
1628:                        case ClassWriter.LDC_INSN:
1629:                            u += 2;
1630:                            break;
1631:                        case ClassWriter.SHORT_INSN:
1632:                        case ClassWriter.LDCW_INSN:
1633:                        case ClassWriter.FIELDORMETH_INSN:
1634:                        case ClassWriter.TYPE_INSN:
1635:                        case ClassWriter.IINC_INSN:
1636:                            u += 3;
1637:                            break;
1638:                        case ClassWriter.ITFMETH_INSN:
1639:                            u += 5;
1640:                            break;
1641:                        // case ClassWriter.MANA_INSN:
1642:                        default:
1643:                            u += 4;
1644:                            break;
1645:                        }
1646:                        if (insert != 0) {
1647:                            // adds a new (u, insert) entry in the allIndexes and
1648:                            // allSizes arrays
1649:                            final int[] newIndexes = new int[allIndexes.length + 1];
1650:                            final int[] newSizes = new int[allSizes.length + 1];
1651:                            System.arraycopy(allIndexes, 0, newIndexes, 0,
1652:                                    allIndexes.length);
1653:                            System.arraycopy(allSizes, 0, newSizes, 0,
1654:                                    allSizes.length);
1655:                            newIndexes[allIndexes.length] = u;
1656:                            newSizes[allSizes.length] = insert;
1657:                            allIndexes = newIndexes;
1658:                            allSizes = newSizes;
1659:                            if (insert > 0) {
1660:                                state = 3;
1661:                            }
1662:                        }
1663:                    }
1664:                    if (state < 3) {
1665:                        --state;
1666:                    }
1667:                } while (state != 0);
1668:
1669:                // 2nd step:
1670:                // copies the bytecode of the method into a new bytevector, updates the
1671:                // offsets, and inserts (or removes) bytes as requested.
1672:
1673:                final ByteVector newCode = new ByteVector(this .code.length);
1674:
1675:                u = 0;
1676:                while (u < this .code.length) {
1677:                    for (i = allIndexes.length - 1; i >= 0; --i) {
1678:                        if (allIndexes[i] == u) {
1679:                            if (i < len) {
1680:                                if (sizes[i] > 0) {
1681:                                    newCode.putByteArray(null, 0, sizes[i]);
1682:                                } else {
1683:                                    newCode.length += sizes[i];
1684:                                }
1685:                                indexes[i] = newCode.length;
1686:                            }
1687:                        }
1688:                    }
1689:                    int opcode = b[u] & 0xFF;
1690:                    switch (ClassWriter.TYPE[opcode]) {
1691:                    case ClassWriter.NOARG_INSN:
1692:                    case ClassWriter.IMPLVAR_INSN:
1693:                        newCode.putByte(opcode);
1694:                        u += 1;
1695:                        break;
1696:                    case ClassWriter.LABEL_INSN:
1697:                        if (opcode > 201) {
1698:                            // changes temporary opcodes 202 to 217 (inclusive), 218
1699:                            // and 219 to IFEQ ... JSR (inclusive), IFNULL and
1700:                            // IFNONNULL
1701:                            opcode = opcode < 218 ? opcode - 49 : opcode - 20;
1702:                            label = u + readUnsignedShort(b, u + 1);
1703:                        } else {
1704:                            label = u + readShort(b, u + 1);
1705:                        }
1706:                        newOffset = getNewOffset(allIndexes, allSizes, u, label);
1707:                        if (resize[u]) {
1708:                            // replaces GOTO with GOTO_W, JSR with JSR_W and IFxxx
1709:                            // <l> with IFNOTxxx <l'> GOTO_W <l>, where IFNOTxxx is
1710:                            // the "opposite" opcode of IFxxx (i.e., IFNE for IFEQ)
1711:                            // and where <l'> designates the instruction just after
1712:                            // the GOTO_W.
1713:                            if (opcode == Opcodes.GOTO) {
1714:                                newCode.putByte(200); // GOTO_W
1715:                            } else if (opcode == Opcodes.JSR) {
1716:                                newCode.putByte(201); // JSR_W
1717:                            } else {
1718:                                newCode
1719:                                        .putByte(opcode <= 166 ? ((opcode + 1) ^ 1) - 1
1720:                                                : opcode ^ 1);
1721:                                newCode.putShort(8); // jump offset
1722:                                newCode.putByte(200); // GOTO_W
1723:                                // newOffset now computed from start of GOTO_W
1724:                                newOffset -= 3;
1725:                            }
1726:                            newCode.putInt(newOffset);
1727:                        } else {
1728:                            newCode.putByte(opcode);
1729:                            newCode.putShort(newOffset);
1730:                        }
1731:                        u += 3;
1732:                        break;
1733:                    case ClassWriter.LABELW_INSN:
1734:                        label = u + readInt(b, u + 1);
1735:                        newOffset = getNewOffset(allIndexes, allSizes, u, label);
1736:                        newCode.putByte(opcode);
1737:                        newCode.putInt(newOffset);
1738:                        u += 5;
1739:                        break;
1740:                    case ClassWriter.TABL_INSN:
1741:                        // skips 0 to 3 padding bytes
1742:                        v = u;
1743:                        u = u + 4 - (v & 3);
1744:                        // reads and copies instruction
1745:                        newCode.putByte(Opcodes.TABLESWITCH);
1746:                        while (newCode.length % 4 != 0) {
1747:                            newCode.putByte(0);
1748:                        }
1749:                        label = v + readInt(b, u);
1750:                        u += 4;
1751:                        newOffset = getNewOffset(allIndexes, allSizes, v, label);
1752:                        newCode.putInt(newOffset);
1753:                        j = readInt(b, u);
1754:                        u += 4;
1755:                        newCode.putInt(j);
1756:                        j = readInt(b, u) - j + 1;
1757:                        u += 4;
1758:                        newCode.putInt(readInt(b, u - 4));
1759:                        for (; j > 0; --j) {
1760:                            label = v + readInt(b, u);
1761:                            u += 4;
1762:                            newOffset = getNewOffset(allIndexes, allSizes, v,
1763:                                    label);
1764:                            newCode.putInt(newOffset);
1765:                        }
1766:                        break;
1767:                    case ClassWriter.LOOK_INSN:
1768:                        // skips 0 to 3 padding bytes
1769:                        v = u;
1770:                        u = u + 4 - (v & 3);
1771:                        // reads and copies instruction
1772:                        newCode.putByte(Opcodes.LOOKUPSWITCH);
1773:                        while (newCode.length % 4 != 0) {
1774:                            newCode.putByte(0);
1775:                        }
1776:                        label = v + readInt(b, u);
1777:                        u += 4;
1778:                        newOffset = getNewOffset(allIndexes, allSizes, v, label);
1779:                        newCode.putInt(newOffset);
1780:                        j = readInt(b, u);
1781:                        u += 4;
1782:                        newCode.putInt(j);
1783:                        for (; j > 0; --j) {
1784:                            newCode.putInt(readInt(b, u));
1785:                            u += 4;
1786:                            label = v + readInt(b, u);
1787:                            u += 4;
1788:                            newOffset = getNewOffset(allIndexes, allSizes, v,
1789:                                    label);
1790:                            newCode.putInt(newOffset);
1791:                        }
1792:                        break;
1793:                    case ClassWriter.WIDE_INSN:
1794:                        opcode = b[u + 1] & 0xFF;
1795:                        if (opcode == Opcodes.IINC) {
1796:                            newCode.putByteArray(b, u, 6);
1797:                            u += 6;
1798:                        } else {
1799:                            newCode.putByteArray(b, u, 4);
1800:                            u += 4;
1801:                        }
1802:                        break;
1803:                    case ClassWriter.VAR_INSN:
1804:                    case ClassWriter.SBYTE_INSN:
1805:                    case ClassWriter.LDC_INSN:
1806:                        newCode.putByteArray(b, u, 2);
1807:                        u += 2;
1808:                        break;
1809:                    case ClassWriter.SHORT_INSN:
1810:                    case ClassWriter.LDCW_INSN:
1811:                    case ClassWriter.FIELDORMETH_INSN:
1812:                    case ClassWriter.TYPE_INSN:
1813:                    case ClassWriter.IINC_INSN:
1814:                        newCode.putByteArray(b, u, 3);
1815:                        u += 3;
1816:                        break;
1817:                    case ClassWriter.ITFMETH_INSN:
1818:                        newCode.putByteArray(b, u, 5);
1819:                        u += 5;
1820:                        break;
1821:                    // case MANA_INSN:
1822:                    default:
1823:                        newCode.putByteArray(b, u, 4);
1824:                        u += 4;
1825:                        break;
1826:                    }
1827:                }
1828:
1829:                // updates the exception handler block labels
1830:                Handler h = this .catchTable;
1831:                while (h != null) {
1832:                    getNewOffset(allIndexes, allSizes, h.start);
1833:                    getNewOffset(allIndexes, allSizes, h.end);
1834:                    getNewOffset(allIndexes, allSizes, h.handler);
1835:                    h = h.next;
1836:                }
1837:                for (i = 0; i < 2; ++i) {
1838:                    final ByteVector bv = i == 0 ? this .localVar
1839:                            : this .localVarType;
1840:                    if (bv != null) {
1841:                        b = bv.data;
1842:                        u = 0;
1843:                        while (u < bv.length) {
1844:                            label = readUnsignedShort(b, u);
1845:                            newOffset = getNewOffset(allIndexes, allSizes, 0,
1846:                                    label);
1847:                            writeShort(b, u, newOffset);
1848:                            label += readUnsignedShort(b, u + 2);
1849:                            newOffset = getNewOffset(allIndexes, allSizes, 0,
1850:                                    label)
1851:                                    - newOffset;
1852:                            writeShort(b, u + 2, newOffset);
1853:                            u += 10;
1854:                        }
1855:                    }
1856:                }
1857:                if (this .lineNumber != null) {
1858:                    b = this .lineNumber.data;
1859:                    u = 0;
1860:                    while (u < this .lineNumber.length) {
1861:                        writeShort(b, u, getNewOffset(allIndexes, allSizes, 0,
1862:                                readUnsignedShort(b, u)));
1863:                        u += 4;
1864:                    }
1865:                }
1866:                // updates the labels of the other attributes
1867:                while (this .cattrs != null) {
1868:                    final Label[] labels = this .cattrs.getLabels();
1869:                    if (labels != null) {
1870:                        for (i = labels.length - 1; i >= 0; --i) {
1871:                            if (!labels[i].resized) {
1872:                                labels[i].position = getNewOffset(allIndexes,
1873:                                        allSizes, 0, labels[i].position);
1874:                                labels[i].resized = true;
1875:                            }
1876:                        }
1877:                    }
1878:                }
1879:
1880:                // replaces old bytecodes with new ones
1881:                this .code = newCode;
1882:
1883:                // returns the positions of the resized instructions
1884:                return indexes;
1885:            }
1886:
1887:            /**
1888:             * Reads an unsigned short value in the given byte array.
1889:             * 
1890:             * @param b a byte array.
1891:             * @param index the start index of the value to be read.
1892:             * @return the read value.
1893:             */
1894:            static int readUnsignedShort(final byte[] b, final int index) {
1895:                return ((b[index] & 0xFF) << 8) | (b[index + 1] & 0xFF);
1896:            }
1897:
1898:            /**
1899:             * Reads a signed short value in the given byte array.
1900:             * 
1901:             * @param b a byte array.
1902:             * @param index the start index of the value to be read.
1903:             * @return the read value.
1904:             */
1905:            static short readShort(final byte[] b, final int index) {
1906:                return (short) (((b[index] & 0xFF) << 8) | (b[index + 1] & 0xFF));
1907:            }
1908:
1909:            /**
1910:             * Reads a signed int value in the given byte array.
1911:             * 
1912:             * @param b a byte array.
1913:             * @param index the start index of the value to be read.
1914:             * @return the read value.
1915:             */
1916:            static int readInt(final byte[] b, final int index) {
1917:                return ((b[index] & 0xFF) << 24)
1918:                        | ((b[index + 1] & 0xFF) << 16)
1919:                        | ((b[index + 2] & 0xFF) << 8) | (b[index + 3] & 0xFF);
1920:            }
1921:
1922:            /**
1923:             * Writes a short value in the given byte array.
1924:             * 
1925:             * @param b a byte array.
1926:             * @param index where the first byte of the short value must be written.
1927:             * @param s the value to be written in the given byte array.
1928:             */
1929:            static void writeShort(final byte[] b, final int index, final int s) {
1930:                b[index] = (byte) (s >>> 8);
1931:                b[index + 1] = (byte) s;
1932:            }
1933:
1934:            /**
1935:             * Computes the future value of a bytecode offset. <p> Note: it is possible
1936:             * to have several entries for the same instruction in the <tt>indexes</tt>
1937:             * and <tt>sizes</tt>: two entries (index=a,size=b) and (index=a,size=b')
1938:             * are equivalent to a single entry (index=a,size=b+b').
1939:             * 
1940:             * @param indexes current positions of the instructions to be resized. Each
1941:             *        instruction must be designated by the index of its <i>last</i>
1942:             *        byte, plus one (or, in other words, by the index of the <i>first</i>
1943:             *        byte of the <i>next</i> instruction).
1944:             * @param sizes the number of bytes to be <i>added</i> to the above
1945:             *        instructions. More precisely, for each i < <tt>len</tt>,
1946:             *        <tt>sizes</tt>[i] bytes will be added at the end of the
1947:             *        instruction designated by <tt>indexes</tt>[i] or, if
1948:             *        <tt>sizes</tt>[i] is negative, the <i>last</i> |<tt>sizes[i]</tt>|
1949:             *        bytes of the instruction will be removed (the instruction size
1950:             *        <i>must not</i> become negative or null).
1951:             * @param begin index of the first byte of the source instruction.
1952:             * @param end index of the first byte of the target instruction.
1953:             * @return the future value of the given bytecode offset.
1954:             */
1955:            static int getNewOffset(final int[] indexes, final int[] sizes,
1956:                    final int begin, final int end) {
1957:                int offset = end - begin;
1958:                for (int i = 0; i < indexes.length; ++i) {
1959:                    if (begin < indexes[i] && indexes[i] <= end) {
1960:                        // forward jump
1961:                        offset += sizes[i];
1962:                    } else if (end < indexes[i] && indexes[i] <= begin) {
1963:                        // backward jump
1964:                        offset -= sizes[i];
1965:                    }
1966:                }
1967:                return offset;
1968:            }
1969:
1970:            /**
1971:             * Updates the offset of the given label.
1972:             * 
1973:             * @param indexes current positions of the instructions to be resized. Each
1974:             *        instruction must be designated by the index of its <i>last</i>
1975:             *        byte, plus one (or, in other words, by the index of the <i>first</i>
1976:             *        byte of the <i>next</i> instruction).
1977:             * @param sizes the number of bytes to be <i>added</i> to the above
1978:             *        instructions. More precisely, for each i < <tt>len</tt>,
1979:             *        <tt>sizes</tt>[i] bytes will be added at the end of the
1980:             *        instruction designated by <tt>indexes</tt>[i] or, if
1981:             *        <tt>sizes</tt>[i] is negative, the <i>last</i> |<tt>sizes[i]</tt>|
1982:             *        bytes of the instruction will be removed (the instruction size
1983:             *        <i>must not</i> become negative or null).
1984:             * @param label the label whose offset must be updated.
1985:             */
1986:            static void getNewOffset(final int[] indexes, final int[] sizes,
1987:                    final Label label) {
1988:                if (!label.resized) {
1989:                    label.position = getNewOffset(indexes, sizes, 0,
1990:                            label.position);
1991:                    label.resized = true;
1992:                }
1993:            }
1994:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.