Source Code Cross Referenced for MethodBuilder.java in  » XML » jibx-1.1.5 » org » jibx » binding » classes » 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 » XML » jibx 1.1.5 » org.jibx.binding.classes 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


0001:        /*
0002:        Copyright (c) 2003-2005, Dennis M. Sosnoski
0003:        All rights reserved.
0004:
0005:        Redistribution and use in source and binary forms, with or without modification,
0006:        are permitted provided that the following conditions are met:
0007:
0008:         * Redistributions of source code must retain the above copyright notice, this
0009:           list of conditions and the following disclaimer.
0010:         * Redistributions in binary form must reproduce the above copyright notice,
0011:           this list of conditions and the following disclaimer in the documentation
0012:           and/or other materials provided with the distribution.
0013:         * Neither the name of JiBX nor the names of its contributors may be used
0014:           to endorse or promote products derived from this software without specific
0015:           prior written permission.
0016:
0017:        THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
0018:        ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
0019:        WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
0020:        DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
0021:        ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
0022:        (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
0023:        LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
0024:        ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
0025:        (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
0026:        SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
0027:         */
0028:
0029:        package org.jibx.binding.classes;
0030:
0031:        import java.util.ArrayList;
0032:        import java.util.HashMap;
0033:
0034:        import org.apache.bcel.Constants;
0035:        import org.apache.bcel.classfile.Method;
0036:        import org.apache.bcel.classfile.Utility;
0037:        import org.apache.bcel.generic.ANEWARRAY;
0038:        import org.apache.bcel.generic.BranchHandle;
0039:        import org.apache.bcel.generic.CompoundInstruction;
0040:        import org.apache.bcel.generic.GOTO;
0041:        import org.apache.bcel.generic.IFEQ;
0042:        import org.apache.bcel.generic.IFGE;
0043:        import org.apache.bcel.generic.IFLT;
0044:        import org.apache.bcel.generic.IFNE;
0045:        import org.apache.bcel.generic.IFNONNULL;
0046:        import org.apache.bcel.generic.IFNULL;
0047:        import org.apache.bcel.generic.IF_ICMPNE;
0048:        import org.apache.bcel.generic.IINC;
0049:        import org.apache.bcel.generic.Instruction;
0050:        import org.apache.bcel.generic.InstructionConstants;
0051:        import org.apache.bcel.generic.InstructionFactory;
0052:        import org.apache.bcel.generic.InstructionHandle;
0053:        import org.apache.bcel.generic.InstructionList;
0054:        import org.apache.bcel.generic.LocalVariableGen;
0055:        import org.apache.bcel.generic.MULTIANEWARRAY;
0056:        import org.apache.bcel.generic.MethodGen;
0057:        import org.apache.bcel.generic.NEWARRAY;
0058:        import org.apache.bcel.generic.ReferenceType;
0059:        import org.apache.bcel.generic.Type;
0060:        import org.jibx.binding.util.StringStack;
0061:        import org.jibx.runtime.JiBXException;
0062:
0063:        /**
0064:         * Method builder. Organizes and tracks the creation of a method, providing
0065:         * convenience methods for common operations. This is customized for the needs
0066:         * of JiBX, with some predetermined settings as appropriate. It supplies hash
0067:         * code and equality checking based on the method signature and actual byte
0068:         * code of the generated method, ignoring the method name.
0069:         *
0070:         * @author Dennis M. Sosnoski
0071:         * @version 1.0
0072:         */
0073:        public abstract class MethodBuilder extends BindingMethod {
0074:            //
0075:            // Constants for code generation.
0076:
0077:            public static final String FRAMEWORK_EXCEPTION_CLASS = "org.jibx.runtime.JiBXException";
0078:
0079:            public static final String EXCEPTION_CONSTRUCTOR_SIGNATURE1 = "(Ljava/lang/String;)V";
0080:
0081:            public static final String EXCEPTION_CONSTRUCTOR_SIGNATURE2 = "(Ljava/lang/String;Ljava/lang/Throwable;)V";
0082:
0083:            public static final int SYNTHETIC_ACCESS_FLAG = 0x1000;
0084:
0085:            //
0086:            // Static data.
0087:
0088:            /** Table of argument name lists (generated as needed). */
0089:            protected static ArrayList s_argNameLists = new ArrayList();
0090:
0091:            /** Zero-length string array. */
0092:            protected static String[] EMPTY_STRING_ARRAY = new String[0];
0093:
0094:            //
0095:            // Actual instance data
0096:
0097:            /** Builder for class instructions. */
0098:            protected InstructionBuilder m_instructionBuilder;
0099:
0100:            /** List of instructions in method definition. */
0101:            private InstructionList m_instructionList;
0102:
0103:            /** List of types currently on stack. */
0104:            private StringStack m_stackState;
0105:
0106:            /** Generator for constructing method. */
0107:            protected MethodGen m_generator;
0108:
0109:            /** Actual generated method information. */
0110:            protected Method m_method;
0111:
0112:            /** Method class item information. */
0113:            protected ClassItem m_item;
0114:
0115:            /** Value types associated with local variable slots. */
0116:            private ArrayList m_localTypes;
0117:
0118:            /** Exceptions needing to be handled in method (lazy create,
0119:             <code>null</code> if not used). */
0120:            protected ArrayList m_exceptions;
0121:
0122:            /** Accumulated hash code from adding instructions. */
0123:            protected int m_hashCode;
0124:
0125:            /** Branch to be aimed at next appended instruction. */
0126:            protected BranchWrapper[] m_targetBranches;
0127:
0128:            /** Map for initialized properties (lazy create, <code>null</code> if not
0129:             used). */
0130:            protected HashMap m_valueMap;
0131:
0132:            /**
0133:             * Constructor. This sets up for constructing a method with public access.
0134:             *
0135:             * @param name method name to be built
0136:             * @param ret method return type
0137:             * @param args types of arguments
0138:             * @param cf owning class file information
0139:             * @param access flags for method access
0140:             * @throws JiBXException on error in constructing method
0141:             */
0142:            protected MethodBuilder(String name, Type ret, Type[] args,
0143:                    ClassFile cf, int access) throws JiBXException {
0144:                super (cf);
0145:
0146:                // make sure the dummy argument names are defined
0147:                if (args.length >= s_argNameLists.size()) {
0148:
0149:                    // append to end of argument names list
0150:                    for (int i = s_argNameLists.size(); i <= args.length; i++) {
0151:                        String[] list = new String[i];
0152:                        if (i > 0) {
0153:                            Object last = s_argNameLists.get(i - 1);
0154:                            System.arraycopy(last, 0, list, 0, i - 1);
0155:                            list[i - 1] = "arg" + i;
0156:                        }
0157:                        s_argNameLists.add(list);
0158:                    }
0159:
0160:                }
0161:
0162:                // create the method generator with empty instruction list
0163:                String[] names = (String[]) s_argNameLists.get(args.length);
0164:                m_instructionList = new InstructionList();
0165:                m_stackState = new StringStack();
0166:                m_instructionBuilder = cf.getInstructionBuilder();
0167:                m_generator = new MethodGen(access | SYNTHETIC_ACCESS_FLAG,
0168:                        ret, args, names, name, cf.getName(),
0169:                        m_instructionList, cf.getConstPoolGen());
0170:
0171:                // initialize local variables for method parameters
0172:                m_localTypes = new ArrayList();
0173:                if ((access & Constants.ACC_STATIC) == 0) {
0174:                    m_localTypes.add(cf.getName());
0175:                }
0176:                for (int i = 0; i < args.length; i++) {
0177:                    m_localTypes.add(args[i].toString());
0178:                    if (args[i].getSize() > 1) {
0179:                        m_localTypes.add(null);
0180:                    }
0181:                }
0182:            }
0183:
0184:            /**
0185:             * Get name of method being constructed.
0186:             *
0187:             * @return name of method being constructed
0188:             */
0189:            public String getName() {
0190:                return m_generator.getName();
0191:            }
0192:
0193:            /**
0194:             * Get signature.
0195:             *
0196:             * @return signature for method
0197:             */
0198:            public String getSignature() {
0199:                return m_generator.getSignature();
0200:            }
0201:
0202:            /**
0203:             * Get access flags.
0204:             *
0205:             * @return flags for access type of method
0206:             */
0207:            public int getAccessFlags() {
0208:                return m_generator.getAccessFlags();
0209:            }
0210:
0211:            /**
0212:             * Set access flags.
0213:             *
0214:             * @param flags access type to be set
0215:             */
0216:            public void setAccessFlags(int flags) {
0217:                m_generator.setAccessFlags(flags);
0218:            }
0219:
0220:            /**
0221:             * Get the actual method. This can only be called once code generation is
0222:             * completed (after the {@link #codeComplete(boolean)} method is called).
0223:             *
0224:             * @return constructed method information
0225:             */
0226:            public Method getMethod() {
0227:                if (m_method == null) {
0228:                    throw new IllegalStateException(
0229:                            "Method still under construction");
0230:                } else {
0231:                    return m_method;
0232:                }
0233:            }
0234:
0235:            /**
0236:             * Add keyed value to method definition.
0237:             *
0238:             * @param key retrieval key
0239:             * @param value keyed value
0240:             * @return prior value for key
0241:             */
0242:            public Object setKeyValue(Object key, Object value) {
0243:                if (m_valueMap == null) {
0244:                    m_valueMap = new HashMap();
0245:                }
0246:                return m_valueMap.put(key, value);
0247:            }
0248:
0249:            /**
0250:             * Get local variable for object.
0251:             * 
0252:             * @param key object key for local variable
0253:             * @return local variable
0254:             */
0255:            public Object getKeyValue(Object key) {
0256:                return m_valueMap == null ? null : m_valueMap.get(key);
0257:            }
0258:
0259:            /**
0260:             * Add exception to those needing handling.
0261:             *
0262:             * @param name fully qualified name of exception class
0263:             */
0264:            public void addException(String name) {
0265:                if (m_exceptions == null) {
0266:                    m_exceptions = new ArrayList();
0267:                }
0268:                if (!m_exceptions.contains(name)) {
0269:                    m_exceptions.add(name);
0270:                }
0271:            }
0272:
0273:            /**
0274:             * Add exceptions thrown by called method to those needing handling.
0275:             *
0276:             * @param method information for method to be handled
0277:             */
0278:            public void addMethodExceptions(ClassItem method) {
0279:                String[] excepts = method.getExceptions();
0280:                if (excepts != null) {
0281:                    for (int i = 0; i < excepts.length; i++) {
0282:                        addException(excepts[i]);
0283:                    }
0284:                }
0285:            }
0286:
0287:            /**
0288:             * Get first instruction in method.
0289:             *
0290:             * @return handle for first instruction in method
0291:             */
0292:            protected InstructionHandle getFirstInstruction() {
0293:                return m_instructionList.getStart();
0294:            }
0295:
0296:            /**
0297:             * Get last instruction in method.
0298:             *
0299:             * @return handle for last instruction in method
0300:             */
0301:            protected InstructionHandle getLastInstruction() {
0302:                return m_instructionList.getEnd();
0303:            }
0304:
0305:            /**
0306:             * Target branches if pending. This implements setting the target of
0307:             * branch instructions supplied using the {@link #targetNext} method.
0308:             *
0309:             * @param inst handle for appended instruction
0310:             */
0311:            protected final void setTarget(InstructionHandle inst) {
0312:                if (m_targetBranches != null) {
0313:
0314:                    // TODO: fix this ugly kludge with code rewrite
0315:                    // adjust stack with POPs if need to match size
0316:                    String[] types = m_stackState.toArray();
0317:                    if (m_targetBranches.length > 0) {
0318:                        boolean match = true;
0319:                        int depth = m_targetBranches[0].getStackState().length;
0320:                        for (int i = 1; i < m_targetBranches.length; i++) {
0321:                            if (depth != m_targetBranches[i].getStackState().length) {
0322:                                match = false;
0323:                                break;
0324:                            }
0325:                        }
0326:                        if (match) {
0327:                            if (depth > types.length) {
0328:                                BranchWrapper merge = new BranchWrapper(
0329:                                        m_instructionList.insert(inst,
0330:                                                new GOTO(null)), types, this );
0331:                                String[] stack = m_targetBranches[0]
0332:                                        .getStackState();
0333:                                m_stackState = new StringStack(stack);
0334:                                InstructionHandle poph = m_instructionList
0335:                                        .insert(inst, InstructionConstants.POP);
0336:                                for (int i = 0; i < m_targetBranches.length; i++) {
0337:                                    m_targetBranches[i].setTarget(poph, stack,
0338:                                            this );
0339:                                }
0340:                                m_stackState.pop();
0341:                                while (m_stackState.size() > types.length) {
0342:                                    m_instructionList.insert(inst,
0343:                                            InstructionConstants.POP);
0344:                                    m_stackState.pop();
0345:                                }
0346:                                merge.setTarget(inst, m_stackState.toArray(),
0347:                                        this );
0348:                                m_targetBranches = null;
0349:                                return;
0350:                            } else {
0351:                                while (depth < types.length) {
0352:                                    m_instructionList.insert(inst,
0353:                                            InstructionConstants.POP);
0354:                                    m_stackState.pop();
0355:                                    types = m_stackState.toArray();
0356:                                }
0357:                            }
0358:                        }
0359:                    }
0360:
0361:                    // set all branch targets
0362:                    for (int i = 0; i < m_targetBranches.length; i++) {
0363:                        m_targetBranches[i].setTarget(inst, types, this );
0364:                    }
0365:                    m_targetBranches = null;
0366:                }
0367:            }
0368:
0369:            /**
0370:             * Generate description of current stack state.
0371:             *
0372:             * @return stack state description
0373:             */
0374:            private String describeStack() {
0375:                StringBuffer buff = new StringBuffer();
0376:                String[] types = m_stackState.toArray();
0377:                for (int i = 0; i < types.length; i++) {
0378:                    buff.append("  ");
0379:                    buff.append(i);
0380:                    buff.append(": ");
0381:                    buff.append(types[i]);
0382:                    buff.append('\n');
0383:                }
0384:                return buff.toString();
0385:            }
0386:
0387:            /**
0388:             * Verify that a pair of value types represent compatible types. This checks
0389:             * for equal types or downcast object types.
0390:             *
0391:             * @param type actual known type of value
0392:             * @param need type needed
0393:             */
0394:            private void verifyCompatible(String type, String need) {
0395:                if (!need.equals(type)) {
0396:                    try {
0397:                        if ("<null>".equals(type)) {
0398:                            if (ClassItem.isPrimitive(need)) {
0399:                                throw new IllegalStateException(
0400:                                        "Internal error: Expected " + need
0401:                                                + " on stack , found null");
0402:                            }
0403:                        } else if ("java.lang.Object".equals(need)) {
0404:                            if (ClassItem.isPrimitive(type)) {
0405:                                throw new IllegalStateException(
0406:                                        "Internal error: "
0407:                                                + "Expected object reference on stack, found "
0408:                                                + type + "\n full stack:\n"
0409:                                                + describeStack());
0410:                            }
0411:                        } else {
0412:                            boolean match = false;
0413:                            if ("int".equals(need)) {
0414:                                match = "boolean".equals(type)
0415:                                        || "short".equals(type)
0416:                                        || "char".equals(type)
0417:                                        || "byte".equals(type);
0418:                            } else if ("int".equals(type)) {
0419:                                match = "boolean".equals(need)
0420:                                        || "short".equals(need)
0421:                                        || "char".equals(need)
0422:                                        || "byte".equals(need);
0423:                            }
0424:                            if (!match && !ClassItem.isAssignable(type, need)) {
0425:                                throw new IllegalStateException(
0426:                                        "Internal error: Expected " + need
0427:                                                + " on stack, found " + type
0428:                                                + "\n full stack:\n"
0429:                                                + describeStack());
0430:                            }
0431:                        }
0432:                    } catch (JiBXException e) {
0433:                        throw new RuntimeException(
0434:                                "Internal error: Attempting to compare types "
0435:                                        + need + " and " + type);
0436:                    }
0437:                }
0438:            }
0439:
0440:            /**
0441:             * Verify that at least the specified number of items are present on the
0442:             * stack.
0443:             *
0444:             * @param count minimum number of items required
0445:             */
0446:            private void verifyStackDepth(int count) {
0447:                if (m_stackState.size() < count) {
0448:                    throw new IllegalStateException(
0449:                            "Internal error: Too few values on stack\n full stack:\n"
0450:                                    + describeStack());
0451:                }
0452:            }
0453:
0454:            /**
0455:             * Verify the top value in the stack state resulting from the current
0456:             * instruction list.
0457:             *
0458:             * @param t1 expected type for top item on stack
0459:             */
0460:            private void verifyStack(String t1) {
0461:                verifyStackDepth(1);
0462:                verifyCompatible(m_stackState.peek(), t1);
0463:            }
0464:
0465:            /**
0466:             * Verify the top value in the stack state resulting from the current
0467:             * instruction list is an array.
0468:             *
0469:             * @return array item type
0470:             */
0471:            private String verifyArray() {
0472:                verifyStackDepth(1);
0473:                String type = m_stackState.peek();
0474:                if (type.endsWith("[]")) {
0475:                    return type.substring(0, type.length() - 2);
0476:                } else {
0477:                    throw new IllegalStateException(
0478:                            "Internal error: Expected array type on stack , found "
0479:                                    + type);
0480:                }
0481:            }
0482:
0483:            /**
0484:             * Verify the top value in the stack state resulting from the current
0485:             * instruction list is an array of the specified type.
0486:             *
0487:             * @param type array item type
0488:             */
0489:            private void verifyArray(String type) {
0490:                String atype = verifyArray();
0491:                if (!atype.equals(type)) {
0492:                    throw new IllegalStateException(
0493:                            "Internal error: Expected array of " + type
0494:                                    + " on stack , found array of " + atype);
0495:                }
0496:            }
0497:
0498:            /**
0499:             * Verify the top two values in the stack state resulting from the current
0500:             * instruction list.
0501:             *
0502:             * @param t1 expected type for first item on stack
0503:             * @param t2 expected type for second item on stack
0504:             */
0505:            private void verifyStack(String t1, String t2) {
0506:                verifyStackDepth(2);
0507:                verifyCompatible(m_stackState.peek(), t1);
0508:                verifyCompatible(m_stackState.peek(1), t2);
0509:            }
0510:
0511:            /**
0512:             * Verify the top values in the stack state resulting from the current
0513:             * instruction list. This form checks only the actual call parameters.
0514:             *
0515:             * @param types expected parameter types on stack
0516:             */
0517:            private void verifyCallStack(String[] types) {
0518:
0519:                // make sure there are enough items on stack
0520:                int count = types.length;
0521:                verifyStackDepth(count);
0522:
0523:                // verify all parameter types for call
0524:                for (int i = 0; i < count; i++) {
0525:                    int slot = count - i - 1;
0526:                    verifyCompatible(m_stackState.peek(slot), types[i]);
0527:                }
0528:            }
0529:
0530:            /**
0531:             * Verify the top values in the stack state resulting from the current
0532:             * instruction list. This form checks both the object being called and the
0533:             * actual call parameters.
0534:             *
0535:             * @param clas name of method class
0536:             * @param types expected parameter types on stack
0537:             */
0538:            private void verifyCallStack(String clas, String[] types) {
0539:
0540:                // start by verifying object reference
0541:                int count = types.length;
0542:                verifyStackDepth(count + 1);
0543:                verifyCompatible(m_stackState.peek(count), clas);
0544:
0545:                // check values for call parameters
0546:                verifyCallStack(types);
0547:            }
0548:
0549:            /**
0550:             * Verify that the top value in the stack state resulting from the current
0551:             * instruction list is an object reference.
0552:             */
0553:            private void verifyStackObject() {
0554:                verifyStackDepth(1);
0555:                String top = m_stackState.peek();
0556:                if (ClassItem.isPrimitive(top)) {
0557:                    throw new IllegalStateException("Internal error: "
0558:                            + "Expected object reference on stack , found "
0559:                            + m_stackState.peek() + "\n full stack:\n"
0560:                            + describeStack());
0561:                }
0562:            }
0563:
0564:            /**
0565:             * Append IFEQ branch instruction to method.
0566:             *
0567:             * @param src object responsible for generating branch
0568:             * @return wrapper for appended conditional branch
0569:             */
0570:            public BranchWrapper appendIFEQ(Object src) {
0571:                verifyStack("int");
0572:                BranchHandle hand = m_instructionList.append(new IFEQ(null));
0573:                setTarget(hand);
0574:                m_stackState.pop();
0575:                return new BranchWrapper(hand, m_stackState.toArray(), src);
0576:            }
0577:
0578:            /**
0579:             * Append IFGE branch instruction to method.
0580:             *
0581:             * @param src object responsible for generating branch
0582:             * @return wrapper for appended conditional branch
0583:             */
0584:            public BranchWrapper appendIFGE(Object src) {
0585:                verifyStack("int");
0586:                BranchHandle hand = m_instructionList.append(new IFGE(null));
0587:                setTarget(hand);
0588:                m_stackState.pop();
0589:                return new BranchWrapper(hand, m_stackState.toArray(), src);
0590:            }
0591:
0592:            /**
0593:             * Append IFLT branch instruction to method.
0594:             *
0595:             * @param src object responsible for generating branch
0596:             * @return wrapper for appended conditional branch
0597:             */
0598:            public BranchWrapper appendIFLT(Object src) {
0599:                verifyStack("int");
0600:                BranchHandle hand = m_instructionList.append(new IFLT(null));
0601:                setTarget(hand);
0602:                m_stackState.pop();
0603:                return new BranchWrapper(hand, m_stackState.toArray(), src);
0604:            }
0605:
0606:            /**
0607:             * Append IFNE branch instruction to method.
0608:             *
0609:             * @param src object responsible for generating branch
0610:             * @return wrapper for appended conditional branch
0611:             */
0612:            public BranchWrapper appendIFNE(Object src) {
0613:                verifyStack("int");
0614:                BranchHandle hand = m_instructionList.append(new IFNE(null));
0615:                setTarget(hand);
0616:                m_stackState.pop();
0617:                return new BranchWrapper(hand, m_stackState.toArray(), src);
0618:            }
0619:
0620:            /**
0621:             * Append IFNONNULL branch instruction to method.
0622:             *
0623:             * @param src object responsible for generating branch
0624:             * @return wrapper for appended conditional branch
0625:             */
0626:            public BranchWrapper appendIFNONNULL(Object src) {
0627:                verifyStackObject();
0628:                BranchHandle hand = m_instructionList
0629:                        .append(new IFNONNULL(null));
0630:                setTarget(hand);
0631:                m_stackState.pop();
0632:                return new BranchWrapper(hand, m_stackState.toArray(), src);
0633:            }
0634:
0635:            /**
0636:             * Append IFNULL branch instruction to method.
0637:             *
0638:             * @param src object responsible for generating branch
0639:             * @return wrapper for appended conditional branch
0640:             */
0641:            public BranchWrapper appendIFNULL(Object src) {
0642:                verifyStackObject();
0643:                BranchHandle hand = m_instructionList.append(new IFNULL(null));
0644:                setTarget(hand);
0645:                m_stackState.pop();
0646:                return new BranchWrapper(hand, m_stackState.toArray(), src);
0647:            }
0648:
0649:            /**
0650:             * Append IF_ICMPNE branch instruction to method.
0651:             *
0652:             * @param src object responsible for generating branch
0653:             * @return wrapper for appended conditional branch
0654:             */
0655:            public BranchWrapper appendIF_ICMPNE(Object src) {
0656:                verifyStack("int", "int");
0657:                BranchHandle hand = m_instructionList
0658:                        .append(new IF_ICMPNE(null));
0659:                setTarget(hand);
0660:                m_stackState.pop(2);
0661:                return new BranchWrapper(hand, m_stackState.toArray(), src);
0662:            }
0663:
0664:            /**
0665:             * Append unconditional branch instruction to method.
0666:             *
0667:             * @param src object responsible for generating branch
0668:             * @return wrapper for appended unconditional branch
0669:             */
0670:            public BranchWrapper appendUnconditionalBranch(Object src) {
0671:                BranchHandle hand = m_instructionList.append(new GOTO(null));
0672:                setTarget(hand);
0673:                BranchWrapper wrapper = new BranchWrapper(hand, m_stackState
0674:                        .toArray(), src);
0675:                m_stackState = null;
0676:                return wrapper;
0677:            }
0678:
0679:            /**
0680:             * Append compound instruction to method.
0681:             *
0682:             * @param ins instruction to be appended
0683:             */
0684:            private void append(CompoundInstruction ins) {
0685:                setTarget(m_instructionList.append(ins));
0686:            }
0687:
0688:            /**
0689:             * Append instruction to method.
0690:             *
0691:             * @param ins instruction to be appended
0692:             */
0693:            private void append(Instruction ins) {
0694:                setTarget(m_instructionList.append(ins));
0695:            }
0696:
0697:            /**
0698:             * Create load constant instruction and append to method. Builds the most
0699:             * appropriate type of instruction for the value.
0700:             *
0701:             * @param value constant value to be loaded
0702:             */
0703:            public void appendLoadConstant(int value) {
0704:                append(m_instructionBuilder.createLoadConstant(value));
0705:                m_stackState.push("int");
0706:            }
0707:
0708:            /**
0709:             * Create load constant instruction and append to method. Loads a
0710:             * <code>String</code> reference from the constant pool.
0711:             *
0712:             * @param value constant value to be loaded
0713:             */
0714:            public void appendLoadConstant(String value) {
0715:                append(m_instructionBuilder.createLoadConstant(value));
0716:                m_stackState.push("java.lang.String");
0717:            }
0718:
0719:            /**
0720:             * Create load constant instruction and append to method. Loads an
0721:             * unwrapped primitive value from the constant pool.
0722:             *
0723:             * @param value constant value to be loaded
0724:             */
0725:            public void appendLoadConstant(Object value) {
0726:                append(m_instructionBuilder.createLoadConstant(value));
0727:                if (value instanceof  Integer || value instanceof  Character
0728:                        || value instanceof  Short || value instanceof  Boolean
0729:                        || value instanceof  Byte) {
0730:                    m_stackState.push("int");
0731:                } else if (value instanceof  Long) {
0732:                    m_stackState.push("long");
0733:                } else if (value instanceof  Float) {
0734:                    m_stackState.push("float");
0735:                } else if (value instanceof  Double) {
0736:                    m_stackState.push("double");
0737:                } else {
0738:                    throw new IllegalArgumentException("Unknown argument type");
0739:                }
0740:            }
0741:
0742:            /**
0743:             * Create getfield instruction and append to method. Uses the target field
0744:             * information to generate the instruction.
0745:             *
0746:             * @param item information for field to be gotton
0747:             */
0748:            public void appendGetField(ClassItem item) {
0749:                verifyStack(item.getClassFile().getName());
0750:                append(m_instructionBuilder.createGetField(item));
0751:                m_stackState.pop();
0752:                m_stackState.push(item.getTypeName());
0753:            }
0754:
0755:            /**
0756:             * Create getstatic instruction and append to method. Uses the target field
0757:             * information to generate the instruction.
0758:             *
0759:             * @param item information for field to be set
0760:             */
0761:            public void appendGetStatic(ClassItem item) {
0762:                append(m_instructionBuilder.createGetStatic(item));
0763:                m_stackState.push(item.getTypeName());
0764:            }
0765:
0766:            /**
0767:             * Create get instruction and append to method. This generates either a
0768:             * getstatic or a getfield instruction, as appropriate.
0769:             *
0770:             * @param item information for field to be gotten
0771:             */
0772:            public void appendGet(ClassItem item) {
0773:                if (item.isStatic()) {
0774:                    appendGetStatic(item);
0775:                } else {
0776:                    appendGetField(item);
0777:                }
0778:            }
0779:
0780:            /**
0781:             * Create putfield instruction and append to method. Uses the target field
0782:             * information to generate the instruction.
0783:             *
0784:             * @param item information for field to be set
0785:             */
0786:            public void appendPutField(ClassItem item) {
0787:                String tname = item.getTypeName();
0788:                verifyStack(tname, item.getClassFile().getName());
0789:                append(m_instructionBuilder.createPutField(item));
0790:                m_stackState.pop(2);
0791:            }
0792:
0793:            /**
0794:             * Create putstatic instruction and append to method. Uses the target field
0795:             * information to generate the instruction.
0796:             *
0797:             * @param item information for field to be set
0798:             */
0799:            public void appendPutStatic(ClassItem item) {
0800:                verifyStack(item.getTypeName());
0801:                append(m_instructionBuilder.createPutStatic(item));
0802:                m_stackState.pop();
0803:            }
0804:
0805:            /**
0806:             * Create put instruction and append to method. This generates either a
0807:             * putstatic or a putfield instruction, as appropriate.
0808:             *
0809:             * @param item information for field to be gotten
0810:             */
0811:            public void appendPut(ClassItem item) {
0812:                if (item.isStatic()) {
0813:                    appendPutStatic(item);
0814:                } else {
0815:                    appendPutField(item);
0816:                }
0817:            }
0818:
0819:            /**
0820:             * Create invoke instruction for static, member, or interface method and
0821:             * append to method. Uses the target method information to generate the
0822:             * correct instruction.
0823:             *
0824:             * @param item information for method to be called
0825:             */
0826:            public void appendCall(ClassItem item) {
0827:
0828:                // process based on call type
0829:                String[] types = item.getArgumentTypes();
0830:                int count = types.length;
0831:                if (item.getClassFile().isInterface()) {
0832:
0833:                    // process parameters and object reference for interface call
0834:                    verifyCallStack(item.getClassFile().getName(), types);
0835:                    append(m_instructionBuilder.createCallInterface(item));
0836:                    m_stackState.pop(count + 1);
0837:
0838:                } else if ((item.getAccessFlags() & Constants.ACC_STATIC) != 0) {
0839:
0840:                    // process only parameters for static call
0841:                    verifyCallStack(types);
0842:                    append(m_instructionBuilder.createCallStatic(item));
0843:                    if (count > 0) {
0844:                        m_stackState.pop(count);
0845:                    }
0846:
0847:                } else {
0848:
0849:                    // process parameters and object reference for normal method call
0850:                    verifyCallStack(item.getClassFile().getName(), types);
0851:                    append(m_instructionBuilder.createCallVirtual(item));
0852:                    m_stackState.pop(count + 1);
0853:                }
0854:
0855:                // adjust stack state to reflect result of call
0856:                if (!"void".equals(item.getTypeName())) {
0857:                    m_stackState.push(item.getTypeName());
0858:                }
0859:            }
0860:
0861:            /**
0862:             * Create invoke static method instruction from signature and append to
0863:             * method.
0864:             *
0865:             * @param method fully qualified class and method name
0866:             * @param signature method signature in standard form
0867:             */
0868:            public void appendCallStatic(String method, String signature) {
0869:
0870:                // verify all call parameters on stack
0871:                String[] types = ClassItem
0872:                        .getParametersFromSignature(signature);
0873:                verifyCallStack(types);
0874:
0875:                // generate the actual method call
0876:                append(m_instructionBuilder.createCallStatic(method, signature));
0877:
0878:                // change stack state to reflect result of call
0879:                if (types.length > 0) {
0880:                    m_stackState.pop(types.length);
0881:                }
0882:                String result = ClassItem.getTypeFromSignature(signature);
0883:                if (!"void".equals(result)) {
0884:                    m_stackState.push(result);
0885:                }
0886:            }
0887:
0888:            /**
0889:             * Create invoke virtual method instruction from signature and append to
0890:             * method.
0891:             *
0892:             * @param method fully qualified class and method name
0893:             * @param signature method signature in standard form
0894:             */
0895:            public void appendCallVirtual(String method, String signature) {
0896:
0897:                // verify all call parameters and object reference on stack
0898:                String[] types = ClassItem
0899:                        .getParametersFromSignature(signature);
0900:                int split = method.lastIndexOf('.');
0901:                if (split < 0) {
0902:                    throw new IllegalArgumentException(
0903:                            "Internal error: Missing class name on method "
0904:                                    + method);
0905:                }
0906:                verifyCallStack(method.substring(0, split), types);
0907:
0908:                // generate the actual method call
0909:                append(m_instructionBuilder
0910:                        .createCallVirtual(method, signature));
0911:
0912:                // change stack state to reflect result of call
0913:                m_stackState.pop(types.length + 1);
0914:                String result = ClassItem.getTypeFromSignature(signature);
0915:                if (!"void".equals(result)) {
0916:                    m_stackState.push(result);
0917:                }
0918:            }
0919:
0920:            /**
0921:             * Create invoke interface method instruction from signature and append to
0922:             * method.
0923:             *
0924:             * @param method fully qualified interface and method name
0925:             * @param signature method signature in standard form
0926:             */
0927:            public void appendCallInterface(String method, String signature) {
0928:
0929:                // verify all call parameters and object reference on stack
0930:                String[] types = ClassItem
0931:                        .getParametersFromSignature(signature);
0932:                int split = method.lastIndexOf('.');
0933:                if (split < 0) {
0934:                    throw new IllegalArgumentException(
0935:                            "Internal error: Missing class name on method "
0936:                                    + method);
0937:                }
0938:                verifyCallStack(method.substring(0, split), types);
0939:
0940:                // generate the actual method call
0941:                append(m_instructionBuilder.createCallInterface(method,
0942:                        signature));
0943:
0944:                // change stack state to reflect result of call
0945:                m_stackState.pop(types.length + 1);
0946:                String result = ClassItem.getTypeFromSignature(signature);
0947:                if (!"void".equals(result)) {
0948:                    m_stackState.push(result);
0949:                }
0950:            }
0951:
0952:            /**
0953:             * Append instruction to create instance of class.
0954:             *
0955:             * @param name fully qualified class name
0956:             */
0957:            public void appendCreateNew(String name) {
0958:                append(m_instructionBuilder.createNew(name));
0959:                m_stackState.push(name);
0960:            }
0961:
0962:            /**
0963:             * Create invoke initializer instruction from signature and append to
0964:             * method.
0965:             *
0966:             * @param name fully qualified class name
0967:             * @param signature method signature in standard form
0968:             */
0969:            public void appendCallInit(String name, String signature) {
0970:
0971:                // verify all call parameters and object reference on stack
0972:                String[] types = ClassItem
0973:                        .getParametersFromSignature(signature);
0974:                verifyCallStack(name, types);
0975:
0976:                // generate the actual method call
0977:                append(m_instructionBuilder.createCallInit(name, signature));
0978:
0979:                // change stack state to reflect result of call
0980:                m_stackState.pop(types.length + 1);
0981:            }
0982:
0983:            /**
0984:             * Append instruction to create instance of array.
0985:             *
0986:             * @param type fully qualified type name of array elements
0987:             */
0988:            public void appendCreateArray(String type) {
0989:                if (ClassItem.isPrimitive(type)) {
0990:                    String sig = Utility.getSignature(type);
0991:                    append(new NEWARRAY(Utility.typeOfSignature(sig)));
0992:                } else if (type.endsWith("[]")) {
0993:                    String cname = Utility.getSignature(type + "[]");
0994:                    append(new MULTIANEWARRAY(m_instructionBuilder
0995:                            .getConstantPoolGen().addClass(cname), (short) 1));
0996:                } else {
0997:                    append(new ANEWARRAY(m_instructionBuilder
0998:                            .getConstantPoolGen().addClass(type)));
0999:                }
1000:                m_stackState.pop();
1001:                m_stackState.push(type + "[]");
1002:            }
1003:
1004:            /**
1005:             * Append check cast instruction (if needed).
1006:             *
1007:             * @param from fully qualified name of current type
1008:             * @param to fully qualified name of desired type
1009:             */
1010:            public void appendCreateCast(String from, String to) {
1011:
1012:                // verify current top of stack
1013:                verifyStack(from);
1014:
1015:                // check if any change of type
1016:                if (!from.equals(to)) {
1017:
1018:                    // generate instruction and change stack state to match
1019:                    append(m_instructionBuilder.createCast(ClassItem
1020:                            .typeFromName(from), ClassItem.typeFromName(to)));
1021:                    m_stackState.pop();
1022:                    m_stackState.push(to);
1023:                }
1024:            }
1025:
1026:            /**
1027:             * Append check cast instruction from object (if needed).
1028:             *
1029:             * @param to fully qualified name of desired type
1030:             */
1031:            public void appendCreateCast(String to) {
1032:
1033:                // verify current top of stack
1034:                verifyStackObject();
1035:
1036:                // check if any change of type
1037:                if (!m_stackState.peek().equals(to)) {
1038:
1039:                    // generate instruction and change stack state to match
1040:                    append(m_instructionBuilder.createCast(Type.OBJECT,
1041:                            ClassItem.typeFromName(to)));
1042:                    m_stackState.pop();
1043:                    m_stackState.push(to);
1044:                }
1045:            }
1046:
1047:            /**
1048:             * Append instanceof check instruction.
1049:             *
1050:             * @param to fully qualified name of type to check
1051:             */
1052:            public void appendInstanceOf(String to) {
1053:
1054:                // make sure the stack has an object reference
1055:                verifyStackObject();
1056:
1057:                // see if anything actually needs to be checked
1058:                if ("java.lang.Object".equals(to)) {
1059:                    append(InstructionConstants.POP);
1060:                    appendLoadConstant(1);
1061:                } else {
1062:                    append(m_instructionBuilder
1063:                            .createInstanceOf((ReferenceType) ClassItem
1064:                                    .typeFromName(to)));
1065:                }
1066:
1067:                // change stack state to reflect results of added code
1068:                m_stackState.pop();
1069:                m_stackState.push("int");
1070:            }
1071:
1072:            /**
1073:             * Add local variable to method. The current code in the method must have
1074:             * the initial value for the variable on the stack. The scope of the
1075:             * variable is defined from the last instruction to the end of the
1076:             * method unless otherwise modified.
1077:             * 
1078:             * @param name local variable name (may be <code>null</code> to use default)
1079:             * @param type variable type
1080:             */
1081:            protected LocalVariableGen createLocal(String name, Type type) {
1082:
1083:                // verify top of stack
1084:                verifyStack(type.toString());
1085:
1086:                // create name if needed
1087:                if (name == null) {
1088:                    name = "var" + m_generator.getLocalVariables().length;
1089:                }
1090:
1091:                // allocation local and store value
1092:                LocalVariableGen var = m_generator.addLocalVariable(name, type,
1093:                        getLastInstruction(), null);
1094:                append(InstructionFactory.createStore(type, var.getIndex()));
1095:
1096:                // save type information for local variable slot
1097:                int slot = var.getIndex();
1098:                while (slot >= m_localTypes.size()) {
1099:                    m_localTypes.add(null);
1100:                }
1101:                m_localTypes.set(slot, type.toString());
1102:
1103:                // change stack state to reflect result
1104:                m_stackState.pop();
1105:                return var;
1106:            }
1107:
1108:            /**
1109:             * Add local variable to method. The current code in the method must have
1110:             * the initial value for the variable on the stack. The scope of the
1111:             * variable is defined from the preceding instruction to the end of the
1112:             * method.
1113:             * 
1114:             * @param name local variable name
1115:             * @param type variable type
1116:             * @return local variable slot number
1117:             */
1118:            public int addLocal(String name, Type type) {
1119:                LocalVariableGen var = createLocal(name, type);
1120:                return var.getIndex();
1121:            }
1122:
1123:            /**
1124:             * Append instruction to load local variable.
1125:             *
1126:             * @param slot local variable slot to load
1127:             */
1128:            public void appendLoadLocal(int slot) {
1129:                String type = (String) m_localTypes.get(slot);
1130:                if (type == null) {
1131:                    throw new IllegalArgumentException(
1132:                            "Internal error: No variable defined at position "
1133:                                    + slot);
1134:                }
1135:                append(InstructionFactory.createLoad(ClassItem
1136:                        .typeFromName(type), slot));
1137:                m_stackState.push(type);
1138:            }
1139:
1140:            /**
1141:             * Append instruction to store local variable.
1142:             *
1143:             * @param slot local variable slot to store
1144:             */
1145:            public void appendStoreLocal(int slot) {
1146:                String type = (String) m_localTypes.get(slot);
1147:                if (type == null) {
1148:                    throw new IllegalArgumentException(
1149:                            "Internal error: No variable defined at position "
1150:                                    + slot);
1151:                }
1152:                verifyStack(type);
1153:                append(InstructionFactory.createStore(ClassItem
1154:                        .typeFromName(type), slot));
1155:                m_stackState.pop();
1156:            }
1157:
1158:            /**
1159:             * Append instruction to increment local integer variable.
1160:             *
1161:             * @param inc amount of incrment
1162:             * @param slot local variable slot to load
1163:             */
1164:            public void appendIncrementLocal(int inc, int slot) {
1165:                String type = (String) m_localTypes.get(slot);
1166:                if (type == null) {
1167:                    throw new IllegalArgumentException(
1168:                            "Internal error: No variable defined at position "
1169:                                    + slot);
1170:                } else if (!"int".equals(type)) {
1171:                    throw new IllegalArgumentException(
1172:                            "Internal error: Variable at " + slot + " is "
1173:                                    + type + ", not int");
1174:                }
1175:                append(new IINC(slot, inc));
1176:            }
1177:
1178:            /**
1179:             * Append simple return.
1180:             */
1181:            public void appendReturn() {
1182:                append(InstructionConstants.RETURN);
1183:                m_stackState = null;
1184:            }
1185:
1186:            /**
1187:             * Append typed return.
1188:             *
1189:             * @param type returned type (may be <code>Type.VOID</code>)
1190:             */
1191:            public void appendReturn(Type type) {
1192:
1193:                // verify and return the object reference
1194:                if (type != Type.VOID) {
1195:                    verifyStack(type.toString());
1196:                }
1197:                append(InstructionFactory.createReturn(type));
1198:
1199:                // set open stack state for potential continuation code
1200:                m_stackState = null;
1201:            }
1202:
1203:            /**
1204:             * Append typed return.
1205:             *
1206:             * @param type returned type (may be <code>void</code>)
1207:             */
1208:            public void appendReturn(String type) {
1209:
1210:                // verify stack and generate return
1211:                if ("void".equals(type)) {
1212:                    append(InstructionConstants.RETURN);
1213:                } else {
1214:                    verifyStack(type);
1215:                    if (ClassItem.isPrimitive(type)) {
1216:                        if ("int".equals(type) || "char".equals(type)
1217:                                || "short".equals(type)
1218:                                || "boolean".equals(type)) {
1219:                            append(InstructionConstants.IRETURN);
1220:                        } else if ("long".equals(type)) {
1221:                            append(InstructionConstants.LRETURN);
1222:                        } else if ("float".equals(type)) {
1223:                            append(InstructionConstants.FRETURN);
1224:                        } else if ("double".equals(type)) {
1225:                            append(InstructionConstants.DRETURN);
1226:                        } else {
1227:                            throw new IllegalArgumentException(
1228:                                    "Unknown argument type");
1229:                        }
1230:                    } else {
1231:                        append(InstructionConstants.ARETURN);
1232:                    }
1233:                }
1234:
1235:                // set open stack state for potential continuation code
1236:                m_stackState = null;
1237:            }
1238:
1239:            /**
1240:             * Append exception throw.
1241:             */
1242:            public void appendThrow() {
1243:                append(InstructionConstants.ATHROW);
1244:                m_stackState = null;
1245:            }
1246:
1247:            /**
1248:             * Append appropriate array load to the instruction list.
1249:             * 
1250:             * @param type array item type expected
1251:             */
1252:            public void appendALOAD(String type) {
1253:                verifyStack("int");
1254:                m_stackState.pop();
1255:                verifyArray(type);
1256:                if ("byte".equals(type) || "boolean".equals(type)) {
1257:                    append(InstructionConstants.BALOAD);
1258:                } else if ("char".equals(type)) {
1259:                    append(InstructionConstants.CALOAD);
1260:                } else if ("double".equals(type)) {
1261:                    append(InstructionConstants.DALOAD);
1262:                } else if ("float".equals(type)) {
1263:                    append(InstructionConstants.FALOAD);
1264:                } else if ("int".equals(type)) {
1265:                    append(InstructionConstants.IALOAD);
1266:                } else if ("long".equals(type)) {
1267:                    append(InstructionConstants.LALOAD);
1268:                } else if ("short".equals(type)) {
1269:                    append(InstructionConstants.SALOAD);
1270:                } else {
1271:                    append(InstructionConstants.AALOAD);
1272:                }
1273:                m_stackState.pop();
1274:                m_stackState.push(type);
1275:            }
1276:
1277:            /**
1278:             * Append an AASTORE to the instruction list. Doesn't actually check the
1279:             * types, just the count of items present.
1280:             */
1281:            public void appendAASTORE() {
1282:                verifyStackDepth(3);
1283:                String vtype = m_stackState.pop();
1284:                verifyStack("int");
1285:                m_stackState.pop();
1286:                String atype = verifyArray();
1287:                verifyCompatible(vtype, atype);
1288:                m_stackState.pop();
1289:                append(InstructionConstants.AASTORE);
1290:            }
1291:
1292:            /**
1293:             * Append the appropriate array store to the instruction list.
1294:             * 
1295:             * @param type array item type expected
1296:             */
1297:            public void appendASTORE(String type) {
1298:                verifyStackDepth(3);
1299:                String vtype = m_stackState.pop();
1300:                verifyStack("int");
1301:                m_stackState.pop();
1302:                String atype = verifyArray();
1303:                verifyCompatible(vtype, atype);
1304:                m_stackState.pop();
1305:                if ("byte".equals(type) || "boolean".equals(type)) {
1306:                    append(InstructionConstants.BASTORE);
1307:                } else if ("char".equals(type)) {
1308:                    append(InstructionConstants.CASTORE);
1309:                } else if ("double".equals(type)) {
1310:                    append(InstructionConstants.DASTORE);
1311:                } else if ("float".equals(type)) {
1312:                    append(InstructionConstants.FASTORE);
1313:                } else if ("int".equals(type)) {
1314:                    append(InstructionConstants.IASTORE);
1315:                } else if ("long".equals(type)) {
1316:                    append(InstructionConstants.LASTORE);
1317:                } else if ("short".equals(type)) {
1318:                    append(InstructionConstants.SASTORE);
1319:                } else {
1320:                    append(InstructionConstants.AASTORE);
1321:                }
1322:            }
1323:
1324:            /**
1325:             * Append an ACONST_NULL to the instruction list.
1326:             */
1327:            public void appendACONST_NULL() {
1328:                append(InstructionConstants.ACONST_NULL);
1329:                m_stackState.push("<null>");
1330:            }
1331:
1332:            /**
1333:             * Append an ARRAYLENGTH to the instruction list.
1334:             */
1335:            public void appendARRAYLENGTH() {
1336:                verifyArray();
1337:                append(InstructionConstants.ARRAYLENGTH);
1338:                m_stackState.pop();
1339:                m_stackState.push("int");
1340:            }
1341:
1342:            /**
1343:             * Append an DCMPG to the instruction list.
1344:             */
1345:            public void appendDCMPG() {
1346:                verifyStack("double", "double");
1347:                append(InstructionConstants.DCMPG);
1348:                m_stackState.pop(2);
1349:                m_stackState.push("int");
1350:            }
1351:
1352:            /**
1353:             * Append a DUP to the instruction list.
1354:             */
1355:            public void appendDUP() {
1356:                verifyStackDepth(1);
1357:                append(InstructionConstants.DUP);
1358:                m_stackState.push(m_stackState.peek());
1359:            }
1360:
1361:            /**
1362:             * Append a DUP2 to the instruction list.
1363:             */
1364:            public void appendDUP2() {
1365:                verifyStackDepth(1);
1366:                append(InstructionConstants.DUP2);
1367:                m_stackState.push(m_stackState.peek());
1368:            }
1369:
1370:            /**
1371:             * Append a DUP_X1 to the instruction list.
1372:             */
1373:            public void appendDUP_X1() {
1374:                verifyStackDepth(2);
1375:                append(InstructionConstants.DUP_X1);
1376:                String hold0 = m_stackState.pop();
1377:                String hold1 = m_stackState.pop();
1378:                m_stackState.push(hold0);
1379:                m_stackState.push(hold1);
1380:                m_stackState.push(hold0);
1381:            }
1382:
1383:            /**
1384:             * Append an FCMPG to the instruction list.
1385:             */
1386:            public void appendFCMPG() {
1387:                verifyStack("float", "float");
1388:                append(InstructionConstants.FCMPG);
1389:                m_stackState.pop(2);
1390:                m_stackState.push("int");
1391:            }
1392:
1393:            /**
1394:             * Append an IASTORE to the instruction list. Doesn't actually check the
1395:             * types, just the count of items present.
1396:             */
1397:            public void appendIASTORE() {
1398:                verifyStackDepth(3);
1399:                append(InstructionConstants.IASTORE);
1400:                m_stackState.pop(3);
1401:            }
1402:
1403:            /**
1404:             * Append an ICONST_0 to the instruction list.
1405:             */
1406:            public void appendICONST_0() {
1407:                append(InstructionConstants.ICONST_0);
1408:                m_stackState.push("int");
1409:            }
1410:
1411:            /**
1412:             * Append an ICONST_1 to the instruction list.
1413:             */
1414:            public void appendICONST_1() {
1415:                append(InstructionConstants.ICONST_1);
1416:                m_stackState.push("int");
1417:            }
1418:
1419:            /**
1420:             * Append an ISUB to the instruction list.
1421:             */
1422:            public void appendISUB() {
1423:                verifyStack("int", "int");
1424:                append(InstructionConstants.ISUB);
1425:                m_stackState.pop(1);
1426:            }
1427:
1428:            /**
1429:             * Append an IXOR to the instruction list.
1430:             */
1431:            public void appendIXOR() {
1432:                verifyStack("int", "int");
1433:                append(InstructionConstants.IXOR);
1434:                m_stackState.pop(1);
1435:            }
1436:
1437:            /**
1438:             * Append an LCMP to the instruction list.
1439:             */
1440:            public void appendLCMP() {
1441:                verifyStack("long", "long");
1442:                append(InstructionConstants.LCMP);
1443:                m_stackState.pop(2);
1444:                m_stackState.push("int");
1445:            }
1446:
1447:            /**
1448:             * Append a POP to the instruction list.
1449:             */
1450:            public void appendPOP() {
1451:                verifyStackDepth(1);
1452:                String type = m_stackState.peek();
1453:                if ("long".equals(type) || "double".equals(type)) {
1454:                    throw new IllegalStateException(
1455:                            "Internal error: POP splits long value");
1456:                }
1457:                append(InstructionConstants.POP);
1458:                m_stackState.pop();
1459:            }
1460:
1461:            /**
1462:             * Append a POP2 to the instruction list.
1463:             */
1464:            public void appendPOP2() {
1465:                verifyStackDepth(1);
1466:                String type = m_stackState.peek();
1467:                if (!"long".equals(type) && !"double".equals(type)) {
1468:                    throw new IllegalStateException(
1469:                            "Internal error: POP2 requires long value");
1470:                }
1471:                append(InstructionConstants.POP2);
1472:                m_stackState.pop();
1473:            }
1474:
1475:            /**
1476:             * Append a SWAP to the instruction list.
1477:             */
1478:            public void appendSWAP() {
1479:                verifyStackDepth(2);
1480:                append(InstructionConstants.SWAP);
1481:                String hold0 = m_stackState.pop();
1482:                String hold1 = m_stackState.pop();
1483:                m_stackState.push(hold0);
1484:                m_stackState.push(hold1);
1485:            }
1486:
1487:            /**
1488:             * Append instructions to exchange a single-word value on the top of the
1489:             * stack with the double-word value below it on the stack.
1490:             */
1491:            public void appendSWAP1For2() {
1492:                verifyStackDepth(2);
1493:                append(InstructionConstants.DUP_X2);
1494:                append(InstructionConstants.POP);
1495:                String hold0 = m_stackState.pop();
1496:                String hold1 = m_stackState.pop();
1497:                m_stackState.push(hold0);
1498:                m_stackState.push(hold1);
1499:            }
1500:
1501:            /**
1502:             * Append a compound instruction to the list as a branch target.
1503:             *
1504:             * @param inst compound instruction to be appended as branch target
1505:             * @return branch target information
1506:             */
1507:            private BranchTarget appendTargetInstruction(
1508:                    CompoundInstruction inst) {
1509:                String[] types = m_stackState.toArray();
1510:                InstructionHandle hand = m_instructionList.append(inst);
1511:                return new BranchTarget(hand, types);
1512:            }
1513:
1514:            /**
1515:             * Append an instruction to the list as a branch target.
1516:             *
1517:             * @param inst instruction to be appended as branch target
1518:             * @return branch target information
1519:             */
1520:            private BranchTarget appendTargetInstruction(Instruction inst) {
1521:                String[] types = m_stackState.toArray();
1522:                InstructionHandle hand = m_instructionList.append(inst);
1523:                return new BranchTarget(hand, types);
1524:            }
1525:
1526:            /**
1527:             * Append a NOP to the instruction list as a branch target.
1528:             *
1529:             * @return branch target information
1530:             */
1531:            public BranchTarget appendTargetNOP() {
1532:                return appendTargetInstruction(InstructionConstants.NOP);
1533:            }
1534:
1535:            /**
1536:             * Append an ACONST_NULL to the instruction list as a branch target.
1537:             *
1538:             * @return branch target information
1539:             */
1540:            public BranchTarget appendTargetACONST_NULL() {
1541:                BranchTarget target = appendTargetInstruction(InstructionConstants.ACONST_NULL);
1542:                m_stackState.push("<null>");
1543:                return target;
1544:            }
1545:
1546:            /**
1547:             * Append a load constant instruction as a branch target. Builds the most
1548:             * appropriate type of instruction for the value.
1549:             *
1550:             * @param value constant value to be loaded
1551:             * @return branch target information
1552:             */
1553:            public BranchTarget appendTargetLoadConstant(int value) {
1554:                BranchTarget target = appendTargetInstruction(m_instructionBuilder
1555:                        .createLoadConstant(value));
1556:                m_stackState.push("int");
1557:                return target;
1558:            }
1559:
1560:            /**
1561:             * Append a load constant instruction as a branch target. Loads a
1562:             * <code>String</code> reference from the constant pool.
1563:             *
1564:             * @param value constant value to be loaded
1565:             * @return branch target information
1566:             */
1567:            public BranchTarget appendTargetLoadConstant(String value) {
1568:                BranchTarget target = appendTargetInstruction(m_instructionBuilder
1569:                        .createLoadConstant(value));
1570:                m_stackState.push("java.lang.String");
1571:                return target;
1572:            }
1573:
1574:            /**
1575:             * Append instruction to create instance of class as a branch target.
1576:             *
1577:             * @param name fully qualified class name
1578:             * @return branch target information
1579:             */
1580:            public BranchTarget appendTargetCreateNew(String name) {
1581:                BranchTarget target = appendTargetInstruction(m_instructionBuilder
1582:                        .createNew(name));
1583:                m_stackState.push(name);
1584:                return target;
1585:            }
1586:
1587:            /**
1588:             * Internal append instruction to create instance of class. This is used by
1589:             * subclasses when they need access to the actual instruction handle.
1590:             *
1591:             * @param name fully qualified class name
1592:             */
1593:            protected InstructionHandle internalAppendCreateNew(String name) {
1594:                InstructionHandle handle = m_instructionList
1595:                        .append(m_instructionBuilder.createNew(name));
1596:                m_stackState.push(name);
1597:                return handle;
1598:            }
1599:
1600:            /**
1601:             * Check if top item on stack is a long value.
1602:             * 
1603:             * @return <code>true</code> if long value, <code>false</code> if not
1604:             */
1605:            public boolean isStackTopLong() {
1606:                verifyStackDepth(1);
1607:                String type = m_stackState.peek();
1608:                return "long".equals(type) || "double".equals(type);
1609:            }
1610:
1611:            /**
1612:             * Initialize stack state to match branch source. This can be used to set
1613:             * the expected stack state following an unconditional transfer of control
1614:             * instruction. The principle here is that the code to be generated must be
1615:             * reached by a branch, so the stack state must match that of the branch
1616:             * source.
1617:             *
1618:             * @param branch wrapper for branch to be for stack initialization
1619:             */
1620:            public void initStackState(BranchWrapper branch) {
1621:                m_stackState = new StringStack(branch.getStackState());
1622:            }
1623:
1624:            /**
1625:             * Initialize stack state to partially match branch source. This can be used
1626:             * to set the expected stack state following an unconditional transfer of
1627:             * control instruction. The specified number of items are removed from the
1628:             * branch stack, with the assumption that code to add these items will be
1629:             * appended before the branch join point is reached.
1630:             *
1631:             * @param branch wrapper for branch to be for stack initialization
1632:             * @param pop number of items to be removed from branch source stack state
1633:             */
1634:            public void initStackState(BranchWrapper branch, int pop) {
1635:                m_stackState = new StringStack(branch.getStackState());
1636:                if (pop > 0) {
1637:                    m_stackState.pop(pop);
1638:                }
1639:            }
1640:
1641:            /**
1642:             * Initialize stack state to array of value types. This can be used to set
1643:             * the expected stack state following an unconditional transfer of control
1644:             * instruction.
1645:             *
1646:             * @param types array of type names on stack
1647:             */
1648:            protected void initStackState(String[] types) {
1649:                m_stackState = new StringStack(types);
1650:            }
1651:
1652:            /**
1653:             * Set branch target as next instruction added to method. This effectively
1654:             * sets up a state trigger for the next append operation. The appended
1655:             * instruction is set as the target for the branch. This requires that
1656:             * instructions are only appended using the methods supplied in this class.
1657:             *
1658:             * @param branch wrapper for branch to be aimed at next instruction (may be
1659:             * <code>null</code>, in which case nothing is done)
1660:             */
1661:            public void targetNext(BranchWrapper branch) {
1662:                if (branch != null) {
1663:                    if (m_targetBranches == null) {
1664:                        m_targetBranches = new BranchWrapper[] { branch };
1665:                        if (m_stackState == null) {
1666:                            m_stackState = new StringStack(branch
1667:                                    .getStackState());
1668:                        }
1669:                    } else {
1670:                        int length = m_targetBranches.length;
1671:                        BranchWrapper[] wrappers = new BranchWrapper[length + 1];
1672:                        System.arraycopy(m_targetBranches, 0, wrappers, 0,
1673:                                length);
1674:                        wrappers[length] = branch;
1675:                        m_targetBranches = wrappers;
1676:                    }
1677:                }
1678:            }
1679:
1680:            /**
1681:             * Set branch targets as next instruction added to method. This effectively
1682:             * sets up a state trigger for the next append operation. The appended
1683:             * instruction is set as the target for all the branches. This requires that
1684:             * instructions are only appended using the methods supplied in this class.
1685:             *
1686:             * @param branches wrappers for branches to be aimed at next instruction
1687:             * (may be <code>null</code>, in which case nothing is done)
1688:             */
1689:            public void targetNext(BranchWrapper[] branches) {
1690:                if (branches != null && branches.length > 0) {
1691:                    if (m_targetBranches == null) {
1692:                        m_targetBranches = branches;
1693:                        if (m_stackState == null) {
1694:                            m_stackState = new StringStack(branches[0]
1695:                                    .getStackState());
1696:                        }
1697:                    } else {
1698:                        int offset = m_targetBranches.length;
1699:                        int length = offset + branches.length;
1700:                        BranchWrapper[] wrappers = new BranchWrapper[length];
1701:                        System.arraycopy(m_targetBranches, 0, wrappers, 0,
1702:                                offset);
1703:                        System.arraycopy(branches, 0, wrappers, offset,
1704:                                branches.length);
1705:                        m_targetBranches = wrappers;
1706:                    }
1707:                }
1708:            }
1709:
1710:            /**
1711:             * Process accumulated exceptions. Each subclass must implement this
1712:             * method to perform the appropriate handling of the checked exceptions
1713:             * that may be thrown in the constructed method.
1714:             * 
1715:             * @throws JiBXException on error in exception handling
1716:             */
1717:            protected abstract void handleExceptions() throws JiBXException;
1718:
1719:            /**
1720:             * Complete method construction. Finalizes the instruction list and
1721:             * generates the byte code for the constructed method, then computes the
1722:             * hash code based on the byte code. If requested, an appropriate suffix is
1723:             * tacked on the end of the supplied name in order to make sure that it will
1724:             * not be duplicated (even in a superclass or subclass).
1725:             * 
1726:             * @param suffix add suffix to make method name unique
1727:             * @throws JiBXException on error in finishing method construction
1728:             */
1729:            public void codeComplete(boolean suffix) throws JiBXException {
1730:                if (m_targetBranches != null) {
1731:                    throw new IllegalStateException(
1732:                            "Method complete with pending branch target");
1733:                }
1734:                if (m_exceptions != null) {
1735:                    handleExceptions();
1736:                }
1737:                if (suffix) {
1738:                    m_generator.setName(getClassFile().makeUniqueMethodName(
1739:                            m_generator.getName()));
1740:                }
1741:                m_generator.setMaxStack();
1742:                m_generator.setMaxLocals();
1743:                m_instructionList.setPositions(true);
1744:                m_method = m_generator.getMethod();
1745:                m_instructionList.dispose();
1746:                m_hashCode = computeMethodHash(m_method);
1747:            }
1748:
1749:            /**
1750:             * Get the method item.
1751:             *
1752:             * @return method item information
1753:             */
1754:            public ClassItem getItem() {
1755:                if (m_item == null) {
1756:                    throw new IllegalStateException("Method not added to class");
1757:                } else {
1758:                    return m_item;
1759:                }
1760:            }
1761:
1762:            /**
1763:             * Get hash code. This is based only on the byte code in the method, and
1764:             * is only valid after the {@link #codeComplete} method is called.
1765:             * 
1766:             * @return hash code based on code sequence
1767:             */
1768:            public int hashCode() {
1769:                if (m_method == null) {
1770:                    throw new IllegalStateException(
1771:                            "Method still under construction");
1772:                } else {
1773:                    return m_hashCode;
1774:                }
1775:            }
1776:
1777:            /**
1778:             * Add constructed method to class. Makes the method callable, generating
1779:             * the method information.
1780:             * 
1781:             * @return added method information
1782:             * @throws JiBXException on error in finishing method construction
1783:             */
1784:            public ClassItem addMethod() throws JiBXException {
1785:                if (m_method == null) {
1786:                    throw new IllegalStateException("Method not finalized.");
1787:                } else {
1788:                    m_item = getClassFile().addMethod(m_method);
1789:                    return m_item;
1790:                }
1791:            }
1792:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.