[Mono-list] Patch: support for method invocations in structures.

Miguel de Icaza miguel@ximian.com
11 Oct 2001 17:51:40 -0400


Some patches from today: 

	* Support method invocation on structures.

	* Bug fix parameter references.

Index: ChangeLog
===================================================================
RCS file: /cvs/public/mcs/mcs/ChangeLog,v
retrieving revision 1.129
diff -u -r1.129 ChangeLog
--- ChangeLog	2001/10/11 16:46:46	1.129
+++ ChangeLog	2001/10/11 17:58:16
@@ -1,3 +1,20 @@
+2001-10-11  Miguel de Icaza  <miguel@ximian.com>
+
+	* expression.cs (Invocation::Emit): Deal with invocation of
+	methods on value types.  We need to pass the address to structure
+	methods rather than the object itself.  (The equivalent code to
+	emit "this" for structures leaves the entire structure on the
+	stack instead of a pointer to it). 
+
+	(ParameterReference::DoResolve): Compute the real index for the
+	argument based on whether the method takes or not a `this' pointer
+	(ie, the method is static).
+
+	* codegen.cs (EmitContext::GetTemporaryStorage): Used to store
+	value types returned from functions when we need to invoke a
+	method on the sturcture.
+	
+
 2001-10-11  Ravi Pratap  <ravi@ximian.com>
 
 	* class.cs (TypeContainer::DefineType): Method to actually do the business of
Index: TODO
===================================================================
RCS file: /cvs/public/mcs/mcs/TODO,v
retrieving revision 1.19
diff -u -r1.19 TODO
--- TODO	2001/10/10 02:36:47	1.19
+++ TODO	2001/10/11 17:58:16
@@ -1,3 +1,8 @@
+* Optimizations
+
+	Handle if (!x) converting to remove the `!' and instead of using
+	a brfalse use a brtrue to jump to the end.
+
 * Emitcontext
 
 	Do we really need to instanciate this variable all the time?
Index: codegen.cs
===================================================================
RCS file: /cvs/public/mcs/mcs/codegen.cs,v
retrieving revision 1.33
diff -u -r1.33 codegen.cs
--- codegen.cs	2001/10/10 02:36:47	1.33
+++ codegen.cs	2001/10/11 17:58:16
@@ -8,6 +8,7 @@
 //
 
 using System;
+using System.Collections;
 using System.Reflection;
 using System.Reflection.Emit;
 
@@ -83,7 +84,6 @@
 	public class EmitContext {
 		public TypeContainer TypeContainer;
 		public ILGenerator   ig;
-		
 		public bool CheckState;
 
 		// <summary>
@@ -96,6 +96,13 @@
 		//   return type.
 		// </summary>
 		public Type ReturnType;
+
+		// <summary>
+		//   Keeps track of the Type to LocalBuilder temporary storage created
+		//   to store structures (used to compute the address of the structure
+		//   value on structure method invocations)
+		// </summary>
+		public Hashtable temporary_storage;
 		
 		public EmitContext (TypeContainer parent, ILGenerator ig, Type return_type, int code_flags)
 		{
@@ -129,6 +136,27 @@
 
 			if (!has_ret)
 				ig.Emit (OpCodes.Ret);
+		}
+
+		// <summary>
+		//   Returns a temporary storage for a variable of type t as 
+		//   a local variable in the current body.
+		// </summary>
+		public LocalBuilder GetTemporaryStorage (Type t)
+		{
+			LocalBuilder location;
+			
+			if (temporary_storage == null)
+				temporary_storage = new Hashtable ();
+
+			location = (LocalBuilder) temporary_storage [t];
+			if (location != null)
+				return location;
+
+			location = ig.DeclareLocal (t);
+			temporary_storage.Add (t, location);
+
+			return location;
 		}
 	}
 }
Index: driver.cs
===================================================================
RCS file: /cvs/public/mcs/mcs/driver.cs,v
retrieving revision 1.28
diff -u -r1.28 driver.cs
--- driver.cs	2001/10/05 21:13:47	1.28
+++ driver.cs	2001/10/11 17:58:16
@@ -338,8 +338,7 @@
 			if (errors > 0){
 				error ("Parsing failed");
 				return;
-			} else
-				notice ("Parsing successful");
+			}
 
 			//
 			// Load assemblies required
