db-derby-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From rhille...@apache.org
Subject svn commit: r579653 - in /db/derby/code/trunk/java/engine/org/apache/derby: iapi/services/loader/ClassInspector.java impl/sql/compile/MethodCallNode.java impl/sql/compile/StaticMethodCallNode.java
Date Wed, 26 Sep 2007 13:50:43 GMT
Author: rhillegas
Date: Wed Sep 26 06:50:42 2007
New Revision: 579653

URL: http://svn.apache.org/viewvc?rev=579653&view=rev
Log:
DERBY-3069: Support varargs in user code.

Modified:
    db/derby/code/trunk/java/engine/org/apache/derby/iapi/services/loader/ClassInspector.java
    db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/MethodCallNode.java
    db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/StaticMethodCallNode.java

Modified: db/derby/code/trunk/java/engine/org/apache/derby/iapi/services/loader/ClassInspector.java
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/engine/org/apache/derby/iapi/services/loader/ClassInspector.java?rev=579653&r1=579652&r2=579653&view=diff
==============================================================================
--- db/derby/code/trunk/java/engine/org/apache/derby/iapi/services/loader/ClassInspector.java
(original)
+++ db/derby/code/trunk/java/engine/org/apache/derby/iapi/services/loader/ClassInspector.java
Wed Sep 26 06:50:42 2007
@@ -21,6 +21,8 @@
 
 package org.apache.derby.iapi.services.loader;
 
+import org.apache.derby.iapi.services.info.JVMInfo;
+
 import org.apache.derby.iapi.services.sanity.SanityManager;
 
 import org.apache.derby.iapi.error.StandardException;
@@ -275,10 +277,11 @@
 		}
 
 		// no overloading possible if there are no arguments, so perform
