Source Code Cross Referenced for MethodEditor.java in  » Database-DBMS » db4o-6.4 » EDU » purdue » cs » bloat » editor » 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 » Database DBMS » db4o 6.4 » EDU.purdue.cs.bloat.editor 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


0001:        /* Copyright (C) 2004 - 2007  db4objects Inc.  http://www.db4o.com
0002:
0003:        This file is part of the db4o open source object database.
0004:
0005:        db4o is free software; you can redistribute it and/or modify it under
0006:        the terms of version 2 of the GNU General Public License as published
0007:        by the Free Software Foundation and as clarified by db4objects' GPL 
0008:        interpretation policy, available at
0009:        http://www.db4o.com/about/company/legalpolicies/gplinterpretation/
0010:        Alternatively you can write to db4objects, Inc., 1900 S Norfolk Street,
0011:        Suite 350, San Mateo, CA 94403, USA.
0012:
0013:        db4o is distributed in the hope that it will be useful, but WITHOUT ANY
0014:        WARRANTY; without even the implied warranty of MERCHANTABILITY or
0015:        FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
0016:        for more details.
0017:
0018:        You should have received a copy of the GNU General Public License along
0019:        with this program; if not, write to the Free Software Foundation, Inc.,
0020:        59 Temple Place - Suite 330, Boston, MA  02111-1307, USA. */
0021:        package EDU.purdue.cs.bloat.editor;
0022:
0023:        import java.io.*;
0024:        import java.util.*;
0025:
0026:        import EDU.purdue.cs.bloat.reflect.*;
0027:        import EDU.purdue.cs.bloat.tree.*;
0028:        import EDU.purdue.cs.bloat.util.*;
0029:
0030:        /**
0031:         * <tt>MethodEditor</tt> provides a means to edit a method of a class. A
0032:         * <tt>MethodEditor</tt> gathers information from a <tt>MethodInfo</tt>
0033:         * object. It then goes through the bytecodes of the method and extracts
0034:         * information about the method. Along the way it creates an array of
0035:         * <tt>Instruction</tt> and <tt>Label</tt> objects that represent the code.
0036:         * Additionally, it models the try-catch blocks in the method and their
0037:         * associated exception handlers.
0038:         * 
0039:         * @see EDU.purdue.cs.bloat.reflect.MethodInfo
0040:         * @see Label
0041:         * @see Instruction
0042:         * 
0043:         * @author Nate Nystrom (<a
0044:         *         href="mailto:nystrom@cs.purdue.edu">nystrom@cs.purdue.edu</a>)
0045:         */
0046:        public class MethodEditor implements  Opcode {
0047:            public static boolean PRESERVE_DEBUG = true;
0048:
0049:            public static boolean UNIQUE_HANDLERS = false;
0050:
0051:            public static boolean OPT_STACK_2 = false; // byte-code level stack opt
0052:
0053:            private ClassEditor editor; // The editor that "owns" this MethodEditor
0054:
0055:            private MethodInfo methodInfo; // Representation of this method
0056:
0057:            private String name; // The name of this method
0058:
0059:            private Type type; // Type variable representing the class's
0060:
0061:            // descriptor
0062:            private LinkedList code; // Label and Instruction objects representing
0063:            // this
0064:
0065:            // method's bytecode
0066:            private LinkedList tryCatches; // Info about the try-catch blocks in this
0067:            // method
0068:
0069:            private LinkedList lineNumbers;
0070:
0071:            private LocalVariable[] params; // The parameters to this method
0072:
0073:            private int maxStack; // Max size of stack while running this method
0074:
0075:            private int maxLabel; // Label pointing to the end of the code
0076:
0077:            private int maxLocals; // Maximum number of local variables
0078:
0079:            private boolean isDirty; // Has the method been modified?
0080:
0081:            private Map locals; // Maps indices to that LocalVariable
0082:
0083:            private Type[] paramTypes; // Types of parameters (accounts for wides)
0084:
0085:            public UseMap uMap; // Structure for remembering use/def info
0086:
0087:            private boolean isDeleted = false;
0088:
0089:            public MethodEditor(final ClassEditor editor, final int modifiers,
0090:                    final Class returnType, final String methodName,
0091:                    final Class[] paramTypes, final Class[] exceptionTypes) {
0092:
0093:                this (editor, modifiers, (returnType == null ? null : Type
0094:                        .getType(returnType)), methodName, MethodEditor
0095:                        .convertTypes(paramTypes), MethodEditor
0096:                        .convertTypes(exceptionTypes));
0097:            }
0098:
0099:            private static Type[] convertTypes(final Class[] classes) {
0100:                if (classes == null) {
0101:                    return (null);
0102:                }
0103:
0104:                final Type[] types = new Type[classes.length];
0105:                for (int i = 0; i < types.length; i++) {
0106:                    types[i] = Type.getType(classes[i]);
0107:                }
0108:                return (types);
0109:            }
0110:
0111:            /**
0112:             * Creates a new <code>MethodEditor</code> for editing a method in a given
0113:             * class with the given modifiers, return type, name, parameter types, and
0114:             * exception types.
0115:             * 
0116:             * @param modifiers
0117:             *            The {@link EDU.purdue.cs.bloat.reflect.Modifiers modifiers}
0118:             *            for the new method
0119:             * @param returnType
0120:             *            The return type of the method. If, <code>returnType</code>
0121:             *            is null, the return type is assumed to be <code>void</code>.
0122:             * @param methodName
0123:             *            The name of the method
0124:             * @param paramTypes
0125:             *            The types of the parameters to the new method. If
0126:             *            <code>paramTypes</code> is <code>null</code>, then we
0127:             *            assume that there are no arguments.
0128:             * @param exceptionTypes
0129:             *            The types of exceptions that may be thrown by the new method.
0130:             *            If <code>exceptionTypes</code> is <code>null</code>, then
0131:             *            we assume that no exceptions are declared.
0132:             */
0133:            public MethodEditor(final ClassEditor editor, final int modifiers,
0134:                    Type returnType, final String methodName,
0135:                    Type[] paramTypes, Type[] exceptionTypes) {
0136:
0137:                // if(ClassEditor.DEBUG) {
0138:                // System.out.println("Creating MethodEditor " +
0139:                // System.identityHashCode(this));
0140:                // Thread.dumpStack();
0141:                // }
0142:
0143:                this .editor = editor;
0144:                this .name = methodName;
0145:
0146:                if (returnType == null) {
0147:                    returnType = Type.VOID;
0148:                }
0149:
0150:                if (paramTypes == null) {
0151:                    paramTypes = new Type[0];
0152:                }
0153:
0154:                if (exceptionTypes == null) {
0155:                    exceptionTypes = new Type[0];
0156:                }
0157:
0158:                // Get the indices in the constant pool for all sorts of
0159:                // interesting information
0160:                final ConstantPool cp = editor.constants();
0161:                final int nameIndex = cp.getUTF8Index(methodName);
0162:                this .type = Type.getType(paramTypes, returnType);
0163:                Assert.isTrue(this .type.isMethod(), "Method type not method: "
0164:                        + this .type);
0165:                final int typeIndex = cp.getTypeIndex(this .type);
0166:                final int exceptionIndex = cp.getUTF8Index("Exceptions");
0167:
0168:                final int[] exceptionTypeIndices = new int[exceptionTypes.length];
0169:                for (int i = 0; i < exceptionTypes.length; i++) {
0170:                    final Type eType = exceptionTypes[i];
0171:                    exceptionTypeIndices[i] = cp.getTypeIndex(eType);
0172:                }
0173:
0174:                final int codeIndex = cp.getUTF8Index("Code");
0175:
0176:                final ClassInfo classInfo = editor.classInfo();
0177:                this .methodInfo = classInfo.addNewMethod(modifiers, typeIndex,
0178:                        nameIndex, exceptionIndex, exceptionTypeIndices,
0179:                        codeIndex);
0180:
0181:                // Initialize other parts of this MethodEditor as best we can
0182:                this .code = new LinkedList();
0183:                this .tryCatches = new LinkedList();
0184:                this .lineNumbers = new LinkedList();
0185:                this .locals = new HashMap();
0186:
0187:                // Be sure to include space for the this pointer.
0188:                if (!isStatic()) {
0189:                    this .params = new LocalVariable[type.stackHeight() + 1];
0190:
0191:                } else {
0192:                    this .params = new LocalVariable[type.stackHeight()];
0193:                }
0194:
0195:                // Initalize the params to hold LocalVariables representing the
0196:                // parameters
0197:                this .paramTypes = new Type[this .params.length];
0198:                final Type[] indexedParams = this .type().indexedParamTypes();
0199:                if (!isStatic()) {
0200:                    // First parameter is the this pointer
0201:                    this .paramTypes[0] = this .declaringClass().type();
0202:                    for (int q = 1; q < this .paramTypes.length; q++) {
0203:                        this .paramTypes[q] = indexedParams[q - 1];
0204:                    }
0205:
0206:                } else {
0207:                    for (int q = 0; q < this .paramTypes.length; q++) {
0208:                        this .paramTypes[q] = indexedParams[q];
0209:                    }
0210:                }
0211:
0212:                for (int q = 0; q < this .params.length; q++) {
0213:                    this .params[q] = new LocalVariable(null,
0214:                            this .paramTypes[q], q);
0215:                }
0216:
0217:                this .maxLocals = this .paramTypes.length;
0218:
0219:                this .isDirty = true;
0220:            }
0221:
0222:            /**
0223:             * Constructor.
0224:             * 
0225:             * @param editor
0226:             *            The class containing the method.
0227:             * @param methodInfo
0228:             *            The method to edit.
0229:             * 
0230:             * @see ClassEditor
0231:             * @see EDU.purdue.cs.bloat.reflect.MethodInfo MethodInfo
0232:             */
0233:            public MethodEditor(final ClassEditor editor,
0234:                    final MethodInfo methodInfo) {
0235:                // if(ClassEditor.DEBUG) {
0236:                // System.out.println("Creating MethodEditor " +
0237:                // System.identityHashCode(this));
0238:                // Thread.dumpStack();
0239:                // }
0240:
0241:                final ConstantPool cp = editor.constants();
0242:
0243:                this .methodInfo = methodInfo;
0244:                this .editor = editor;
0245:                this .isDirty = false;
0246:
0247:                maxLabel = 0;
0248:                maxLocals = methodInfo.maxLocals();
0249:                maxStack = methodInfo.maxStack();
0250:                locals = new HashMap();
0251:
0252:                int index;
0253:                int i;
0254:                int j;
0255:
0256:                index = methodInfo.nameIndex();
0257:                name = (String) cp.constantAt(index);
0258:
0259:                index = methodInfo.typeIndex();
0260:                final String typeName = (String) cp.constantAt(index);
0261:                type = Type.getType(typeName);
0262:
0263:                code = new LinkedList();
0264:                tryCatches = new LinkedList();
0265:                lineNumbers = new LinkedList();
0266:
0267:                // Be sure to include space for the this pointer.
0268:                if (!isStatic()) {
0269:                    params = new LocalVariable[type.stackHeight() + 1];
0270:                } else {
0271:                    params = new LocalVariable[type.stackHeight()];
0272:                }
0273:
0274:                // Initalize the params to hold LocalVariables representing the
0275:                // parameters
0276:                paramTypes = new Type[params.length];
0277:                final Type[] indexedParams = this .type().indexedParamTypes();
0278:                if (!isStatic()) {
0279:                    // First parameter is the this pointer
0280:                    paramTypes[0] = this .declaringClass().type();
0281:                    for (int q = 1; q < paramTypes.length; q++) {
0282:                        paramTypes[q] = indexedParams[q - 1];
0283:                    }
0284:
0285:                } else {
0286:                    for (int q = 0; q < paramTypes.length; q++) {
0287:                        paramTypes[q] = indexedParams[q];
0288:                    }
0289:                }
0290:                for (int q = 0; q < params.length; q++) {
0291:                    params[q] = new LocalVariable(null, paramTypes[q], q);
0292:                }
0293:
0294:                // Get the byte code for this method
0295:                final byte[] array = methodInfo.code();
0296:
0297:                if ((array == null) || (array.length == 0)) {
0298:                    return;
0299:                }
0300:
0301:                // Build the array of Instructions (and Labels).
0302:                //
0303:                // next[i] contains the index of the instruction following i.
0304:                // targets[i] contains an array of the branch targets of i.
0305:                // lookups[i] contains an array of the switch lookup values of i.
0306:                // label[i] contains a label if a label should be inserted before i.
0307:                // lines[i] contains the line number of instruction i (or 0).
0308:                //
0309:                final int[] next = new int[array.length];
0310:                final int[][] targets = new int[array.length][];
0311:                final int[][] lookups = new int[array.length][];
0312:                final Label[] label = new Label[array.length + 1];
0313:                LocalVariable[][] localVars;
0314:
0315:                if (MethodEditor.PRESERVE_DEBUG && (array.length < 0x10000)) {
0316:                    // LocalDebugInfo maps a local variable in the generated code
0317:                    // back to the name of a local variable in the original Java
0318:                    // source file.
0319:                    final LocalDebugInfo[] locals = methodInfo.locals();
0320:                    int max = 0;
0321:
0322:                    // Find the maximum local variable index for the code.
0323:                    for (i = 0; i < locals.length; i++) {
0324:                        if (max <= locals[i].index()) {
0325:                            max = locals[i].index() + 1;
0326:                        }
0327:                    }
0328:
0329:                    // localVars[i][j] contains the a LocalVariable, j, for
0330:                    // instruction i
0331:                    localVars = new LocalVariable[array.length][max];
0332:
0333:                    // Create LocalVariables for those locals with debug info
0334:                    // and set the params array so the name and type will be returned
0335:                    // be paramAt.
0336:                    //
0337:                    for (i = 0; i < locals.length; i++) {
0338:                        final int start = locals[i].startPC();
0339:                        final int end = start + locals[i].length();
0340:
0341:                        final String localName = (String) cp
0342:                                .constantAt(locals[i].nameIndex());
0343:                        final String localType = (String) cp
0344:                                .constantAt(locals[i].typeIndex());
0345:
0346:                        final LocalVariable var = new LocalVariable(localName,
0347:                                Type.getType(localType), locals[i].index());
0348:
0349:                        for (int pc = start; pc <= end; pc++) {
0350:                            if (pc < localVars.length) {
0351:                                localVars[pc][locals[i].index()] = var;
0352:                            }
0353:                        }
0354:
0355:                        if ((start == 0) && (locals[i].index() < params.length)) {
0356:                            params[locals[i].index()] = var;
0357:                        }
0358:                    }
0359:
0360:                    // Create a list of line number entries and add a label at the
0361:                    // start PC for each entry.
0362:                    final LineNumberDebugInfo[] lineNumbers = methodInfo
0363:                            .lineNumbers();
0364:
0365:                    for (i = 0; i < lineNumbers.length; i++) {
0366:                        final int start = lineNumbers[i].startPC();
0367:
0368:                        if (label[start] == null) {
0369:                            label[start] = new Label(start, false);
0370:                        }
0371:
0372:                        addLineNumberEntry(label[start], lineNumbers[i]
0373:                                .lineNumber());
0374:                    }
0375:                } else {
0376:                    // We're not preserving debugging information. So, we don't
0377:                    // need to worry about which local variables are live at
0378:                    // which instructions.
0379:
0380:                    localVars = new LocalVariable[array.length][0];
0381:                }
0382:
0383:                // Create a label for the beginning of the code and for each
0384:                // branch target. Also set next[i] for all instructions i.
0385:                //
0386:                label[0] = new Label(0, true);
0387:
0388:                int numInst = 0;
0389:
0390:                for (i = 0; i < array.length; i = next[i]) {
0391:                    // Examine an instruction and extract its target labels
0392:                    // and switch lookups
0393:                    next[i] = munchCode(array, i, targets, lookups);
0394:                    numInst++;
0395:
0396:                    // Generate Labels for all the targets local to the code
0397:                    if (targets[i] != null) {
0398:                        for (j = 0; j < targets[i].length; j++) {
0399:                            if (targets[i][j] < array.length) {
0400:                                label[targets[i][j]] = new Label(targets[i][j],
0401:                                        true);
0402:                            }
0403:                        }
0404:                    }
0405:                }
0406:
0407:                // Create a label for the beginning and end of protected blocks and the
0408:                // beginning of catch blocks. Add a TryCatch entry for each
0409:                // exception handler in the method.
0410:                //
0411:                final Catch[] exc = methodInfo.exceptionHandlers();
0412:
0413:                for (i = 0; i < exc.length; i++) {
0414:                    final int start = exc[i].startPC();
0415:                    final int end = exc[i].endPC();
0416:                    final int handler = exc[i].handlerPC();
0417:
0418:                    label[start] = new Label(start, true);
0419:                    label[end] = new Label(end, true);
0420:                    label[handler] = new Label(handler, true);
0421:
0422:                    final Type catchType = (Type) cp.constantAt(exc[i]
0423:                            .catchTypeIndex());
0424:
0425:                    addTryCatch(new TryCatch(label[start], label[end],
0426:                            label[handler], catchType));
0427:                }
0428:
0429:                // Go through the bytecode and create Instructions and build the
0430:                // code linked list.
0431:                // Add a label for instructions following branches.
0432:                for (i = 0; i < array.length; i = next[i]) {
0433:                    final Instruction inst = new Instruction(array, i,
0434:                            targets[i], lookups[i], localVars[i], cp);
0435:
0436:                    if (label[i] != null) {
0437:                        code.add(label[i]);
0438:                    }
0439:
0440:                    code.add(inst);
0441:
0442:                    if (inst.isJump() || inst.isReturn() || inst.isJsr()
0443:                            || inst.isRet() || inst.isThrow()
0444:                            || inst.isSwitch()) {
0445:
0446:                        // Add a label for the next instruction after a branch.
0447:                        if (next[i] < array.length) {
0448:                            label[next[i]] = new Label(next[i], true);
0449:                        }
0450:                    }
0451:                }
0452:
0453:                // Add a label at the end. This label must start a block.
0454:                label[array.length] = new Label(array.length, true);
0455:                code.add(label[array.length]);
0456:
0457:                maxLabel = array.length + 1;
0458:
0459:                if (ClassEditor.DEBUG) {
0460:                    System.out.println("Editing method " + name + " " + type);
0461:                }
0462:
0463:                if (MethodEditor.OPT_STACK_2) {
0464:                    uMap = new UseMap(); // structure for remembering use/def info.
0465:                }
0466:
0467:                this .setDirty(false);
0468:            }
0469:
0470:            /**
0471:             * Returns the <tt>Type</tt>s of exceptions that this method may throw.
0472:             */
0473:            public Type[] exceptions() {
0474:                final ConstantPool cp = editor.constants();
0475:                final int[] indices = methodInfo.exceptionTypes();
0476:                final Type[] types = new Type[indices.length];
0477:
0478:                for (int i = 0; i < indices.length; i++) {
0479:                    types[i] = (Type) cp.constantAt(indices[i]);
0480:                }
0481:
0482:                return (types);
0483:            }
0484:
0485:            /**
0486:             * Returns <tt>true</tt> if this method has been modified.
0487:             */
0488:            public boolean isDirty() {
0489:                return (this .isDirty);
0490:            }
0491:
0492:            /**
0493:             * Sets the dirty flag of this method. The dirty flag is <tt>true</tt> if
0494:             * the method has been modified.
0495:             */
0496:            public void setDirty(final boolean dirty) {
0497:                this .isDirty = dirty;
0498:                if (isDirty == true) {
0499:                    this .editor.setDirty(true);
0500:                }
0501:            }
0502:
0503:            /**
0504:             * Marks this method for deletion. Once a method has been marked for
0505:             * deletion all attempts to change it will throw an
0506:             * <code>IllegalStateException</code>.
0507:             */
0508:            public void delete() {
0509:                this .setDirty(true);
0510:                this .isDeleted = true;
0511:            }
0512:
0513:            /**
0514:             * Returns an array of <tt>Type</tt>s representing the types of the
0515:             * parameters of this method. It's really used to figure out the type of the
0516:             * local variables that hold the parameters. So, wide data is succeeded by
0517:             * an empty slot. Also, for virtual methods, the first element in the array
0518:             * is the receiver.
0519:             */
0520:            public Type[] paramTypes() {
0521:                return (this .paramTypes);
0522:            }
0523:
0524:            /**
0525:             * Get the LocalVariable for the parameter at the given index.
0526:             * 
0527:             * @param index
0528:             *            The index into the params (0 is the this pointer or the first
0529:             *            argument, if static).
0530:             * @return The LocalVariable for the parameter at the given index.
0531:             * 
0532:             */
0533:            public LocalVariable paramAt(final int index) {
0534:                if ((index >= params.length) || (params[index] == null)) {
0535:                    final LocalVariable local = new LocalVariable(index);
0536:                    if (index < params.length) {
0537:                        params[index] = local;
0538:                    }
0539:                    return (local);
0540:                }
0541:
0542:                return params[index];
0543:            }
0544:
0545:            /**
0546:             * Returns the raw MethodInfo of the method being edited.
0547:             */
0548:            public MethodInfo methodInfo() {
0549:                return methodInfo;
0550:            }
0551:
0552:            /**
0553:             * Returns the class which declared the method.
0554:             */
0555:            public ClassEditor declaringClass() {
0556:                return editor;
0557:            }
0558:
0559:            /**
0560:             * Returns the maximum number of locals used by the method.
0561:             */
0562:            public int maxLocals() {
0563:                return maxLocals;
0564:            }
0565:
0566:            public boolean isPublic() {
0567:                return (methodInfo.modifiers() & Modifiers.PUBLIC) != 0;
0568:            }
0569:
0570:            public boolean isPrivate() {
0571:                return (methodInfo.modifiers() & Modifiers.PRIVATE) != 0;
0572:            }
0573:
0574:            public boolean isProtected() {
0575:                return (methodInfo.modifiers() & Modifiers.PROTECTED) != 0;
0576:            }
0577:
0578:            /**
0579:             * Returns true is the method has package level visibility
0580:             */
0581:            public boolean isPackage() {
0582:                return (!isPublic() && !isPrivate() && !isProtected());
0583:            }
0584:
0585:            public boolean isStatic() {
0586:                return (methodInfo.modifiers() & Modifiers.STATIC) != 0;
0587:            }
0588:
0589:            public boolean isFinal() {
0590:                return (methodInfo.modifiers() & Modifiers.FINAL) != 0;
0591:            }
0592:
0593:            public boolean isSynchronized() {
0594:                return (methodInfo.modifiers() & Modifiers.SYNCHRONIZED) != 0;
0595:            }
0596:
0597:            public boolean isNative() {
0598:                return (methodInfo.modifiers() & Modifiers.NATIVE) != 0;
0599:            }
0600:
0601:            public boolean isAbstract() {
0602:                return (methodInfo.modifiers() & Modifiers.ABSTRACT) != 0;
0603:            }
0604:
0605:            /**
0606:             * Returns <tt>true</tt> if this method's class is an interface.
0607:             */
0608:            public boolean isInterface() {
0609:                return (editor.isInterface());
0610:            }
0611:
0612:            // TODO: Only change the methodInfo at commit time.
0613:            // TODO: Add similar methods to field and class editors.
0614:            /**
0615:             * @throws IllegalStateException This field has been marked for deletion
0616:             */
0617:            public void setPublic(final boolean flag) {
0618:                if (this .isDeleted) {
0619:                    final String s = "Cannot change a field once it has been marked "
0620:                            + "for deletion";
0621:                    throw new IllegalStateException(s);
0622:                }
0623:
0624:                int mod = methodInfo.modifiers();
0625:
0626:                if (flag) {
0627:                    mod |= Modifiers.PUBLIC;
0628:                } else {
0629:                    mod &= ~Modifiers.PUBLIC;
0630:                }
0631:
0632:                methodInfo.setModifiers(mod);
0633:                this .setDirty(true);
0634:            }
0635:
0636:            /**
0637:             * @throws IllegalStateException This field has been marked for deletion
0638:             */
0639:            public void setPrivate(final boolean flag) {
0640:                if (this .isDeleted) {
0641:                    final String s = "Cannot change a field once it has been marked "
0642:                            + "for deletion";
0643:                    throw new IllegalStateException(s);
0644:                }
0645:
0646:                int mod = methodInfo.modifiers();
0647:
0648:                if (flag) {
0649:                    mod |= Modifiers.PRIVATE;
0650:                } else {
0651:                    mod &= ~Modifiers.PRIVATE;
0652:                }
0653:
0654:                methodInfo.setModifiers(mod);
0655:                this .setDirty(true);
0656:            }
0657:
0658:            /**
0659:             * @throws IllegalStateException This field has been marked for deletion
0660:             */
0661:            public void setProtected(final boolean flag) {
0662:                if (this .isDeleted) {
0663:                    final String s = "Cannot change a field once it has been marked "
0664:                            + "for deletion";
0665:                    throw new IllegalStateException(s);
0666:                }
0667:
0668:                int mod = methodInfo.modifiers();
0669:
0670:                if (flag) {
0671:                    mod |= Modifiers.PROTECTED;
0672:                } else {
0673:                    mod &= ~Modifiers.PROTECTED;
0674:                }
0675:
0676:                methodInfo.setModifiers(mod);
0677:                this .setDirty(true);
0678:            }
0679:
0680:            /**
0681:             * @throws IllegalStateException This field has been marked for deletion
0682:             */
0683:            public void setStatic(final boolean flag) {
0684:                if (this .isDeleted) {
0685:                    final String s = "Cannot change a field once it has been marked "
0686:                            + "for deletion";
0687:                    throw new IllegalStateException(s);
0688:                }
0689:
0690:                int mod = methodInfo.modifiers();
0691:
0692:                if (flag) {
0693:                    mod |= Modifiers.STATIC;
0694:                } else {
0695:                    mod &= ~Modifiers.STATIC;
0696:                }
0697:
0698:                methodInfo.setModifiers(mod);
0699:                this .setDirty(true);
0700:            }
0701:
0702:            /**
0703:             * @throws IllegalStateException This field has been marked for deletion
0704:             */
0705:            public void setFinal(final boolean flag) {
0706:                if (this .isDeleted) {
0707:                    final String s = "Cannot change a field once it has been marked "
0708:                            + "for deletion";
0709:                    throw new IllegalStateException(s);
0710:                }
0711:
0712:                int mod = methodInfo.modifiers();
0713:
0714:                if (flag) {
0715:                    mod |= Modifiers.FINAL;
0716:                } else {
0717:                    mod &= ~Modifiers.FINAL;
0718:                }
0719:
0720:                methodInfo.setModifiers(mod);
0721:                this .setDirty(true);
0722:            }
0723:
0724:            /**
0725:             * @throws IllegalStateException This field has been marked for deletion
0726:             */
0727:            public void setSynchronized(final boolean flag) {
0728:                if (this .isDeleted) {
0729:                    final String s = "Cannot change a field once it has been marked "
0730:                            + "for deletion";
0731:                    throw new IllegalStateException(s);
0732:                }
0733:
0734:                int mod = methodInfo.modifiers();
0735:
0736:                if (flag) {
0737:                    mod |= Modifiers.SYNCHRONIZED;
0738:                } else {
0739:                    mod &= ~Modifiers.SYNCHRONIZED;
0740:                }
0741:
0742:                methodInfo.setModifiers(mod);
0743:                this .setDirty(true);
0744:            }
0745:
0746:            /**
0747:             * @throws IllegalStateException This field has been marked for deletion
0748:             */
0749:            public void setNative(final boolean flag) {
0750:                if (this .isDeleted) {
0751:                    final String s = "Cannot change a field once it has been marked "
0752:                            + "for deletion";
0753:                    throw new IllegalStateException(s);
0754:                }
0755:
0756:                int mod = methodInfo.modifiers();
0757:
0758:                if (flag) {
0759:                    mod |= Modifiers.NATIVE;
0760:                } else {
0761:                    mod &= ~Modifiers.NATIVE;
0762:                }
0763:
0764:                methodInfo.setModifiers(mod);
0765:                this .setDirty(true);
0766:            }
0767:
0768:            public void setAbstract(final boolean flag) {
0769:                int mod = methodInfo.modifiers();
0770:
0771:                if (flag) {
0772:                    mod |= Modifiers.ABSTRACT;
0773:                } else {
0774:                    mod &= ~Modifiers.ABSTRACT;
0775:                }
0776:
0777:                methodInfo.setModifiers(mod);
0778:                this .setDirty(true);
0779:            }
0780:
0781:            /**
0782:             * Scan the raw bytes of a single instruction, saving the indices of branch
0783:             * targets and the values of switch lookups. That is, gather information
0784:             * needed for creating <tt>Instruction</tt> instances.
0785:             * 
0786:             * @param code
0787:             *            The byte code array.
0788:             * @param index
0789:             *            The index into the code array.
0790:             * @param targets
0791:             *            Branch targets for the instruction scanned. This is set by the
0792:             *            method.
0793:             * @param lookups
0794:             *            Switch lookups for the instruction scanned. This is set by the
0795:             *            method.
0796:             * @return The index of the next instruction in the code array.
0797:             */
0798:            private int munchCode(final byte[] code, final int index,
0799:                    final int[][] targets, final int[][] lookups) {
0800:                final int opcode = Instruction.toUByte(code[index]);
0801:                int next = index + Opcode.opcSize[opcode];
0802:
0803:                switch (opcode) {
0804:                case opc_ifeq:
0805:                case opc_ifne:
0806:                case opc_iflt:
0807:                case opc_ifge:
0808:                case opc_ifgt:
0809:                case opc_ifle:
0810:                case opc_if_icmpeq:
0811:                case opc_if_icmpne:
0812:                case opc_if_icmplt:
0813:                case opc_if_icmpge:
0814:                case opc_if_icmpgt:
0815:                case opc_if_icmple:
0816:                case opc_if_acmpeq:
0817:                case opc_if_acmpne:
0818:                case opc_ifnull:
0819:                case opc_ifnonnull: {
0820:                    // Branch target
0821:                    final int target = Instruction.toShort(code[index + 1],
0822:                            code[index + 2]);
0823:                    targets[index] = new int[1];
0824:                    targets[index][0] = index + target;
0825:                    break;
0826:                }
0827:                case opc_goto:
0828:                case opc_jsr: {
0829:                    // Branch target
0830:                    final int target = Instruction.toShort(code[index + 1],
0831:                            code[index + 2]);
0832:                    targets[index] = new int[1];
0833:                    targets[index][0] = index + target;
0834:                    break;
0835:                }
0836:                case opc_goto_w:
0837:                case opc_jsr_w: {
0838:                    // Branch target
0839:                    final int target = Instruction.toInt(code[index + 1],
0840:                            code[index + 2], code[index + 3], code[index + 4]);
0841:                    targets[index] = new int[1];
0842:                    targets[index][0] = index + target;
0843:                    break;
0844:                }
0845:                case opc_ret: {
0846:                    // Unconditional branch to the address in a local variable.
0847:                    // Work on finding branch targets later.
0848:                    break;
0849:                }
0850:                case opc_tableswitch: {
0851:                    int target;
0852:                    int lo;
0853:                    int hi;
0854:                    int j;
0855:
0856:                    // The targets and low and high values are aligned on
0857:                    // 4-byte boundaries.
0858:                    for (j = index + 1; j % 4 != 0; j++) {
0859:                        // Empty statement.
0860:                    }
0861:
0862:                    // Read the default target.
0863:                    target = Instruction.toInt(code[j], code[j + 1],
0864:                            code[j + 2], code[j + 3]);
0865:                    j += 4;
0866:
0867:                    lo = Instruction.toInt(code[j], code[j + 1], code[j + 2],
0868:                            code[j + 3]);
0869:                    j += 4;
0870:
0871:                    hi = Instruction.toInt(code[j], code[j + 1], code[j + 2],
0872:                            code[j + 3]);
0873:                    j += 4;
0874:
0875:                    lookups[index] = new int[2];
0876:                    lookups[index][0] = lo;
0877:                    lookups[index][1] = hi;
0878:
0879:                    targets[index] = new int[hi - lo + 2];
0880:
0881:                    int k = 0;
0882:                    targets[index][k++] = index + target;
0883:
0884:                    next = j + (hi - lo + 1) * 4;
0885:
0886:                    while (j < next) {
0887:                        target = Instruction.toInt(code[j], code[j + 1],
0888:                                code[j + 2], code[j + 3]);
0889:                        j += 4;
0890:
0891:                        targets[index][k++] = index + target;
0892:                    }
0893:
0894:                    break;
0895:                }
0896:                case opc_lookupswitch: {
0897:                    int target;
0898:                    int value;
0899:                    int npairs;
0900:                    int j;
0901:
0902:                    // The targets and pairs are aligned on 4-byte boundaries.
0903:                    for (j = index + 1; j % 4 != 0; j++) {
0904:                        // Empty statement.
0905:                    }
0906:
0907:                    // Read the default target.
0908:                    target = Instruction.toInt(code[j], code[j + 1],
0909:                            code[j + 2], code[j + 3]);
0910:                    j += 4;
0911:
0912:                    npairs = Instruction.toInt(code[j], code[j + 1],
0913:                            code[j + 2], code[j + 3]);
0914:                    j += 4;
0915:
0916:                    lookups[index] = new int[npairs];
0917:                    targets[index] = new int[npairs + 1];
0918:
0919:                    int k = 0;
0920:                    targets[index][k++] = index + target;
0921:
0922:                    next = j + npairs * 8;
0923:
0924:                    while (j < next) {
0925:                        value = Instruction.toInt(code[j], code[j + 1],
0926:                                code[j + 2], code[j + 3]);
0927:                        j += 4;
0928:
0929:                        target = Instruction.toInt(code[j], code[j + 1],
0930:                                code[j + 2], code[j + 3]);
0931:                        j += 4;
0932:
0933:                        lookups[index][k - 1] = value;
0934:                        targets[index][k++] = index + target;
0935:                    }
0936:
0937:                    break;
0938:                }
0939:                case opc_wide: {
0940:                    if (code[index + 1] == (byte) Opcode.opc_iinc) {
0941:                        next = index + 6;
0942:                    } else {
0943:                        next = index + 4;
0944:                    }
0945:                    break;
0946:                }
0947:                }
0948:
0949:                return next;
0950:            }
0951:
0952:            /**
0953:             * Remove all the instructions in preparation for the instructions being
0954:             * added back after a control flow graph edit.
0955:             * 
0956:             * @throws IllegalStateException This field has been marked for deletion
0957:             */
0958:            public void clearCode() {
0959:                if (this .isDeleted) {
0960:                    final String s = "Cannot change a field once it has been marked "
0961:                            + "for deletion";
0962:                    throw new IllegalStateException(s);
0963:                }
0964:
0965:                if (ClassEditor.DEBUG) {
0966:                    System.out.println("Clearing code");
0967:                    Thread.dumpStack();
0968:                }
0969:
0970:                code.clear();
0971:                tryCatches.clear();
0972:                maxLocals = 0;
0973:                maxStack = 0;
0974:                this .setDirty(true);
0975:            }
0976:
0977:            /**
0978:             * Like clear code, but doesn't reset the maxLocals. I'm not really sure why
0979:             * this works, but it stops certain parts of code that is generated and then
0980:             * re-cfg'd from being eliminated as dead
0981:             */
0982:
0983:            public void clearCode2() {
0984:                code.clear();
0985:                tryCatches.clear();
0986:                maxStack = 0;
0987:                this .setDirty(true);
0988:            }
0989:
0990:            /**
0991:             * Returns the name of the method.
0992:             */
0993:            public String name() {
0994:                return name;
0995:            }
0996:
0997:            /**
0998:             * Returns <tt>true</tt> if the method being edited is a constructor.
0999:             */
1000:            public boolean isConstructor() {
1001:                return (name.equals("<init>"));
1002:            }
1003:
1004:            /**
1005:             * Returns the type of the method.
1006:             */
1007:            public Type type() {
1008:                return type;
1009:            }
1010:
1011:            /**
1012:             * Returns the <Tt>NameAndType</tt> of the method.
1013:             */
1014:            public NameAndType nameAndType() {
1015:                return (new NameAndType(this .name(), this .type()));
1016:            }
1017:
1018:            /**
1019:             * Returns a <tt>MemberRef</tt> for the method.
1020:             */
1021:            public MemberRef memberRef() {
1022:                return (new MemberRef(this .declaringClass().type(), this 
1023:                        .nameAndType()));
1024:            }
1025:
1026:            /**
1027:             * Get the length of the code array.
1028:             * 
1029:             * @return The length of the code array.
1030:             */
1031:            public int codeLength() {
1032:                return code.size();
1033:            }
1034:
1035:            /**
1036:             * @throws IllegalStateException This field has been marked for deletion
1037:             */
1038:            public void setCode(final List v) {
1039:                if (this .isDeleted) {
1040:                    final String s = "Cannot change a field once it has been marked "
1041:                            + "for deletion";
1042:                    throw new IllegalStateException(s);
1043:                }
1044:
1045:                if (ClassEditor.DEBUG) {
1046:                    System.out.println("Setting code to " + v.size()
1047:                            + " instructions");
1048:                    Thread.dumpStack();
1049:                }
1050:                code = new LinkedList(v);
1051:                this .setDirty(true);
1052:            }
1053:
1054:            /**
1055:             * Returns the code (<tt>Instruction</tt>s and <Tt>Label</tt>s) in
1056:             * the method.
1057:             */
1058:            public List code() {
1059:                return code;
1060:            }
1061:
1062:            /**
1063:             * Get the label of the first block.
1064:             */
1065:            public Label firstBlock() {
1066:                final Iterator iter = code.iterator();
1067:
1068:                while (iter.hasNext()) {
1069:                    final Object obj = iter.next();
1070:
1071:                    if (obj instanceof  Label) {
1072:                        final Label l = (Label) obj;
1073:                        if (l.startsBlock()) {
1074:                            return l;
1075:                        }
1076:                    }
1077:                }
1078:
1079:                return null;
1080:            }
1081:
1082:            /**
1083:             * Get the label of the next block after the parameter.
1084:             * 
1085:             * @param label
1086:             *            The label at which to begin.
1087:             * @return The label.
1088:             */
1089:            public Label nextBlock(final Label label) {
1090:                boolean seen = false;
1091:
1092:                final Iterator iter = code.iterator();
1093:
1094:                while (iter.hasNext()) {
1095:                    final Object obj = iter.next();
1096:
1097:                    if (obj instanceof  Label) {
1098:                        if (seen) {
1099:                            final Label l = (Label) obj;
1100:                            if (l.startsBlock()) {
1101:                                return l;
1102:                            }
1103:                        } else if (label.equals(obj)) {
1104:                            seen = true;
1105:                        }
1106:                    }
1107:                }
1108:
1109:                return null;
1110:            }
1111:
1112:            /**
1113:             * Removes a Label or Instruction from the code array.
1114:             * 
1115:             * @param i
1116:             *            The index of the element to remove.
1117:             * 
1118:             * @throws IllegalStateException This field has been marked for deletion
1119:             */
1120:            public void removeCodeAt(final int i) {
1121:                if (this .isDeleted) {
1122:                    final String s = "Cannot change a field once it has been marked "
1123:                            + "for deletion";
1124:                    throw new IllegalStateException(s);
1125:                }
1126:
1127:                code.remove(i);
1128:                this .setDirty(true);
1129:            }
1130:
1131:            /**
1132:             * Inserts a Label or Instruction into the code array.
1133:             * 
1134:             * @param i
1135:             *            The index of the element to insert before.
1136:             * 
1137:             * @throws IllegalStateException This field has been marked for deletion
1138:             */
1139:            public void insertCodeAt(final Object obj, final int i) {
1140:                if (this .isDeleted) {
1141:                    final String s = "Cannot change a field once it has been marked "
1142:                            + "for deletion";
1143:                    throw new IllegalStateException(s);
1144:                }
1145:
1146:                code.add(i, obj);
1147:                this .setDirty(true);
1148:            }
1149:
1150:            /**
1151:             * Replace a Label or Instruction in the code array.
1152:             * 
1153:             * @param obj
1154:             *            The new element.
1155:             * @param i
1156:             *            The index of the element to replace
1157:             * 
1158:             * @throws IllegalStateException This field has been marked for deletion
1159:             */
1160:            public void replaceCodeAt(final Object obj, final int i) {
1161:                if (this .isDeleted) {
1162:                    final String s = "Cannot change a field once it has been marked "
1163:                            + "for deletion";
1164:                    throw new IllegalStateException(s);
1165:                }
1166:
1167:                code.set(i, obj);
1168:                this .setDirty(true);
1169:            }
1170:
1171:            /**
1172:             * Returns a Label or Instruction in the code array.
1173:             * 
1174:             * @param i
1175:             *            The index into the code array.
1176:             * @return The element at the index.
1177:             */
1178:            public Object codeElementAt(final int i) {
1179:                return code.get(i);
1180:            }
1181:
1182:            /**
1183:             * Add a line number entry.
1184:             * 
1185:             * @param label
1186:             *            The label beginning the range of instructions for this line
1187:             *            number.
1188:             * @param lineNumber
1189:             *            The line number.
1190:             * 
1191:             * @throws IllegalStateException This field has been marked for deletion
1192:             */
1193:            public void addLineNumberEntry(final Label label,
1194:                    final int lineNumber) {
1195:                if (this .isDeleted) {
1196:                    final String s = "Cannot change a field once it has been marked "
1197:                            + "for deletion";
1198:                    throw new IllegalStateException(s);
1199:                }
1200:
1201:                lineNumbers.add(new LineNumberEntry(label, lineNumber));
1202:                this .setDirty(true);
1203:            }
1204:
1205:            /**
1206:             * Returns the number of exception handlers in the method.
1207:             */
1208:            public int numTryCatches() {
1209:                return tryCatches.size();
1210:            }
1211:
1212:            /**
1213:             * Returns the exception handlers (<tt>TryCatch</tt>) in the method.
1214:             */
1215:            public Collection tryCatches() {
1216:                return tryCatches;
1217:            }
1218:
1219:            /**
1220:             * Add an exception handler.
1221:             * 
1222:             * @param tryCatch
1223:             *            An exception handler.
1224:             * 
1225:             * @throws IllegalStateException This field has been marked for deletion
1226:             */
1227:            public void addTryCatch(final TryCatch tryCatch) {
1228:                if (this .isDeleted) {
1229:                    final String s = "Cannot change a field once it has been marked "
1230:                            + "for deletion";
1231:                    throw new IllegalStateException(s);
1232:                }
1233:
1234:                if (ClassEditor.DEBUG) {
1235:                    System.out.println("add " + tryCatch);
1236:                }
1237:
1238:                tryCatches.add(tryCatch);
1239:                this .setDirty(true);
1240:            }
1241:
1242:            class LineNumberEntry {
1243:                Label label;
1244:
1245:                int lineNumber;
1246:
1247:                public LineNumberEntry(final Label label, final int lineNumber) {
1248:                    this .label = label;
1249:                    this .lineNumber = lineNumber;
1250:                }
1251:            }
1252:
1253:            class LocalInfo {
1254:                LocalVariable var;
1255:
1256:                Type type;
1257:
1258:                public LocalInfo(final LocalVariable var, final Type type) {
1259:                    this .var = var;
1260:                    this .type = type;
1261:                }
1262:
1263:                public boolean equals(final Object obj) {
1264:                    return (obj != null) && (obj instanceof  LocalInfo)
1265:                            && ((LocalInfo) obj).var.equals(var)
1266:                            && ((LocalInfo) obj).type.equals(type);
1267:                }
1268:
1269:                public int hashCode() {
1270:                    return var.hashCode() ^ type.hashCode();
1271:                }
1272:            }
1273:
1274:            /**
1275:             * Creates a new local variable.
1276:             */
1277:            public LocalVariable newLocal(final Type type) {
1278:                final int index = maxLocals;
1279:
1280:                maxLocals += type.stackHeight();
1281:                this .setDirty(true);
1282:
1283:                final LocalVariable local = new LocalVariable(index);
1284:
1285:                locals.put(new Integer(index), local);
1286:
1287:                return (local);
1288:            }
1289:
1290:            /**
1291:             * Creates a new local variable of an undertermined type.
1292:             * 
1293:             * @throws IllegalStateException This field has been marked for deletion
1294:             */
1295:            public LocalVariable newLocal(final boolean isWide) {
1296:                if (this .isDeleted) {
1297:                    final String s = "Cannot change a field once it has been marked "
1298:                            + "for deletion";
1299:                    throw new IllegalStateException(s);
1300:                }
1301:
1302:                final int index = maxLocals;
1303:
1304:                maxLocals += (isWide ? 2 : 1);
1305:                this .setDirty(true);
1306:
1307:                final LocalVariable local = new LocalVariable(index);
1308:
1309:                locals.put(new Integer(index), local);
1310:
1311:                return (local);
1312:            }
1313:
1314:            /**
1315:             * Returns the <tt>LocalVariable</tt> with the given index. If there is no
1316:             * local variable at that index, a new one is created at that index. We
1317:             * assume that this variable is not wide.
1318:             */
1319:            public LocalVariable localAt(int index) {
1320:                LocalVariable local = (LocalVariable) locals.get(new Integer(
1321:                        index));
1322:
1323:                if (local == null) {
1324:                    local = new LocalVariable(index);
1325:                    locals.put(new Integer(index), local);
1326:                    if (index >= maxLocals) {
1327:                        maxLocals = index++; // Dangerous?
1328:                    }
1329:                }
1330:
1331:                return (local);
1332:            }
1333:
1334:            /**
1335:             * Add an instruction.
1336:             * 
1337:             * @param opcodeClass
1338:             *            The instruction to add.
1339:             */
1340:            public void addInstruction(final int opcodeClass) {
1341:                addInstruction(new Instruction(opcodeClass));
1342:            }
1343:
1344:            /**
1345:             * Add an instruction.
1346:             * 
1347:             * @param opcodeClass
1348:             *            The instruction to add.
1349:             */
1350:            public void addInstruction(final int opcodeClass,
1351:                    final Object operand) {
1352:                addInstruction(new Instruction(opcodeClass, operand));
1353:            }
1354:
1355:            /**
1356:             * Add an instruction to the end of the code array.
1357:             * 
1358:             * @param inst
1359:             *            The instruction to add.
1360:             * 
1361:             * @throws IllegalStateException This field has been marked for deletion
1362:             */
1363:            public void addInstruction(final Instruction inst) {
1364:                if (this .isDeleted) {
1365:                    final String s = "Cannot change a field once it has been marked "
1366:                            + "for deletion";
1367:                    throw new IllegalStateException(s);
1368:                }
1369:
1370:                if (ClassEditor.DEBUG) {
1371:                    System.out.println("    " + inst + " to "
1372:                            + System.identityHashCode(this ) + ":"
1373:                            + System.identityHashCode(this .code));
1374:                }
1375:
1376:                code.add(inst);
1377:                this .setDirty(true);
1378:            }
1379:
1380:            /**
1381:             * Get the next available label. That is the Label after the final
1382:             * Instruction in the code array.
1383:             * 
1384:             * @return A new label.
1385:             * 
1386:             * @throws IllegalStateException This field has been marked for deletion
1387:             */
1388:            public Label newLabel() {
1389:                if (this .isDeleted) {
1390:                    final String s = "Cannot change a field once it has been marked "
1391:                            + "for deletion";
1392:                    throw new IllegalStateException(s);
1393:                }
1394:
1395:                this .setDirty(true);
1396:                return new Label(maxLabel++);
1397:            }
1398:
1399:            public Label newLabelTrue() {
1400:                return new Label(maxLabel++, true);
1401:            }
1402:
1403:            /**
1404:             * Add a label to the code array to the end of the code array.
1405:             * 
1406:             * @param label
1407:             *            The label to add.
1408:             * 
1409:             * @throws IllegalStateException This field has been marked for deletion
1410:             */
1411:            public void addLabel(final Label label) {
1412:                if (this .isDeleted) {
1413:                    final String s = "Cannot change a field once it has been marked "
1414:                            + "for deletion";
1415:                    throw new IllegalStateException(s);
1416:                }
1417:
1418:                if (ClassEditor.DEBUG) {
1419:                    System.out.println("    " + label + " to "
1420:                            + System.identityHashCode(this ) + ":"
1421:                            + System.identityHashCode(this .code));
1422:                }
1423:
1424:                if (label.index() >= maxLabel) {
1425:                    maxLabel = label.index() + 1;
1426:                }
1427:
1428:                code.add(label);
1429:                this .setDirty(true);
1430:            }
1431:
1432:            class LocalVarEntry {
1433:                LocalVariable var;
1434:
1435:                Label start;
1436:
1437:                Label end;
1438:
1439:                public LocalVarEntry(final LocalVariable var,
1440:                        final Label start, final Label end) {
1441:                    this .var = var;
1442:                    this .start = start;
1443:                    this .end = end;
1444:                }
1445:            }
1446:
1447:            /**
1448:             * Commits changes made to this MethodEditor back to the MethodInfo on which
1449:             * it is based. Note that committal will take place regardless of whether or
1450:             * not the method is dirty.
1451:             */
1452:            public void commit() {
1453:                if (ClassEditor.DEBUG) {
1454:                    System.out.println("Committing method " + this .name + " "
1455:                            + this .type + ": " + this .code.size() + " insts "
1456:                            + System.identityHashCode(this ) + ":"
1457:                            + System.identityHashCode(this .code));
1458:                }
1459:
1460:                final ConstantPool cp = editor.constants();
1461:
1462:                if (this .isDeleted) {
1463:                    final int nameIndex = cp.getUTF8Index(this .name);
1464:                    final int typeIndex = cp.getTypeIndex(this .type);
1465:                    this .editor.classInfo().deleteMethod(nameIndex, typeIndex);
1466:
1467:                } else {
1468:                    methodInfo
1469:                            .setNameIndex(cp.addConstant(Constant.UTF8, name));
1470:                    methodInfo.setTypeIndex(cp.addConstant(Constant.UTF8, type
1471:                            .descriptor()));
1472:
1473:                    if (isNative() || isAbstract()) {
1474:                        return;
1475:                    }
1476:
1477:                    final List vars = new ArrayList();
1478:                    final List copy = new LinkedList();
1479:
1480:                    Iterator iter = code.iterator();
1481:
1482:                    CODE: while (iter.hasNext()) {
1483:                        final Object ce = iter.next();
1484:
1485:                        if (ce instanceof  Label) {
1486:                            copy.add(ce);
1487:                            continue CODE;
1488:                        }
1489:
1490:                        final Instruction inst = (Instruction) ce;
1491:
1492:                        LocalVariable var = null;
1493:
1494:                        if (inst.operand() instanceof  LocalVariable) {
1495:                            var = (LocalVariable) inst.operand();
1496:                        } else if (inst.operand() instanceof  IncOperand) {
1497:                            var = ((IncOperand) inst.operand()).var();
1498:                        }
1499:
1500:                        if ((var == null) || (var.name() == null)
1501:                                || (var.type() == null)) {
1502:                            copy.add(ce);
1503:                            continue CODE;
1504:                        }
1505:
1506:                        for (int j = vars.size() - 1; j >= 0; j--) {
1507:                            final LocalVarEntry v = (LocalVarEntry) vars.get(j);
1508:
1509:                            // Same variable, extend the range of the variable and
1510:                            // go to the next instruction.
1511:                            if (v.var.equals(var)) {
1512:                                v.end = newLabel();
1513:
1514:                                // Add a label after the instruction.
1515:                                copy.add(ce);
1516:                                copy.add(v.end);
1517:                                continue CODE;
1518:                            }
1519:
1520:                            // Different variable, same index. We have to add an entry
1521:                            // for the variable since we know the live range for this
1522:                            // index starts here.
1523:                            if (v.var.index() == var.index()) {
1524:                                break;
1525:                            }
1526:                        }
1527:
1528:                        final Label start = newLabel();
1529:                        final Label end = newLabel();
1530:
1531:                        vars.add(new LocalVarEntry(var, start, end));
1532:
1533:                        // Add labels before and after the instruction.
1534:                        copy.add(start);
1535:                        copy.add(ce);
1536:                        copy.add(end);
1537:                    }
1538:
1539:                    final HashSet seen = new HashSet();
1540:                    final ArrayList dup = new ArrayList();
1541:
1542:                    iter = tryCatches.iterator();
1543:
1544:                    while (iter.hasNext()) {
1545:                        final TryCatch tc = (TryCatch) iter.next();
1546:
1547:                        if (!seen.contains(tc.handler())) {
1548:                            if (ClassEditor.DEBUG) {
1549:                                System.out.println("See " + tc.handler());
1550:                            }
1551:                            seen.add(tc.handler());
1552:                        } else {
1553:                            if (ClassEditor.DEBUG) {
1554:                                System.out.println("See " + tc.handler()
1555:                                        + " again");
1556:                            }
1557:                            dup.add(tc);
1558:                        }
1559:                    }
1560:
1561:                    if (dup.size() != 0) {
1562:                        final ListIterator liter = copy.listIterator();
1563:
1564:                        while (liter.hasNext()) {
1565:                            final Object ce = liter.next();
1566:
1567:                            if (ce instanceof  Label) {
1568:                                final Iterator d = dup.iterator();
1569:
1570:                                while (d.hasNext()) {
1571:                                    final TryCatch tc = (TryCatch) d.next();
1572:
1573:                                    if (tc.handler().equals(ce)) {
1574:                                        // Split the exception handler.
1575:                                        //
1576:                                        // Handler:
1577:                                        // nop <-- nop needed to prevent TowerJ
1578:                                        // goto L2 from removing the goto
1579:                                        // Handler2:
1580:                                        // nop
1581:                                        // goto L2
1582:                                        // Code:
1583:                                        // handler code
1584:
1585:                                        Instruction jump;
1586:                                        Instruction nop;
1587:
1588:                                        final Label handler2 = newLabel();
1589:                                        final Label code = newLabel();
1590:
1591:                                        nop = new Instruction(Opcode.opcx_nop);
1592:                                        liter.add(nop);
1593:
1594:                                        jump = new Instruction(
1595:                                                Opcode.opcx_goto, code);
1596:                                        liter.add(jump);
1597:
1598:                                        liter.add(handler2);
1599:
1600:                                        nop = new Instruction(Opcode.opcx_nop);
1601:                                        liter.add(nop);
1602:
1603:                                        jump = new Instruction(
1604:                                                Opcode.opcx_goto, code);
1605:                                        liter.add(jump);
1606:
1607:                                        liter.add(code);
1608:
1609:                                        if (ClassEditor.DEBUG) {
1610:                                            System.out
1611:                                                    .println("Insert " + jump);
1612:                                            System.out.println("Insert "
1613:                                                    + handler2);
1614:                                            System.out
1615:                                                    .println("Insert " + jump);
1616:                                            System.out
1617:                                                    .println("Insert " + code);
1618:                                        }
1619:
1620:                                        tc.setHandler(handler2);
1621:
1622:                                        d.remove();
1623:                                    }
1624:                                }
1625:                            }
1626:                        }
1627:                    }
1628:
1629:                    final CodeArray array = new CodeArray(this , cp, copy);
1630:                    final byte[] arr = array.array();
1631:
1632:                    methodInfo.setCode(arr);
1633:
1634:                    methodInfo.setMaxLocals(array.maxLocals());
1635:                    methodInfo.setMaxStack(array.maxStack());
1636:
1637:                    if (MethodEditor.PRESERVE_DEBUG && (arr.length < 0x10000)) {
1638:                        final LocalDebugInfo[] locals = new LocalDebugInfo[vars
1639:                                .size()];
1640:
1641:                        for (int i = 0; i < vars.size(); i++) {
1642:                            final LocalVarEntry entry = (LocalVarEntry) vars
1643:                                    .get(i);
1644:
1645:                            final int start = array.labelIndex(entry.start);
1646:                            final int end = array.labelIndex(entry.end);
1647:
1648:                            if (start < end) {
1649:                                locals[i] = new LocalDebugInfo(start, end
1650:                                        - start, cp.addConstant(Constant.UTF8,
1651:                                        entry.var.name()), cp.addConstant(
1652:                                        Constant.UTF8, entry.var.type()
1653:                                                .descriptor()), entry.var
1654:                                        .index());
1655:                            }
1656:                        }
1657:
1658:                        methodInfo.setLocals(locals);
1659:
1660:                        final LineNumberDebugInfo[] lines = new LineNumberDebugInfo[lineNumbers
1661:                                .size()];
1662:                        int i = 0;
1663:
1664:                        iter = lineNumbers.iterator();
1665:
1666:                        while (iter.hasNext()) {
1667:                            final LineNumberEntry line = (LineNumberEntry) iter
1668:                                    .next();
1669:                            lines[i++] = new LineNumberDebugInfo(array
1670:                                    .labelIndex(line.label), line.lineNumber);
1671:                        }
1672:
1673:                        methodInfo.setLineNumbers(lines);
1674:                    } else {
1675:                        methodInfo.setLineNumbers(null);
1676:                        methodInfo.setLocals(null);
1677:                    }
1678:
1679:                    final List c = new LinkedList();
1680:
1681:                    iter = tryCatches.iterator();
1682:
1683:                    while (iter.hasNext()) {
1684:                        final TryCatch tc = (TryCatch) iter.next();
1685:
1686:                        final int start = array.labelIndex(tc.start());
1687:                        final int end = array.labelIndex(tc.end());
1688:
1689:                        if (start < end) {
1690:                            c.add(new Catch(start, end, array.labelIndex(tc
1691:                                    .handler()), cp.addConstant(Constant.CLASS,
1692:                                    tc.type())));
1693:                        }
1694:                    }
1695:
1696:                    final Object[] a = c.toArray();
1697:                    final Catch[] catches = new Catch[a.length];
1698:                    System.arraycopy(a, 0, catches, 0, a.length);
1699:
1700:                    methodInfo.setExceptionHandlers(catches);
1701:
1702:                }
1703:
1704:                if (ClassEditor.DEBUG) {
1705:                    System.out
1706:                            .println("MethodInfo after commit: " + methodInfo);
1707:                }
1708:
1709:                // Method is no longer dirty
1710:                this .isDirty = false;
1711:            }
1712:
1713:            /**
1714:             * Print the method.
1715:             * 
1716:             * @param out
1717:             *            Stream to which to print.
1718:             */
1719:            public void print(final PrintStream out) {
1720:                out.println(name + "." + type + (isDirty ? " (dirty) " : "")
1721:                        + ":");
1722:
1723:                Iterator iter;
1724:
1725:                iter = code.iterator();
1726:
1727:                while (iter.hasNext()) {
1728:                    out.println("    " + iter.next());
1729:                }
1730:
1731:                iter = tryCatches.iterator();
1732:
1733:                while (iter.hasNext()) {
1734:                    out.println("    " + iter.next());
1735:                }
1736:            }
1737:
1738:            /**
1739:             * Two <tt>MethodEditor</tt>s are equal if they edit the same method in
1740:             * the same class.
1741:             */
1742:            public boolean equals(final Object o) {
1743:                if (o instanceof  MethodEditor) {
1744:                    final MethodEditor other = (MethodEditor) o;
1745:
1746:                    if (!other.declaringClass().equals(this .declaringClass())) {
1747:                        return (false);
1748:                    }
1749:                    if (!other.name().equals(this .name())) {
1750:                        return (false);
1751:                    }
1752:                    if (!other.type().equals(this .type())) {
1753:                        return (false);
1754:                    }
1755:
1756:                    return (true);
1757:                }
1758:
1759:                return (false);
1760:            }
1761:
1762:            /**
1763:             * A <tt>MethodEditor</tt>'s hash code is based on the hash codes for its
1764:             * class, name, and type.
1765:             */
1766:            public int hashCode() {
1767:                return (this .declaringClass().hashCode()
1768:                        + this .name().hashCode() + this .type().hashCode());
1769:            }
1770:
1771:            public String toString() {
1772:                return (editor.type() + "." + name + type);
1773:            }
1774:
1775:            public UseMap uMap() {
1776:                return uMap;
1777:            }
1778:
1779:            public void rememberDef(final LocalExpr e) {
1780:                if (MethodEditor.OPT_STACK_2) {
1781:                    uMap.add(e, (Instruction) code.get(code.size() - 1));
1782:                }
1783:            }
1784:
1785:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.