Index: expression.cs
===================================================================
RCS file: /cvs/public/mcs/mcs/expression.cs,v
retrieving revision 1.79
diff -u -r1.79 expression.cs
--- expression.cs	2001/10/11 16:46:46	1.79
+++ expression.cs	2001/10/11 17:58:16
@@ -3211,6 +3211,7 @@
 		public readonly Parameters Pars;
 		public readonly String Name;
 		public readonly int Idx;
+		int arg_idx;
 		
 		public ParameterReference (Parameters pars, int idx, string name)
 		{
@@ -3226,32 +3227,36 @@
 
 			type = types [Idx];
 
+			arg_idx = Idx;
+			if (!ec.IsStatic)
+				arg_idx++;
+			
 			return this;
 		}
 
 		public override void Emit (EmitContext ec)
 		{
-			if (Idx <= 255)
-				ec.ig.Emit (OpCodes.Ldarg_S, (byte) Idx);
+			if (arg_idx <= 255)
+				ec.ig.Emit (OpCodes.Ldarg_S, (byte) arg_idx);
 			else
-				ec.ig.Emit (OpCodes.Ldarg, Idx);
+				ec.ig.Emit (OpCodes.Ldarg, arg_idx);
 		}
 
 		public void Store (EmitContext ec)
 		{
-			if (Idx <= 255)
-				ec.ig.Emit (OpCodes.Starg_S, (byte) Idx);
+			if (arg_idx <= 255)
+				ec.ig.Emit (OpCodes.Starg_S, (byte) arg_idx);
 			else
-				ec.ig.Emit (OpCodes.Starg, Idx);
+				ec.ig.Emit (OpCodes.Starg, arg_idx);
 			
 		}
 
 		public void AddressOf (EmitContext ec)
 		{
-			if (Idx <= 255)
-				ec.ig.Emit (OpCodes.Ldarga_S, (byte) Idx);
+			if (arg_idx <= 255)
+				ec.ig.Emit (OpCodes.Ldarga_S, (byte) arg_idx);
 			else
-				ec.ig.Emit (OpCodes.Ldarga, Idx);
+				ec.ig.Emit (OpCodes.Ldarga, arg_idx);
 		}
 	}
 	
@@ -3869,7 +3874,9 @@
 		public override void Emit (EmitContext ec)
 		{
 			bool is_static = method.IsStatic;
-
+			ILGenerator ig = ec.ig;
+			bool struct_call = false;
+				
 			if (!is_static){
 				MethodGroupExpr mg = (MethodGroupExpr) this.expr;
 
@@ -3877,28 +3884,50 @@
 				// If this is ourselves, push "this"
 				//
 				if (mg.InstanceExpression == null){
-					ec.ig.Emit (OpCodes.Ldarg_0);
+					ig.Emit (OpCodes.Ldarg_0);
 				} else {
+					Expression ie = mg.InstanceExpression;
+					
 					//
 					// Push the instance expression
 					//
-					mg.InstanceExpression.Emit (ec);
+					if (ie.Type.IsSubclassOf (TypeManager.value_type)){
+
+						struct_call = true;
+
+						//
+						// If the expression is an LValue, then
+						// we can optimize and use AddressOf on the
+						// return.
+						//
+						// If not we have to use some temporary storage for
+						// it.
+						if (ie is LValue)
+							((LValue) ie).AddressOf (ec);
+						else {
+							ie.Emit (ec);
+							LocalBuilder temp = ec.GetTemporaryStorage (ie.Type);
+							ig.Emit (OpCodes.Stloc, temp);
+							ig.Emit (OpCodes.Ldloca, temp);
+						}
+					} else 
+						ie.Emit (ec);
 				}
 			}
 
 			if (Arguments != null)
 				EmitArguments (ec, method, Arguments);
 
-			if (is_static){
+			if (is_static || struct_call){
 				if (method is MethodInfo)
-					ec.ig.Emit (OpCodes.Call, (MethodInfo) method);
+					ig.Emit (OpCodes.Call, (MethodInfo) method);
 				else
-					ec.ig.Emit (OpCodes.Call, (ConstructorInfo) method);
+					ig.Emit (OpCodes.Call, (ConstructorInfo) method);
 			} else {
 				if (method is MethodInfo)
-					ec.ig.Emit (OpCodes.Callvirt, (MethodInfo) method);
+					ig.Emit (OpCodes.Callvirt, (MethodInfo) method);
 				else
-					ec.ig.Emit (OpCodes.Callvirt, (ConstructorInfo) method);
+					ig.Emit (OpCodes.Callvirt, (ConstructorInfo) method);
 			}
 		}