Adding JMCR-Stable version
[Benchmarks_CSolver.git] / JMCR-Stable / real-world application / derby-10.3.2.1 / java / engine / org / apache / derby / impl / services / bytecode / BCMethod.java
diff --git a/JMCR-Stable/real-world application/derby-10.3.2.1/java/engine/org/apache/derby/impl/services/bytecode/BCMethod.java b/JMCR-Stable/real-world application/derby-10.3.2.1/java/engine/org/apache/derby/impl/services/bytecode/BCMethod.java
new file mode 100644 (file)
index 0000000..5290483
--- /dev/null
@@ -0,0 +1,1391 @@
+/*\r
+\r
+   Derby - Class org.apache.derby.impl.services.bytecode.BCMethod\r
+\r
+   Licensed to the Apache Software Foundation (ASF) under one or more\r
+   contributor license agreements.  See the NOTICE file distributed with\r
+   this work for additional information regarding copyright ownership.\r
+   The ASF licenses this file to you under the Apache License, Version 2.0\r
+   (the "License"); you may not use this file except in compliance with\r
+   the License.  You may obtain a copy of the License at\r
+\r
+      http://www.apache.org/licenses/LICENSE-2.0\r
+\r
+   Unless required by applicable law or agreed to in writing, software\r
+   distributed under the License is distributed on an "AS IS" BASIS,\r
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+   See the License for the specific language governing permissions and\r
+   limitations under the License.\r
+\r
+ */\r
+\r
+package org.apache.derby.impl.services.bytecode;\r
+\r
+import org.apache.derby.iapi.services.compiler.ClassBuilder;\r
+import org.apache.derby.iapi.services.compiler.MethodBuilder;\r
+import org.apache.derby.iapi.services.classfile.ClassFormatOutput;\r
+import org.apache.derby.iapi.services.compiler.LocalField;\r
+import org.apache.derby.iapi.services.classfile.ClassHolder;\r
+import org.apache.derby.iapi.services.classfile.ClassMember;\r
+\r
+import org.apache.derby.iapi.services.sanity.SanityManager;\r
+\r
+import org.apache.derby.iapi.services.classfile.VMDescriptor;\r
+import org.apache.derby.iapi.services.classfile.VMOpcode;\r
+\r
+import java.lang.reflect.Modifier;\r
+import java.util.Vector;\r
+import java.io.IOException;\r
+\r
+/**\r
+ * MethodBuilder is used to piece together a method when\r
+ * building a java class definition.\r
+ * <p>\r
+ * When a method is first created, it has:\r
+ * <ul>\r
+ * <li> a return type\r
+ * <li> modifiers\r
+ * <li> a name\r
+ * <li> an empty parameter list\r
+ * <li> an empty throws list\r
+ * <li> an empty statement block\r
+ * </ul>\r
+ * <p>\r
+ * MethodBuilder implementations are required to supply a way for\r
+ * Statements and Expressions to give them code.  Most typically, they may have\r
+ * a stream to which their contents writes the code that is of\r
+ * the type to satisfy what the contents represent.\r
+ * MethodBuilder implementations also have to have a way to supply\r
+ * ClassBuilders with their code, that satisfies the type of class\r
+ * builder they are implemented with.  This is implementation-dependent,\r
+ * so ClassBuilders, MethodBuilders, Statements, and Expressions all have\r
+ * to be of the same implementation in order to interact to generate a class.\r
+ * <p>\r
+ * Method Builder implementation for generating bytecode.\r
+ *\r
+ */\r
+class BCMethod implements MethodBuilder {\r
+    \r
+    /**\r
+     * Code length at which to split into sub-methods.\r
+     * Normally set to the maximim code length the\r
+     * JVM can support, but for testing the split code\r
+     * it can be reduced so that the standard tests\r
+     * cause some splitting. Tested with value set to 2000.\r
+     */\r
+    static final int CODE_SPLIT_LENGTH = VMOpcode.MAX_CODE_LENGTH;\r
+    \r
+       final BCClass           cb;\r
+       protected final ClassHolder modClass; // the class it is in (modifiable fmt)\r
+       final String myReturnType;\r
+       \r
+       /**\r
+        * The original name of the method, this\r
+        * represents how any user would call this method.\r
+        */\r
+       private final String myName;\r
+\r
+    /**\r
+     * Fast access for the parametes, will be null\r
+     * if the method has no parameters.\r
+     */\r
+       BCLocalField[] parameters; \r
+    \r
+    /**\r
+     * List of parameter types with java language class names.\r
+     * Can be null or zero length for no parameters.\r
+     */\r
+    private final String[] parameterTypes;\r
+    \r
+    \r
+       Vector thrownExceptions; // expected to be names of Classes under Throwable\r
+\r
+       CodeChunk myCode;\r
+       protected ClassMember myEntry;\r
+\r
+       private int currentVarNum;\r
+       private int statementNum;\r
+       \r
+       /**\r
+        * True if we are currently switching control\r
+        * over to a sub method to avoid hitting the code generation\r
+        * limit of 65535 bytes per method.\r
+        */\r
+       private boolean handlingOverflow;\r
+       \r
+       /**\r
+        * How many sub-methods we have overflowed to.\r
+        */\r
+       private int subMethodCount;\r
+\r
+       BCMethod(ClassBuilder cb,\r
+                       String returnType,\r
+                       String methodName,\r
+                       int modifiers,\r
+                       String[] parms,\r
+                       BCJava factory) {\r
+\r
+               this.cb = (BCClass) cb;\r
+               modClass = this.cb.modify();\r
+               myReturnType = returnType;\r
+               myName = methodName;\r
+\r
+               if (SanityManager.DEBUG) {\r
+                       this.cb.validateType(returnType);\r
+               }\r
+\r
+               // if the method is not static, allocate for "this".\r
+               if ((modifiers & Modifier.STATIC) == 0 )\r
+                       currentVarNum = 1;\r
+\r
+               String[] vmParamterTypes;\r
+\r
+               if (parms != null && parms.length != 0) {\r
+                       int len = parms.length;\r
+                       vmParamterTypes = new String[len];\r
+                       parameters = new BCLocalField[len];\r
+                       for (int i = 0; i < len; i++) {\r
+                               Type t = factory.type(parms[i]);\r
+                               parameters[i] = new BCLocalField(t, currentVarNum);\r
+                               currentVarNum += t.width();\r
+\r
+                               // convert to vmname for the BCMethodDescriptor.get() call\r
+                               vmParamterTypes[i] = t.vmName();\r
+                       }\r
+               }\r
+               else\r
+                       vmParamterTypes = BCMethodDescriptor.EMPTY;\r
+\r
+               // create a code attribute\r
+               String sig = BCMethodDescriptor.get(vmParamterTypes, factory.type(returnType).vmName(), factory);\r
+\r
+               // stuff the completed information into the class.\r
+               myEntry = modClass.addMember(methodName, sig, modifiers);\r
+\r
+               // get code chunk\r
+               myCode = new CodeChunk(this.cb);\r
+        \r
+        parameterTypes = parms;\r
+       }\r
+       //\r
+       // MethodBuilder interface\r
+       //\r
+\r
+       /**\r
+        * Return the logical name of the method. The current\r
+        * myEntry refers to the sub method we are currently\r
+        * overflowing to. Those sub-methods are hidden from any caller.\r
+        */\r
+       public String getName() {\r
+               return myName;\r
+       }\r
+\r
+       public void getParameter(int id) {\r
+\r
+               int num = parameters[id].cpi;\r
+               short typ = parameters[id].type.vmType();\r
+               if (num < 4)\r
+                       myCode.addInstr((short) (CodeChunk.LOAD_VARIABLE_FAST[typ]+num));\r
+               else\r
+                       myCode.addInstrWide(CodeChunk.LOAD_VARIABLE[typ], num);\r
+\r
+               growStack(parameters[id].type);\r
+       }\r
+\r
+       /**\r
+        * a throwable can be added to the end of\r
+        * the list of thrownExceptions.\r
+        */\r
+       public void addThrownException(String exceptionClass) {\r
+               \r
+               // cannot add exceptions after code generation has started.\r
+               // Allowing this would cause the method overflow/split to\r
+               // break as the top-level method would not have the exception\r
+               // added in the sub method.\r
+               if (SanityManager.DEBUG)\r
+               {\r
+                       if (myCode.getPC() != 0)\r
+                               SanityManager.THROWASSERT("Adding exception after code generation " + exceptionClass\r
+                                               + " to method " + getName());\r
+               }\r
+\r
+               if (thrownExceptions == null)\r
+                       thrownExceptions = new Vector();\r
+               thrownExceptions.addElement(exceptionClass);\r
+       }\r
+\r
+       /**\r
+        * when the method has had all of its parameters\r
+        * and thrown exceptions defined, and its statement\r
+        * block has been completed, it can be completed and\r
+        * its class file information generated.\r
+        * <p>\r
+        * further alterations of the method will not be\r
+        * reflected in the code generated for it.\r
+        */\r
+       public void complete() {\r
+        \r
+        // myCode.getPC() gives the code length since\r
+        // the program counter will be positioned after\r
+        // the last instruction. Note this value can\r
+        // be changed by the splitMethod call.\r
+        \r
+        if (myCode.getPC() > CODE_SPLIT_LENGTH)\r
+            splitMethod();\r
+                         \r
+       // write exceptions attribute info\r
+        writeExceptions();\r
+               \r
+               // get the code attribute to put itself into the class\r
+               // provide the final header information needed\r
+               myCode.complete(this, modClass, myEntry, maxStack, currentVarNum);\r
+       }\r
+    \r
+    /**\r
+     * Attempt to split a large method by pushing code out to several\r
+     * sub-methods. Performs a number of steps.\r
+     * <OL>\r
+     * <LI> Split at zero stack depth.\r
+     * <LI> Split at non-zero stack depth (FUTURE)\r
+     * </OL>\r
+     * \r
+     * If the class has already exceeded some limit in building the\r
+     * class file format structures then don't attempt to split.\r
+     * Most likely the number of constant pool entries has been exceeded\r
+     * and thus the built class file no longer has integrity.\r
+     * The split code relies on being able to read the in-memory\r
+     * version of the class file in order to determine descriptors\r
+     * for methods and fields.\r
+     */\r
+    private void splitMethod() {\r
+        \r
+        int split_pc = 0;\r
+        boolean splittingZeroStack = true;\r
+        for (int codeLength = myCode.getPC();\r
+               (cb.limitMsg == null) &&\r
+               (codeLength > CODE_SPLIT_LENGTH);\r
+            codeLength = myCode.getPC())\r
+        {\r
+            int lengthToCheck = codeLength - split_pc;\r
+\r
+            int optimalMinLength;\r
+            if (codeLength < CODE_SPLIT_LENGTH * 2) {\r
+                // minimum required\r
+                optimalMinLength = codeLength - CODE_SPLIT_LENGTH;\r
+            } else {\r
+                // try to split as much as possible\r
+                // need one for the return instruction\r
+                optimalMinLength = CODE_SPLIT_LENGTH - 1;\r
+            }\r
+\r
+            if (optimalMinLength > lengthToCheck)\r
+                optimalMinLength = lengthToCheck;\r
+\r
+            if (splittingZeroStack)\r
+            {\r
+                split_pc = myCode.splitZeroStack(this, modClass, split_pc,\r
+                    optimalMinLength);\r
+            }\r
+            else\r
+            {\r
+                // Note the split expression does not re-start split\r
+                // at point left off by the previous split expression.\r
+                // This could be done but would require some level\r
+                // of stack depth history to be kept across calls.\r
+                split_pc = myCode.splitExpressionOut(this, modClass,\r
+                        optimalMinLength, maxStack);\r
+\r
+             }\r
+\r
+            // Negative split point returned means that no split\r
+            // was possible. Give up on this approach and goto\r
+            // the next approach.\r
+            if (split_pc < 0) {\r
+                if (!splittingZeroStack)\r
+                   break;\r
+                splittingZeroStack = false;\r
+                split_pc = 0;\r
+            }\r
+\r
+            // success, continue on splitting after the call to the\r
+            // sub-method if the method still execeeds the maximum length.\r
+        }\r
+        \r
\r
+    }\r
+\r
+       /*\r
+     * class interface\r
+     */\r
+\r
+       /**\r
+     * In their giveCode methods, the parts of the method body will want to get\r
+     * to the constant pool to add their constants. We really only want them\r
+     * treating it like a constant pool inclusion mechanism, we could write a\r
+     * wrapper to limit it to that.\r
+     */\r
+       ClassHolder constantPool() {\r
+               return modClass;\r
+       }\r
+\r
+\r
+    //\r
+    // Class implementation\r
+    //\r
+\r
+\r
+       /**\r
+        * sets exceptionBytes to the attribute_info needed\r
+        * for a method's Exceptions attribute.\r
+        * The ClassUtilities take care of the header 6 bytes for us,\r
+        * so they are not included here.\r
+        * See The Java Virtual Machine Specification Section 4.7.5,\r
+        * Exceptions attribute.\r
+        */\r
+       protected void writeExceptions() {\r
+               if (thrownExceptions == null)\r
+                       return;\r
+\r
+               int numExc = thrownExceptions.size();\r
+\r
+               // don't write an Exceptions attribute if there are no exceptions.\r
+               if (numExc != 0) {\r
+\r
+                       try{\r
+                               ClassFormatOutput eout = new ClassFormatOutput((numExc * 2) + 2);\r
+\r
+                               eout.putU2(numExc); // number_of_exceptions\r
+\r
+                               for (int i = 0; i < numExc; i++) {\r
+                                       // put each exception into the constant pool\r
+                                       String e = thrownExceptions.elementAt(i).toString();\r
+                                       int ei2 = modClass.addClassReference(e);\r
+\r
+                                       // add constant pool index to exception attribute_info\r
+                                       eout.putU2(ei2);\r
+                               }\r
+\r
+                               myEntry.addAttribute("Exceptions", eout);\r
+\r
+                       } catch (IOException ioe) {\r
+                       }                       \r
+               }\r
+       }\r
+\r
+       /*\r
+       ** New push compiler api.\r
+       */\r
+\r
+       /**\r
+        * Array of the current types of the values on the stack.\r
+        * A type that types up two words on the stack, e.g. double\r
+        * will only occupy one element in this array.\r
+        * This array is dynamically re-sized as needed.\r
+        */\r
+       private Type[]  stackTypes = new Type[8];\r
+       \r
+       /**\r
+        * Points to the next array offset in stackTypes\r
+        * to be used. Really it's the number of valid entries\r
+        * in stackTypes.\r
+        */\r
+       private int     stackTypeOffset;\r
+\r
+       /**\r
+        * Maximum stack depth seen in this method, measured in words.\r
+        * Corresponds to max_stack in the Code attribute of section 4.7.3\r
+        * of the vm spec.\r
+        */\r
+       int maxStack;\r
+       \r
+       /**\r
+        * Current stack depth in this method, measured in words.\r
+        */\r
+       private int stackDepth;\r
+\r
+       private void growStack(int size, Type type) {\r
+               stackDepth += size;\r
+               if (stackDepth > maxStack)\r
+                       maxStack = stackDepth;\r
+               \r
+               if (stackTypeOffset >= stackTypes.length) {\r
+\r
+                       Type[] newStackTypes = new Type[stackTypes.length + 8];\r
+                       System.arraycopy(stackTypes, 0, newStackTypes, 0, stackTypes.length);\r
+                       stackTypes = newStackTypes;\r
+               }\r
+\r
+               stackTypes[stackTypeOffset++] = type;\r
+\r
+               if (SanityManager.DEBUG) {\r
+\r
+                       int sum = 0;\r
+                       for (int i = 0 ; i < stackTypeOffset; i++) {\r
+                               sum += stackTypes[i].width();\r
+                       }\r
+                       if (sum != stackDepth) {\r
+                               SanityManager.THROWASSERT("invalid stack depth " + stackDepth + " calc " + sum);\r
+                       }\r
+               }\r
+       }\r
+\r
+       private void growStack(Type type) {\r
+               growStack(type.width(), type);\r
+       }\r
+\r
+       private Type popStack() {\r
+               stackTypeOffset--;\r
+               Type topType = stackTypes[stackTypeOffset];\r
+               stackDepth -= topType.width();\r
+               return topType;\r
+\r
+       }\r
+       \r
+       private Type[] copyStack()\r
+       {\r
+               Type[] stack = new Type[stackTypeOffset];\r
+               System.arraycopy(stackTypes, 0, stack, 0, stackTypeOffset);\r
+               return stack;\r
+       }\r
+\r
+       public void pushThis() {\r
+               myCode.addInstr(VMOpcode.ALOAD_0);\r
+               growStack(1, cb.classType);\r
+       }\r
+\r
+       public void push(byte value) {\r
+               push(value, Type.BYTE);\r
+       }\r
+\r
+       public void push(boolean value) {\r
+               push(value ? 1 : 0, Type.BOOLEAN);\r
+       }\r
+\r
+       public void push(short value) {\r
+               push(value, Type.SHORT);\r
+       }\r
+\r
+       public void push(int value) {\r
+               push(value, Type.INT);\r
+       }\r
+\r
+       public void dup() {\r
+               Type dup = popStack();\r
+               myCode.addInstr(dup.width() == 2  ? VMOpcode.DUP2 : VMOpcode.DUP);\r
+               growStack(dup);\r
+               growStack(dup);\r
+\r
+       }\r
+\r
+       public void swap() {\r
+\r
+               // have A,B\r
+               // want B,A\r
+\r
+               Type wB = popStack();\r
+               Type wA = popStack();\r
+               growStack(wB);\r
+               growStack(wA);\r
+\r
+               if (wB.width() == 1) {\r
+                       // top value is one word\r
+                       if (wA.width() == 1) {\r
+                               myCode.addInstr(VMOpcode.SWAP);\r
+                               return;\r
+                       } else {\r
+                               myCode.addInstr(VMOpcode.DUP_X2);\r
+                               myCode.addInstr(VMOpcode.POP);\r
+                       }\r
+               } else {\r
+                       // top value is two words\r
+                       if (wA.width() == 1) {\r
+                               myCode.addInstr(VMOpcode.DUP2_X1);\r
+                               myCode.addInstr(VMOpcode.POP2);\r
+                       } else {\r
+                               myCode.addInstr(VMOpcode.DUP2_X2);\r
+                               myCode.addInstr(VMOpcode.POP2);\r
+                       }\r
+               }\r
+\r
+               // all except the simple swap push an extra\r
+               // copy of B which needs to be popped.\r
+               growStack(wB);\r
+               popStack();\r
+\r
+       }\r
+\r
+    /**\r
+     * Push an integer value. Uses the special integer opcodes\r
+     * for the constants -1 to 5, BIPUSH for values that fit in\r
+     * a byte and SIPUSH for values that fit in a short. Otherwise\r
+     * uses LDC with a constant pool entry.\r
+     * \r
+     * @param value Value to be pushed\r
+     * @param type Final type of the value.\r
+     */\r
+       private void push(int value, Type type) {\r
+\r
+               CodeChunk chunk = myCode;\r
+\r
+               if (value >= -1 && value <= 5)\r
+                       chunk.addInstr((short)(VMOpcode.ICONST_0+value));\r
+               else if (value >= Byte.MIN_VALUE && value <= Byte.MAX_VALUE)\r
+                       chunk.addInstrU1(VMOpcode.BIPUSH,value);\r
+               else if (value >= Short.MIN_VALUE && value <= Short.MAX_VALUE)\r
+                       chunk.addInstrU2(VMOpcode.SIPUSH,value);\r
+               else {\r
+                       int cpe = modClass.addConstant(value);\r
+                       addInstrCPE(VMOpcode.LDC, cpe);\r
+               }\r
+               growStack(type.width(), type);\r
+               \r
+       }\r
+\r
+    /**\r
+     * Push a long value onto the stack.\r
+     * For the values zero and one the LCONST_0 and\r
+     * LCONST_1 instructions are used.\r
+     * For values betwee Short.MIN_VALUE and Short.MAX_VALUE\r
+     * inclusive an byte/short/int value is pushed\r
+     * using push(int, Type) followed by an I2L instruction.\r
+     * This saves using a constant pool entry for such values.\r
+     * All other values use a constant pool entry. For values\r
+     * in the range of an Integer an integer constant pool\r
+     * entry is created to allow sharing with integer constants\r
+     * and to reduce constant pool slot entries.\r
+     */\r
+       public void push(long value) {\r
+        CodeChunk chunk = myCode;\r
+\r
+        if (value == 0L || value == 1L) {\r
+            short opcode = value == 0L ? VMOpcode.LCONST_0 : VMOpcode.LCONST_1;\r
+            chunk.addInstr(opcode);\r
+        } else if (value >= Integer.MIN_VALUE && value <= Integer.MAX_VALUE) {\r
+            // the push(int, Type) method grows the stack for us.\r
+            push((int) value, Type.LONG);\r
+            chunk.addInstr(VMOpcode.I2L);\r
+            return;\r
+        } else {\r
+            int cpe = modClass.addConstant(value);\r
+            chunk.addInstrU2(VMOpcode.LDC2_W, cpe);\r
+        }\r
+        growStack(2, Type.LONG);\r
+    }\r
+       public void push(float value) {\r
+\r
+               CodeChunk chunk = myCode;\r
+               \r
+               if (value == 0.0)\r
+               {\r
+                       chunk.addInstr(VMOpcode.FCONST_0);\r
+               }\r
+               else if (value == 1.0)\r
+               {\r
+                       chunk.addInstr(VMOpcode.FCONST_1);\r
+               }\r
+               else if (value == 2.0)\r
+               {\r
+                       chunk.addInstr(VMOpcode.FCONST_2);\r
+               }\r
+               else \r
+               {\r
+                       int cpe = modClass.addConstant(value);\r
+                       addInstrCPE(VMOpcode.LDC, cpe);\r
+               }\r
+               growStack(1, Type.FLOAT);\r
+       }\r
+\r
+       public void push(double value) {\r
+               CodeChunk chunk = myCode;\r
+\r
+               if (value == 0.0) {\r
+                               chunk.addInstr(VMOpcode.DCONST_0);\r
+               }\r
+               else {\r
+                       int cpe = modClass.addConstant(value);\r
+                       chunk.addInstrU2(VMOpcode.LDC2_W, cpe);\r
+               }\r
+               growStack(2, Type.DOUBLE);\r
+       }\r
+       public void push(String value) {\r
+               int cpe = modClass.addConstant(value);\r
+               addInstrCPE(VMOpcode.LDC, cpe);\r
+               growStack(1, Type.STRING);\r
+       }\r
\r
+\r
+       public void methodReturn() {\r
+\r
+               short opcode;           \r
+               if (stackDepth != 0) {\r
+                       Type topType = popStack();\r
+                       opcode = CodeChunk.RETURN_OPCODE[topType.vmType()];\r
+               } else {\r
+                       opcode = VMOpcode.RETURN;\r
+               }\r
+\r
+               myCode.addInstr(opcode);\r
+\r
+               if (SanityManager.DEBUG) {\r
+                       if (stackDepth != 0)\r
+                               SanityManager.THROWASSERT("items left on stack " + stackDepth);\r
+               }\r
+       }\r
+\r
+       public Object describeMethod(short opcode, String declaringClass, String methodName, String returnType) {\r
+\r
+               Type rt = cb.factory.type(returnType);\r
+\r
+               String methodDescriptor = BCMethodDescriptor.get(BCMethodDescriptor.EMPTY, rt.vmName(), cb.factory);\r
+\r
+               if ((declaringClass == null) && (opcode != VMOpcode.INVOKESTATIC)) {\r
+\r
+                       Type dt = stackTypes[stackTypeOffset - 1];\r
+\r
+                       if (declaringClass == null)\r
+                               declaringClass = dt.javaName();\r
+               }\r
+               \r
+               int cpi = modClass.addMethodReference(declaringClass, methodName,\r
+                               methodDescriptor, opcode == VMOpcode.INVOKEINTERFACE);\r
+\r
+               return new BCMethodCaller(opcode, rt, cpi);\r
+       }\r
+\r
+       public int callMethod(Object methodDescriptor) {\r
+\r
+               // pop the reference off the stack\r
+               popStack();\r
+\r
+               BCMethodCaller mc = (BCMethodCaller) methodDescriptor;\r
+\r
+               int cpi = mc.cpi;\r
+               short opcode = mc.opcode;\r
+\r
+               if (opcode == VMOpcode.INVOKEINTERFACE) {\r
+                       myCode.addInstrU2U1U1(opcode, cpi, (short) 1, (short) 0);\r
+               }\r
+               else\r
+                       myCode.addInstrU2(opcode, cpi);\r
+               \r
+               // this is the return type of the method\r
+               Type rt = mc.type;\r
+               int rw = rt.width();\r
+               if (rw != 0)\r
+                       growStack(rw, rt);\r
+               else\r
+               {\r
+                       if (stackDepth == 0)\r
+                               overflowMethodCheck();\r
+               }\r
+               return cpi;\r
+       }\r
+\r
+       public int callMethod(short opcode, String declaringClass, String methodName,\r
+               String returnType, int numArgs) {\r
+\r
+               Type rt = cb.factory.type(returnType);\r
+\r
+               int initialStackDepth = stackDepth;\r
+\r
+               // get the array of parameter types\r
+\r
+               String [] debugParameterTypes = null;\r
+               String[] vmParameterTypes;\r
+               if (numArgs == 0) {\r
+                       vmParameterTypes = BCMethodDescriptor.EMPTY;\r
+               } else {\r
+                       if (SanityManager.DEBUG) {\r
+                               debugParameterTypes = new String[numArgs];\r
+                       }\r
+                       vmParameterTypes = new String[numArgs];\r
+                       for (int i = numArgs - 1; i >= 0; i--) {\r
+                               Type at = popStack();\r
+\r
+                               vmParameterTypes[i] = at.vmName();\r
+                               if (SanityManager.DEBUG) {\r
+                                       debugParameterTypes[i] = at.javaName();\r
+                               }\r
+                       }\r
+               }\r
+               \r
+               String methodDescriptor = BCMethodDescriptor.get(vmParameterTypes, rt.vmName(), cb.factory);\r
+\r
+               Type dt = null;\r
+               if (opcode != VMOpcode.INVOKESTATIC) {\r
+\r
+                       dt = popStack();\r
+               }\r
+               Type dtu = vmNameDeclaringClass(declaringClass);\r
+               if (dtu != null)\r
+                       dt = dtu;\r
+               \r
+               int cpi = modClass.addMethodReference(dt.vmNameSimple, methodName,\r
+                               methodDescriptor, opcode == VMOpcode.INVOKEINTERFACE);\r
+\r
+               if (opcode == VMOpcode.INVOKEINTERFACE) {\r
+                       short callArgCount = (short) (initialStackDepth - stackDepth);\r
+                       myCode.addInstrU2U1U1(opcode, cpi, callArgCount, (short) 0);\r
+               }\r
+               else\r
+                       myCode.addInstrU2(opcode, cpi);\r
+               \r
+               // this is the return type of the method\r
+               int rw = rt.width();\r
+               if (rw != 0)\r
+                       growStack(rw, rt);\r
+               else\r
+               {\r
+                       if (stackDepth == 0)\r
+                               overflowMethodCheck();\r
+               }\r
+               // Check the declared type of the method\r
+               if (SanityManager.DEBUG) {\r
+\r
+                       d_BCValidate.checkMethod(opcode, dt, methodName, debugParameterTypes, rt);\r
+               }\r
+\r
+               return cpi;\r
+       }\r
+\r
+       private Type vmNameDeclaringClass(String declaringClass) {\r
+               if (declaringClass == null)\r
+                       return null;\r
+               return cb.factory.type(declaringClass);\r
+       }\r
+\r
+       public void callSuper() {\r
+\r
+               pushThis();\r
+               callMethod(VMOpcode.INVOKESPECIAL, cb.getSuperClassName(), "<init>", "void", 0);\r
+       }\r
+\r
+       public void pushNewStart(String className) {\r
+\r
+               int cpi = modClass.addClassReference(className);\r
+\r
+               // Use U2, not CPE, since only wide form exists.\r
+               myCode.addInstrU2(VMOpcode.NEW, cpi);\r
+               myCode.addInstr(VMOpcode.DUP);\r
+\r
+               // Grow the stack twice as we are pushing\r
+               // two instances of newly created reference\r
+               Type nt = cb.factory.type(className);\r
+               growStack(1, nt);\r
+               growStack(1, nt);\r
+       }\r
+\r
+       public void pushNewComplete(int numArgs) {\r
+               callMethod(VMOpcode.INVOKESPECIAL, (String) null, "<init>", "void", numArgs);\r
+       }\r
+\r
+       public void upCast(String className) {\r
+               Type uct = cb.factory.type(className);\r
+\r
+               stackTypes[stackTypeOffset - 1] = uct;\r
+               //popStack();\r
+               //growStack(1, uct);\r
+       }\r
+\r
+       public void cast(String className) {\r
+               \r
+               // Perform a simple optimization to not\r
+               // insert a checkcast when the classname\r
+               // of the cast exactly matches the type name\r
+               // currently on the stack.\r
+               // This can reduce the amount of generated code.\r
+               // This compiler/class generator does not load\r
+               // classes to check relationships or any other\r
+               // information. Thus other optimizations where a cast\r
+               // is not required are not implemented.\r
+               Type tbc = stackTypes[stackTypeOffset - 1];\r
+               \r
+               short sourceType = tbc.vmType();\r
+               \r
+               if (sourceType == BCExpr.vm_reference)\r
+               {\r
+                       // Simple optimize step\r
+                       if (className.equals(tbc.javaName()))\r
+                       {\r
+                               // do nothing, exact matching type\r
+                               return;\r
+                       }\r
+               }\r
+               \r
+               Type ct = cb.factory.type(className);\r
+               popStack();\r
+               \r
+               short targetType = ct.vmType();\r
+\r
+               if (SanityManager.DEBUG) {\r
+\r
+                       if (!((sourceType == BCExpr.vm_reference &&\r
+                               targetType == BCExpr.vm_reference) ||\r
+                               (sourceType != BCExpr.vm_reference &&\r
+                               targetType != BCExpr.vm_reference))) {\r
+                               SanityManager.THROWASSERT("Both or neither must be object types " + ct.javaName() + " " + tbc.javaName());\r
+                       }\r
+               }\r
+\r
+               // if it is an object type, do a checkcast on it.\r
+               if (sourceType == BCExpr.vm_reference) {\r
+\r
+                       int cpi = modClass.addClassReference(ct.vmNameSimple);\r
+                       myCode.addInstrU2(VMOpcode.CHECKCAST, cpi);\r
+               }\r
+               // otherwise, try to convert it.\r
+               else {\r
+                       short opcode = VMOpcode.NOP;\r
+\r
+                       // we use the conversionInfo array\r
+                       // to determine how to convert; if\r
+                       // the result type of the conversion\r
+                       // is not our target type, we are not done\r
+                       // yet.  Make sure there are no\r
+                       // infinite loop possibilities in the\r
+                       // conversionInfo array!\r
+                       while (sourceType!=targetType && opcode!=VMOpcode.BAD) {\r
+                               short[] currentConversion = \r
+                                       CodeChunk.CAST_CONVERSION_INFO[sourceType][targetType];\r
+                               sourceType = currentConversion[1];\r
+                               opcode = currentConversion[0];\r
+                               if (opcode != VMOpcode.NOP) {\r
+                                       myCode.addInstr(opcode);\r
+                               }\r
+                       }\r
+                       if (SanityManager.DEBUG) {\r
+                               SanityManager.ASSERT(opcode != VMOpcode.BAD,\r
+                                       "BAD VMOpcode not expected in cast");\r
+                       }\r
+               }\r
+               growStack(ct);\r
+       }\r
+\r
+       public void isInstanceOf(String className) {\r
+               int cpi = modClass.addClassReference(className);\r
+               myCode.addInstrU2(VMOpcode.INSTANCEOF, cpi);\r
+               popStack();\r
+               growStack(1, Type.BOOLEAN);\r
+       }\r
+\r
+       public void pushNull(String type) {\r
+               myCode.addInstr(VMOpcode.ACONST_NULL);\r
+               growStack(1, cb.factory.type(type));\r
+       }\r
+\r
+\r
+       public void getField(LocalField field) {\r
+\r
+               BCLocalField lf = (BCLocalField) field;\r
+               Type lt = lf.type;\r
+\r
+               pushThis();\r
+               myCode.addInstrU2(VMOpcode.GETFIELD, lf.cpi);\r
+\r
+               popStack();\r
+               growStack(lt);\r
+\r
+       }\r
+\r
+       public void getField(String declaringClass, String fieldName, String fieldType) {\r
+               Type dt = popStack();\r
+\r
+               Type dtu = vmNameDeclaringClass(declaringClass);\r
+               if (dtu != null)\r
+                       dt = dtu;\r
+\r
+               getField(VMOpcode.GETFIELD, dt.vmNameSimple, fieldName, fieldType);\r
+       }\r
+       /**\r
+               Push the contents of the described static field onto the stack.         \r
+       */\r
+       public void getStaticField(String declaringClass, String fieldName, String fieldType) {\r
+               getField(VMOpcode.GETSTATIC, declaringClass, fieldName, fieldType);\r
+       }\r
+\r
+       private void getField(short opcode, String declaringClass, String fieldName, String fieldType) { \r
+\r
+               Type ft = cb.factory.type(fieldType);\r
+               int cpi = modClass.addFieldReference(vmNameDeclaringClass(declaringClass).vmNameSimple, fieldName, ft.vmName());\r
+               myCode.addInstrU2(opcode, cpi);\r
+\r
+               growStack(ft);\r
+       }\r
+       \r
+       /**\r
+        * Set the field but don't duplicate its value so\r
+        * nothing is left on the stack after this call.\r
+        */\r
+       public void setField(LocalField field) {\r
+               BCLocalField lf = (BCLocalField) field;\r
+               Type lt = lf.type;\r
+\r
+               putField(lf.type, lf.cpi, false);\r
+\r
+               if (stackDepth == 0)\r
+                       overflowMethodCheck();\r
+       }\r
+\r
+       /**\r
+               Upon entry the top word(s) on the stack is\r
+               the value to be put into the field. Ie.\r
+               we have\r
+               <PRE>\r
+               word\r
+               </PRE>\r
+\r
+               Before the call we need \r
+               <PRE>\r
+               word\r
+               this\r
+               word\r
+               </PRE>\r
+               word2,word1 -> word2, word1, word2\r
+\r
+               So that we are left with word after the put.\r
+\r
+       */\r
+       public void putField(LocalField field) {\r
+               BCLocalField lf = (BCLocalField) field;\r
+               Type lt = lf.type;\r
+\r
+               putField(lf.type, lf.cpi, true);\r
+       }\r
+\r
+       /**\r
+               Pop the top stack value and store it in the instance field of this class.\r
+       */\r
+       public void putField(String fieldName, String fieldType) {\r
+\r
+               Type ft = cb.factory.type(fieldType);\r
+               int cpi = modClass.addFieldReference(cb.classType.vmNameSimple, fieldName, ft.vmName());\r
+\r
+               putField(ft, cpi, true);\r
+       }\r
+\r
+       private void putField(Type fieldType, int cpi, boolean dup) {\r
+\r
+               // now have ...,value\r
+               if (dup)\r
+               {\r
+                       myCode.addInstr(fieldType.width() == 2  ? VMOpcode.DUP2 : VMOpcode.DUP);\r
+                       growStack(fieldType);\r
+               }\r
+               // now have\r
+               // dup true:  ...,value,value\r
+               // dup false: ...,value,\r
+\r
+               pushThis();\r
+               // now have\r
+               // dup true:  ...,value,value,this\r
+               // dup false: ...,value,this\r
+\r
+               swap();\r
+               // now have\r
+               // dup true:  ...,value,this,value\r
+               // dup false: ...,this,value\r
+\r
+               myCode.addInstrU2(VMOpcode.PUTFIELD, cpi);\r
+               popStack(); // the value\r
+               popStack(); // this\r
+\r
+               // now have\r
+               // dup true:  ...,value\r
+               // dup false: ...\r
+       }\r
+       /**\r
+               Pop the top stack value and store it in the field.\r
+               This call requires the instance to be pushed by the caller.\r
+       */\r
+       public void putField(String declaringClass, String fieldName, String fieldType) {\r
+               Type vt = popStack();\r
+               Type dt = popStack();\r
+\r
+               if (SanityManager.DEBUG) {\r
+                       if (dt.width() != 1)\r
+                               SanityManager.THROWASSERT("reference expected for field access - is " + dt.javaName());\r
+               }\r
+\r
+               // have objectref,value\r
+               // need value,objectref,value\r
+\r
+               myCode.addInstr(vt.width() == 2  ? VMOpcode.DUP2_X1 : VMOpcode.DUP_X1);\r
+               growStack(vt);\r
+               growStack(dt);\r
+               growStack(vt);\r
+\r
+               Type dtu = vmNameDeclaringClass(declaringClass);\r
+               if (dtu != null)\r
+                       dt = dtu;\r
+\r
+               Type ft = cb.factory.type(fieldType);\r
+               int cpi = modClass.addFieldReference(dt.vmNameSimple, fieldName, ft.vmName());\r
+               myCode.addInstrU2(VMOpcode.PUTFIELD, cpi);\r
+\r
+               popStack(); // value\r
+               popStack(); // reference\r
+       }\r
+\r
+       public void conditionalIfNull() {\r
+\r
+               conditionalIf(VMOpcode.IFNONNULL);\r
+       }\r
+\r
+       public void conditionalIf() {\r
+               conditionalIf(VMOpcode.IFEQ);\r
+       }\r
+\r
+       private Conditional condition;\r
+\r
+       private void conditionalIf(short opcode) {\r
+               popStack();\r
+               \r
+               // Save the stack upon entry to the 'then' block of the\r
+               // 'if' so that we can set up the 'else' block with the\r
+               // correct stack on entry.\r
+\r
+               condition = new Conditional(condition, myCode, opcode, copyStack());\r
+       }\r
+\r
+       public void startElseCode() {\r
+               \r
+               // start the else code\r
+               Type[] entryStack = condition.startElse(this, myCode, copyStack());\r
+               \r
+               for (int i = stackDepth = 0; i  < entryStack.length; i++)\r
+               {\r
+                       stackDepth += (stackTypes[i] = entryStack[i]).width();\r
+               }\r
+               this.stackTypeOffset = entryStack.length;\r
+\r
+       }\r
+       public void completeConditional() {\r
+               condition = condition.end(this, myCode, stackTypes, stackTypeOffset);\r
+       }\r
+       \r
+       public void pop() {\r
+               if (SanityManager.DEBUG) {\r
+                       if (stackDepth == 0)\r
+                               SanityManager.THROWASSERT("pop when stack is empty!");\r
+               }\r
+               Type toPop = popStack();\r
+\r
+               myCode.addInstr(toPop.width() == 2  ? VMOpcode.POP2 : VMOpcode.POP);\r
+               \r
+               if (stackDepth == 0)\r
+                       overflowMethodCheck();\r
+       }       \r
+\r
+       public void endStatement() {\r
+               if (stackDepth != 0) {\r
+                       pop();\r
+               }\r
+\r
+               //if (SanityManager.DEBUG) {\r
+               //      if (stackDepth != 0)\r
+               //              SanityManager.THROWASSERT("items left on stack " + stackDepth);\r
+       //      }\r
+       }\r
+\r
+       /**\r
+       */\r
+       public void getArrayElement(int element) {\r
+\r
+               push(element);\r
+               popStack(); // int just pushed will be popped by array access\r
+\r
+               Type arrayType = popStack();\r
+\r
+               String arrayJava = arrayType.javaName();\r
+               String componentString = arrayJava.substring(0,arrayJava.length()-2);\r
+\r
+               Type componentType = cb.factory.type(componentString);\r
+\r
+               short typ = componentType.vmType();\r
+\r
+               // boolean has a type id of integer, here it needs to be byte.\r
+               if ((typ == BCExpr.vm_int) && (componentType.vmName().equals("Z")))\r
+                       typ = BCExpr.vm_byte;\r
+               myCode.addInstr(CodeChunk.ARRAY_ACCESS[typ]);\r
+\r
+               growStack(componentType);\r
+\r
+       }\r
+       // come in with ref, value\r
+\r
+       public void setArrayElement(int element) {\r
+\r
+               // ref, value\r
+\r
+               push(element);\r
+\r
+               // ref, value, index\r
+               swap();\r
+               \r
+               Type componentType = popStack(); // value\r
+               popStack(); // int just pushed will be popped by array access\r
+               \r
+               popStack(); // array ref.\r
+\r
+               short typ = componentType.vmType();\r
+\r
+               // boolean has a type id of integer, here it needs to be byte.\r
+               if ((typ == BCExpr.vm_int) && (componentType.vmName().equals("Z")))\r
+                       typ = BCExpr.vm_byte;\r
+\r
+               myCode.addInstr(CodeChunk.ARRAY_STORE[typ]);\r
+       }\r
+       /**\r
+               this array maps the BCExpr vm_* constants 0..6 to\r
+               the expected VM type constants for the newarray instruction.\r
+               <p>\r
+               Because boolean was mapped to integer for general instructions,\r
+               it will have to be specially matched and mapped to its value\r
+               directly (4).\r
+        */\r
+       private static final byte newArrayElementTypeMap[] = { 8, 9, 10, 11, 6, 7, 5 };\r
+       static final byte T_BOOLEAN = 4;\r
+       /**\r
+               Create an array instance\r
+\r
+               Stack ... =>\r
+                     ...,arrayref\r
+       */\r
+       public void pushNewArray(String className, int size) {\r
+\r
+               push(size);\r
+               popStack(); // int just pushed will be popped by array creation\r
+\r
+               Type elementType = cb.factory.type(className);\r
+\r
+               // determine the instruction to use based on the element type\r
+               if (elementType.vmType() == BCExpr.vm_reference) {\r
+\r
+                       // For an array of Java class/interface elements, generate:\r
+                       // ANEWARRAY #cpei ; where cpei is a constant pool index for the class\r
+\r
+                       int cpi = modClass.addClassReference(elementType.javaName());\r
+                       // Use U2, not CPE, since only wide form exists.\r
+                       myCode.addInstrU2(VMOpcode.ANEWARRAY, cpi);\r
+               } else {\r
+                       byte atype;\r
+\r
+                       // get the argument for the array type\r
+                       // if the element type is boolean, we can't use the map\r
+                       // because the type id will say integer.\r
+                       // but we can use vm_int test to weed out some tests\r
+                       if (elementType.vmType() == BCExpr.vm_int &&\r
+                           VMDescriptor.C_BOOLEAN == elementType.vmName().charAt(0))\r
+                               atype = T_BOOLEAN;\r
+                       else\r
+                               atype = newArrayElementTypeMap[elementType.vmType()];\r
+\r
+                       // For an array of Java builtin type elements, generate:\r
+                       // NEWARRAY #atype ; where atype is a constant for the builtin type\r
+\r
+                       myCode.addInstrU1(VMOpcode.NEWARRAY, atype);\r
+               }\r
+\r
+               // an array reference is an object, hence width of 1\r
+               growStack(1, cb.factory.type(className.concat("[]")));\r
+       }\r
+    \r
+    /**\r
+     * Write a instruction that uses a constant pool entry\r
+     * as an operand, add a limit exceeded message if\r
+     * the number of constant pool entries has exceeded\r
+     * the limit.\r
+     */\r
+    private void addInstrCPE(short opcode, int cpe)\r
+    {\r
+        if (cpe >= VMOpcode.MAX_CONSTANT_POOL_ENTRIES)\r
+            cb.addLimitExceeded(this, "constant_pool_count",\r
+                    VMOpcode.MAX_CONSTANT_POOL_ENTRIES, cpe);\r
+        \r
+        myCode.addInstrCPE(opcode, cpe);\r
+    }\r
+\r
+       /**\r
+               Tell if statement number in this method builder hits limit.  This\r
+               method builder keeps a counter of how many statements are added to it.\r
+               Caller should call this function every time it tries to add a statement\r
+               to this method builder (counter is increased by 1), then the function\r
+               returns whether the accumulated statement number hits a limit.\r
+               The reason of doing this is that Java compiler has a limit of 64K code\r
+               size for each method.  We might hit this limit if an extremely long\r
+               insert statement is issued, for example (see beetle 4293).  Counting\r
+               statement number is an approximation without too much overhead.\r
+       */\r
+       public boolean statementNumHitLimit(int noStatementsAdded)\r
+       {\r
+               if (statementNum > 2048)    // 2K limit\r
+               {\r
+                       return true;\r
+               }\r
+               else\r
+               {\r
+                       statementNum = statementNum + noStatementsAdded;\r
+                       return false;\r
+               }\r
+       }\r
+       \r
+       /**\r
+        * Check to see if the current method byte code is nearing the\r
+        * limit of 65535. If it is start overflowing to a new method.\r
+        * <P>\r
+        * Overflow is handled for a method named e23 as:\r
+        * <CODE>\r
+        public Object e23()\r
+        {\r
+          ... existing code\r
+          // split point\r
+          return e23_0();\r
+        }\r
+        private Object e23_0()\r
+        {\r
+           ... first set overflowed code\r
+           // split point\r
+           return e23_1(); \r
+        }\r
+        private Object e23_1()\r
+        {\r
+           ... second set overflowed code\r
+           // method complete\r
+           return result; \r
+        }\r
+                </CODE>\r
+        <P>\r
+        \r
+        These overflow methods are hidden from the code using this MethodBuilder,\r
+        it continues to think that it is building a single method with the\r
+        original name.\r
+\r
+\r
+        * <BR> Restrictions:\r
+        * <UL>\r
+        * <LI> Only handles methods with no arguments\r
+        * <LI> Stack depth must be zero\r
+        * </UL>\r
+        * \r
+        *\r
+        */\r
+       private void overflowMethodCheck()\r
+       {\r
+               if (handlingOverflow)\r
+                       return;\r
+               \r
+               // don't sub method in the middle of a conditional\r
+               if (condition != null)\r
+                       return;\r
+               \r
+               int currentCodeSize = myCode.getPC();\r
+               \r
+               // Overflow at >= 55,000 bytes which is someway\r
+               // below the limit of 65,535. Ideally overflow\r
+               // would occur at 65535 minus the few bytes needed\r
+               // to call the sub-method, but the issue is at this level\r
+               // we don't know frequently we are called given the restriction\r
+               // of only being called when the stack depth is zero.\r
+               // Thus split earlier to try ensure most cases are caught.\r
+               // Only downside is that we may split into N methods when N-1 would suffice.\r
+               if (currentCodeSize < 55000)\r
+                       return;\r
+                               \r
+               // only handle no-arg methods at the moment.\r
+               if (parameters != null)\r
+               {\r
+                       if (parameters.length != 0)\r
+                               return;\r
+               }\r
+                       \r
+               BCMethod subMethod = getNewSubMethod(myReturnType, false);\r
+                               \r
+               // stop any recursion\r
+               handlingOverflow = true;\r
+               \r
+               // in this method make a call to the sub method we will\r
+               // be transferring control to.\r
+        callSubMethod(subMethod);\r
+       \r
+               // and return its value, works just as well for a void method!\r
+               this.methodReturn();\r
+               this.complete();\r
+               \r
+               handlingOverflow = false;\r
+               \r
+               // now the tricky bit, make this object take over the\r
+               // code etc. from the sub method. This is done so\r
+               // that any code that has a reference to this MethodBuilder\r
+               // will continue to work. They will be writing code into the\r
+               // new sub method.\r
+               \r
+               this.myEntry = subMethod.myEntry;\r
+               this.myCode = subMethod.myCode;\r
+               this.currentVarNum = subMethod.currentVarNum;\r
+               this.statementNum = subMethod.statementNum;\r
+               \r
+               // copy stack info\r
+               this.stackTypes = subMethod.stackTypes;\r
+               this.stackTypeOffset = subMethod.stackTypeOffset;\r
+               this.maxStack = subMethod.maxStack;\r
+               this.stackDepth = subMethod.stackDepth;\r
+       }\r
+       \r
+    /**\r
+     * Create a sub-method from this method to allow the code builder to split a\r
+     * single logical method into multiple methods to avoid the 64k per-method\r
+     * code size limit. The sub method with inherit the thrown exceptions of\r
+     * this method.\r
+     * \r
+     * @param returnType\r
+     *            Return type of the new method\r
+     * @param withParameters\r
+     *            True to define the method with matching parameters false to\r
+     *            define it with no parameters.\r
+     * @return A valid empty sub method.\r
+     */\r
+    final BCMethod getNewSubMethod(String returnType, boolean withParameters) {\r
+        int modifiers = myEntry.getModifier();\r
+\r
+        // the sub-method can be private to ensure that no-one\r
+        // can call it accidentally from outside the class.\r
+        modifiers &= ~(Modifier.PROTECTED | Modifier.PUBLIC);\r
+        modifiers |= Modifier.PRIVATE;\r
+\r
+        String subMethodName = myName + "_s"\r
+                + Integer.toString(subMethodCount++);\r
+        BCMethod subMethod = (BCMethod) cb.newMethodBuilder(modifiers,\r
+                returnType, subMethodName, withParameters ? parameterTypes\r
+                        : null);\r
+        subMethod.thrownExceptions = this.thrownExceptions;\r
+        \r
+        return subMethod;\r
+    }\r
+\r
+    /**\r
+     * Call a sub-method created by getNewSubMethod handling parameters\r
+     * correctly.\r
+     */\r
+    final void callSubMethod(BCMethod subMethod) {\r
+        // in this method make a call to the sub method we will\r
+        // be transferring control to.\r
+        short op;\r
+        if ((myEntry.getModifier() & Modifier.STATIC) == 0) {\r
+            op = VMOpcode.INVOKEVIRTUAL;\r
+            this.pushThis();\r
+        } else {\r
+            op = VMOpcode.INVOKESTATIC;\r
+        }\r
+\r
+        int parameterCount = subMethod.parameters == null ? 0\r
+                : subMethod.parameters.length;\r
+\r
+        // push my parameter values for the call.\r
+        for (int pi = 0; pi < parameterCount; pi++)\r
+            this.getParameter(pi);\r
+\r
+        this.callMethod(op, modClass.getName(), subMethod.getName(),\r
+                subMethod.myReturnType, parameterCount);\r
+    }\r
+}\r
+\r