-		// an exact match lookup.
-		if (paramClasses.length == 0) {
-
-			try {
+		// an exact match lookup. this short-circuiting will not work if the VM
+		// level supports varargs--this is because no arguments at all will
+		// still match a signature which is just a varargs argument
+		if ( !vmSupportsVarargs() && (paramClasses.length == 0) ) {
+            try {
 				Method method = receiverClass.getMethod(methodName, paramClasses);
 
 				if (staticMethod) {
@@ -557,7 +560,6 @@
 				Member[] methods)
 			throws StandardException
 	{
-
 		if (SanityManager.DEBUG) {
 		  if (SanityManager.DEBUG_ON("MethodResolutionInfo"))
 		  {
@@ -580,6 +582,7 @@
 		boolean firstTimeAround = true;
 		boolean	ambiguous;
 		boolean somethingChanged;
+        Class[]    varargsType = new Class[ methods.length ];
 		do {
 
 			ambiguous = false;
@@ -589,6 +592,8 @@
 
 				Member currentMethod = methods[i];
 
+                if ( firstTimeAround ) { varargsType[ i ] = getVarargsType( currentMethod
); }
+
 				// on second and later times around there will be null entries
 				// also, don't compare ourself to ourself
 				if ((currentMethod == null) ||
@@ -616,8 +621,13 @@
 
 					} else {
 
-						// regular match on parameter count
-						if (currentMethodParameters.length != paramClasses.length) {
+						// regular match on parameter count. a varargs method
+						// can have fewer arguments than the invoking expression.
+						if (
+                            ( ( (currentMethodParameters.length-1) > paramClasses.length)
&& (varargsType[ i ] != null) ) ||
+                            ( (currentMethodParameters.length != paramClasses.length) &&
(varargsType[ i ] == null) )
+                            )
+                        {
 							methods[i] = null; // remove non-applicable methods
 							continue;
 						}
@@ -660,7 +670,7 @@
 
 				// can the required signature be converted to those of this method
 				if (!signatureConvertableFromTo(paramClasses, primParamClasses,
-							currentMethodParameters, isParam, false)) {
+                                                currentMethodParameters, isParam, false,
varargsType[ i ])) {
 
 					if (SanityManager.DEBUG) {
 					  if (SanityManager.DEBUG_ON("MethodResolutionInfo")) {
@@ -785,7 +795,8 @@
 			if (methods[candidateIndex] == null)
 				SanityManager.THROWASSERT("methods is null at index " + candidateIndex);
 		}
-		return methods[candidateIndex];
+
+        return methods[candidateIndex];
 	}
 
 	/**
@@ -893,7 +904,7 @@
 			UC = ((Constructor) U).getParameterTypes();
 		}
 
-		return signatureConvertableFromTo(TC, null, UC, isParam, true);
+		return signatureConvertableFromTo(TC, null, UC, isParam, true, null);
 	}
 
 	/**
@@ -907,23 +918,33 @@
 	 *	@param toTypes		to types' classes
 	 *	@param isParam		is parameter (?) or not
 	 *	@param mixTypes		mixing object/primitive types for comparison
+	 *	@param varargsType  non-array type of last toTypes if the method/constructor has a varargs
signature
 	 **/
 	private boolean signatureConvertableFromTo(Class[] fromTypes, Class[] primFromTypes,
 												 Class[] toTypes, boolean[] isParam,
-												 boolean mixTypes) {
+                                               boolean mixTypes, Class varargsType) {
 
 		// In the case repeatLastParameter was true, then the two methods may have
 		// different numbers of parameters. We need to compare only the non-repeated
 		// parameters, which is the number of input parameters.
 
 		int checkCount = fromTypes.length;
-		if (toTypes.length < checkCount)
+		if ( (toTypes.length < checkCount) && (varargsType == null) )
 			checkCount = toTypes.length;
 
 		for (int i = 0; i < checkCount; i++) {
 
 			Class fromClass = fromTypes[i];
-			Class toClass = toTypes[i];
+			Class toClass;
+
+            // if the candidate method has a varargs signature, then the
+            // concluding types must all be the type of the candidate's
+            // last argument
+            if ( (i >= (toTypes.length-1)) && (varargsType != null) )
+            {
+                toClass = varargsType;
+            }
+            else { toClass = toTypes[ i ]; }
 
 			// this means an untyped null was passed in. Can only ever be in the
 			// from side as the null can only be in the signature passed in by
@@ -1115,6 +1136,57 @@
 	public String getDeclaringClass(Member method)
 	{
 		return method.getDeclaringClass().getName();
+	}		
+
+    /**
+	 * Get the type of the final, varargs argument to a method or
+	 * constructor. This is the base type (we strip off the array
+	 * marker). Returns null if this is not a varargs method or constructor.
+	 */
+	public static     Class    getVarargsType( Member member )
+	{
+        if ( !memberHasVarargs( member ) ) { return null; }
+        
+		Class[] parameterClasses;
+		if (member instanceof Method) {
+			parameterClasses = ((Method) member).getParameterTypes();
+		} else {
+			parameterClasses = ((Constructor) member).getParameterTypes();
+		}
+        Class   lastParamType = parameterClasses[ parameterClasses.length - 1 ];
+
+        // now strip off the array wrapper
+        lastParamType = lastParamType.getComponentType();
+
+        return lastParamType;
+    }		
+
+    /**
+	 * Report whether a method or constructor has a variable argument list at
+	 * the end. We use reflection so that we can compile this support on and for
+	 * versions of Java prior to Java 5.
+	 */
+	public static   boolean  memberHasVarargs( Member member )
+	{
+        if ( !vmSupportsVarargs() ) { return false; }
+
+        try {
+            Method      isVarargsMethod = member.getClass().getMethod( "isVarArgs", null
);
+
+            return ((Boolean) isVarargsMethod.invoke( member, null )).booleanValue();
+        }
+        catch (Exception e)
+        {
+            return false;
+        }
+	}		
+
+    /**
+	 * Report whether the VM supports varargs in method signatures.
+	 */
+	public static   boolean  vmSupportsVarargs()
+	{
+        return (JVMInfo.JDK_ID >= JVMInfo.J2SE_15);
 	}		
 
 }

Modified: db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/MethodCallNode.java
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/MethodCallNode.java?rev=579653&r1=579652&r2=579653&view=diff
==============================================================================
--- db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/MethodCallNode.java
(original)
+++ db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/MethodCallNode.java
Wed Sep 26 06:50:42 2007
@@ -23,6 +23,7 @@
 
 import org.apache.derby.iapi.services.loader.ClassInspector;
 
+import org.apache.derby.iapi.services.compiler.LocalField;
 import org.apache.derby.iapi.services.compiler.MethodBuilder;
 
 import org.apache.derby.iapi.services.sanity.SanityManager;
@@ -58,6 +59,8 @@
 import java.lang.reflect.Modifier;
 import java.lang.reflect.Member;
 
+import java.sql.ResultSet;
+
 import java.util.Enumeration;
 import java.util.StringTokenizer;
 import java.util.Vector;
@@ -528,23 +531,49 @@
 	{
 		int				param;
 
-		String[] expectedTypes = methodParameterTypes;
+		String[]    expectedTypes = methodParameterTypes;
+        String      varargsType = getVarargsType();
+        int         numPushedArgs = methodParms.length;
+        int         firstVararg = -1;
+        LocalField  varargsArrayField = null;
 
-		ClassInspector classInspector = getClassFactory().getClassInspector();
+        if ( varargsType != null )
+        {
+            numPushedArgs = expectedTypes.length;
+            firstVararg = numPushedArgs - 1;
+            varargsArrayField = acb.newFieldDeclaration(Modifier.PRIVATE, varargsType + "[]"
);
+
+            mb.pushNewArray( varargsType, methodParms.length - firstVararg );
+            mb.setField( varargsArrayField );  
+        }
+
+        ClassInspector classInspector = getClassFactory().getClassInspector();
 
 		/* Generate the code for each user parameter, generating the appropriate
 		 * cast when the passed type needs to get widened to the expected type.
 		 */
+
 		for (param = 0; param < methodParms.length; param++)
 		{
+            boolean     isVararg = (varargsType != null) && (param >= firstVararg);
+            
+            // if this is a varargs method/constructor, then the trailing
+            // arguments must be stuffed into a single array argument
+            if ( isVararg ) { mb.getField( varargsArrayField ); }
+            
 			generateOneParameter( acb, mb, param );
 
 			// type from the SQL-J expression
 			String argumentType = getParameterTypeName( methodParms[param] );
 
-			// type of the method
-			String parameterType = expectedTypes[param];
-
+			// type of the method. check if it is a varargs method/constrctor
+			// and if we have moved on to the varargs.
+			String parameterType;
+
+            if ( isVararg )
+            { parameterType = varargsType; }
+            else { parameterType = expectedTypes[param]; }
+            
 			if (!parameterType.equals(argumentType))
 			{
 				// since we reached here through method resolution
@@ -574,9 +603,12 @@
 				}
 			}
 
+            if ( isVararg ) { mb.setArrayElement( param - firstVararg ); }
 		}
 
-		return methodParms.length;
+        if ( varargsType != null ) { mb.getField( varargsArrayField ); }
+
+		return numPushedArgs;
 	}
 
 	static	public	String	getParameterTypeName( JavaValueNode param )
@@ -1276,4 +1308,35 @@
 
 		return returnNode;
 	}
+
+	/**
+	 * Get the type name of the method/constructor's final varargs argument if
+	 * the method/constructor has a varargs signature. Returns null if the
+	 * method/constructor does not have a varargs signature.
+	 *
+	 * @exception StandardException on error
+	 */
+	private String  getVarargsType() 
+    {
+        Class   varargsTypeClass = ClassInspector.getVarargsType( method );
+
+        if ( varargsTypeClass == null ) { return null; }
+        else { return varargsTypeClass.getName(); }
+    }
+
+	/**
+	 * Get the number of compiled ResultSets added to the end of the method
+	 * signature.
+	 */
+	protected int getCompiledResultSetCount()
+	{
+        Class   varargsType = ClassInspector.getVarargsType( method );
+
+        if ( (varargsType != null) && !ResultSet.class.equals( varargsType ) ) {
return 0; }
+        
+        return methodParameterTypes.length - methodParms.length;		
+	}
+
 }
+
+

Modified: db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/StaticMethodCallNode.java
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/StaticMethodCallNode.java?rev=579653&r1=579652&r2=579653&view=diff
==============================================================================
--- db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/StaticMethodCallNode.java
(original)
+++ db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/StaticMethodCallNode.java
Wed Sep 26 06:50:42 2007
@@ -892,7 +892,7 @@
 		// add in the ResultSet arrays.
 		if (routineInfo != null) {
 
-			int compiledResultSets = methodParameterTypes.length - methodParms.length;
+			int compiledResultSets = getCompiledResultSetCount();
 
 			if (compiledResultSets != 0) {
 
@@ -939,7 +939,7 @@
 				// complete the method that returns the ResultSet[][] to the 
 				gdr.methodReturn();
 				gdr.complete();
-
+                
 				nargs += compiledResultSets;
 			}
 
@@ -950,7 +950,6 @@
 		MethodBuilder mbnc = null;
 		MethodBuilder mbcm = mb;
 
-
 		// If any of the parameters are null then
 		// do not call the method, just return null.
 		if (returnsNullOnNullState != null)
@@ -1125,4 +1124,5 @@
 	{
 		return Authorizer.EXECUTE_PRIV;
 	}
+
 }



Mime
View raw message