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 2005/04/07 20:50:40 UTC

svn commit: r160429 - incubator/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/BinaryLogicalOperatorNode.java incubator/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/BinaryOperatorNode.java

Author: djd
Date: Thu Apr  7 11:50:39 2005
New Revision: 160429

URL: http://svn.apache.org/viewcvs?view=rev&rev=160429
Log:
Derby-176 (partial)

Reduce the number of constant pool entries in code generation by removing some uses of java fields.

In the binary operator nodes code is generated like

<left>.method(<left>, <right>)

where <left> and <right> are arbitary expressions.
In this case <left> must only be evaluated once and the existing implementation used Java fields.

DataValueDescriptor f34;

f34 = <left>;

f34.method(f34, <right>)

The issue is that a field is not required, really a local variable is,
and a field and its use will create three unique constant pool entries.
However local variables are not supported by the byte code compiler currently.

The stack based code generation allows the use of the stack through MethodBuilder.dup()
method to evaluate <left> once and re-use the result.
E.g.

<left>
dup
<right>

leaves the stack as left,left,right which is the correct order for such a method call.
The use of MethodBuilder.swap() allows the same pattern when <right> needs to be re-used in <right>.method(<left>, <right>)

<right>
dup
<left>
swap

leaves right,left,right on the stack.


Modified:
    incubator/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/BinaryLogicalOperatorNode.java
    incubator/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/BinaryOperatorNode.java

Modified: incubator/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/BinaryLogicalOperatorNode.java
URL: http://svn.apache.org/viewcvs/incubator/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/BinaryLogicalOperatorNode.java?view=diff&r1=160428&r2=160429
==============================================================================
--- incubator/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/BinaryLogicalOperatorNode.java (original)
+++ incubator/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/BinaryLogicalOperatorNode.java Thu Apr  7 11:50:39 2005
@@ -148,23 +148,22 @@
 		*/
 
 		/*
-		** Save the evaluation of the left operand in a field.
-		** Generated code is:
-		**		(<fieldx> = <leftOperand>)
-		*/
-		LocalField leftOperandSaver = acb.newFieldDeclaration(Modifier.PRIVATE,
-												ClassName.BooleanDataValue);
-
-		/*
 		** See whether the left operand equals the short-circuit value.
 		** Generated code is:
 		**		.equals(shortCircuitValue)
 		*/
 
 		leftOperand.generateExpression(acb, mb);
-		mb.putField(leftOperandSaver);
+		// stack - left
+
+		// put an extra left of the stack for potential
+		// use in the else clause.
+		mb.dup();
+		// stack - left, left
 		mb.push(shortCircuitValue);
+		// stack - left, left, shortcircuit
 		mb.callMethod(VMOpcode.INVOKEINTERFACE, (String) null, "equals", "boolean", 1);
+		// stack left, result
 
 		/*
 		** Generate the if expression.  This is what accomplishes
@@ -177,7 +176,9 @@
 		*/
 
 		mb.conditionalIf();
-
+		
+		// stack: left
+		
 		/*
 		** Generate the return value if the left operand equals the short-
 		** circuit value.  Generated code calls a static method in the
@@ -187,8 +188,11 @@
 		LocalField reusableBoolean = acb.newFieldDeclaration(Modifier.PRIVATE,
 												ClassName.BooleanDataValue);
 
+
 		mb.push(shortCircuitValue);
+		// stack: left, shortcircuit
 		acb.generateDataValue(mb, getTypeCompiler(), reusableBoolean);
+		// stack: left, dvf
 
 
 		mb.startElseCode();
@@ -202,14 +206,34 @@
 		**	<fieldx>.<methodName>(<rightOperand>)
 		*/
 
-		mb.getField(leftOperandSaver);
+		// stack: left
+		
+		// we duplicate left here rather than just pop'ing left
+		// in the 'then' clause. pop'ing in the then clause
+		// breaks the current conditional implementation
+		// which is modeling a simple ? : operator.
+		// note that this will leave through either path
+		// an extra left on the stack after the conditional
+		mb.dup();
+		// stack left, left
 
 		rightOperand.generateExpression(acb, mb);
