Adding JMCR-Stable version
[Benchmarks_CSolver.git] / JMCR-Stable / real-world application / MyDerby-10.3 / java / engine / org / apache / derby / impl / services / bytecode / CodeChunk.java
diff --git a/JMCR-Stable/real-world application/MyDerby-10.3/java/engine/org/apache/derby/impl/services/bytecode/CodeChunk.java b/JMCR-Stable/real-world application/MyDerby-10.3/java/engine/org/apache/derby/impl/services/bytecode/CodeChunk.java
new file mode 100644 (file)
index 0000000..9249dcc
--- /dev/null
@@ -0,0 +1,2225 @@
+/*\r
+\r
+   Derby - Class org.apache.derby.impl.services.bytecode.CodeChunk\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.classfile.CONSTANT_Index_info;\r
+import org.apache.derby.iapi.services.classfile.CONSTANT_Utf8_info;\r
+import org.apache.derby.iapi.services.classfile.ClassFormatOutput;\r
+import org.apache.derby.iapi.services.classfile.ClassHolder;\r
+import org.apache.derby.iapi.services.classfile.ClassMember;\r
+import org.apache.derby.iapi.services.classfile.VMDescriptor;\r
+\r
+import org.apache.derby.iapi.services.sanity.SanityManager;\r
+import org.apache.derby.iapi.services.classfile.VMOpcode;\r
+import org.apache.derby.iapi.services.io.ArrayOutputStream;\r
+\r
+import java.io.IOException;\r
+import java.lang.reflect.Modifier;\r
+import java.util.Arrays;\r
+\r
+/**\r
+ * This class represents a chunk of code in a CodeAttribute.\r
+ * Typically, a CodeAttribute represents the code in a method.\r
+ * If there is a try/catch block, each catch block will get its\r
+ * own code chunk.  This allows the catch blocks to all be put at\r
+ * the end of the generated code for a method, which eliminates\r
+ * the need to generate a jump around each catch block, which\r
+ * would be a forward reference.\r
+ */\r
+final class CodeChunk {\r
+       \r
+       /**\r
+        * Starting point of the byte code stream in the underlying stream/array.\r
+        */\r
+       private static final int CODE_OFFSET = 8;\r
+               \r
+       // The use of ILOAD for the non-integer types is correct.\r
+       // We have to assume that the appropriate checks/conversions\r
+       // are defined on math operation results to ensure that\r
+       // the type is preserved when/as needed.\r
+       static final short[] LOAD_VARIABLE = {\r
+               VMOpcode.ILOAD, /* vm_byte */\r
+               VMOpcode.ILOAD, /* vm_short */\r
+               VMOpcode.ILOAD, /* vm_int */\r
+               VMOpcode.LLOAD, /* vm_long */\r
+               VMOpcode.FLOAD, /* vm_float */\r
+               VMOpcode.DLOAD, /* vm_double */\r
+               VMOpcode.ILOAD, /* vm_char */\r
+               VMOpcode.ALOAD  /* vm_reference */\r
+       };\r
+\r
+       static final short[] LOAD_VARIABLE_FAST = {\r
+               VMOpcode.ILOAD_0,       /* vm_byte */\r
+               VMOpcode.ILOAD_0,       /* vm_short */\r
+               VMOpcode.ILOAD_0,       /* vm_int */\r
+               VMOpcode.LLOAD_0,       /* vm_long */\r
+               VMOpcode.FLOAD_0,       /* vm_float */\r
+               VMOpcode.DLOAD_0,       /* vm_double */\r
+               VMOpcode.ILOAD_0,       /* vm_char */\r
+               VMOpcode.ALOAD_0        /* vm_reference */\r
+       };\r
+\r
+       // The ISTOREs for non-int types are how things work.\r
+       // It assumes that the appropriate casts are done\r
+       // on operations on non-ints to ensure that the values\r
+       // remain in the valid ranges.\r
+       static final short[] STORE_VARIABLE = {\r
+               VMOpcode.ISTORE,        /* vm_byte */\r
+               VMOpcode.ISTORE,        /* vm_short */\r
+               VMOpcode.ISTORE,        /* vm_int */\r
+               VMOpcode.LSTORE,        /* vm_long */\r
+               VMOpcode.FSTORE,        /* vm_float */\r
+               VMOpcode.DSTORE,        /* vm_double */\r
+               VMOpcode.ISTORE,        /* vm_char */\r
+               VMOpcode.ASTORE /* vm_reference */\r
+       };\r
+\r
+       static final short[] STORE_VARIABLE_FAST = {\r
+               VMOpcode.ISTORE_0,      /* vm_byte */\r
+               VMOpcode.ISTORE_0,      /* vm_short */\r
+               VMOpcode.ISTORE_0,      /* vm_int */\r
+               VMOpcode.LSTORE_0,      /* vm_long */\r
+               VMOpcode.FSTORE_0,      /* vm_float */\r
+               VMOpcode.DSTORE_0,      /* vm_double */\r
+               VMOpcode.ISTORE_0,      /* vm_char */\r
+               VMOpcode.ASTORE_0       /* vm_reference */\r
+       };\r
+\r
+       static final short ARRAY_ACCESS[] = {\r
+               VMOpcode.BALOAD,        /* vm_byte */\r
+               VMOpcode.SALOAD,        /* vm_short */\r
+               VMOpcode.IALOAD,        /* vm_int */\r
+               VMOpcode.LALOAD,        /* vm_long */\r
+               VMOpcode.FALOAD,        /* vm_float */\r
+               VMOpcode.DALOAD,        /* vm_double */\r
+               VMOpcode.CALOAD,        /* vm_char */\r
+               VMOpcode.AALOAD /* vm_reference */\r
+       };\r
+       static final short ARRAY_STORE[] = {\r
+               VMOpcode.BASTORE,       /* vm_byte */\r
+               VMOpcode.SASTORE,       /* vm_short */\r
+               VMOpcode.IASTORE,       /* vm_int */\r
+               VMOpcode.LASTORE,       /* vm_long */\r
+               VMOpcode.FASTORE,       /* vm_float */\r
+               VMOpcode.DASTORE,       /* vm_double */\r
+               VMOpcode.CASTORE,       /* vm_char */\r
+               VMOpcode.AASTORE        /* vm_reference */\r
+       };      \r
+       static final short[] RETURN_OPCODE = {\r
+               VMOpcode.IRETURN,  /* 0 = byte      */\r
+               VMOpcode.IRETURN,  /* 1 = short     */\r
+               VMOpcode.IRETURN,  /* 2 = int       */\r
+               VMOpcode.LRETURN,  /* 3 = long      */\r
+               VMOpcode.FRETURN,  /* 4 = float     */\r
+               VMOpcode.DRETURN,  /* 5 = double    */\r
+               VMOpcode.IRETURN,  /* 6 = char      */\r
+               VMOpcode.ARETURN   /* 7 = reference */\r
+               };\r
+\r
+       // the first dimension is the current vmTypeId\r
+       // the second dimension is the target vmTypeId\r
+       //\r
+       // the cells of the entry at [current,target] are:\r
+       // 0: operation\r
+       // 1: result type of operation\r
+       // if entry[1] = target, we are done. otherwise,\r
+       // you have to continue with entry[1] as the new current\r
+       // after generating the opcode listed (don't generate if it is NOP).\r
+       // if entry[0] = BAD, we can\r
+       \r
+       static final short CAST_CONVERSION_INFO[][][] = {\r
+               /* current = vm_byte */\r
+               {\r
+               /* target = vm_byte      */ { VMOpcode.NOP, BCExpr.vm_byte },\r
+               /* target = vm_short     */ { VMOpcode.NOP, BCExpr.vm_short },\r
+               /* target = vm_int       */ { VMOpcode.NOP, BCExpr.vm_int },\r
+               /* target = vm_long      */ { VMOpcode.NOP, BCExpr.vm_int },\r
+               /* target = vm_float     */ { VMOpcode.NOP, BCExpr.vm_int },\r
+               /* target = vm_double    */ { VMOpcode.NOP, BCExpr.vm_int },\r
+               /* target = vm_char      */ { VMOpcode.NOP, BCExpr.vm_char }, \r
+               /* target = vm_reference */ { VMOpcode.BAD, BCExpr.vm_reference }\r
+               },\r
+               /* current = vm_short */\r
+               {\r
+               /* target = vm_byte      */ { VMOpcode.NOP, BCExpr.vm_byte },\r
+               /* target = vm_short     */ { VMOpcode.NOP, BCExpr.vm_short },\r
+               /* target = vm_int       */ { VMOpcode.NOP, BCExpr.vm_int },\r
+               /* target = vm_long      */ { VMOpcode.NOP, BCExpr.vm_int },\r
+               /* target = vm_float     */ { VMOpcode.NOP, BCExpr.vm_int },\r
+               /* target = vm_double    */ { VMOpcode.NOP, BCExpr.vm_int },\r
+               /* target = vm_char      */ { VMOpcode.NOP, BCExpr.vm_char }, \r
+               /* target = vm_reference */ { VMOpcode.BAD, BCExpr.vm_reference }\r
+               },\r
+               /* current = vm_int */\r
+               {\r
+               /* target = vm_byte      */ { VMOpcode.I2B, BCExpr.vm_byte },\r
+               /* target = vm_short     */ { VMOpcode.I2S, BCExpr.vm_short },\r
+               /* target = vm_int       */ { VMOpcode.NOP, BCExpr.vm_int },\r
+               /* target = vm_long      */ { VMOpcode.I2L, BCExpr.vm_long },\r
+               /* target = vm_float     */ { VMOpcode.I2F, BCExpr.vm_float },\r
+               /* target = vm_double    */ { VMOpcode.I2D, BCExpr.vm_double },\r
+               /* target = vm_char      */ { VMOpcode.I2B, BCExpr.vm_char }, \r
+               /* target = vm_reference */ { VMOpcode.BAD, BCExpr.vm_reference }\r
+               },\r
+               /* current = vm_long */\r
+               {\r
+               /* target = vm_byte      */ { VMOpcode.L2I, BCExpr.vm_int },\r
+               /* target = vm_short     */ { VMOpcode.L2I, BCExpr.vm_int },\r
+               /* target = vm_int       */ { VMOpcode.L2I, BCExpr.vm_int },\r
+               /* target = vm_long      */ { VMOpcode.NOP, BCExpr.vm_long },\r
+               /* target = vm_float     */ { VMOpcode.L2F, BCExpr.vm_float },\r
+               /* target = vm_double    */ { VMOpcode.L2D, BCExpr.vm_double },\r
+               /* target = vm_char      */ { VMOpcode.L2I, BCExpr.vm_int }, \r
+               /* target = vm_reference */ { VMOpcode.BAD, BCExpr.vm_reference }\r
+               },\r
+               /* current = vm_float */\r
+               {\r
+               /* target = vm_byte      */ { VMOpcode.F2I, BCExpr.vm_int },\r
+               /* target = vm_short     */ { VMOpcode.F2I, BCExpr.vm_int },\r
+               /* target = vm_int       */ { VMOpcode.F2I, BCExpr.vm_int },\r
+               /* target = vm_long      */ { VMOpcode.F2L, BCExpr.vm_long },\r
+               /* target = vm_float     */ { VMOpcode.NOP, BCExpr.vm_float },\r
+               /* target = vm_double    */ { VMOpcode.F2D, BCExpr.vm_double },\r
+               /* target = vm_char      */ { VMOpcode.F2I, BCExpr.vm_int }, \r
+               /* target = vm_reference */ { VMOpcode.BAD, BCExpr.vm_reference }\r
+               },\r
+               /* current = vm_double */\r
+               {\r
+               /* target = vm_byte      */ { VMOpcode.D2I, BCExpr.vm_int },\r
+               /* target = vm_short     */ { VMOpcode.D2I, BCExpr.vm_int },\r
+               /* target = vm_int       */ { VMOpcode.D2I, BCExpr.vm_int },\r
+               /* target = vm_long      */ { VMOpcode.D2L, BCExpr.vm_long },\r
+               /* target = vm_float     */ { VMOpcode.D2F, BCExpr.vm_float },\r
+               /* target = vm_double    */ { VMOpcode.NOP, BCExpr.vm_double },\r
+               /* target = vm_char      */ { VMOpcode.D2I, BCExpr.vm_int }, \r
+               /* target = vm_reference */ { VMOpcode.BAD, BCExpr.vm_reference }\r
+               },\r
+               /* current = vm_char */\r
+               {\r
+               /* target = vm_byte      */ { VMOpcode.NOP, BCExpr.vm_byte },\r
+               /* target = vm_short     */ { VMOpcode.NOP, BCExpr.vm_short },\r
+               /* target = vm_int       */ { VMOpcode.NOP, BCExpr.vm_int },\r
+               /* target = vm_long      */ { VMOpcode.NOP, BCExpr.vm_int },\r
+               /* target = vm_float     */ { VMOpcode.NOP, BCExpr.vm_int },\r
+               /* target = vm_double    */ { VMOpcode.NOP, BCExpr.vm_int },\r
+               /* target = vm_char      */ { VMOpcode.NOP, BCExpr.vm_char },\r
+               /* target = vm_reference */ { VMOpcode.BAD, BCExpr.vm_reference }\r
+               },\r
+               /* current = vm_reference */\r
+               {\r
+               /* target = vm_byte      */ { VMOpcode.BAD, BCExpr.vm_byte },\r
+               /* target = vm_short     */ { VMOpcode.BAD, BCExpr.vm_short },\r
+               /* target = vm_int       */ { VMOpcode.BAD, BCExpr.vm_int },\r
+               /* target = vm_long      */ { VMOpcode.BAD, BCExpr.vm_long },\r
+               /* target = vm_float     */ { VMOpcode.BAD, BCExpr.vm_float },\r
+               /* target = vm_double    */ { VMOpcode.BAD, BCExpr.vm_double },\r
+               /* target = vm_char      */ { VMOpcode.BAD, BCExpr.vm_char },\r
+               /* target = vm_reference */ { VMOpcode.NOP, BCExpr.vm_reference }\r
+               }\r
+       };\r
+       \r
+       /**\r
+        * Constant used by OPCODE_ACTION to represent the\r
+        * common action of push one word, 1 byte\r
+        * for the instruction.\r
+        */\r
+       private static final byte[] push1_1i = {1, 1};\r
+\r
+       /**\r
+        * Constant used by OPCODE_ACTION to represent the\r
+        * common action of push two words, 1 byte\r
+        * for the instruction.\r
+        */\r
+       private static final byte[] push2_1i = {2, 1};  \r
+       /**\r
+        * Constant used by OPCODE_ACTION to the opcode is\r
+        * not yet supported.\r
+        */\r
+       private static final byte[] NS = {0, -1};\r
+       \r
+       \r
+       /**\r
+        * Value for OPCODE_ACTION[opcode][0] to represent\r
+        * the number of words popped or pushed in variable.\r
+        */\r
+       private static final byte VARIABLE_STACK = -128;\r
+       \r
+       /**\r
+        * Array that provides two pieces of information about\r
+        * each VM opcode. Each opcode has a two byte array.\r
+        * <P>\r
+        * The first element in the array [0] is the number of\r
+        * stack words (double/long count as two) pushed by the opcode.\r
+        * Will be negative if the opcode pops values.\r
+        * \r
+        * <P>\r
+        * The second element in the array [1] is the number of bytes\r
+        * in the instruction stream that this opcode's instruction\r
+        * takes up, including the opocode.\r
+        */\r
+       private static final byte[][] OPCODE_ACTION =\r
+       {\r
+       \r
+    /* NOP  0 */           { 0, 1 },\r
+    \r
+    /* ACONST_NULL  1 */  push1_1i,\r
+    /* ICONST_M1  2 */    push1_1i,\r
+    /* ICONST_0  3 */     push1_1i,\r
+    /* ICONST_1  4 */     push1_1i,\r
+    /* ICONST_2  5 */     push1_1i,\r
+    /* ICONST_3  6 */     push1_1i,\r
+    /* ICONST_4  7 */     push1_1i,\r
+    /* ICONST_5  8 */     push1_1i,\r
+    /* LCONST_0  9 */     push2_1i,\r
+    /* LCONST_1  10 */    push2_1i,\r
+    /* FCONST_0  11 */    push1_1i,\r
+    /* FCONST_1  12 */    push1_1i,\r
+    /* FCONST_2  13 */    push1_1i,\r
+    /* DCONST_0  14 */    push2_1i,\r
+    /* DCONST_1  15 */    push2_1i,\r
+    \r
+    /* BIPUSH  16 */     {1, 2},\r
+    /* SIPUSH  17 */     {1, 3},\r
+    /* LDC  18 */        {1, 2},\r
+    /* LDC_W  19 */      {1, 3},\r
+    /* LDC2_W  20 */     {2, 3},\r
+    \r
+    /* ILOAD  21 */     { 1, 2 },\r
+    /* LLOAD  22 */     { 2, 2 },\r
+    /* FLOAD  23 */     { 1, 2 },\r
+    /* DLOAD  24 */     { 2, 2 },\r
+    /* ALOAD  25 */     { 1, 2 },\r
+    /* ILOAD_0  26 */   push1_1i,\r
+    /* ILOAD_1  27 */   push1_1i,\r
+    /* ILOAD_2  28 */   push1_1i,\r
+    /* ILOAD_3  29 */   push1_1i,\r
+    /* LLOAD_0  30 */   push2_1i,\r
+    /* LLOAD_1  31 */   push2_1i,\r
+    /* LLOAD_2  32 */   push2_1i,\r
+    /* LLOAD_3  33 */   push2_1i,\r
+    /* FLOAD_0  34 */   push1_1i,\r
+    /* FLOAD_1  35 */   push1_1i,\r
+    /* FLOAD_2  36 */   push1_1i,\r
+    /* FLOAD_3  37 */   push1_1i,\r
+    /* DLOAD_0  38 */   push2_1i,\r
+    /* DLOAD_1  39 */   push2_1i,\r
+    /* DLOAD_2  40 */   push2_1i,\r
+    /* DLOAD_3  41 */   push2_1i,\r
+    /* ALOAD_0  42 */   push1_1i,\r
+    /* ALOAD_1  43 */   push1_1i,\r
+    /* ALOAD_2  44 */   push1_1i,\r
+    /* ALOAD_3  45 */   push1_1i,\r
+    /* IALOAD  46 */    { -1, 1 },\r
+    /* LALOAD  47 */    { 0, 1 },\r
+    /* FALOAD  48 */    { -1, 1 },\r
+    /* DALOAD  49 */    { 0, 1 },\r
+    /* AALOAD  50 */    { -1, 1 },\r
+    /* BALOAD  51 */    { -1, 1 },\r
+    /* CALOAD  52 */    { -1, 1 },\r
+    \r
+    /* SALOAD  53 */       { -1, 1 },\r
+    /* ISTORE  54 */       { -1, 2 },\r
+    /* LSTORE  55 */       { -2, 2 },\r
+    /* FSTORE  56 */       { -1, 2 },\r
+    /* DSTORE  57 */       { -2, 2 },\r
+    /* ASTORE  58 */       { -1, 2 },\r
+    /* ISTORE_0  59 */     { -1, 1 },\r
+    /* ISTORE_1  60 */     { -1, 1 },\r
+    /* ISTORE_2  61 */     { -1, 1 },\r
+    /* ISTORE_3  62 */     { -1, 1 },\r
+    /* LSTORE_0  63 */     { -2, 1 },\r
+    /* LSTORE_1  64 */     { -2, 1 },\r
+    /* LSTORE_2  65 */     { -2, 1 },\r
+    /* LSTORE_3  66 */     { -2, 1 },\r
+    /* FSTORE_0  67 */     { -1, 1 },\r
+    /* FSTORE_1  68 */     { -1, 1 },\r
+    /* FSTORE_2  69 */     { -1, 1 },\r
+    /* FSTORE_3  70 */     { -1, 1 },\r
+    /* DSTORE_0  71 */     { -2, 1 },\r
+    /* DSTORE_1  72 */     { -2, 1 },\r
+    /* DSTORE_2  73 */     { -2, 1 },\r
+    /* DSTORE_3  74 */     { -2, 1 },\r
+    /* ASTORE_0  75 */     { -1, 1 },\r
+    /* ASTORE_1  76 */     { -1, 1 },\r
+    /* ASTORE_2  77 */     { -1, 1 },\r
+    /* ASTORE_3  78 */     { -1, 1 },\r
+    /* IASTORE  79 */      { -3, 1 },\r
+    /* LASTORE  80 */      { -4, 1 },\r
+    /* FASTORE  81 */      { -3, 1 },\r
+    /* DASTORE  82 */      { -4, 1 },\r
+    /* AASTORE  83 */      { -3, 1 },\r
+    /* BASTORE  84 */      { -3, 1 },\r
+    /* CASTORE  85 */      { -3, 1 },\r
+    /* SASTORE  86 */      { -3, 1 },\r
+    \r
+    /* POP  87 */      { -1, 1 },\r
+    /* POP2  88 */     { -2, 1 },\r
+    /* DUP  89 */      push1_1i,\r
+    /* DUP_X1  90 */   push1_1i,\r
+    /* DUP_X2  91 */   push1_1i,\r
+    /* DUP2  92 */     push2_1i,\r
+    /* DUP2_X1  93 */  push2_1i,\r
+    /* DUP2_X2  94 */  push2_1i,\r
+    /* SWAP  95 */     { 0, 1 },\r
+    \r
+    /* IADD  96 */     NS,\r
+    /* LADD  97 */     NS,\r
+    /* FADD  98 */     { -1, 1 },\r
+    /* DADD  99 */     { -2, 1 },\r
+    /* ISUB  100 */     NS,\r
+    /* LSUB  101 */     NS,\r
+    /* FSUB  102 */     { -1, 1 },\r
+    /* DSUB  103 */     { -2, 1 },\r
+    /* IMUL  104 */     NS,\r
+    /* LMUL  105 */     NS,\r
+    /* FMUL  106 */     { -1, 1 },\r
+    /* DMUL  107 */     { -2, 1 },\r
+    /* IDIV  108 */     NS,\r
+    /* LDIV  109 */     NS,\r
+    /* FDIV  110 */     { -1, 1 },\r
+    /* DDIV  111 */     { -2, 1 },\r
+    /* IREM  112 */     { -1, 1 },\r
+    /* LREM  113 */     { -2, 1 },\r
+    /* FREM  114 */     { -1, 1 },\r
+    /* DREM  115 */     { -2, 1 },\r
+    /* INEG  116 */     { 0, 1 },\r
+    /* LNEG  117 */     { 0, 1 },\r
+    /* FNEG  118 */     { 0, 1 },\r
+    /* DNEG  119 */     { 0, 1 },\r
+    /* ISHL  120 */     { -1, 1 },\r
+    /* LSHL  121 */     NS,\r
+    /* ISHR  122 */     NS,\r
+    /* LSHR  123 */     NS,\r
+    /* IUSHR  124 */     NS,\r
+    /* LUSHR  125 */     NS,\r
+    \r
+    /* IAND  126 */     { -1, 1 },\r
+    /* LAND  127 */     NS,\r
+    /* IOR  128 */      { -1, 1 },\r
+    /* LOR  129 */      NS,\r
+    /* IXOR  130 */     NS,\r
+    /* LXOR  131 */     NS,\r
+    /* IINC  132 */     NS,\r
+    \r
+    /* I2L  133 */     push1_1i,\r
+    /* I2F  134 */     { 0, 1 },\r
+    /* I2D  135 */     push1_1i,\r
+    /* L2I  136 */     { -1, 1 },\r
+    /* L2F  137 */     { -1, 1 },\r
+    /* L2D  138 */     { 0, 1 },\r
+    /* F2I  139 */     { 0, 1 },\r
+    /* F2L  140 */     push2_1i,\r
+    /* F2D  141 */     push1_1i,\r
+    /* D2I  142 */     { -1, 1 },\r
+    /* D2L  143 */     { 0, 1 },\r
+    /* D2F  144 */     { -1, 1 },\r
+    /* I2B  145 */     { 0, 1 },\r
+    /* I2C  146 */     { 0, 1 },\r
+    /* I2S  147 */     { 0, 1 },\r
+    \r
+    /* LCMP  148 */        NS,\r
+    /* FCMPL  149 */       { -1, 1 },\r
+    /* FCMPG  150 */       { -1, 1 },\r
+    /* DCMPL  151 */       { -3, 1 },\r
+    /* DCMPG  152 */       { -3, 1 },\r
+    /* IFEQ  153 */        { -1, VMOpcode.IF_INS_LENGTH },\r
+    /* IFNE  154 */        { -1, VMOpcode.IF_INS_LENGTH },\r
+    /* IFLT  155 */        { -1, VMOpcode.IF_INS_LENGTH },\r
+    /* IFGE  156 */        { -1, VMOpcode.IF_INS_LENGTH },\r
+    /* IFGT  157 */        { -1, VMOpcode.IF_INS_LENGTH },\r
+    /* IFLE  158 */        { -1, VMOpcode.IF_INS_LENGTH },\r
+    /* IF_ICMPEQ  159 */   NS,\r
+    /* IF_ICMPNE  160 */   NS,\r
+    /* IF_ICMPLT  161 */   NS,\r
+    /* IF_ICMPGE  162 */   NS,\r
+    /* IF_ICMPGT  163 */   NS,\r
+    /* IF_ICMPLE  164 */   NS,\r
+    /* IF_ACMPEQ  165 */   NS,\r
+    /* IF_ACMPNE  166 */   NS,\r
+    /* GOTO  167 */        { 0, VMOpcode.GOTO_INS_LENGTH },\r
+    /* JSR  168 */         NS,\r
+    /* RET  169 */         NS,\r
+    /* TABLESWITCH  170 */ NS,\r
+    /* LOOKUPSWITCH  171 */NS,\r
+    \r
+    /* IRETURN  172 */     { -1, 1 }, // strictly speaking all words on the stack are popped.\r
+    /* LRETURN  173 */     { -2, 1 }, // strictly speaking all words on the stack are popped.\r
+    /* FRETURN  174 */     { -1, 1 }, // strictly speaking all words on the stack are popped.\r
+    /* DRETURN  175 */     { -2, 1 }, // strictly speaking all words on the stack are popped.\r
+    /* ARETURN  176 */     { -1, 1 }, // strictly speaking all words on the stack are popped.\r
+    /* RETURN  177 */      { 0, 1 }, // strictly speaking all words on the stack are popped.\r
+\r
+    /* GETSTATIC  178 */           {VARIABLE_STACK, 3 },\r
+    /* PUTSTATIC  179 */           {VARIABLE_STACK, 3 },\r
+    /* GETFIELD  180 */            {VARIABLE_STACK, 3 },\r
+    /* PUTFIELD  181 */            {VARIABLE_STACK, 3 },\r
+    /* INVOKEVIRTUAL  182 */       {VARIABLE_STACK, 3 },\r
+    /* INVOKESPECIAL  183 */       {VARIABLE_STACK, 3 },\r
+    /* INVOKESTATIC  184 */        {VARIABLE_STACK, 3 },\r
+    /* INVOKEINTERFACE  185 */     {VARIABLE_STACK, 5 },\r
+    \r
+    /* XXXUNUSEDXXX  186 */        NS,\r
+\r
+    /* NEW  187 */                 { 1, 3 },\r
+    /* NEWARRAY  188 */            { 0, 2 },\r
+    /* ANEWARRAY  189 */           { 0, 3 },\r
+    /* ARRAYLENGTH  190 */         { 0, 1 },\r
+    /* ATHROW  191 */              NS,\r
+    /* CHECKCAST  192 */           { 0, 3},\r
+    /* INSTANCEOF  193 */          { 0, 3 },\r
+    /* MONITORENTER  194 */        NS,\r
+    /* MONITOREXIT  195 */         NS,\r
+    /* WIDE  196 */                NS,\r
+    /* MULTIANEWARRAY  197 */      NS,\r
+    /* IFNULL  198 */              { -1, VMOpcode.IF_INS_LENGTH },\r
+    /* IFNONNULL  199 */           { -1, VMOpcode.IF_INS_LENGTH },\r
+    /* GOTO_W  200 */              {0, VMOpcode.GOTO_W_INS_LENGTH },\r
+    /* JSR_W  201 */               NS,\r
+    /* BREAKPOINT  202 */          NS,\r
+       \r
+       };\r
+       \r
+    /**\r
+     * Assume an IOException means some limit of the class file\r
+     * format was hit\r
+     * \r
+     */\r
+    private void limitHit(IOException ioe)\r
+    {\r
+        cb.addLimitExceeded(ioe.toString());\r
+    }\r
+       \r
+       \r
+       /**\r
+        * Add an instruction that has no operand.\r
+        * All opcodes are 1 byte large.\r
+        */\r
+       void addInstr(short opcode) {\r
+               try {\r
+               cout.putU1(opcode);\r
+               } catch (IOException ioe) {\r
+            limitHit(ioe);\r
+               }\r
+\r
+               if (SanityManager.DEBUG) {                      \r
+                       if (OPCODE_ACTION[opcode][1] != 1)\r
+                               SanityManager.THROWASSERT("Opcode " + opcode + " incorrect entry in OPCODE_ACTION -" +\r
+                                               " writing 1 byte - set as " + OPCODE_ACTION[opcode][1]);                \r
+               }\r
+       }\r
+\r
+       /**\r
+        * Add an instruction that has a 16 bit operand.\r
+        */\r
+       void addInstrU2(short opcode, int operand) {\r
+        \r
+               try {\r
+               cout.putU1(opcode);\r
+               cout.putU2(operand);\r
+               } catch (IOException ioe) {\r
+            limitHit(ioe);\r
+               }\r
+\r
+               if (SanityManager.DEBUG) {                      \r
+                       if (OPCODE_ACTION[opcode][1] != 3)\r
+                               SanityManager.THROWASSERT("Opcode " + opcode + " incorrect entry in OPCODE_ACTION -" +\r
+                                               " writing 3 bytes - set as " + OPCODE_ACTION[opcode][1]);               \r
+               }\r
+       }\r
+\r
+       /**\r
+        * Add an instruction that has a 32 bit operand.\r
+        */\r
+     void addInstrU4(short opcode, int operand) {\r
+               try {\r
+               cout.putU1(opcode);\r
+               cout.putU4(operand);\r
+               } catch (IOException ioe) {\r
+            limitHit(ioe);\r
+               }\r
+               if (SanityManager.DEBUG) {                      \r
+                       if (OPCODE_ACTION[opcode][1] != 5)\r
+                               SanityManager.THROWASSERT("Opcode " + opcode + " incorrect entry in OPCODE_ACTION -" +\r
+                                               " writing 5 bytes - set as " + OPCODE_ACTION[opcode][1]);               \r
+               }\r
+       }\r
+\r
+     \r
+       /**\r
+        * Add an instruction that has an 8 bit operand.\r
+        */\r
+     void addInstrU1(short opcode, int operand) {\r
+               try {\r
+               cout.putU1(opcode);\r
+               cout.putU1(operand);\r
+               } catch (IOException ioe) {\r
+            limitHit(ioe);\r
+               }\r
+\r
+               // Only debug code from here.\r
+               if (SanityManager.DEBUG) {\r
+                       \r
+                       if (OPCODE_ACTION[opcode][1] != 2)\r
+                               SanityManager.THROWASSERT("Opcode " + opcode + " incorrect entry in OPCODE_ACTION -" +\r
+                                               " writing 2 bytes - set as " + OPCODE_ACTION[opcode][1]);\r
+               \r
+               }\r
+       }\r
+\r
+       /**\r
+        * This takes an instruction that has a narrow\r
+        * and a wide form for CPE access, and\r
+        * generates accordingly the right one.\r
+        * We assume the narrow instruction is what\r
+        * we were given, and that the wide form is\r
+        * the next possible instruction.\r
+        */\r
+       void addInstrCPE(short opcode, int cpeNum) {\r
+               if (cpeNum < 256) {\r
+                       addInstrU1(opcode, cpeNum);\r
+               }\r
+               else {\r
+                       addInstrU2((short) (opcode+1), cpeNum);\r
+               }\r
+       }\r
+\r
+       /**\r
+        * This takes an instruction that can be wrapped in\r
+        * a wide for large variable #s and does so.\r
+        */\r
+       void addInstrWide(short opcode, int varNum) {\r
+               if (varNum < 256) {\r
+                       addInstrU1(opcode, varNum);\r
+               }\r
+               else {\r
+                       addInstr(VMOpcode.WIDE);\r
+                       addInstrU2(opcode, varNum);\r
+               }\r
+       }\r
+\r
+       /**\r
+        * For adding an instruction with 3 operands, a U2 and two U1's.\r
+        * So far, this is used by VMOpcode.INVOKEINTERFACE.\r
+        */\r
+       void addInstrU2U1U1(short opcode, int operand1, short operand2,\r
+               short operand3) {\r
+               try {\r
+               cout.putU1(opcode);\r
+               cout.putU2(operand1);\r
+               cout.putU1(operand2);\r
+               cout.putU1(operand3);\r
+               } catch (IOException ioe) {\r
+            limitHit(ioe);\r
+               }\r
+               if (SanityManager.DEBUG) {                      \r
+                       if (OPCODE_ACTION[opcode][1] != 5)\r
+                               SanityManager.THROWASSERT("Opcode " + opcode + " incorrect entry in OPCODE_ACTION -" +\r
+                                               " writing 5 bytes - set as " + OPCODE_ACTION[opcode][1]);               \r
+               }\r
+       }\r
+\r
+       /** Get the current program counter */\r
+       int getPC() {\r
+               return cout.size() + pcDelta;\r
+       }\r
+       \r
+       /**\r
+        * Return the complete instruction length for the\r
+        * passed in opcode. This will include the space for\r
+        * the opcode and its operand.\r
+        */\r
+       private static int instructionLength(short opcode)\r
+       {\r
+               int instructionLength = OPCODE_ACTION[opcode][1];\r
+               \r
+               if (SanityManager.DEBUG)\r
+               {\r
+                       if (instructionLength < 0)\r
+                               SanityManager.THROWASSERT("Opcode without instruction length " + opcode);\r
+               }\r
+               \r
+               return instructionLength;\r
+       }\r
+       \r
+       /**\r
+        * The delta between cout.size() and the pc.\r
+        * For an initial code chunk this is -8 (CODE_OFFSET)\r
+        * since 8 bytes are written.\r
+        * For a nested CodeChunk return by insertCodeSpace the delta\r
+        * corresponds to the original starting pc.\r
+        * @see #insertCodeSpace\r
+        */\r
+       private final int pcDelta;\r
+    \r
+    /**\r
+     * The class we are generating code for, used to indicate that\r
+     * some limit was hit during code generation.\r
+     */\r
+    final BCClass       cb;\r
+\r
+       CodeChunk(BCClass cb) {\r
+        this.cb = cb;\r
+        cout = new ClassFormatOutput();\r
+               try {\r
+                       cout.putU2(0); // max_stack, placeholder for now\r
+                       cout.putU2(0); // max_locals, placeholder for now\r
+                       cout.putU4(0); // code_length, placeholder 4 now\r
+               } catch (IOException ioe) {\r
+            limitHit(ioe);\r
+               }\r
+               pcDelta = - CodeChunk.CODE_OFFSET;\r
+       }\r
+       \r
+       /**\r
+        * Return a CodeChunk that has limited visibility into\r
+        * this CodeChunk. Used when a caller needs to insert instructions\r
+        * into an existing stream.\r
+        * @param pc\r
+        * @param byteCount\r
+        */\r
+       private CodeChunk(CodeChunk main, int pc, int byteCount)\r
+       {\r
+        this.cb = main.cb;\r
+               ArrayOutputStream aos =\r
+                       new ArrayOutputStream(main.cout.getData());\r
+               \r
+               try {\r
+                       aos.setPosition(CODE_OFFSET + pc);\r
+                       aos.setLimit(byteCount);\r
+               } catch (IOException e) {\r
+            limitHit(e);\r
+               }\r
+               \r
+               cout = new ClassFormatOutput(aos);\r
+               pcDelta = pc;\r
+       }\r
+\r
+       private final ClassFormatOutput cout;\r
+\r
+       /**\r
+        * now that we have codeBytes, fix the lengths fields in it\r
+        * to reflect what was stored.\r
+        * Limits checked here are from these sections of the JVM spec.\r
+        * <UL>\r
+        * <LI> 4.7.3 The Code Attribute\r
+        * <LI> 4.10 Limitations of the Java Virtual Machine \r
+        * </UL>\r
+        */\r
+       private void fixLengths(BCMethod mb, int maxStack, int maxLocals, int codeLength) {\r
+\r
+               byte[] codeBytes = cout.getData();\r
+\r
+               // max_stack is in bytes 0-1\r
+               if (mb != null && maxStack > 65535)\r
+                       cb.addLimitExceeded(mb, "max_stack", 65535, maxStack);\r
+                       \r
+               codeBytes[0] = (byte)(maxStack >> 8 );\r
+               codeBytes[1] = (byte)(maxStack );\r
+\r
+               // max_locals is in bytes 2-3\r
+               if (mb != null && maxLocals > 65535)\r
+                       cb.addLimitExceeded(mb, "max_locals", 65535, maxLocals);\r
+               codeBytes[2] = (byte)(maxLocals >> 8 );\r
+               codeBytes[3] = (byte)(maxLocals );\r
+\r
+               // code_length is in bytes 4-7\r
+               if (mb != null && codeLength > VMOpcode.MAX_CODE_LENGTH)\r
+                       cb.addLimitExceeded(mb, "code_length",\r
+                                       VMOpcode.MAX_CODE_LENGTH, codeLength);\r
+               codeBytes[4] = (byte)(codeLength >> 24 );\r
+               codeBytes[5] = (byte)(codeLength >> 16 );\r
+               codeBytes[6] = (byte)(codeLength >> 8 );\r
+               codeBytes[7] = (byte)(codeLength );                     \r
+       }\r
+\r
+       /**\r
+        * wrap up the entry and stuff it in the class,\r
+        * now that it holds all of the instructions and\r
+        * the exception table.\r
+        */\r
+       void complete(BCMethod mb, ClassHolder ch,\r
+                       ClassMember method, int maxStack, int maxLocals) {\r
+\r
+        int codeLength =  getPC();\r
+\r
+               ClassFormatOutput out = cout;\r
+               \r
+               try {\r
+\r
+                       out.putU2(0); // exception_table_length\r
+\r
+                       if (SanityManager.DEBUG) {\r
+                         if (SanityManager.DEBUG_ON("ClassLineNumbers")) {\r
+                               // Add a single attribute - LineNumberTable\r
+                               // This add fake line numbers that are the pc offset in the method.\r
+                               out.putU2(1); // attributes_count\r
+\r
+                               int cpiUTF = ch.addUtf8("LineNumberTable");\r
+\r
+                               out.putU2(cpiUTF);\r
+                               out.putU4((codeLength * 4) + 2);\r
+                               out.putU2(codeLength);\r
+                               for (int i = 0; i < codeLength; i++) {\r
+                                       out.putU2(i);\r
+                                       out.putU2(i);\r
+                               }\r
+                         } else {\r
+                                 out.putU2(0); // attributes_count\r
+                         }\r
+\r
+                       } else {\r
+                               out.putU2(0); // attributes_count\r
+                               // attributes is empty, a 0-element array.\r
+                       }\r
+               } catch (IOException ioe) {\r
+            limitHit(ioe);\r
+               }\r
+\r
+               fixLengths(mb, maxStack, maxLocals, codeLength);\r
+               method.addAttribute("Code", out);\r
+               \r
+               if (SanityManager.DEBUG)\r
+               {\r
+            // Only validate if the class file format is valid.\r
+            // Ok code length and guaranteed no errors building the class.\r
+            if ((codeLength <= VMOpcode.MAX_CODE_LENGTH)\r
+                && (mb != null && mb.cb.limitMsg == null))\r
+            {              \r
+                               // Validate the alternate way to calculate the\r
+                               // max stack agrees with the dynamic as the code\r
+                               // is built way.\r
+                               int walkedMaxStack = findMaxStack(ch, 0, codeLength);\r
+                               if (walkedMaxStack != maxStack)\r
+                               {\r
+                                       SanityManager.THROWASSERT("MAX STACK MISMATCH!! " +\r
+                                                       maxStack + " <> " + walkedMaxStack);\r
+                               }\r
+                       }\r
+               }\r
+\r
+       }\r
+       /**\r
+        * Return the opcode at the given pc.\r
+        */\r
+       short getOpcode(int pc)\r
+       {\r
+               return (short) (cout.getData()[CODE_OFFSET + pc] & 0xff);\r
+       }\r
+       \r
+       /**\r
+        * Get the unsigned short value for the opcode at the program\r
+        * counter pc.\r
+        */\r
+       private int getU2(int pc)\r
+       {\r
+               byte[] codeBytes = cout.getData();\r
+               \r
+               int u2p = CODE_OFFSET + pc + 1;\r
+                       \r
+               return ((codeBytes[u2p] & 0xff) << 8) | (codeBytes[u2p+1] & 0xff);\r
+       }\r
+\r
+       /**\r
+        * Get the unsigned 32 bit value for the opcode at the program\r
+        * counter pc.\r
+        */\r
+       private int getU4(int pc)\r
+       {\r
+               byte[] codeBytes = cout.getData();\r
+               \r
+               int u4p = CODE_OFFSET + pc + 1;\r
+               \r
+               return (((codeBytes[u4p] & 0xff) << 24) |\r
+                       ((codeBytes[u4p+1] & 0xff) << 16) |\r
+                       ((codeBytes[u4p+2] & 0xff) << 8) |\r
+                       ((codeBytes[u4p+3] & 0xff)));\r
+       }       \r
+       /**\r
+        * Insert room for byteCount bytes after the instruction at pc\r
+        * and prepare to replace the instruction at pc. The instruction\r
+        * at pc is not modified by this call, space is allocated after it.\r
+        * The newly inserted space will be filled with NOP instructions.\r
+        * \r
+        * Returns a CodeChunk positioned at pc and available to write\r
+        * instructions upto (byteCode + length(existing instruction at pc) bytes.\r
+        * \r
+        * This chunk is left correctly positioned at the end of the code\r
+        * stream, ready to accept more code. Its pc will have increased by\r
+        * additionalBytes.\r
+        * \r
+        * It is the responsibility of the caller to patch up any\r
+        * branches or gotos.\r
+        * \r
+        * @param pc\r
+        * @param additionalBytes\r
+        */\r
+       CodeChunk insertCodeSpace(int pc, int additionalBytes)\r
+       {\r
+               short existingOpcode = getOpcode(pc);\r
+\r
+               int lengthOfExistingInstruction\r
+                   = instructionLength(existingOpcode);\r
+                       \r
+               \r
+               if (additionalBytes > 0)\r
+               {\r
+                       // Size of the current code after this pc.\r
+                       int sizeToMove = (getPC() - pc) - lengthOfExistingInstruction;\r
+\r
+                       // Increase the code by the number of bytes to be\r
+                       // inserted. These NOPs will be overwritten by the\r
+                       // moved code by the System.arraycopy below.\r
+                       // It's assumed that the number of inserted bytes\r
+                       // is small, one or two instructions worth, so it\r
+                       // won't be a performance issue.\r
+                       for (int i = 0; i < additionalBytes; i++)\r
+                               addInstr(VMOpcode.NOP);\r
+               \r
+                       // Must get codeBytes here as the array might have re-sized.\r
+                       byte[] codeBytes = cout.getData();\r
+                       \r
+                       int byteOffset = CODE_OFFSET + pc + lengthOfExistingInstruction;\r
+                                       \r
+                       \r
+                       // Shift the existing code stream down\r
+                       System.arraycopy(\r
+                                       codeBytes, byteOffset,\r
+                                       codeBytes, byteOffset + additionalBytes,\r
+                                       sizeToMove);\r
+                       \r
+                       // Place NOPs in the space just freed by the move.\r
+                       // This is not required, it ias assumed the caller\r
+                       // will overwrite all the bytes they requested, but\r
+                       // to be safe fill in with NOPs rather than leaving code\r
+                       // that could break the verifier.\r
+                       Arrays.fill(codeBytes, byteOffset, byteOffset + additionalBytes,\r
+                                       (byte) VMOpcode.NOP);\r
+               }\r
+               \r
+               // The caller must overwrite the original instruction\r
+               // at pc, thus increase the range of the limit stream\r
+               // created to include those bytes.\r
+               additionalBytes += lengthOfExistingInstruction;\r
+               \r
+               // Now the caller needs to fill in the instructions\r
+               // that make up the modified byteCount bytes of bytecode stream.\r
+               // Return a CodeChunk that can be used for this and\r
+               // is limited to only those bytes.\r
+               // The pc of the original code chunk is left unchanged.\r
+               \r
+               return new CodeChunk(this, pc, additionalBytes);\r
+                                               \r
+       }\r
+       \r
+       /*\r
+     * * Methods related to splitting the byte code chunks into sections that\r
+     * fit in the JVM's limits for a single method.\r
+     */\r
+\r
+    /**\r
+     * For a block of byte code starting at program counter pc for codeLength\r
+     * bytes return the maximum stack value, assuming a initial stack depth of\r
+     * zero.\r
+     */\r
+    private int findMaxStack(ClassHolder ch, int pc, int codeLength) {\r
+\r
+        final int endPc = pc + codeLength;\r
+        int stack = 0;\r
+        int maxStack = 0;\r
+\r
+        for (; pc < endPc;) {\r
+\r
+            short opcode = getOpcode(pc);\r
+            \r
\r
+            int stackDelta = stackWordDelta(ch, pc, opcode);\r
+\r
+            stack += stackDelta;\r
+            if (stack > maxStack)\r
+                maxStack = stack;\r
\r
+            int[] cond_pcs = findConditionalPCs(pc, opcode);\r
+            if (cond_pcs != null) {                 \r
+                // an else block exists.\r
+                if (cond_pcs[3] != -1) {\r
+                    int blockMaxStack = findMaxStack(ch, cond_pcs[1],\r
+                            cond_pcs[2]);\r
+                    if ((stack + blockMaxStack) > maxStack)\r
+                        maxStack = stack + blockMaxStack;\r
+\r
+                    pc = cond_pcs[3];\r
+                    continue;\r
+                }\r
+            }\r
+\r
+            pc += instructionLength(opcode);\r
+        }\r
+\r
+        return maxStack;\r
+    }\r
+\r
+    /**\r
+     * Return the number of stack words pushed (positive) or popped (negative)\r
+     * by this instruction.\r
+     */\r
+    private int stackWordDelta(ClassHolder ch, int pc, short opcode) {\r
+        if (SanityManager.DEBUG) {\r
+            // this validates the OPCODE_ACTION entry\r
+            instructionLength(opcode);\r
+        }\r
+\r
+        int stackDelta = OPCODE_ACTION[opcode][0];\r
+        if (stackDelta == VARIABLE_STACK) {\r
+            stackDelta = getVariableStackDelta(ch, pc, opcode);\r
+        }\r
+\r
+        return stackDelta;\r
+    }\r
+\r
+    /**\r
+     * Get the type descriptor in the virtual machine format for the type\r
+     * defined by the constant pool index for the instruction at pc.\r
+     */\r
+    private String getTypeDescriptor(ClassHolder ch, int pc) {\r
+        int cpi = getU2(pc);\r
+\r
+\r
+        // Field reference or method reference\r
+        CONSTANT_Index_info cii = (CONSTANT_Index_info) ch.getEntry(cpi);\r
+\r
+        // NameAndType reference\r
+        int nameAndType = cii.getI2();\r
+        cii = (CONSTANT_Index_info) ch.getEntry(nameAndType);\r
+\r
+        // UTF8 descriptor\r
+        int descriptor = cii.getI2();\r
+        CONSTANT_Utf8_info type = (CONSTANT_Utf8_info) ch.getEntry(descriptor);\r
+\r
+        String vmDescriptor = type.toString();\r
+\r
+        return vmDescriptor;\r
+    }\r
+\r
+    /**\r
+     * Get the word count for a type descriptor in the format of the virual\r
+     * machine. For a method this returns the the word count for the return\r
+     * type.\r
+     */\r
+    private static int getDescriptorWordCount(String vmDescriptor) {\r
\r
+        int width;\r
+        if (VMDescriptor.DOUBLE.equals(vmDescriptor))\r
+            width = 2;\r
+        else if (VMDescriptor.LONG.equals(vmDescriptor))\r
+            width = 2;\r
+        else if (vmDescriptor.charAt(0) == VMDescriptor.C_METHOD) {\r
+            switch (vmDescriptor.charAt(vmDescriptor.length() - 1)) {\r
+            case VMDescriptor.C_DOUBLE:\r
+            case VMDescriptor.C_LONG:\r
+                width = 2;\r
+                break;\r
+            case VMDescriptor.C_VOID:\r
+                width = 0;\r
+                break;\r
+            default:\r
+                width = 1;\r
+                break;\r
+            }\r
+        } else\r
+            width = 1;\r
+\r
+        return width;\r
+    }\r
+\r
+    /**\r
+     * Get the number of words pushed (positive) or popped (negative) by this\r
+     * instruction. The instruction is a get/put field or a method call, thus\r
+     * the size of the words is defined by the field or method being access.\r
+     */\r
+    private int getVariableStackDelta(ClassHolder ch, int pc, int opcode) {\r
+        String vmDescriptor = getTypeDescriptor(ch, pc);\r
+        int width = CodeChunk.getDescriptorWordCount(vmDescriptor);\r
+\r
+        int stackDelta = 0;\r
+        // Stack delta depends on context.\r
+        switch (opcode) {\r
+        case VMOpcode.GETSTATIC:\r
+            stackDelta = width;\r
+            break;\r
+\r
+        case VMOpcode.GETFIELD:\r
+            stackDelta = width - 1; // one for popped object ref\r
+            break;\r
+\r
+        case VMOpcode.PUTSTATIC:\r
+            stackDelta = -width;\r
+            break;\r
+\r
+        case VMOpcode.PUTFIELD:\r
+            stackDelta = -width - 1; // one for pop object ref\r
+            break;\r
+\r
+        case VMOpcode.INVOKEVIRTUAL:\r
+        case VMOpcode.INVOKESPECIAL:\r
+            stackDelta = -1; // for instance reference for method call.\r
+        case VMOpcode.INVOKESTATIC:\r
+            stackDelta += (width - CodeChunk.parameterWordCount(vmDescriptor));\r
+            // System.out.println("invoked non-interface " + stackDelta);\r
+            break;\r
+\r
+        case VMOpcode.INVOKEINTERFACE:\r
+            // third byte contains the number of arguments to be popped\r
+            stackDelta = width - getOpcode(pc + 3);\r
+            // System.out.println("invoked interface " + stackDelta);\r
+            break;\r
+        default:\r
+            System.out.println("WHO IS THIS ");\r
+            break;\r
+\r
+        }\r
+\r
+        return stackDelta;\r
+    }\r
+\r
+    /**\r
+     * Calculate the number of stack words in the arguments pushed for this\r
+     * method descriptor.\r
+     */\r
+    private static int parameterWordCount(String methodDescriptor) {\r
+        int wordCount = 0;\r
+        for (int i = 1;; i++) {\r
+            switch (methodDescriptor.charAt(i)) {\r
+            case VMDescriptor.C_ENDMETHOD:\r
+                return wordCount;\r
+            case VMDescriptor.C_DOUBLE:\r
+            case VMDescriptor.C_LONG:\r
+                wordCount += 2;\r
+                break;\r
+            case VMDescriptor.C_ARRAY:\r
+                // skip while there are array symbols.\r
+                do {\r
+                    i++;\r
+                } while (methodDescriptor.charAt(i) == VMDescriptor.C_ARRAY);\r
+                if (methodDescriptor.charAt(i) != VMDescriptor.C_CLASS) {\r
+                    // an array is a reference, even an array of doubles.\r
+                    wordCount += 1;\r
+                    break;\r
+                }\r
+\r
+            // fall through to skip the Lclassname; after the array.\r
+\r
+            case VMDescriptor.C_CLASS:\r
+                // skip until ;\r
+                do {\r
+                    i++;\r
+                } while (methodDescriptor.charAt(i) != VMDescriptor.C_ENDCLASS);\r
+                wordCount += 1;\r
+                break;\r
+            default:\r
+                wordCount += 1;\r
+                break;\r
+            }\r
+        }\r
+    }\r
+\r
+    /**\r
+     * Find the limits of a conditional block starting at the instruction with\r
+     * the given opcode at the program counter pc.\r
+     * <P>\r
+     * Returns a six element integer array of program counters and lengths.\r
+     * <code. [0] - program counter of the IF opcode (passed in as pc) [1] -\r
+     * program counter of the start of the then block [2] - length of the then\r
+     * block [3] - program counter of the else block, -1 if no else block\r
+     * exists. [4] - length of of the else block, -1 if no else block exists.\r
+     * [5] - program counter of the common end point. </code>\r
+     * \r
+     * Looks for and handles conditionals that are written by the Conditional\r
+     * class.\r
+     * \r
+     * @return Null if the opcode is not the start of a conditional otherwise\r
+     *         the array of values.\r
+     */\r
+    private int[] findConditionalPCs(int pc, short opcode) {\r
+        switch (opcode) {\r
+        default:\r
+            return null;\r
+        case VMOpcode.IFNONNULL:\r
+        case VMOpcode.IFNULL:\r
+        case VMOpcode.IFEQ:\r
+        case VMOpcode.IFNE:\r
+            break;\r
+        }\r
+\r
+        int then_pc;\r
+        int else_pc;\r
+        int if_off = getU2(pc);\r
+\r
+        if ((if_off == 8)\r
+                && (getOpcode(pc + VMOpcode.IF_INS_LENGTH) == VMOpcode.GOTO_W)) {\r
+            // 32 bit branch\r
+            then_pc = pc + VMOpcode.IF_INS_LENGTH + VMOpcode.GOTO_W_INS_LENGTH;\r
+\r
+            // Get else PC from the 32 bit offset within the GOTO_W\r
+            // instruction remembering to add it to the pc of that\r
+            // instruction, not the original IF.\r
+            else_pc = pc + VMOpcode.IF_INS_LENGTH\r
+                    + getU4(pc + VMOpcode.IF_INS_LENGTH);\r
+\r
+        } else {\r
+            then_pc = pc + VMOpcode.IF_INS_LENGTH;\r
+            else_pc = pc + if_off;\r
+        }\r
+\r
+        // Need to look for the goto or goto_w at the\r
+        // end of the then block. There might not be\r
+        // one for the case when there is no else block.\r
+        // In that case the then block will just run into\r
+        // what we currently think the else pc.\r
+\r
+        int end_pc = -1;\r
+        for (int tpc = then_pc; tpc < else_pc;) {\r
+            short opc = getOpcode(tpc);\r
+\r
+            // need to handle conditionals\r
+            int[] innerCond = findConditionalPCs(tpc, opc);\r
+            if (innerCond != null) {\r
+                // skip to the end of this conditional\r
+                tpc = innerCond[5]; // end_pc\r
+                continue;\r
+            }\r
+\r
+            if (opc == VMOpcode.GOTO) {\r
+                // not at the end of the then block\r
+                // so not our goto. Shouldn't see this\r
+                // with the current code due to the\r
+                // skipping of the conditional above.\r
+                // But safe defensive programming.\r
+                if (tpc != (else_pc - VMOpcode.GOTO_INS_LENGTH))\r
+                    continue;\r
+\r
+                end_pc = tpc + getU2(tpc);\r
+                break;\r
+            } else if (opc == VMOpcode.GOTO_W) {\r
+                // not at the end of the then block\r
+                // so not our goto. SHouldn't see this\r
+                // with the current code due to the\r
+                // skipping of the conditional above.\r
+                // But safe defensive programming.\r
+                if (tpc != (else_pc - VMOpcode.GOTO_W_INS_LENGTH))\r
+                    continue;\r
+\r
+                end_pc = tpc + getU4(tpc);\r
+                break;\r
+\r
+            }\r
+            tpc += instructionLength(opc);\r
+        }\r
+\r
+        int else_len;\r
+        int then_len;\r
+        if (end_pc == -1) {\r
+            // no else block;\r
+            end_pc = else_pc;\r
+            else_pc = -1;\r
+\r
+            then_len = end_pc - then_pc;\r
+            else_len = -1;\r
+        } else {\r
+            then_len = else_pc - then_pc;\r
+            else_len = end_pc - else_pc;\r
+        }\r
+\r
+        int[] ret = new int[6];\r
+\r
+        ret[0] = pc;\r
+        ret[1] = then_pc;\r
+        ret[2] = then_len;\r
+        ret[3] = else_pc;\r
+        ret[4] = else_len;\r
+        ret[5] = end_pc;\r
+\r
+        return ret;\r
+    }\r
+    \r
+    /**\r
+     * Attempt to split the current method by pushing a chunk of\r
+     * its code into a sub-method. The starting point of the split\r
+     * (split_pc) must correspond to a stack depth of zero. It is the\r
+     * reponsibility of the caller to ensure this.\r
+     * Split is only made if there exists a chunk of code starting at\r
+     * pc=split_pc, whose stack depth upon termination is zero.\r
+     * The method will try to split a code section greater than\r
+     * optimalMinLength but may split earlier if no such block exists.\r
+     * <P>\r
+     * The method is aimed at splitting methods that contain\r
+     * many independent statements.\r
+     * <P>\r
+     * If a split is possible this method will perform the split and\r
+     * create a void sub method, and move the code into the sub-method\r
+     * and setup this method to call the sub-method before continuing.\r
+     * This method's max stack and current pc will be correctly set\r
+     * as though the method had just been created.\r
+     * \r
+     * @param mb Method for this chunk.\r
+     * @param ch Class definition\r
+     * @param optimalMinLength minimum length required for split\r
+     */\r
+    final int splitZeroStack(BCMethod mb, ClassHolder ch, final int split_pc,\r
+            final int optimalMinLength) {\r
+        \r
+        int splitMinLength = splitMinLength(mb);\r
+        \r
+        int stack = 0;\r
+\r
+        // maximum possible split seen that is less than\r
+        // the minimum.\r
+        int possibleSplitLength = -1;\r
+\r
+        // do not split until at least this point (inclusive)\r
+        // used to ensure no split occurs in the middle of\r
+        // a conditional.\r
+        int outerConditionalEnd_pc = -1;\r
+\r
+        int end_pc = getPC(); // pc will be positioned at the end.\r
+        for (int pc = split_pc; pc < end_pc;) {\r
+\r
+            short opcode = getOpcode(pc);\r
+\r
+            int stackDelta = stackWordDelta(ch, pc, opcode);\r
+\r
+            stack += stackDelta;\r
+\r
+            // Cannot split a conditional but need to calculate\r
+            // the stack depth at the end of the conditional.\r
+            // Each path through the conditional will have the\r
+            // same stack depth.\r
+            int[] cond_pcs = findConditionalPCs(pc, opcode);\r
+            if (cond_pcs != null) {\r
+                // an else block exists, skip the then block.\r
+                if (cond_pcs[3] != -1) {\r
+                    pc = cond_pcs[3];\r
+                    continue;\r
+                }\r
+\r
+                if (SanityManager.DEBUG) {\r
+                    if (outerConditionalEnd_pc != -1) {\r
+                        if (cond_pcs[5] >= outerConditionalEnd_pc)\r
+                            SanityManager.THROWASSERT("NESTED CONDITIONALS!");\r
+                    }\r
+                }\r
+\r
+                if (outerConditionalEnd_pc == -1) {\r
+                    outerConditionalEnd_pc = cond_pcs[5];\r
+                }\r
+            }\r
+\r
+            pc += instructionLength(opcode);\r
+\r
+            // Don't split in the middle of a conditional\r
+            if (outerConditionalEnd_pc != -1) {\r
+                if (pc > outerConditionalEnd_pc) {\r
+                    // passed the outermost conditional\r
+                    outerConditionalEnd_pc = -1;\r
+                }\r
+                continue;\r
+            }\r
+\r
+            if (stack != 0)\r
+                continue;\r
+\r
+            int splitLength = pc - split_pc;\r
+\r
+            if (splitLength < optimalMinLength) {\r
+                // record we do have a possible split.\r
+                possibleSplitLength = splitLength;\r
+                continue;\r
+            }\r
+\r
+            // no point splitting to a method bigger\r
+            // than the VM can handle. Save one for\r
+            // return instruction.\r
+            if (splitLength > BCMethod.CODE_SPLIT_LENGTH - 1) {\r
+                splitLength = -1;\r
+            }\r
+            else if (CodeChunk.isReturn(opcode))\r
+            {\r
+                // Don't handle a return in the middle of\r
+                // an instruction stream. Don't think this\r
+                // is generated, but be safe.           \r
+                splitLength = -1;\r
+            }\r
+            \r
+            // if splitLenth was set to -1 above then there\r
+            // is no possible split at this instruction.\r
+            if (splitLength == -1)\r
+            {\r
+                // no earlier split at all\r
+                if (possibleSplitLength == -1)\r
+                    return -1;\r
\r
+                // Decide if the earlier possible split is\r
+                // worth it.\r
+                if (possibleSplitLength <= splitMinLength)\r
+                    return -1;\r
+\r
+                // OK go with the earlier split\r
+                splitLength = possibleSplitLength;\r
+\r
+            }\r
+\r
+            // Yes, we can split this big method into a smaller method!!\r
+\r
+            BCMethod subMethod = startSubMethod(mb, "void", split_pc,\r
+                    splitLength);\r
+\r
+            return splitCodeIntoSubMethod(mb, ch, subMethod,\r
+                    split_pc, splitLength);\r
+        }\r
+        return -1;\r
+    }\r
+\r
+    /**\r
+     * Start a sub method that we will split the portion of our current code to,\r
+     * starting from start_pc and including codeLength bytes of code.\r
+     * \r
+     * Return a BCMethod obtained from BCMethod.getNewSubMethod with the passed\r
+     * in return type and same parameters as mb if the code block to be moved\r
+     * uses parameters.\r
+     */\r
+    private BCMethod startSubMethod(BCMethod mb, String returnType,\r
+            int split_pc, int blockLength) {\r
+\r
+        boolean needParameters = usesParameters(mb, split_pc, blockLength);\r
+\r
+        return mb.getNewSubMethod(returnType, needParameters);\r
+    }\r
+\r
+    /**\r
+     * Does a section of code use parameters.\r
+     * Any load, exception ALOAD_0 in an instance method, is\r
+     * seen as using parameters, as this complete byte code\r
+     * implementation does not use local variables.\r
+     * \r
+     */\r
+    private boolean usesParameters(BCMethod mb, int pc, int codeLength) {\r
+\r
+        // does the method even have parameters?\r
+        if (mb.parameters == null)\r
+            return false;\r
+\r
+        boolean isStatic = (mb.myEntry.getModifier() & Modifier.STATIC) != 0;\r
+\r
+        int endPc = pc + codeLength;\r
+\r
+        for (; pc < endPc;) {\r
+            short opcode = getOpcode(pc);\r
+            switch (opcode) {\r
+            case VMOpcode.ILOAD_0:\r
+            case VMOpcode.LLOAD_0:\r
+            case VMOpcode.FLOAD_0:\r
+            case VMOpcode.DLOAD_0:\r
+                return true;\r
+\r
+            case VMOpcode.ALOAD_0:\r
+                if (isStatic)\r
+                    return true;\r
+                break;\r
+\r
+            case VMOpcode.ILOAD_1:\r
+            case VMOpcode.LLOAD_1:\r
+            case VMOpcode.FLOAD_1:\r
+            case VMOpcode.DLOAD_1:\r
+            case VMOpcode.ALOAD_1:\r
+                return true;\r
+\r
+            case VMOpcode.ILOAD_2:\r
+            case VMOpcode.LLOAD_2:\r
+            case VMOpcode.FLOAD_2:\r
+            case VMOpcode.DLOAD_2:\r
+            case VMOpcode.ALOAD_2:\r
+                return true;\r
+\r
+            case VMOpcode.ILOAD_3:\r
+            case VMOpcode.LLOAD_3:\r
+            case VMOpcode.FLOAD_3:\r
+            case VMOpcode.DLOAD_3:\r
+            case VMOpcode.ALOAD_3:\r
+                return true;\r
+\r
+            case VMOpcode.ILOAD:\r
+            case VMOpcode.LLOAD:\r
+            case VMOpcode.FLOAD:\r
+            case VMOpcode.DLOAD:\r
+            case VMOpcode.ALOAD:\r
+                return true;\r
+            default:\r
+                break;\r
+\r
+            }\r
+            pc += instructionLength(opcode);\r
+        }\r
+        return false;\r
+    }\r
+    /**\r
+     * Split a block of code from this method into a sub-method\r
+     * and call it.\r
+     * \r
+     * Returns the pc of this method just after the call\r
+     * to the sub-method.\r
+     \r
+     * @param mb My method\r
+     * @param ch My class\r
+     * @param subMethod Sub-method code was pushed into\r
+     * @param split_pc Program counter the split started at\r
+     * @param splitLength Length of code split\r
+     */\r
+    private int splitCodeIntoSubMethod(BCMethod mb, ClassHolder ch,\r
+            BCMethod subMethod, final int split_pc, final int splitLength) {\r
+        CodeChunk subChunk = subMethod.myCode;\r
+\r
+        byte[] codeBytes = cout.getData();\r
+\r
+        // the code to be moved into the sub method\r
+        // as a block. This will correctly increase the\r
+        // program counter.\r
+        try {\r
+            subChunk.cout.write(codeBytes, CODE_OFFSET + split_pc, splitLength);\r
+        } catch (IOException ioe) {\r
+            limitHit(ioe);\r
+        }\r
+\r
+        // Just cause the sub-method to return,\r
+        // fix up its maxStack and then complete it.\r
+        if (subMethod.myReturnType.equals("void"))\r
+            subChunk.addInstr(VMOpcode.RETURN);\r
+        else\r
+           subChunk.addInstr(VMOpcode.ARETURN);\r
+        \r
+        // Finding the max stack requires the class format to\r
+        // still be valid. If we have blown the number of constant\r
+        // pool entries then we can no longer guarantee that indexes\r
+        // into the constant pool in the code stream are valid.\r
+        if (cb.limitMsg != null)\r
+            return -1;\r
+        \r
+        subMethod.maxStack = subChunk.findMaxStack(ch, 0, subChunk.getPC());\r
+        subMethod.complete();\r
+\r
+        return removePushedCode(mb, ch, subMethod, split_pc, splitLength);\r
+    }\r
+\r
+    /**\r
+     * Remove a block of code from this method that was pushed into a sub-method\r
+     * and call the sub-method.\r
+     * \r
+     * Returns the pc of this method just after the call to the sub-method.\r
+     * \r
+     * @param mb\r
+     *            My method\r
+     * @param ch\r
+     *            My class\r
+     * @param subMethod\r
+     *            Sub-method code was pushed into\r
+     * @param split_pc\r
+     *            Program counter the split started at\r
+     * @param splitLength\r
+     *            Length of code split\r
+     */\r
+    private int removePushedCode(BCMethod mb, ClassHolder ch,\r
+            BCMethod subMethod, final int split_pc, final int splitLength) {\r
+        // now need to fix up this method, create\r
+        // a new CodeChunk just to be clearer than\r
+        // trying to modify this chunk directly.\r
+        \r
+        // total length of the code for this method before split\r
+        final int codeLength = getPC();\r
+        \r
+        CodeChunk replaceChunk = new CodeChunk(mb.cb);\r
+        mb.myCode = replaceChunk;\r
+        mb.maxStack = 0;\r
+\r
+        byte[] codeBytes = cout.getData();\r
+        \r
+        // write any existing code before the split point\r
+        // into the replacement chunk.\r
+        if (split_pc != 0) {\r
+            try {\r
+                replaceChunk.cout.write(codeBytes, CODE_OFFSET, split_pc);\r
+            } catch (IOException ioe) {\r
+                limitHit(ioe);\r
+            }\r
+        }\r
+\r
+        // Call the sub method, will write into replaceChunk.\r
+        mb.callSubMethod(subMethod);\r
+\r
+        int postSplit_pc = replaceChunk.getPC();\r
+\r
+        // Write the code remaining in this method into the replacement chunk\r
+\r
+        int remainingCodePC = split_pc + splitLength;\r
+        int remainingCodeLength = codeLength - splitLength - split_pc;\r
+        \r
+       try {\r
+            replaceChunk.cout.write(codeBytes, CODE_OFFSET + remainingCodePC,\r
+                    remainingCodeLength);\r
+        } catch (IOException ioe) {\r
+            limitHit(ioe);\r
+        }\r
+\r
+        // Finding the max stack requires the class format to\r
+        // still be valid. If we have blown the number of constant\r
+        // pool entries then we can no longer guarantee that indexes\r
+        // into the constant pool in the code stream are valid.\r
+        if (cb.limitMsg != null)\r
+            return -1;\r
+        \r
+        mb.maxStack = replaceChunk.findMaxStack(ch, 0, replaceChunk.getPC());\r
+\r
+        return postSplit_pc;\r
+    }\r
+    \r
+    /**\r
+     * Split an expression out of a large method into its own\r
+     * sub-method.\r
+     * <P>\r
+     * Method call expressions are of the form:\r
+     * <UL>\r
+     * <LI> expr.method(args) -- instance method call\r
+     * <LI> method(args) -- static method call\r
+     * </UL>\r
+     * Two special cases of instance method calls will be handled\r
+     * by the first incarnation of splitExpressionOut. \r
+     * three categories:\r
+     * <UL>\r
+     * <LI>this.method(args)\r
+     * <LI>this.getter().method(args)\r
+     * </UL>\r
+     * These calls are choosen as they are easier sub-cases\r
+     * and map to the code generated for SQL statements.\r
+     * Future coders can expand the method to cover more cases.\r
+     * <P>\r
+     * This method will split out such expressions in sub-methods\r
+     * and replace the original code with a call to that submethod.\r
+     * <UL>\r
+     * <LI>this.method(args) ->> this.sub1([parameters])\r
+     * <LI>this.getter().method(args) ->> this.sub1([parameters])\r
+     * </UL>\r
+     * The assumption is of course that the call to the sub-method\r
+     * is much smaller than the code it replaces.\r
+     * <P>\r
+     * Looking at the byte code for such calls they would look like\r
+     * (for an example three argument method):\r
+     * <code>\r
+     * this arg1 arg2 arg3 INVOKE // this.method(args)\r
+     * this INVOKE arg1 arg2 arg3 INVOKE // this.getter().metod(args)\r
+     * </code>\r
+     * The bytecode for the arguments can be arbitary long and\r
+     * consist of expressions, typical Derby code for generated\r
+     * queries is deeply nested method calls.\r
+     * <BR>\r
+     * If none of the arguments requred the parameters passed into\r
+     * the method, then in both cases the replacement bytecode\r
+     * would look like:\r
+     * <code>\r
+     * this.sub1();\r
+     * </code>\r
+     * Parameter handling is just as in the method splitZeroStack().\r
+     * <P>\r
+     * Because the VM is a stack machine the original byte code\r
+     * sequences are self contained. The stack at the start of\r
+     * is sequence is N and at the end (after the method call) will\r
+     * be:\r
+     * <UL>\r
+     * <LI> N - void method\r
+     * <LI> N + 1 - method returning a single word\r
+     * <LI> N + 2 - method returning a double word (java long or double)\r
+     * </UL>\r
+     * This code will handle the N+1 where the word is a reference,\r
+     * the typical case for generated code.\r
+     * <BR>\r
+     * The code is self contained because in general the byte code\r
+     * for the arguments will push and pop values but never drop\r
+     * below the stack value at the start of the byte code sequence.\r
+     * E.g. in the examples the stack before the first arg will be\r
+     * N+1 (the objectref for the method call) and at the end of the\r
+     * byte code for arg1 will be N+2 or N+3 depending on if arg1 is\r
+     * a single or double word argument. During the execution of\r
+     * the byte code the stack may have had many arguments pushed\r
+     * and popped, but will never have dropped below N+1. Thus the\r
+     * code for arg1 is independent of the stack's previous values\r
+     * and is self contained. This self-containment then extends to\r
+     * all the arguements, the method call itself and pushing the\r
+     * objectref for the method call, thus the complete\r
+     * sequence is self-contained.\r
+     * <BR>\r
+     * The self-containment breaks in a few cases, take the simple\r
+     * method call this.method(3), the byte code for this could be:\r
+     * <code>\r
+     * push3 this swap invoke\r
+     * </code>\r
+     * In this case the byte code for arg1 (swap) is not self-contained\r
+     * and relies on earlier stack values.\r
+     * <P>\r
+     * How to identify "self-contained blocks of code".\r
+     * <BR>\r
+     * We walk through the byte code and maintain a history of\r
+     * the program counter that indicates the start of the\r
+     * independent sequence each stack word depends on.\r
+     * Thus for a ALOAD_0 instruction which pushes 'this' the\r
+     * dependent pc is that of the this. If a DUP instruction followed\r
+     * then the top-word is now dependent on the previous word (this)\r
+     * and thus the dependence of it is equal to the dependence of\r
+     * the previous word. This information is kept in earliestIndepPC\r
+     * array as we process the instruction stream.\r
+     * <BR>\r
+     * When a INVOKE instruction is seen for an instance method\r
+     * that returns a single or double word, the dependence of\r
+     * the returned value is the dependence of the word in the\r
+     * stack that is the objectref for the call. This complete\r
+     * sequence from the pc the objectref depended on to the\r
+     * INVOKE instruction is then a self contained sequence\r
+     * and can be split into a sub-method.\r
+\r
+     * <BR>\r
+     * If the block is self-contained then it can be split, following\r
+     * similar logic to splitZeroStack().\r
+     *  \r
+     *  <P>\r
+     *  WORK IN PROGRESS - Incremental development\r
+     *  <BR>\r
+     *  Currently walks the method maintaining the\r
+     *  earliestIndepPC array and identifies potential blocks\r
+     *  to splt, performs splits as required.\r
+     *  Called by BCMethod but commented out in submitted code.\r
+     *  Tested with local changes from calls in BCMethod.\r
+     *  Splits generally work, though largeCodeGen shows\r
+     *  a problem that will be fixed before the code in\r
+     *  enabled for real.\r
+     *  \r
+      */\r
+\r
+    final int splitExpressionOut(final BCMethod mb, final ClassHolder ch,\r
+            final int optimalMinLength,\r
+            final int maxStack)\r
+    {\r
+        // Save the best block we have seen for splitting out.\r
+        int bestSplitPC = -1;\r
+        int bestSplitBlockLength = -1;\r
+        String bestSplitRT = null;  \r
+        \r
+        int splitMinLength = splitMinLength(mb);\r
+        \r
+        // Program counter of the earliest instruction\r
+        // that the word in the current active stack\r
+        // at the given depth depends on.\r
+        //\r
+        // Some examples, N is the stack depth *after*\r
+        // the instruction.\r
+        // E.g. \r
+        // ALOAD_0 - pushes this, is an instruction that\r
+        // pushes an independent value, so the current\r
+        // stack word depends on the pc of current instruction.\r
+        // earliestIndepPC[N] = pc (that pushed the value).\r
+        //\r
+        // DUP - duplicates the top word, so the duplicated\r
+        // top word will depend on the same pc as the word\r
+        // it was duplicated from.\r
+        // I.e. earliestIndepPC[N]\r
+        //            = earliestIndepPC[N-1];\r
+        //\r
+        // instance method call returning single word value.\r
+        // The top word will depend on the same pc as the\r
+        // objectref for the method call, which was at the\r
+        // same depth in this case.\r
+        // earliestIndepPC[N] unchanged\r
+        //\r
+        // at any time earliestIndepPC is only valid\r
+        // from 1 to N where N is the depth of the stack.\r
+       int[] earliestIndepPC = new int[maxStack+1];\r
+       \r
+        int stack = 0;\r
+               \r
+        //TODO: this conditional handling is copied from\r
+        //the splitZeroStack code, need to check to see\r
+        // how it fits with the expression logic.\r
+        // do not split until at least this point (inclusive)\r
+        // used to ensure no split occurs in the middle of\r
+        // a conditional.\r
+        int outerConditionalEnd_pc = -1;  \r
+\r
+        int end_pc = getPC();\r
+        \r
+        for (int pc = 0; pc < end_pc;) {\r
+\r
+            short opcode = getOpcode(pc);\r
+            \r
+            int stackDelta = stackWordDelta(ch, pc, opcode);\r
+            \r
+            stack += stackDelta;\r
+            \r
+            // Cannot split a conditional but need to calculate\r
+            // the stack depth at the end of the conditional.\r
+            // Each path through the conditional will have the\r
+            // same stack depth.\r
+            int[] cond_pcs = findConditionalPCs(pc, opcode);\r
+            if (cond_pcs != null) {\r
+                \r
+                // TODO: This conditional handling was copied\r
+                // from splitZeroStack, haven't looked in detail\r
+                // to see how a conditional should be handled\r
+                // with an expression split. So for the time\r
+                // being just bail.\r
+                if (true)\r
+                    return -1;\r
+\r
+                // an else block exists, skip the then block.\r
+                if (cond_pcs[3] != -1) {\r
+                    pc = cond_pcs[3];\r
+                    continue;\r
+                }\r
+                \r
+                if (SanityManager.DEBUG)\r
+                {\r
+                    if (outerConditionalEnd_pc != -1)\r
+                    {\r
+                        if (cond_pcs[5] >= outerConditionalEnd_pc)\r
+                            SanityManager.THROWASSERT("NESTED CONDITIONALS!");\r
+                    }\r
+                }\r
+\r
+                if (outerConditionalEnd_pc == -1)\r
+                {\r
+                    outerConditionalEnd_pc = cond_pcs[5];\r
+                }\r
+            }\r
+                       \r
+            pc += instructionLength(opcode);\r
+            \r
+            // Don't split in the middle of a conditional\r
+            if (outerConditionalEnd_pc != -1) {\r
+                if (pc > outerConditionalEnd_pc) {\r
+                    // passed the outermost conditional\r
+                    outerConditionalEnd_pc = -1;\r
+                }\r
+                continue;\r
+            }\r
+            \r
+            int opcode_pc = pc - instructionLength(opcode);\r
+            switch (opcode)\r
+            {\r
+            // Any instruction we don't have any information\r
+            // on, we simply clear all evidence of independent\r
+            // starting points, and start again.\r
+            default:\r
+                Arrays.fill(earliestIndepPC,\r
+                        0, stack + 1, -1);\r
+                break;\r
+            \r
+            // Independent instructions do not change the stack depth\r
+            // and the independence of the top word picks up\r
+            // the independence of the previous word at the same\r
+            // position. Ie. no change!\r
+            case VMOpcode.ARRAYLENGTH:\r
+            case VMOpcode.NOP:\r
+            case VMOpcode.CHECKCAST:\r
+            case VMOpcode.D2L:\r
+            case VMOpcode.DNEG:\r
+            case VMOpcode.F2I:\r
+               break;\r
+               \r
+            // Independent instructions that push one word\r
+            case VMOpcode.ALOAD_0:\r
+            case VMOpcode.ALOAD_1:\r
+            case VMOpcode.ALOAD_2:\r
+            case VMOpcode.ALOAD_3:\r
+            case VMOpcode.ALOAD:\r
+            case VMOpcode.ACONST_NULL:\r
+            case VMOpcode.BIPUSH:\r
+            case VMOpcode.FCONST_0:\r
+            case VMOpcode.FCONST_1:\r
+            case VMOpcode.FCONST_2:\r
+            case VMOpcode.FLOAD:\r
+            case VMOpcode.ICONST_0:\r
+            case VMOpcode.ICONST_1:\r
+            case VMOpcode.ICONST_2:\r
+            case VMOpcode.ICONST_3:\r
+            case VMOpcode.ICONST_4:\r
+            case VMOpcode.ICONST_5:\r
+            case VMOpcode.ICONST_M1:\r
+            case VMOpcode.LDC:\r
+            case VMOpcode.LDC_W:\r
+            case VMOpcode.SIPUSH:\r
+               earliestIndepPC[stack] = opcode_pc;\r
+               break;\r
+            \r
+            // Independent instructions that push two words\r
+            case VMOpcode.DCONST_0:\r
+            case VMOpcode.DCONST_1:\r
+            case VMOpcode.LCONST_0:\r
+            case VMOpcode.LCONST_1:\r
+            case VMOpcode.LDC2_W:\r
+            case VMOpcode.LLOAD:\r
+            case VMOpcode.LLOAD_0:\r
+            case VMOpcode.LLOAD_1:\r
+            case VMOpcode.LLOAD_2:\r
+            case VMOpcode.LLOAD_3:\r
+                earliestIndepPC[stack - 1] = \r
+                    earliestIndepPC[stack] = opcode_pc;\r
+                break;\r
+                \r
+            // nothing to do for pop, obviously no\r
+            // code will be dependent on the popped words.\r
+            case VMOpcode.POP:\r
+            case VMOpcode.POP2:\r
+                break;\r
+                \r
+            case VMOpcode.SWAP:\r
+                earliestIndepPC[stack] = earliestIndepPC[stack -1];\r
+                break;\r
+            \r
+            // push a value that depends on the previous value\r
+            case VMOpcode.I2L:\r
+                earliestIndepPC[stack] = earliestIndepPC[stack -1];\r
+                break;\r
+                \r
+            case VMOpcode.GETFIELD:\r
+            {\r
+                String vmDescriptor = getTypeDescriptor(ch, opcode_pc);\r
+                int width = CodeChunk.getDescriptorWordCount(vmDescriptor);\r
+                if (width == 2)\r
+                    earliestIndepPC[stack] = earliestIndepPC[stack -1];\r
+                    \r
+                break;\r
+            }\r
+\r
+            case VMOpcode.INVOKEINTERFACE:\r
+            case VMOpcode.INVOKEVIRTUAL:\r
+            {\r
+               //   ...,objectref[,word]*\r
+               //   \r
+               // => ...\r
+               // => ...,word\r
+               // => ...,word1,word2\r
+               \r
+                // Width of the value returned by the method call.\r
+                String vmDescriptor = getTypeDescriptor(ch, opcode_pc);\r
+                int width = CodeChunk.getDescriptorWordCount(vmDescriptor);\r
+                \r
+                // Independence of this block is the independence\r
+                // of the objectref that invokved the method.\r
+                int selfContainedBlockStart;\r
+                if (width == 0)\r
+                {\r
+                    // objectref was at one more than the current depth\r
+                    // no plan to split here though, as we are only\r
+                    // splitting methods that return a reference.\r
+                    selfContainedBlockStart = -1;\r
+                        // earliestIndepPC[stack + 1];\r
+                }\r
+                else if (width == 1)\r
+                {     \r
+                    // stack is unchanged, objectref was at\r
+                    // the current stack depth\r
+                    selfContainedBlockStart = earliestIndepPC[stack];\r
+               }\r
+                else\r
+                {\r
+                    // width == 2, objectref was one below the\r
+                    // current stack depth.\r
+                    // no plan to split here though, as we are only\r
+                    // splitting methods that return a reference.\r
+                    selfContainedBlockStart = -1;\r
+                        \r
+                    // top two words depend on the objectref\r
+                    // which was at the same depth of the first word\r
+                    // of the 64 bit value.\r
+                    earliestIndepPC[stack] =\r
+                        earliestIndepPC[stack - 1];\r
+                 }\r
+                \r
+                if (selfContainedBlockStart != -1)\r
+                {\r
+                    int blockLength = pc - selfContainedBlockStart;\r
+                    \r
+                    if (blockLength <= splitMinLength)\r
+                    {\r
+                        // No point splitting, too small\r
+                    }\r
+                    else if (blockLength > (VMOpcode.MAX_CODE_LENGTH - 1))\r
+                    {\r
+                        // too big to split into a single method\r
+                        // (one for the return opcode)\r
+                    }\r
+                    else\r
+                    {\r
+                        // Only split for a method that returns\r
+                        // an class reference.\r
+                        int me = vmDescriptor.lastIndexOf(')');\r
+                    \r
+                        if (vmDescriptor.charAt(me+1) == 'L')\r
+                        {\r
+                            String rt = vmDescriptor.substring(me + 2,\r
+                                    vmDescriptor.length() - 1);\r
+                            \r
+                            // convert to external format.\r
+                            rt = rt.replace('/', '.');\r
+                            \r
+                            if (blockLength >= optimalMinLength)\r
+                            {\r
+                                // Split now!\r
+                                BCMethod subMethod = startSubMethod(mb,\r
+                                        rt, selfContainedBlockStart,\r
+                                        blockLength);\r
+    \r
+                                return splitCodeIntoSubMethod(mb, ch, subMethod,\r
+                                        selfContainedBlockStart, blockLength);                             \r
+                            }                       \r
+                            else if (blockLength > bestSplitBlockLength)\r
+                            {\r
+                                // Save it, may split at this point\r
+                                // if nothing better seen.\r
+                                bestSplitPC = selfContainedBlockStart;\r
+                                bestSplitBlockLength = blockLength;\r
+                                bestSplitRT = rt;\r
+                            }\r
+                        }\r
+                    }\r
+                }\r
+               break;\r
+              }\r
+            }   \r
+            \r
+       }\r
+        \r
+\r
+        if (bestSplitBlockLength != -1) {\r
+            BCMethod subMethod = startSubMethod(mb,\r
+                    bestSplitRT, bestSplitPC,\r
+                    bestSplitBlockLength);\r
+    \r
+            return splitCodeIntoSubMethod(mb, ch, subMethod,\r
+                    bestSplitPC, bestSplitBlockLength);  \r
+        }\r
+               \r
+        return -1;\r
+    }\r
+    \r
+    /**\r
+     * See if the opcode is a return instruction.\r
+     * @param opcode opcode to be checked\r
+     * @return true for is a return instruction, false otherwise.\r
+     */\r
+    private static boolean isReturn(short opcode)\r
+    {\r
+        switch (opcode)\r
+        {\r
+        case VMOpcode.RETURN:\r
+        case VMOpcode.ARETURN:\r
+        case VMOpcode.IRETURN:\r
+        case VMOpcode.FRETURN:\r
+        case VMOpcode.DRETURN:\r
+        case VMOpcode.LRETURN:\r
+            return true;\r
+         default:\r
+            return false;\r
+        }        \r
+    }\r
+    \r
+    /**\r
+     * Minimum split length for a sub-method. If the number of\r
+     * instructions to call the sub-method exceeds the length\r
+     * of the sub-method, then there's no point splitting.\r
+     * The number of bytes in the code stream to call\r
+     * a generated sub-method can take is based upon the number of method args.\r
+     * A method can have maximum of 255 words of arguments (section 4.10 JVM spec)\r
+     * which in the worst case would be 254 (one-word) parameters\r
+     * and this. For a sub-method the arguments will come from the\r
+     * parameters to the method, i.e. ALOAD, ILOAD etc.\r
+     * <BR>\r
+     * This leads to this number of instructions.\r
+     * <UL>\r
+     * <LI> 4 - 'this' and first 3 parameters have single byte instructions\r
+     * <LI> (N-4)*2 - Remaining parameters have two byte instructions\r
+     * <LI> 3 for the invoke instruction.\r
+     * </UL>\r
+     */\r
+    private static int splitMinLength(BCMethod mb) {\r
+        int min = 1 + 3; // For ALOAD_0 (this) and invoke instruction\r
+        \r
+        if (mb.parameters != null) {\r
+            int paramCount = mb.parameters.length;\r
+            \r
+            min += paramCount;\r
+            \r
+            if (paramCount > 3)\r
+                min += (paramCount - 3);\r
+        }\r
+        \r
+        return min;\r
+    }\r
+    /*\r
+    final int splitNonZeroStack(BCMethod mb, ClassHolder ch,\r
+            final int codeLength, final int optimalMinLength,\r
+            int maxStack) {\r
+        \r
+        // program counter for the instruction that\r
+        // made the stack reach the given stack depth.\r
+        int[] stack_pcs = new int[maxStack+1];\r
+        Arrays.fill(stack_pcs, -1);\r
+        \r
+        int stack = 0;\r
+        \r
+        // maximum possible split seen that is less than\r
+        // the minimum.\r
+        int possibleSplitLength = -1;\r
+        \r
+        System.out.println("NZ SPLIT + " + mb.getName());\r
+\r
+        // do not split until at least this point (inclusive)\r
+        // used to ensure no split occurs in the middle of\r
+        // a conditional.\r
+        int outerConditionalEnd_pc = -1;\r
+\r
+        int end_pc = 0 + codeLength;\r
+        for (int pc = 0; pc < end_pc;) {\r
+\r
+            short opcode = getOpcode(pc);\r
+\r
+            int stackDelta = stackWordDelta(ch, pc, opcode);\r
+            \r
+            stack += stackDelta;\r
+            \r
+            // Cannot split a conditional but need to calculate\r
+            // the stack depth at the end of the conditional.\r
+            // Each path through the conditional will have the\r
+            // same stack depth.\r
+            int[] cond_pcs = findConditionalPCs(pc, opcode);\r
+            if (cond_pcs != null) {\r
+                // an else block exists, skip the then block.\r
+                if (cond_pcs[3] != -1) {\r
+                    pc = cond_pcs[3];\r
+                    continue;\r
+                }\r
+                \r
+                if (SanityManager.DEBUG)\r
+                {\r
+                    if (outerConditionalEnd_pc != -1)\r
+                    {\r
+                        if (cond_pcs[5] >= outerConditionalEnd_pc)\r
+                            SanityManager.THROWASSERT("NESTED CONDITIONALS!");\r
+                    }\r
+                }\r
+\r
+                if (outerConditionalEnd_pc == -1)\r
+                {\r
+                    outerConditionalEnd_pc = cond_pcs[5];\r
+                }\r
+            }\r
+                       \r
+            pc += instructionLength(opcode);\r
+            \r
+            // Don't split in the middle of a conditional\r
+            if (outerConditionalEnd_pc != -1) {\r
+                if (pc > outerConditionalEnd_pc) {\r
+                    // passed the outermost conditional\r
+                    outerConditionalEnd_pc = -1;\r
+                }\r
+                continue;\r
+            }\r
+            \r
+            if (stackDelta == 0)\r
+                continue;\r
+\r
+            // Only split when the stack is having items popped\r
+            if (stackDelta > 0)\r
+            {\r
+                // pushing double word, clear out a\r
+                if (stackDelta == 2)\r
+                    stack_pcs[stack - 1] = pc;\r
+                stack_pcs[stack] = pc;\r
+                continue;\r
+            }\r
+            \r
+            int opcode_pc = pc - instructionLength(opcode);\r
+            \r
+            // Look for specific opcodes that have the capability\r
+            // of having a significant amount of code in a self\r
+            // contained block.\r
+            switch (opcode)\r
+            {\r
+            // this.method(A) construct\r
+            //  ...         -- stack N\r
+            //  push this -- stack N+1\r
+            //  push args -- stack N+1+A\r
+            //  call method -- stack N+R (R=0,1,2)\r
+            //\r
+            //  stackDelta = (N+R) - (N+1+A) = R-(1+A)\r
+            //  stack = N+R\r
+            //  Need to determine N+1\r
+            //  \r
+            //  \r
+            //\r
+            //  this.a(<i2>, <i2>, <i3>)\r
+            //  returning int\r
+            //\r
+            //  stackDelta = -3 (this & 3 args popped, ret pushed)\r
+            //  initial depth N = 10\r
+            //  pc        - stack\r
+            //  100 ...       - stack 10\r
+            //  101 push this - stack 11\r
+            //  109 push i1   - stack 12\r
+            //  125 push i2   - stack 13\r
+            //  156 push i3   - stack 14\r
+            //  157 call      - stack 11\r
+            //  \r
+            //  need stack_pcs[11] = stack_pcs[11 + -3]\r
+            //\r
+            // ref.method(args).method(args) ... method(args)\r
+            // \r
+            case VMOpcode.INVOKEINTERFACE:\r
+            case VMOpcode.INVOKESPECIAL:\r
+            case VMOpcode.INVOKEVIRTUAL:\r
+            {\r
+                String vmDescriptor = getTypeDescriptor(ch, opcode_pc);\r
+                int r = CodeChunk.getDescriptorWordCount(vmDescriptor);\r
+             \r
+                // PC of the opcode that pushed the reference for\r
+                // this method call.\r
+                int ref_pc = stack_pcs[stack - r + 1];\r
+               if (getOpcode(ref_pc) == VMOpcode.ALOAD_0) {\r
+                    System.out.println("POSS SPLIT " + (pc - ref_pc) + " @ " + ref_pc);\r
+                }\r
+               break;\r
+            }\r
+            case VMOpcode.INVOKESTATIC:\r
+                String vmDescriptor = getTypeDescriptor(ch, opcode_pc);\r
+                int r = CodeChunk.getDescriptorWordCount(vmDescriptor);\r
+                int p1_pc = stack_pcs[stack - r + 1];\r
+                System.out.println("POSS STATIC SPLIT " + (pc - p1_pc) + " @ " + p1_pc);\r
+                \r
+            }\r
+            stack_pcs[stack] = opcode_pc;\r
+        }\r
+        return -1;\r
+    }*/\r
+}\r