You are viewing a plain text version of this content. The canonical link for it is here.
Posted to derby-commits@db.apache.org by dj...@apache.org on 2006/08/21 01:45:18 UTC

svn commit: r433086 - in /db/derby/code/branches/10.2/java/engine/org/apache/derby/impl/services/bytecode: BCMethod.java CodeChunk.java

Author: djd
Date: Sun Aug 20 16:45:16 2006
New Revision: 433086

URL: http://svn.apache.org/viewvc?rev=433086&view=rev
Log:
DERBY-766 DERBY-1714 Working method in CodeChunk that splits expressions out of generated methods that are too large.
Bumps the number of unions supported in largeCodeGen to over 6,000 from around 800. Also increases the
number of rows supported in a VALUES clause. A large number of UNION clauses still requires a large amount of
memory for optimization (see DERBY-1315). A large number of rows in a VALUES clause fails at some point due to
a StackOverflow. Subsequent commit will modify largeCodeGen to be a JUnit test and adapt to these changes
but running into issues finding a useful workign limits that can produce repeatable results without
hitting memory issues.
Merge of 432856 from trunk.

Modified:
    db/derby/code/branches/10.2/java/engine/org/apache/derby/impl/services/bytecode/BCMethod.java
    db/derby/code/branches/10.2/java/engine/org/apache/derby/impl/services/bytecode/CodeChunk.java

Modified: db/derby/code/branches/10.2/java/engine/org/apache/derby/impl/services/bytecode/BCMethod.java
URL: http://svn.apache.org/viewvc/db/derby/code/branches/10.2/java/engine/org/apache/derby/impl/services/bytecode/BCMethod.java?rev=433086&r1=433085&r2=433086&view=diff
==============================================================================
--- db/derby/code/branches/10.2/java/engine/org/apache/derby/impl/services/bytecode/BCMethod.java (original)
+++ db/derby/code/branches/10.2/java/engine/org/apache/derby/impl/services/bytecode/BCMethod.java Sun Aug 20 16:45:16 2006
@@ -74,7 +74,7 @@
      * cause some splitting. Tested with value set to 2000.
      */
     static final int CODE_SPLIT_LENGTH = VMOpcode.MAX_CODE_LENGTH;
-
+    
 	final BCClass		cb;
 	protected final ClassHolder modClass; // the class it is in (modifiable fmt)
 	final String myReturnType;
@@ -288,13 +288,14 @@
             }
             else
             {
-                //TODO: re-start split at point left off
-                //split_pc = myCode.splitExpressionOut(this, modClass,
-                //        optimalMinLength, maxStack);
-                
-                // DERBY-766 temp - don't call the split method yet.
-                split_pc = -1;
-            }
+                // Note the split expression does not re-start split
+                // at point left off by the previous split expression.
+                // This could be done but would require some level
+                // of stack depth history to be kept across calls.
+                split_pc = myCode.splitExpressionOut(this, modClass,
+                        optimalMinLength, maxStack);
+
+             }
 
             // Negative split point returned means that no split
             // was possible. Give up on this approach and goto