+		// stack: left, left, right
 		mb.upCast(ClassName.BooleanDataValue);
 
 		mb.callMethod(VMOpcode.INVOKEINTERFACE, (String) null, methodName, ClassName.BooleanDataValue, 1);
+		// stack: left, result(left op right)
 
 		mb.completeConditional();
+		//	 stack: left, result
+		
+		// remove the extra left on the stack, see the
+		// comments in the else clause.
+		mb.swap();
+		// stack: result, left
+		mb.pop();
+		
+		// stack: result
 	}
 
 	DataTypeDescriptor resolveLogicalBinaryOperator(

Modified: incubator/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/BinaryOperatorNode.java
URL: http://svn.apache.org/viewcvs/incubator/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/BinaryOperatorNode.java?view=diff&r1=160428&r2=160429
==============================================================================
--- incubator/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/BinaryOperatorNode.java (original)
+++ incubator/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/BinaryOperatorNode.java Thu Apr  7 11:50:39 2005
@@ -338,7 +338,6 @@
 		throws StandardException
 	{
 		String		resultTypeName;
-		LocalField	receiverField;
 		String		receiverType;
 
 /*
@@ -353,9 +352,6 @@
 		** The receiver is the operand with the higher type precedence.
 		** Like always makes the left the receiver.
 		**
-		** Allocate an object for re-use to hold the receiver.  This is because
-		** the receiver is passed to the method as one of the parameters,
-		** and we don't want to evaluate it twice.
 		*/
 		if (leftOperand.getTypeId().typePrecedence() >
 			rightOperand.getTypeId().typePrecedence())
@@ -371,20 +367,22 @@
 		    receiverType = getReceiverInterfaceName();
 
 			/*
-			** Generate (field = <left expression>).  This assignment is
-			** used as the receiver of the method call for this operator,
-			** and the field is used as the left operand:
+			** Generate (with <left expression> only being evaluated once)
 			**
-			**	(field = <left expression>).method(field, <right expression>...)
+			**	<left expression>.method(<left expression>, <right expression>...)
 			*/
-			receiverField =
-				acb.newFieldDeclaration(Modifier.PRIVATE, receiverType);
 
 			leftOperand.generateExpression(acb, mb);
-			mb.putField(receiverField); // method instance
 			mb.cast(receiverType); // cast the method instance
-			mb.getField(receiverField); mb.cast(leftInterfaceType); // first arg with cast
-			rightOperand.generateExpression(acb, mb); mb.cast(rightInterfaceType); // second arg with cast
+			// stack: left
+			
+			mb.dup();
+			mb.cast(leftInterfaceType);
+			// stack: left, left
+			
+			rightOperand.generateExpression(acb, mb);
+			mb.cast(rightInterfaceType); // second arg with cast
+			// stack: left, left, right
 		}
 		else
 		{
@@ -399,20 +397,25 @@
 		    receiverType = getReceiverInterfaceName();
 
 			/*
-			** Generate (field = <right expression>).  This assignment is
-			** used as the receiver of the method call for this operator,
-			** and the field is used as the right operand:
+			** Generate (with <right expression> only being evaluated once)
 			**
-			**	(field = <right expression>).method(<left expression>, field...)
+			**	<right expression>.method(<left expression>, <right expression>)
 			*/
-			receiverField =
-				acb.newFieldDeclaration(Modifier.PRIVATE, rightInterfaceType);
 
-			rightOperand.generateExpression(acb, mb);
-			mb.putField(receiverField); // method instance
+			rightOperand.generateExpression(acb, mb);			
 			mb.cast(receiverType); // cast the method instance
-			leftOperand.generateExpression(acb, mb); mb.cast(leftInterfaceType); // second arg with cast
-			mb.getField(receiverField); mb.cast(rightInterfaceType); // first arg with cast
+			// stack: right
+			
+			mb.dup();
+			mb.cast(rightInterfaceType);
+			// stack: right,right
+			
+			leftOperand.generateExpression(acb, mb);
+			mb.cast(leftInterfaceType); // second arg with cast
+			// stack: right,right,left
+			
+			mb.swap();
+			// stack: right,left,right			
 		}
 
 		/* Figure out the result type name */