Source Code Cross Referenced for BCMethod.java in  » Database-DBMS » db-derby-10.2 » org » apache » derby » impl » services » bytecode » 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 » db derby 10.2 » org.apache.derby.impl.services.bytecode 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


0001:        /*
0002:
0003:           Derby - Class org.apache.derby.impl.services.bytecode.BCMethod
0004:
0005:           Licensed to the Apache Software Foundation (ASF) under one or more
0006:           contributor license agreements.  See the NOTICE file distributed with
0007:           this work for additional information regarding copyright ownership.
0008:           The ASF licenses this file to you under the Apache License, Version 2.0
0009:           (the "License"); you may not use this file except in compliance with
0010:           the License.  You may obtain a copy of the License at
0011:
0012:              http://www.apache.org/licenses/LICENSE-2.0
0013:
0014:           Unless required by applicable law or agreed to in writing, software
0015:           distributed under the License is distributed on an "AS IS" BASIS,
0016:           WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
0017:           See the License for the specific language governing permissions and
0018:           limitations under the License.
0019:
0020:         */
0021:
0022:        package org.apache.derby.impl.services.bytecode;
0023:
0024:        import org.apache.derby.iapi.services.compiler.ClassBuilder;
0025:        import org.apache.derby.iapi.services.compiler.MethodBuilder;
0026:        import org.apache.derby.iapi.services.classfile.ClassFormatOutput;
0027:        import org.apache.derby.iapi.services.compiler.LocalField;
0028:        import org.apache.derby.iapi.services.classfile.ClassHolder;
0029:        import org.apache.derby.iapi.services.classfile.ClassMember;
0030:
0031:        import org.apache.derby.iapi.services.sanity.SanityManager;
0032:
0033:        import org.apache.derby.iapi.services.classfile.VMDescriptor;
0034:        import org.apache.derby.iapi.services.classfile.VMOpcode;
0035:
0036:        import java.lang.reflect.Modifier;
0037:        import java.util.Vector;
0038:        import java.io.IOException;
0039:
0040:        /**
0041:         * MethodBuilder is used to piece together a method when
0042:         * building a java class definition.
0043:         * <p>
0044:         * When a method is first created, it has:
0045:         * <ul>
0046:         * <li> a return type
0047:         * <li> modifiers
0048:         * <li> a name
0049:         * <li> an empty parameter list
0050:         * <li> an empty throws list
0051:         * <li> an empty statement block
0052:         * </ul>
0053:         * <p>
0054:         * MethodBuilder implementations are required to supply a way for
0055:         * Statements and Expressions to give them code.  Most typically, they may have
0056:         * a stream to which their contents writes the code that is of
0057:         * the type to satisfy what the contents represent.
0058:         * MethodBuilder implementations also have to have a way to supply
0059:         * ClassBuilders with their code, that satisfies the type of class
0060:         * builder they are implemented with.  This is implementation-dependent,
0061:         * so ClassBuilders, MethodBuilders, Statements, and Expressions all have
0062:         * to be of the same implementation in order to interact to generate a class.
0063:         * <p>
0064:         * Method Builder implementation for generating bytecode.
0065:         *
0066:         */
0067:        class BCMethod implements  MethodBuilder {
0068:
0069:            /**
0070:             * Code length at which to split into sub-methods.
0071:             * Normally set to the maximim code length the
0072:             * JVM can support, but for testing the split code
0073:             * it can be reduced so that the standard tests
0074:             * cause some splitting. Tested with value set to 2000.
0075:             */
0076:            static final int CODE_SPLIT_LENGTH = VMOpcode.MAX_CODE_LENGTH;
0077:
0078:            final BCClass cb;
0079:            protected final ClassHolder modClass; // the class it is in (modifiable fmt)
0080:            final String myReturnType;
0081:
0082:            /**
0083:             * The original name of the method, this
0084:             * represents how any user would call this method.
0085:             */
0086:            private final String myName;
0087:
0088:            /**
0089:             * Fast access for the parametes, will be null
0090:             * if the method has no parameters.
0091:             */
0092:            BCLocalField[] parameters;
0093:
0094:            /**
0095:             * List of parameter types with java language class names.
0096:             * Can be null or zero length for no parameters.
0097:             */
0098:            private final String[] parameterTypes;
0099:
0100:            Vector thrownExceptions; // expected to be names of Classes under Throwable
0101:
0102:            CodeChunk myCode;
0103:            protected ClassMember myEntry;
0104:
0105:            private int currentVarNum;
0106:            private int statementNum;
0107:
0108:            /**
0109:             * True if we are currently switching control
0110:             * over to a sub method to avoid hitting the code generation
0111:             * limit of 65535 bytes per method.
0112:             */
0113:            private boolean handlingOverflow;
0114:
0115:            /**
0116:             * How many sub-methods we have overflowed to.
0117:             */
0118:            private int subMethodCount;
0119:
0120:            BCMethod(ClassBuilder cb, String returnType, String methodName,
0121:                    int modifiers, String[] parms, BCJava factory) {
0122:
0123:                this .cb = (BCClass) cb;
0124:                modClass = this .cb.modify();
0125:                myReturnType = returnType;
0126:                myName = methodName;
0127:
0128:                if (SanityManager.DEBUG) {
0129:                    this .cb.validateType(returnType);
0130:                }
0131:
0132:                // if the method is not static, allocate for "this".
0133:                if ((modifiers & Modifier.STATIC) == 0)
0134:                    currentVarNum = 1;
0135:
0136:                String[] vmParamterTypes;
0137:
0138:                if (parms != null && parms.length != 0) {
0139:                    int len = parms.length;
0140:                    vmParamterTypes = new String[len];
0141:                    parameters = new BCLocalField[len];
0142:                    for (int i = 0; i < len; i++) {
0143:                        Type t = factory.type(parms[i]);
0144:                        parameters[i] = new BCLocalField(t, currentVarNum);
0145:                        currentVarNum += t.width();
0146:
0147:                        // convert to vmname for the BCMethodDescriptor.get() call
0148:                        vmParamterTypes[i] = t.vmName();
0149:                    }
0150:                } else
0151:                    vmParamterTypes = BCMethodDescriptor.EMPTY;
0152:
0153:                // create a code attribute
0154:                String sig = BCMethodDescriptor.get(vmParamterTypes, factory
0155:                        .type(returnType).vmName(), factory);
0156:
0157:                // stuff the completed information into the class.
0158:                myEntry = modClass.addMember(methodName, sig, modifiers);
0159:
0160:                // get code chunk
0161:                myCode = new CodeChunk(this .cb);
0162:
0163:                parameterTypes = parms;
0164:            }
0165:
0166:            //
0167:            // MethodBuilder interface
0168:            //
0169:
0170:            /**
0171:             * Return the logical name of the method. The current
0172:             * myEntry refers to the sub method we are currently
0173:             * overflowing to. Those sub-methods are hidden from any caller.
0174:             */
0175:            public String getName() {
0176:                return myName;
0177:            }
0178:
0179:            public void getParameter(int id) {
0180:
0181:                int num = parameters[id].cpi;
0182:                short typ = parameters[id].type.vmType();
0183:                if (num < 4)
0184:                    myCode
0185:                            .addInstr((short) (CodeChunk.LOAD_VARIABLE_FAST[typ] + num));
0186:                else
0187:                    myCode.addInstrWide(CodeChunk.LOAD_VARIABLE[typ], num);
0188:
0189:                growStack(parameters[id].type);
0190:            }
0191:
0192:            /**
0193:             * a throwable can be added to the end of
0194:             * the list of thrownExceptions.
0195:             */
0196:            public void addThrownException(String exceptionClass) {
0197:
0198:                // cannot add exceptions after code generation has started.
0199:                // Allowing this would cause the method overflow/split to
0200:                // break as the top-level method would not have the exception
0201:                // added in the sub method.
0202:                if (SanityManager.DEBUG) {
0203:                    if (myCode.getPC() != 0)
0204:                        SanityManager
0205:                                .THROWASSERT("Adding exception after code generation "
0206:                                        + exceptionClass
0207:                                        + " to method "
0208:                                        + getName());
0209:                }
0210:
0211:                if (thrownExceptions == null)
0212:                    thrownExceptions = new Vector();
0213:                thrownExceptions.addElement(exceptionClass);
0214:            }
0215:
0216:            /**
0217:             * when the method has had all of its parameters
0218:             * and thrown exceptions defined, and its statement
0219:             * block has been completed, it can be completed and
0220:             * its class file information generated.
0221:             * <p>
0222:             * further alterations of the method will not be
0223:             * reflected in the code generated for it.
0224:             */
0225:            public void complete() {
0226:
0227:                // myCode.getPC() gives the code length since
0228:                // the program counter will be positioned after
0229:                // the last instruction. Note this value can
0230:                // be changed by the splitMethod call.
0231:
0232:                if (myCode.getPC() > CODE_SPLIT_LENGTH)
0233:                    splitMethod();
0234:
0235:                // write exceptions attribute info
0236:                writeExceptions();
0237:
0238:                // get the code attribute to put itself into the class
0239:                // provide the final header information needed
0240:                myCode.complete(this , modClass, myEntry, maxStack,
0241:                        currentVarNum);
0242:            }
0243:
0244:            /**
0245:             * Attempt to split a large method by pushing code out to several
0246:             * sub-methods. Performs a number of steps.
0247:             * <OL>
0248:             * <LI> Split at zero stack depth.
0249:             * <LI> Split at non-zero stack depth (FUTURE)
0250:             * </OL>
0251:             * 
0252:             * If the class has already exceeded some limit in building the
0253:             * class file format structures then don't attempt to split.
0254:             * Most likely the number of constant pool entries has been exceeded
0255:             * and thus the built class file no longer has integrity.
0256:             * The split code relies on being able to read the in-memory
0257:             * version of the class file in order to determine descriptors
0258:             * for methods and fields.
0259:             */
0260:            private void splitMethod() {
0261:
0262:                int split_pc = 0;
0263:                boolean splittingZeroStack = true;
0264:                for (int codeLength = myCode.getPC(); (cb.limitMsg == null)
0265:                        && (codeLength > CODE_SPLIT_LENGTH); codeLength = myCode
0266:                        .getPC()) {
0267:                    int lengthToCheck = codeLength - split_pc;
0268:
0269:                    int optimalMinLength;
0270:                    if (codeLength < CODE_SPLIT_LENGTH * 2) {
0271:                        // minimum required
0272:                        optimalMinLength = codeLength - CODE_SPLIT_LENGTH;
0273:                    } else {
0274:                        // try to split as much as possible
0275:                        // need one for the return instruction
0276:                        optimalMinLength = CODE_SPLIT_LENGTH - 1;
0277:                    }
0278:
0279:                    if (optimalMinLength > lengthToCheck)
0280:                        optimalMinLength = lengthToCheck;
0281:
0282:                    if (splittingZeroStack) {
0283:                        split_pc = myCode.splitZeroStack(this , modClass,
0284:                                split_pc, optimalMinLength);
0285:                    } else {
0286:                        // Note the split expression does not re-start split
0287:                        // at point left off by the previous split expression.
0288:                        // This could be done but would require some level
0289:                        // of stack depth history to be kept across calls.
0290:                        split_pc = myCode.splitExpressionOut(this , modClass,
0291:                                optimalMinLength, maxStack);
0292:
0293:                    }
0294:
0295:                    // Negative split point returned means that no split
0296:                    // was possible. Give up on this approach and goto
0297:                    // the next approach.
0298:                    if (split_pc < 0) {
0299:                        if (!splittingZeroStack)
0300:                            break;
0301:                        splittingZeroStack = false;
0302:                        split_pc = 0;
0303:                    }
0304:
0305:                    // success, continue on splitting after the call to the
0306:                    // sub-method if the method still execeeds the maximum length.
0307:                }
0308:
0309:            }
0310:
0311:            /*
0312:             * class interface
0313:             */
0314:
0315:            /**
0316:             * In their giveCode methods, the parts of the method body will want to get
0317:             * to the constant pool to add their constants. We really only want them
0318:             * treating it like a constant pool inclusion mechanism, we could write a
0319:             * wrapper to limit it to that.
0320:             */
0321:            ClassHolder constantPool() {
0322:                return modClass;
0323:            }
0324:
0325:            //
0326:            // Class implementation
0327:            //
0328:
0329:            /**
0330:             * sets exceptionBytes to the attribute_info needed
0331:             * for a method's Exceptions attribute.
0332:             * The ClassUtilities take care of the header 6 bytes for us,
0333:             * so they are not included here.
0334:             * See The Java Virtual Machine Specification Section 4.7.5,
0335:             * Exceptions attribute.
0336:             */
0337:            protected void writeExceptions() {
0338:                if (thrownExceptions == null)
0339:                    return;
0340:
0341:                int numExc = thrownExceptions.size();
0342:
0343:                // don't write an Exceptions attribute if there are no exceptions.
0344:                if (numExc != 0) {
0345:
0346:                    try {
0347:                        ClassFormatOutput eout = new ClassFormatOutput(
0348:                                (numExc * 2) + 2);
0349:
0350:                        eout.putU2(numExc); // number_of_exceptions
0351:
0352:                        for (int i = 0; i < numExc; i++) {
0353:                            // put each exception into the constant pool
0354:                            String e = thrownExceptions.elementAt(i).toString();
0355:                            int ei2 = modClass.addClassReference(e);
0356:
0357:                            // add constant pool index to exception attribute_info
0358:                            eout.putU2(ei2);
0359:                        }
0360:
0361:                        myEntry.addAttribute("Exceptions", eout);
0362:
0363:                    } catch (IOException ioe) {
0364:                    }
0365:                }
0366:            }
0367:
0368:            /*
0369:             ** New push compiler api.
0370:             */
0371:
0372:            /**
0373:             * Array of the current types of the values on the stack.
0374:             * A type that types up two words on the stack, e.g. double
0375:             * will only occupy one element in this array.
0376:             * This array is dynamically re-sized as needed.
0377:             */
0378:            private Type[] stackTypes = new Type[8];
0379:
0380:            /**
0381:             * Points to the next array offset in stackTypes
0382:             * to be used. Really it's the number of valid entries
0383:             * in stackTypes.
0384:             */
0385:            private int stackTypeOffset;
0386:
0387:            /**
0388:             * Maximum stack depth seen in this method, measured in words.
0389:             * Corresponds to max_stack in the Code attribute of section 4.7.3
0390:             * of the vm spec.
0391:             */
0392:            int maxStack;
0393:
0394:            /**
0395:             * Current stack depth in this method, measured in words.
0396:             */
0397:            private int stackDepth;
0398:
0399:            private void growStack(int size, Type type) {
0400:                stackDepth += size;
0401:                if (stackDepth > maxStack)
0402:                    maxStack = stackDepth;
0403:
0404:                if (stackTypeOffset >= stackTypes.length) {
0405:
0406:                    Type[] newStackTypes = new Type[stackTypes.length + 8];
0407:                    System.arraycopy(stackTypes, 0, newStackTypes, 0,
0408:                            stackTypes.length);
0409:                    stackTypes = newStackTypes;
0410:                }
0411:
0412:                stackTypes[stackTypeOffset++] = type;
0413:
0414:                if (SanityManager.DEBUG) {
0415:
0416:                    int sum = 0;
0417:                    for (int i = 0; i < stackTypeOffset; i++) {
0418:                        sum += stackTypes[i].width();
0419:                    }
0420:                    if (sum != stackDepth) {
0421:                        SanityManager.THROWASSERT("invalid stack depth "
0422:                                + stackDepth + " calc " + sum);
0423:                    }
0424:                }
0425:            }
0426:
0427:            private void growStack(Type type) {
0428:                growStack(type.width(), type);
0429:            }
0430:
0431:            private Type popStack() {
0432:                stackTypeOffset--;
0433:                Type topType = stackTypes[stackTypeOffset];
0434:                stackDepth -= topType.width();
0435:                return topType;
0436:
0437:            }
0438:
0439:            private Type[] copyStack() {
0440:                Type[] stack = new Type[stackTypeOffset];
0441:                System.arraycopy(stackTypes, 0, stack, 0, stackTypeOffset);
0442:                return stack;
0443:            }
0444:
0445:            public void pushThis() {
0446:                myCode.addInstr(VMOpcode.ALOAD_0);
0447:                growStack(1, cb.classType);
0448:            }
0449:
0450:            public void push(byte value) {
0451:                push(value, Type.BYTE);
0452:            }
0453:
0454:            public void push(boolean value) {
0455:                push(value ? 1 : 0, Type.BOOLEAN);
0456:            }
0457:
0458:            public void push(short value) {
0459:                push(value, Type.SHORT);
0460:            }
0461:
0462:            public void push(int value) {
0463:                push(value, Type.INT);
0464:            }
0465:
0466:            public void dup() {
0467:                Type dup = popStack();
0468:                myCode
0469:                        .addInstr(dup.width() == 2 ? VMOpcode.DUP2
0470:                                : VMOpcode.DUP);
0471:                growStack(dup);
0472:                growStack(dup);
0473:
0474:            }
0475:
0476:            public void swap() {
0477:
0478:                // have A,B
0479:                // want B,A
0480:
0481:                Type wB = popStack();
0482:                Type wA = popStack();
0483:                growStack(wB);
0484:                growStack(wA);
0485:
0486:                if (wB.width() == 1) {
0487:                    // top value is one word
0488:                    if (wA.width() == 1) {
0489:                        myCode.addInstr(VMOpcode.SWAP);
0490:                        return;
0491:                    } else {
0492:                        myCode.addInstr(VMOpcode.DUP_X2);
0493:                        myCode.addInstr(VMOpcode.POP);
0494:                    }
0495:                } else {
0496:                    // top value is two words
0497:                    if (wA.width() == 1) {
0498:                        myCode.addInstr(VMOpcode.DUP2_X1);
0499:                        myCode.addInstr(VMOpcode.POP2);
0500:                    } else {
0501:                        myCode.addInstr(VMOpcode.DUP2_X2);
0502:                        myCode.addInstr(VMOpcode.POP2);
0503:                    }
0504:                }
0505:
0506:                // all except the simple swap push an extra
0507:                // copy of B which needs to be popped.
0508:                growStack(wB);
0509:                popStack();
0510:
0511:            }
0512:
0513:            /**
0514:             * Push an integer value. Uses the special integer opcodes
0515:             * for the constants -1 to 5, BIPUSH for values that fit in
0516:             * a byte and SIPUSH for values that fit in a short. Otherwise
0517:             * uses LDC with a constant pool entry.
0518:             * 
0519:             * @param value Value to be pushed
0520:             * @param type Final type of the value.
0521:             */
0522:            private void push(int value, Type type) {
0523:
0524:                CodeChunk chunk = myCode;
0525:
0526:                if (value >= -1 && value <= 5)
0527:                    chunk.addInstr((short) (VMOpcode.ICONST_0 + value));
0528:                else if (value >= Byte.MIN_VALUE && value <= Byte.MAX_VALUE)
0529:                    chunk.addInstrU1(VMOpcode.BIPUSH, value);
0530:                else if (value >= Short.MIN_VALUE && value <= Short.MAX_VALUE)
0531:                    chunk.addInstrU2(VMOpcode.SIPUSH, value);
0532:                else {
0533:                    int cpe = modClass.addConstant(value);
0534:                    addInstrCPE(VMOpcode.LDC, cpe);
0535:                }
0536:                growStack(type.width(), type);
0537:
0538:            }
0539:
0540:            /**
0541:             * Push a long value onto the stack.
0542:             * For the values zero and one the LCONST_0 and
0543:             * LCONST_1 instructions are used.
0544:             * For values betwee Short.MIN_VALUE and Short.MAX_VALUE
0545:             * inclusive an byte/short/int value is pushed
0546:             * using push(int, Type) followed by an I2L instruction.
0547:             * This saves using a constant pool entry for such values.
0548:             * All other values use a constant pool entry. For values
0549:             * in the range of an Integer an integer constant pool
0550:             * entry is created to allow sharing with integer constants
0551:             * and to reduce constant pool slot entries.
0552:             */
0553:            public void push(long value) {
0554:                CodeChunk chunk = myCode;
0555:
0556:                if (value == 0L || value == 1L) {
0557:                    short opcode = value == 0L ? VMOpcode.LCONST_0
0558:                            : VMOpcode.LCONST_1;
0559:                    chunk.addInstr(opcode);
0560:                } else if (value >= Integer.MIN_VALUE
0561:                        && value <= Integer.MAX_VALUE) {
0562:                    // the push(int, Type) method grows the stack for us.
0563:                    push((int) value, Type.LONG);
0564:                    chunk.addInstr(VMOpcode.I2L);
0565:                    return;
0566:                } else {
0567:                    int cpe = modClass.addConstant(value);
0568:                    chunk.addInstrU2(VMOpcode.LDC2_W, cpe);
0569:                }
0570:                growStack(2, Type.LONG);
0571:            }
0572:
0573:            public void push(float value) {
0574:
0575:                CodeChunk chunk = myCode;
0576:
0577:                if (value == 0.0) {
0578:                    chunk.addInstr(VMOpcode.FCONST_0);
0579:                } else if (value == 1.0) {
0580:                    chunk.addInstr(VMOpcode.FCONST_1);
0581:                } else if (value == 2.0) {
0582:                    chunk.addInstr(VMOpcode.FCONST_2);
0583:                } else {
0584:                    int cpe = modClass.addConstant(value);
0585:                    addInstrCPE(VMOpcode.LDC, cpe);
0586:                }
0587:                growStack(1, Type.FLOAT);
0588:            }
0589:
0590:            public void push(double value) {
0591:                CodeChunk chunk = myCode;
0592:
0593:                if (value == 0.0) {
0594:                    chunk.addInstr(VMOpcode.DCONST_0);
0595:                } else {
0596:                    int cpe = modClass.addConstant(value);
0597:                    chunk.addInstrU2(VMOpcode.LDC2_W, cpe);
0598:                }
0599:                growStack(2, Type.DOUBLE);
0600:            }
0601:
0602:            public void push(String value) {
0603:                int cpe = modClass.addConstant(value);
0604:                addInstrCPE(VMOpcode.LDC, cpe);
0605:                growStack(1, Type.STRING);
0606:            }
0607:
0608:            public void methodReturn() {
0609:
0610:                short opcode;
0611:                if (stackDepth != 0) {
0612:                    Type topType = popStack();
0613:                    opcode = CodeChunk.RETURN_OPCODE[topType.vmType()];
0614:                } else {
0615:                    opcode = VMOpcode.RETURN;
0616:                }
0617:
0618:                myCode.addInstr(opcode);
0619:
0620:                if (SanityManager.DEBUG) {
0621:                    if (stackDepth != 0)
0622:                        SanityManager.THROWASSERT("items left on stack "
0623:                                + stackDepth);
0624:                }
0625:            }
0626:
0627:            public Object describeMethod(short opcode, String declaringClass,
0628:                    String methodName, String returnType) {
0629:
0630:                Type rt = cb.factory.type(returnType);
0631:
0632:                String methodDescriptor = BCMethodDescriptor.get(
0633:                        BCMethodDescriptor.EMPTY, rt.vmName(), cb.factory);
0634:
0635:                if ((declaringClass == null)
0636:                        && (opcode != VMOpcode.INVOKESTATIC)) {
0637:
0638:                    Type dt = stackTypes[stackTypeOffset - 1];
0639:
0640:                    if (declaringClass == null)
0641:                        declaringClass = dt.javaName();
0642:                }
0643:
0644:                int cpi = modClass.addMethodReference(declaringClass,
0645:                        methodName, methodDescriptor,
0646:                        opcode == VMOpcode.INVOKEINTERFACE);
0647:
0648:                return new BCMethodCaller(opcode, rt, cpi);
0649:            }
0650:
0651:            public int callMethod(Object methodDescriptor) {
0652:
0653:                // pop the reference off the stack
0654:                popStack();
0655:
0656:                BCMethodCaller mc = (BCMethodCaller) methodDescriptor;
0657:
0658:                int cpi = mc.cpi;
0659:                short opcode = mc.opcode;
0660:
0661:                if (opcode == VMOpcode.INVOKEINTERFACE) {
0662:                    myCode.addInstrU2U1U1(opcode, cpi, (short) 1, (short) 0);
0663:                } else
0664:                    myCode.addInstrU2(opcode, cpi);
0665:
0666:                // this is the return type of the method
0667:                Type rt = mc.type;
0668:                int rw = rt.width();
0669:                if (rw != 0)
0670:                    growStack(rw, rt);
0671:                else {
0672:                    if (stackDepth == 0)
0673:                        overflowMethodCheck();
0674:                }
0675:                return cpi;
0676:            }
0677:
0678:            public int callMethod(short opcode, String declaringClass,
0679:                    String methodName, String returnType, int numArgs) {
0680:
0681:                Type rt = cb.factory.type(returnType);
0682:
0683:                int initialStackDepth = stackDepth;
0684:
0685:                // get the array of parameter types
0686:
0687:                String[] debugParameterTypes = null;
0688:                String[] vmParameterTypes;
0689:                if (numArgs == 0) {
0690:                    vmParameterTypes = BCMethodDescriptor.EMPTY;
0691:                } else {
0692:                    if (SanityManager.DEBUG) {
0693:                        debugParameterTypes = new String[numArgs];
0694:                    }
0695:                    vmParameterTypes = new String[numArgs];
0696:                    for (int i = numArgs - 1; i >= 0; i--) {
0697:                        Type at = popStack();
0698:
0699:                        vmParameterTypes[i] = at.vmName();
0700:                        if (SanityManager.DEBUG) {
0701:                            debugParameterTypes[i] = at.javaName();
0702:                        }
0703:                    }
0704:                }
0705:
0706:                String methodDescriptor = BCMethodDescriptor.get(
0707:                        vmParameterTypes, rt.vmName(), cb.factory);
0708:
0709:                Type dt = null;
0710:                if (opcode != VMOpcode.INVOKESTATIC) {
0711:
0712:                    dt = popStack();
0713:                }
0714:                Type dtu = vmNameDeclaringClass(declaringClass);
0715:                if (dtu != null)
0716:                    dt = dtu;
0717:
0718:                int cpi = modClass.addMethodReference(dt.vmNameSimple,
0719:                        methodName, methodDescriptor,
0720:                        opcode == VMOpcode.INVOKEINTERFACE);
0721:
0722:                if (opcode == VMOpcode.INVOKEINTERFACE) {
0723:                    short callArgCount = (short) (initialStackDepth - stackDepth);
0724:                    myCode.addInstrU2U1U1(opcode, cpi, callArgCount, (short) 0);
0725:                } else
0726:                    myCode.addInstrU2(opcode, cpi);
0727:
0728:                // this is the return type of the method
0729:                int rw = rt.width();
0730:                if (rw != 0)
0731:                    growStack(rw, rt);
0732:                else {
0733:                    if (stackDepth == 0)
0734:                        overflowMethodCheck();
0735:                }
0736:                // Check the declared type of the method
0737:                if (SanityManager.DEBUG) {
0738:
0739:                    d_BCValidate.checkMethod(opcode, dt, methodName,
0740:                            debugParameterTypes, rt);
0741:                }
0742:
0743:                return cpi;
0744:            }
0745:
0746:            private Type vmNameDeclaringClass(String declaringClass) {
0747:                if (declaringClass == null)
0748:                    return null;
0749:                return cb.factory.type(declaringClass);
0750:            }
0751:
0752:            public void callSuper() {
0753:
0754:                pushThis();
0755:                callMethod(VMOpcode.INVOKESPECIAL, cb.getSuperClassName(),
0756:                        "<init>", "void", 0);
0757:            }
0758:
0759:            public void pushNewStart(String className) {
0760:
0761:                int cpi = modClass.addClassReference(className);
0762:
0763:                // Use U2, not CPE, since only wide form exists.
0764:                myCode.addInstrU2(VMOpcode.NEW, cpi);
0765:                myCode.addInstr(VMOpcode.DUP);
0766:
0767:                // Grow the stack twice as we are pushing
0768:                // two instances of newly created reference
0769:                Type nt = cb.factory.type(className);
0770:                growStack(1, nt);
0771:                growStack(1, nt);
0772:            }
0773:
0774:            public void pushNewComplete(int numArgs) {
0775:                callMethod(VMOpcode.INVOKESPECIAL, (String) null, "<init>",
0776:                        "void", numArgs);
0777:            }
0778:
0779:            public void upCast(String className) {
0780:                Type uct = cb.factory.type(className);
0781:
0782:                stackTypes[stackTypeOffset - 1] = uct;
0783:                //popStack();
0784:                //growStack(1, uct);
0785:            }
0786:
0787:            public void cast(String className) {
0788:
0789:                // Perform a simple optimization to not
0790:                // insert a checkcast when the classname
0791:                // of the cast exactly matches the type name
0792:                // currently on the stack.
0793:                // This can reduce the amount of generated code.
0794:                // This compiler/class generator does not load
0795:                // classes to check relationships or any other
0796:                // information. Thus other optimizations where a cast
0797:                // is not required are not implemented.
0798:                Type tbc = stackTypes[stackTypeOffset - 1];
0799:
0800:                short sourceType = tbc.vmType();
0801:
0802:                if (sourceType == BCExpr.vm_reference) {
0803:                    // Simple optimize step
0804:                    if (className.equals(tbc.javaName())) {
0805:                        // do nothing, exact matching type
0806:                        return;
0807:                    }
0808:                }
0809:
0810:                Type ct = cb.factory.type(className);
0811:                popStack();
0812:
0813:                short targetType = ct.vmType();
0814:
0815:                if (SanityManager.DEBUG) {
0816:
0817:                    if (!((sourceType == BCExpr.vm_reference && targetType == BCExpr.vm_reference) || (sourceType != BCExpr.vm_reference && targetType != BCExpr.vm_reference))) {
0818:                        SanityManager
0819:                                .THROWASSERT("Both or neither must be object types "
0820:                                        + ct.javaName() + " " + tbc.javaName());
0821:                    }
0822:                }
0823:
0824:                // if it is an object type, do a checkcast on it.
0825:                if (sourceType == BCExpr.vm_reference) {
0826:
0827:                    int cpi = modClass.addClassReference(ct.vmNameSimple);
0828:                    myCode.addInstrU2(VMOpcode.CHECKCAST, cpi);
0829:                }
0830:                // otherwise, try to convert it.
0831:                else {
0832:                    short opcode = VMOpcode.NOP;
0833:
0834:                    // we use the conversionInfo array
0835:                    // to determine how to convert; if
0836:                    // the result type of the conversion
0837:                    // is not our target type, we are not done
0838:                    // yet.  Make sure there are no
0839:                    // infinite loop possibilities in the
0840:                    // conversionInfo array!
0841:                    while (sourceType != targetType && opcode != VMOpcode.BAD) {
0842:                        short[] currentConversion = CodeChunk.CAST_CONVERSION_INFO[sourceType][targetType];
0843:                        sourceType = currentConversion[1];
0844:                        opcode = currentConversion[0];
0845:                        if (opcode != VMOpcode.NOP) {
0846:                            myCode.addInstr(opcode);
0847:                        }
0848:                    }
0849:                    if (SanityManager.DEBUG) {
0850:                        SanityManager.ASSERT(opcode != VMOpcode.BAD,
0851:                                "BAD VMOpcode not expected in cast");
0852:                    }
0853:                }
0854:                growStack(ct);
0855:            }
0856:
0857:            public void isInstanceOf(String className) {
0858:                int cpi = modClass.addClassReference(className);
0859:                myCode.addInstrU2(VMOpcode.INSTANCEOF, cpi);
0860:                popStack();
0861:                growStack(1, Type.BOOLEAN);
0862:            }
0863:
0864:            public void pushNull(String type) {
0865:                myCode.addInstr(VMOpcode.ACONST_NULL);
0866:                growStack(1, cb.factory.type(type));
0867:            }
0868:
0869:            public void getField(LocalField field) {
0870:
0871:                BCLocalField lf = (BCLocalField) field;
0872:                Type lt = lf.type;
0873:
0874:                pushThis();
0875:                myCode.addInstrU2(VMOpcode.GETFIELD, lf.cpi);
0876:
0877:                popStack();
0878:                growStack(lt);
0879:
0880:            }
0881:
0882:            public void getField(String declaringClass, String fieldName,
0883:                    String fieldType) {
0884:                Type dt = popStack();
0885:
0886:                Type dtu = vmNameDeclaringClass(declaringClass);
0887:                if (dtu != null)
0888:                    dt = dtu;
0889:
0890:                getField(VMOpcode.GETFIELD, dt.vmNameSimple, fieldName,
0891:                        fieldType);
0892:            }
0893:
0894:            /**
0895:            	Push the contents of the described static field onto the stack.		
0896:             */
0897:            public void getStaticField(String declaringClass, String fieldName,
0898:                    String fieldType) {
0899:                getField(VMOpcode.GETSTATIC, declaringClass, fieldName,
0900:                        fieldType);
0901:            }
0902:
0903:            private void getField(short opcode, String declaringClass,
0904:                    String fieldName, String fieldType) {
0905:
0906:                Type ft = cb.factory.type(fieldType);
0907:                int cpi = modClass.addFieldReference(
0908:                        vmNameDeclaringClass(declaringClass).vmNameSimple,
0909:                        fieldName, ft.vmName());
0910:                myCode.addInstrU2(opcode, cpi);
0911:
0912:                growStack(ft);
0913:            }
0914:
0915:            /**
0916:             * Set the field but don't duplicate its value so
0917:             * nothing is left on the stack after this call.
0918:             */
0919:            public void setField(LocalField field) {
0920:                BCLocalField lf = (BCLocalField) field;
0921:                Type lt = lf.type;
0922:
0923:                putField(lf.type, lf.cpi, false);
0924:
0925:                if (stackDepth == 0)
0926:                    overflowMethodCheck();
0927:            }
0928:
0929:            /**
0930:            	Upon entry the top word(s) on the stack is
0931:            	the value to be put into the field. Ie.
0932:            	we have
0933:            	<PRE>
0934:            	word
0935:            	</PRE>
0936:
0937:            	Before the call we need 
0938:            	<PRE>
0939:            	word
0940:            	this
0941:            	word
0942:            	</PRE>
0943:            	word2,word1 -> word2, word1, word2
0944:
0945:            	So that we are left with word after the put.
0946:
0947:             */
0948:            public void putField(LocalField field) {
0949:                BCLocalField lf = (BCLocalField) field;
0950:                Type lt = lf.type;
0951:
0952:                putField(lf.type, lf.cpi, true);
0953:            }
0954:
0955:            /**
0956:            	Pop the top stack value and store it in the instance field of this class.
0957:             */
0958:            public void putField(String fieldName, String fieldType) {
0959:
0960:                Type ft = cb.factory.type(fieldType);
0961:                int cpi = modClass.addFieldReference(cb.classType.vmNameSimple,
0962:                        fieldName, ft.vmName());
0963:
0964:                putField(ft, cpi, true);
0965:            }
0966:
0967:            private void putField(Type fieldType, int cpi, boolean dup) {
0968:
0969:                // now have ...,value
0970:                if (dup) {
0971:                    myCode.addInstr(fieldType.width() == 2 ? VMOpcode.DUP2
0972:                            : VMOpcode.DUP);
0973:                    growStack(fieldType);
0974:                }
0975:                // now have
0976:                // dup true:  ...,value,value
0977:                // dup false: ...,value,
0978:
0979:                pushThis();
0980:                // now have
0981:                // dup true:  ...,value,value,this
0982:                // dup false: ...,value,this
0983:
0984:                swap();
0985:                // now have
0986:                // dup true:  ...,value,this,value
0987:                // dup false: ...,this,value
0988:
0989:                myCode.addInstrU2(VMOpcode.PUTFIELD, cpi);
0990:                popStack(); // the value
0991:                popStack(); // this
0992:
0993:                // now have
0994:                // dup true:  ...,value
0995:                // dup false: ...
0996:            }
0997:
0998:            /**
0999:            	Pop the top stack value and store it in the field.
1000:            	This call requires the instance to be pushed by the caller.
1001:             */
1002:            public void putField(String declaringClass, String fieldName,
1003:                    String fieldType) {
1004:                Type vt = popStack();
1005:                Type dt = popStack();
1006:
1007:                if (SanityManager.DEBUG) {
1008:                    if (dt.width() != 1)
1009:                        SanityManager
1010:                                .THROWASSERT("reference expected for field access - is "
1011:                                        + dt.javaName());
1012:                }
1013:
1014:                // have objectref,value
1015:                // need value,objectref,value
1016:
1017:                myCode.addInstr(vt.width() == 2 ? VMOpcode.DUP2_X1
1018:                        : VMOpcode.DUP_X1);
1019:                growStack(vt);
1020:                growStack(dt);
1021:                growStack(vt);
1022:
1023:                Type dtu = vmNameDeclaringClass(declaringClass);
1024:                if (dtu != null)
1025:                    dt = dtu;
1026:
1027:                Type ft = cb.factory.type(fieldType);
1028:                int cpi = modClass.addFieldReference(dt.vmNameSimple,
1029:                        fieldName, ft.vmName());
1030:                myCode.addInstrU2(VMOpcode.PUTFIELD, cpi);
1031:
1032:                popStack(); // value
1033:                popStack(); // reference
1034:            }
1035:
1036:            public void conditionalIfNull() {
1037:
1038:                conditionalIf(VMOpcode.IFNONNULL);
1039:            }
1040:
1041:            public void conditionalIf() {
1042:                conditionalIf(VMOpcode.IFEQ);
1043:            }
1044:
1045:            private Conditional condition;
1046:
1047:            private void conditionalIf(short opcode) {
1048:                popStack();
1049:
1050:                // Save the stack upon entry to the 'then' block of the
1051:                // 'if' so that we can set up the 'else' block with the
1052:                // correct stack on entry.
1053:
1054:                condition = new Conditional(condition, myCode, opcode,
1055:                        copyStack());
1056:            }
1057:
1058:            public void startElseCode() {
1059:
1060:                // start the else code
1061:                Type[] entryStack = condition.startElse(this , myCode,
1062:                        copyStack());
1063:
1064:                for (int i = stackDepth = 0; i < entryStack.length; i++) {
1065:                    stackDepth += (stackTypes[i] = entryStack[i]).width();
1066:                }
1067:                this .stackTypeOffset = entryStack.length;
1068:
1069:            }
1070:
1071:            public void completeConditional() {
1072:                condition = condition.end(this , myCode, stackTypes,
1073:                        stackTypeOffset);
1074:            }
1075:
1076:            public void pop() {
1077:                if (SanityManager.DEBUG) {
1078:                    if (stackDepth == 0)
1079:                        SanityManager.THROWASSERT("pop when stack is empty!");
1080:                }
1081:                Type toPop = popStack();
1082:
1083:                myCode.addInstr(toPop.width() == 2 ? VMOpcode.POP2
1084:                        : VMOpcode.POP);
1085:
1086:                if (stackDepth == 0)
1087:                    overflowMethodCheck();
1088:            }
1089:
1090:            public void endStatement() {
1091:                if (stackDepth != 0) {
1092:                    pop();
1093:                }
1094:
1095:                //if (SanityManager.DEBUG) {
1096:                //	if (stackDepth != 0)
1097:                //		SanityManager.THROWASSERT("items left on stack " + stackDepth);
1098:                //	}
1099:            }
1100:
1101:            /**
1102:             */
1103:            public void getArrayElement(int element) {
1104:
1105:                push(element);
1106:                popStack(); // int just pushed will be popped by array access
1107:
1108:                Type arrayType = popStack();
1109:
1110:                String arrayJava = arrayType.javaName();
1111:                String componentString = arrayJava.substring(0, arrayJava
1112:                        .length() - 2);
1113:
1114:                Type componentType = cb.factory.type(componentString);
1115:
1116:                short typ = componentType.vmType();
1117:
1118:                // boolean has a type id of integer, here it needs to be byte.
1119:                if ((typ == BCExpr.vm_int)
1120:                        && (componentType.vmName().equals("Z")))
1121:                    typ = BCExpr.vm_byte;
1122:                myCode.addInstr(CodeChunk.ARRAY_ACCESS[typ]);
1123:
1124:                growStack(componentType);
1125:
1126:            }
1127:
1128:            // come in with ref, value
1129:
1130:            public void setArrayElement(int element) {
1131:
1132:                // ref, value
1133:
1134:                push(element);
1135:
1136:                // ref, value, index
1137:                swap();
1138:
1139:                Type componentType = popStack(); // value
1140:                popStack(); // int just pushed will be popped by array access
1141:
1142:                popStack(); // array ref.
1143:
1144:                short typ = componentType.vmType();
1145:
1146:                // boolean has a type id of integer, here it needs to be byte.
1147:                if ((typ == BCExpr.vm_int)
1148:                        && (componentType.vmName().equals("Z")))
1149:                    typ = BCExpr.vm_byte;
1150:
1151:                myCode.addInstr(CodeChunk.ARRAY_STORE[typ]);
1152:            }
1153:
1154:            /**
1155:            	this array maps the BCExpr vm_* constants 0..6 to
1156:            	the expected VM type constants for the newarray instruction.
1157:            	<p>
1158:            	Because boolean was mapped to integer for general instructions,
1159:            	it will have to be specially matched and mapped to its value
1160:            	directly (4).
1161:             */
1162:            private static final byte newArrayElementTypeMap[] = { 8, 9, 10,
1163:                    11, 6, 7, 5 };
1164:            static final byte T_BOOLEAN = 4;
1165:
1166:            /**
1167:            	Create an array instance
1168:
1169:            	Stack ... =>
1170:            	      ...,arrayref
1171:             */
1172:            public void pushNewArray(String className, int size) {
1173:
1174:                push(size);
1175:                popStack(); // int just pushed will be popped by array creation
1176:
1177:                Type elementType = cb.factory.type(className);
1178:
1179:                // determine the instruction to use based on the element type
1180:                if (elementType.vmType() == BCExpr.vm_reference) {
1181:
1182:                    // For an array of Java class/interface elements, generate:
1183:                    // ANEWARRAY #cpei ; where cpei is a constant pool index for the class
1184:
1185:                    int cpi = modClass
1186:                            .addClassReference(elementType.javaName());
1187:                    // Use U2, not CPE, since only wide form exists.
1188:                    myCode.addInstrU2(VMOpcode.ANEWARRAY, cpi);
1189:                } else {
1190:                    byte atype;
1191:
1192:                    // get the argument for the array type
1193:                    // if the element type is boolean, we can't use the map
1194:                    // because the type id will say integer.
1195:                    // but we can use vm_int test to weed out some tests
1196:                    if (elementType.vmType() == BCExpr.vm_int
1197:                            && VMDescriptor.C_BOOLEAN == elementType.vmName()
1198:                                    .charAt(0))
1199:                        atype = T_BOOLEAN;
1200:                    else
1201:                        atype = newArrayElementTypeMap[elementType.vmType()];
1202:
1203:                    // For an array of Java builtin type elements, generate:
1204:                    // NEWARRAY #atype ; where atype is a constant for the builtin type
1205:
1206:                    myCode.addInstrU1(VMOpcode.NEWARRAY, atype);
1207:                }
1208:
1209:                // an array reference is an object, hence width of 1
1210:                growStack(1, cb.factory.type(className.concat("[]")));
1211:            }
1212:
1213:            /**
1214:             * Write a instruction that uses a constant pool entry
1215:             * as an operand, add a limit exceeded message if
1216:             * the number of constant pool entries has exceeded
1217:             * the limit.
1218:             */
1219:            private void addInstrCPE(short opcode, int cpe) {
1220:                if (cpe >= VMOpcode.MAX_CONSTANT_POOL_ENTRIES)
1221:                    cb.addLimitExceeded(this , "constant_pool_count",
1222:                            VMOpcode.MAX_CONSTANT_POOL_ENTRIES, cpe);
1223:
1224:                myCode.addInstrCPE(opcode, cpe);
1225:            }
1226:
1227:            /**
1228:            	Tell if statement number in this method builder hits limit.  This
1229:            	method builder keeps a counter of how many statements are added to it.
1230:            	Caller should call this function every time it tries to add a statement
1231:            	to this method builder (counter is increased by 1), then the function
1232:            	returns whether the accumulated statement number hits a limit.
1233:            	The reason of doing this is that Java compiler has a limit of 64K code
1234:            	size for each method.  We might hit this limit if an extremely long
1235:            	insert statement is issued, for example (see beetle 4293).  Counting
1236:            	statement number is an approximation without too much overhead.
1237:             */
1238:            public boolean statementNumHitLimit(int noStatementsAdded) {
1239:                if (statementNum > 2048) // 2K limit
1240:                {
1241:                    return true;
1242:                } else {
1243:                    statementNum = statementNum + noStatementsAdded;
1244:                    return false;
1245:                }
1246:            }
1247:
1248:            /**
1249:             * Check to see if the current method byte code is nearing the
1250:             * limit of 65535. If it is start overflowing to a new method.
1251:             * <P>
1252:             * Overflow is handled for a method named e23 as:
1253:             * <CODE>
1254:             public Object e23()
1255:             {
1256:               ... existing code
1257:               // split point
1258:               return e23_0();
1259:             }
1260:             private Object e23_0()
1261:             {
1262:                ... first set overflowed code
1263:                // split point
1264:                return e23_1(); 
1265:             }
1266:             private Object e23_1()
1267:             {
1268:                ... second set overflowed code
1269:                // method complete
1270:                return result; 
1271:             }
1272:             	 </CODE>
1273:             <P>
1274:             
1275:             These overflow methods are hidden from the code using this MethodBuilder,
1276:             it continues to think that it is building a single method with the
1277:             original name.
1278:
1279:
1280:             * <BR> Restrictions:
1281:             * <UL>
1282:             * <LI> Only handles methods with no arguments
1283:             * <LI> Stack depth must be zero
1284:             * </UL>
1285:             * 
1286:             *
1287:             */
1288:            private void overflowMethodCheck() {
1289:                if (handlingOverflow)
1290:                    return;
1291:
1292:                // don't sub method in the middle of a conditional
1293:                if (condition != null)
1294:                    return;
1295:
1296:                int currentCodeSize = myCode.getPC();
1297:
1298:                // Overflow at >= 55,000 bytes which is someway
1299:                // below the limit of 65,535. Ideally overflow
1300:                // would occur at 65535 minus the few bytes needed
1301:                // to call the sub-method, but the issue is at this level
1302:                // we don't know frequently we are called given the restriction
1303:                // of only being called when the stack depth is zero.
1304:                // Thus split earlier to try ensure most cases are caught.
1305:                // Only downside is that we may split into N methods when N-1 would suffice.
1306:                if (currentCodeSize < 55000)
1307:                    return;
1308:
1309:                // only handle no-arg methods at the moment.
1310:                if (parameters != null) {
1311:                    if (parameters.length != 0)
1312:                        return;
1313:                }
1314:
1315:                BCMethod subMethod = getNewSubMethod(myReturnType, false);
1316:
1317:                // stop any recursion
1318:                handlingOverflow = true;
1319:
1320:                // in this method make a call to the sub method we will
1321:                // be transferring control to.
1322:                callSubMethod(subMethod);
1323:
1324:                // and return its value, works just as well for a void method!
1325:                this .methodReturn();
1326:                this .complete();
1327:
1328:                handlingOverflow = false;
1329:
1330:                // now the tricky bit, make this object take over the
1331:                // code etc. from the sub method. This is done so
1332:                // that any code that has a reference to this MethodBuilder
1333:                // will continue to work. They will be writing code into the
1334:                // new sub method.
1335:
1336:                this .myEntry = subMethod.myEntry;
1337:                this .myCode = subMethod.myCode;
1338:                this .currentVarNum = subMethod.currentVarNum;
1339:                this .statementNum = subMethod.statementNum;
1340:
1341:                // copy stack info
1342:                this .stackTypes = subMethod.stackTypes;
1343:                this .stackTypeOffset = subMethod.stackTypeOffset;
1344:                this .maxStack = subMethod.maxStack;
1345:                this .stackDepth = subMethod.stackDepth;
1346:            }
1347:
1348:            /**
1349:             * Create a sub-method from this method to allow the code builder to split a
1350:             * single logical method into multiple methods to avoid the 64k per-method
1351:             * code size limit. The sub method with inherit the thrown exceptions of
1352:             * this method.
1353:             * 
1354:             * @param returnType
1355:             *            Return type of the new method
1356:             * @param withParameters
1357:             *            True to define the method with matching parameters false to
1358:             *            define it with no parameters.
1359:             * @return A valid empty sub method.
1360:             */
1361:            final BCMethod getNewSubMethod(String returnType,
1362:                    boolean withParameters) {
1363:                int modifiers = myEntry.getModifier();
1364:
1365:                // the sub-method can be private to ensure that no-one
1366:                // can call it accidentally from outside the class.
1367:                modifiers &= ~(Modifier.PROTECTED | Modifier.PUBLIC);
1368:                modifiers |= Modifier.PRIVATE;
1369:
1370:                String subMethodName = myName + "_s"
1371:                        + Integer.toString(subMethodCount++);
1372:                BCMethod subMethod = (BCMethod) cb.newMethodBuilder(modifiers,
1373:                        returnType, subMethodName,
1374:                        withParameters ? parameterTypes : null);
1375:                subMethod.thrownExceptions = this .thrownExceptions;
1376:
1377:                return subMethod;
1378:            }
1379:
1380:            /**
1381:             * Call a sub-method created by getNewSubMethod handling parameters
1382:             * correctly.
1383:             */
1384:            final void callSubMethod(BCMethod subMethod) {
1385:                // in this method make a call to the sub method we will
1386:                // be transferring control to.
1387:                short op;
1388:                if ((myEntry.getModifier() & Modifier.STATIC) == 0) {
1389:                    op = VMOpcode.INVOKEVIRTUAL;
1390:                    this .pushThis();
1391:                } else {
1392:                    op = VMOpcode.INVOKESTATIC;
1393:                }
1394:
1395:                int parameterCount = subMethod.parameters == null ? 0
1396:                        : subMethod.parameters.length;
1397:
1398:                // push my parameter values for the call.
1399:                for (int pi = 0; pi < parameterCount; pi++)
1400:                    this.getParameter(pi);
1401:
1402:                this.callMethod(op, modClass.getName(), subMethod.getName(),
1403:                        subMethod.myReturnType, parameterCount);
1404:            }
1405:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.