Преглед изворни кода

2001-10-11 Miguel de Icaza <[email protected]>

	* 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.

svn path=/trunk/mcs/; revision=1147
Miguel de Icaza пре 24 година
родитељ
комит
8dd59fa103
6 измењених фајлова са 144 додато и 20 уклоњено
  1. 17 0
      mcs/mcs/ChangeLog
  2. 5 0
      mcs/mcs/TODO
  3. 29 1
      mcs/mcs/codegen.cs
  4. 1 2
      mcs/mcs/driver.cs
  5. 46 17
      mcs/mcs/expression.cs
  6. 46 0
      mcs/tests/test-22.cs

+ 17 - 0
mcs/mcs/ChangeLog

@@ -1,3 +1,20 @@
+2001-10-11  Miguel de Icaza  <[email protected]>
+
+	* 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  <[email protected]>
 
 	* class.cs (TypeContainer::DefineType): Method to actually do the business of

+ 5 - 0
mcs/mcs/TODO

@@ -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?

+ 29 - 1
mcs/mcs/codegen.cs

@@ -8,6 +8,7 @@
 //
 
 using System;
+using System.Collections;
 using System.Reflection;
 using System.Reflection.Emit;
 
@@ -83,7 +84,6 @@ namespace CIR {
 	public class EmitContext {
 		public TypeContainer TypeContainer;
 		public ILGenerator   ig;
-		
 		public bool CheckState;
 
 		// <summary>
@@ -96,6 +96,13 @@ namespace CIR {
 		//   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)
 		{
@@ -130,5 +137,26 @@ namespace CIR {
 			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;
+		}
 	}
 }

+ 1 - 2
mcs/mcs/driver.cs

@@ -338,8 +338,7 @@ namespace CIR
 			if (errors > 0){
 				error ("Parsing failed");
 				return;
-			} else
-				notice ("Parsing successful");
+			}
 
 			//
 			// Load assemblies required

+ 46 - 17
mcs/mcs/expression.cs

@@ -3211,6 +3211,7 @@ namespace CIR {
 		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 @@ namespace CIR {
 
 			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 @@ namespace CIR {
 		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 @@ namespace CIR {
 				// 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);
 			}
 		}
 

+ 46 - 0
mcs/tests/test-22.cs

@@ -0,0 +1,46 @@
+//
+// This test excercises invocations of methods in structures.
+//
+// Unlike classes, we can not just leave the result of a computed
+// structure in the IL stack as a result.  The reason is that the
+// result is the whole structure, not a pointer to it.
+//
+// This program excercises invocations to methods on structures
+//
+
+struct T {
+	public int a, b;
+}
+
+struct S {
+	T t;
+
+	public T GetT ()
+	{
+		return t;
+	}
+
+	public void Init ()
+	{
+		t.a = 1;
+		t.b = 2;
+	}
+}
+
+class M {
+	static int Main ()
+	{
+		S s = new S ();
+
+		s.Init ();
+		
+		if (s.GetT ().a != 1)
+			return 1;
+
+		if (s.GetT ().b != 2)
+			return 2;
+
+		return 0;
+	}
+}
+