Modified: db/derby/code/branches/10.2/java/engine/org/apache/derby/impl/services/bytecode/CodeChunk.java
URL: http://svn.apache.org/viewvc/db/derby/code/branches/10.2/java/engine/org/apache/derby/impl/services/bytecode/CodeChunk.java?rev=433086&r1=433085&r2=433086&view=diff
==============================================================================
--- db/derby/code/branches/10.2/java/engine/org/apache/derby/impl/services/bytecode/CodeChunk.java (original)
+++ db/derby/code/branches/10.2/java/engine/org/apache/derby/impl/services/bytecode/CodeChunk.java Sun Aug 20 16:45:16 2006
@@ -1285,6 +1285,9 @@
      */
     final int splitZeroStack(BCMethod mb, ClassHolder ch, final int split_pc,
             final int optimalMinLength) {
+        
+        int splitMinLength = splitMinLength(mb);
+        
         int stack = 0;
 
         // maximum possible split seen that is less than
@@ -1374,11 +1377,8 @@
                     return -1;
  
                 // Decide if the earlier possible split is
-                // worth it. 100 is an arbitary number,
-                // a real low limit would be the number of
-                // bytes of instructions required to call
-                // the sub-method, four I think.
-                if (possibleSplitLength < 100)
+                // worth it.
+                if (possibleSplitLength <= splitMinLength)
                     return -1;
 
                 // OK go with the earlier split
@@ -1718,14 +1718,16 @@
      *  
       */
 
-    final int splitExpressionOut(BCMethod mb, ClassHolder ch,
+    final int splitExpressionOut(final BCMethod mb, final ClassHolder ch,
             final int optimalMinLength,
-            int maxStack)
+            final int maxStack)
     {
         // Save the best block we have seen for splitting out.
         int bestSplitPC = -1;
         int bestSplitBlockLength = -1;
-        String bestSplitRT = null;      
+        String bestSplitRT = null;  
+        
+        int splitMinLength = splitMinLength(mb);
         
         // Program counter of the earliest instruction
         // that the word in the current active stack
@@ -1781,6 +1783,15 @@
             // same stack depth.
             int[] cond_pcs = findConditionalPCs(pc, opcode);
             if (cond_pcs != null) {
+                
+                // TODO: This conditional handling was copied
+                // from splitZeroStack, haven't looked in detail
+                // to see how a conditional should be handled
+                // with an expression split. So for the time
+                // being just bail.
+                if (true)
+                    return -1;
+
                 // an else block exists, skip the then block.
                 if (cond_pcs[3] != -1) {
                     pc = cond_pcs[3];
@@ -1920,8 +1931,10 @@
                 if (width == 0)
                 {
                     // objectref was at one more than the current depth
-                    selfContainedBlockStart =
-                        earliestIndepPC[stack + 1];
+                    // no plan to split here though, as we are only
+                    // splitting methods that return a reference.
+                    selfContainedBlockStart = -1;
+                        // earliestIndepPC[stack + 1];
                 }
                 else if (width == 1)
                 {     
@@ -1933,47 +1946,62 @@
                 {
                     // width == 2, objectref was one below the
                     // current stack depth.
-                    selfContainedBlockStart = earliestIndepPC[stack] =
+                    // no plan to split here though, as we are only
+                    // splitting methods that return a reference.
+                    selfContainedBlockStart = -1;
+                        
+                    // top two words depend on the objectref
+                    // which was at the same depth of the first word
+                    // of the 64 bit value.
+                    earliestIndepPC[stack] =
                         earliestIndepPC[stack - 1];
                  }
                 
                 if (selfContainedBlockStart != -1)
                 {
                     int blockLength = pc - selfContainedBlockStart;
-
-                    // Only split for a method that returns
-                    // an class reference.
-                    int me = vmDescriptor.lastIndexOf(')');
                     
-                    if (vmDescriptor.charAt(me+1) == 'L')
+                    if (blockLength <= splitMinLength)
                     {
-                        String rt = vmDescriptor.substring(me + 2,
-                                vmDescriptor.length() - 1);
-                        
-                        if (blockLength > (VMOpcode.MAX_CODE_LENGTH - 1))
-                        {
-                            // too big to split into a single method
-                            // (one for the return opcode)
-                        }                       
-                        else if (blockLength >= optimalMinLength)
-                        {
-                            // Split now!
-                            System.out.println("NOW " + blockLength
-                                    + " @ " + selfContainedBlockStart);
-                            BCMethod subMethod = startSubMethod(mb,
-                                    rt, selfContainedBlockStart,
-                                    blockLength);
-
-                            return splitCodeIntoSubMethod(mb, ch, subMethod,
-                                    selfContainedBlockStart, blockLength);                             
-                        }                       
-                        else if (blockLength > bestSplitBlockLength)
+                        // No point splitting, too small
+                    }
+                    else if (blockLength > (VMOpcode.MAX_CODE_LENGTH - 1))
+                    {
+                        // too big to split into a single method
+                        // (one for the return opcode)
+                    }
+                    else
+                    {
+                        // Only split for a method that returns
+                        // an class reference.
+                        int me = vmDescriptor.lastIndexOf(')');
+                    
+                        if (vmDescriptor.charAt(me+1) == 'L')
                         {
-                            // Save it, may split at this point
-                            // if nothing better seen.                          
-                            bestSplitPC = selfContainedBlockStart;
-                            bestSplitBlockLength = blockLength;
-                            bestSplitRT = rt;
+                            String rt = vmDescriptor.substring(me + 2,
+                                    vmDescriptor.length() - 1);
+                            
+                            // convert to external format.
+                            rt = rt.replace('/', '.');
+                            
+                            if (blockLength >= optimalMinLength)
+                            {
+                                // Split now!
+                                BCMethod subMethod = startSubMethod(mb,
+                                        rt, selfContainedBlockStart,
+                                        blockLength);
+    
+                                return splitCodeIntoSubMethod(mb, ch, subMethod,
+                                        selfContainedBlockStart, blockLength);                             
+                            }                       
+                            else if (blockLength > bestSplitBlockLength)
+                            {
+                                // Save it, may split at this point
+                                // if nothing better seen.
+                                bestSplitPC = selfContainedBlockStart;
+                                bestSplitBlockLength = blockLength;
+                                bestSplitRT = rt;
+                            }
                         }
                     }
                 }
@@ -1983,19 +2011,16 @@
             
        }
         
-        if (bestSplitBlockLength > 100)
-        {
-            System.out.println("BEST " + bestSplitBlockLength
-                    + " @ " + bestSplitPC);
+
+        if (bestSplitBlockLength != -1) {
             BCMethod subMethod = startSubMethod(mb,
                     bestSplitRT, bestSplitPC,
                     bestSplitBlockLength);
-
+    
             return splitCodeIntoSubMethod(mb, ch, subMethod,
-                    bestSplitBlockLength, bestSplitBlockLength); 
-            
+                    bestSplitPC, bestSplitBlockLength);  
         }
-                       
+               
         return -1;
     }
     
@@ -2020,6 +2045,38 @@
         }        
     }
     
+    /**
+     * Minimum split length for a sub-method. If the number of
+     * instructions to call the sub-method exceeds the length
+     * of the sub-method, then there's no point splitting.
+     * The number of bytes in the code stream to call
+     * a generated sub-method can take is based upon the number of method args.
+     * A method can have maximum of 255 words of arguments (section 4.10 JVM spec)
+     * which in the worst case would be 254 (one-word) parameters
+     * and this. For a sub-method the arguments will come from the
+     * parameters to the method, i.e. ALOAD, ILOAD etc.
+     * <BR>
+     * This leads to this number of instructions.
+     * <UL>
+     * <LI> 4 - 'this' and first 3 parameters have single byte instructions
+     * <LI> (N-4)*2 - Remaining parameters have two byte instructions
+     * <LI> 3 for the invoke instruction.
+     * </UL>
+     */
+    private static int splitMinLength(BCMethod mb) {
+        int min = 1 + 3; // For ALOAD_0 (this) and invoke instruction
+        
+        if (mb.parameters != null) {
+            int paramCount = mb.parameters.length;
+            
+            min += paramCount;
+            
+            if (paramCount > 3)
+                min += (paramCount - 3);
+        }
+        
+        return min;
+    }
     /*
     final int splitNonZeroStack(BCMethod mb, ClassHolder ch,
             final int codeLength, final int optimalMinLength,