Browse Source

Bug fixes and a couple of optimizations (used a nice profiler to find
a few easy to fix hot spots):

2002-03-05 Miguel de Icaza <[email protected]>

* typemanager.cs (NoTypes): Move the definition for the empty Type
array here.

* class.cs (TypeContainer.FindMembers): Also look for methods defined by
properties.
(TypeContainer.DefineProxy): New function used to proxy to parent
implementations when implementing interfaces.
(TypeContainer.ParentImplements): used to lookup if our parent
implements a public function that is required by an interface.
(TypeContainer.VerifyPendingMethods): Hook this up.

* typemanager.cs (TypeManager, AddModule, AddAssembly): Make the
`modules' and `assemblies' arraylists into arrays. We only grow
these are the very early start up of the program, so this improves
the speedof LookupType (nicely measured).

svn path=/trunk/mcs/; revision=2929

Miguel de Icaza 24 years ago
parent
commit
620746bb06

+ 16 - 0
mcs/mcs/ChangeLog

@@ -1,5 +1,21 @@
 2002-03-05  Miguel de Icaza  <[email protected]>
 
+	* typemanager.cs (NoTypes): Move the definition for the empty Type
+	array here. 
+
+	* class.cs (TypeContainer.FindMembers): Also look for methods defined by
+	properties. 
+	(TypeContainer.DefineProxy): New function used to proxy to parent
+	implementations when implementing interfaces.
+	(TypeContainer.ParentImplements): used to lookup if our parent
+	implements a public function that is required by an interface.
+	(TypeContainer.VerifyPendingMethods): Hook this up.
+
+	* typemanager.cs (TypeManager, AddModule, AddAssembly): Make the
+	`modules' and `assemblies' arraylists into arrays.  We only grow
+	these are the very early start up of the program, so this improves
+	the speedof LookupType (nicely measured).
+
 	* expression.cs (MakeByteBlob): Replaced unsafe code with
 	BitConverter, as suggested by Paolo.
 

+ 94 - 5
mcs/mcs/class.cs

@@ -1301,6 +1301,20 @@ namespace Mono.CSharp {
 							members.Add (ob);
 					}
 				}
+
+				if (properties != null){
+					foreach (Property p in properties){
+						MethodBuilder b;
+
+						b = p.GetBuilder;
+						if (b != null && filter (b, criteria) == true)
+							members.Add (b);
+
+						b = p.SetBuilder;
+						if (b != null && filter (b, criteria) == true)
+							members.Add (b);
+					}
+				}
 			}
 
 			if ((mt & MemberTypes.Event) != 0) {
@@ -1505,6 +1519,75 @@ namespace Mono.CSharp {
 			return null;
 		}
 
+		/// <summary>
+		///   C# allows this kind of scenarios:
+		///   interface I { void M (); }
+		///   class X { public void M (); }
+		///   class Y : X, I { }
+		///
+		///   For that case, we create an explicit implementation function
+		///   I.M in Y.
+		/// </summary>
+		void DefineProxy (Type iface, MethodInfo parent_method, MethodInfo iface_method,
+				  Type [] args)
+		{
+			MethodBuilder proxy;
+
+			string proxy_name = iface.Name + "." + iface_method.Name;
+
+			proxy = TypeBuilder.DefineMethod (
+				proxy_name,
+				MethodAttributes.HideBySig |
+				MethodAttributes.NewSlot |
+				MethodAttributes.Virtual,
+				CallingConventions.Standard | CallingConventions.HasThis,
+				parent_method.ReturnType, args);
+
+			int top = args.Length;
+			ILGenerator ig = proxy.GetILGenerator ();
+
+			ig.Emit (OpCodes.Ldarg_0);
+			for (int i = 0; i < top; i++){
+				switch (i){
+				case 0:
+					ig.Emit (OpCodes.Ldarg_1); break;
+				case 1:
+					ig.Emit (OpCodes.Ldarg_2); break;
+				case 2:
+					ig.Emit (OpCodes.Ldarg_3); break;
+				default:
+					ig.Emit (OpCodes.Ldarg, i - 1); break;
+				}
+			}
+			ig.Emit (OpCodes.Call, parent_method);
+			ig.Emit (OpCodes.Ret);
+
+			TypeBuilder.DefineMethodOverride (proxy, iface_method);
+		}
+		
+		/// <summary>
+		///   This function tells whether one of our parent classes implements
+		///   the given method (which turns out, it is valid to have an interface
+		///   implementation in a parent
+		/// </summary>
+		bool ParentImplements (Type iface_type, MethodInfo mi)
+		{
+			MethodSignature ms;
+			
+			Type [] args = TypeManager.GetArgumentTypes (mi);
+			ms = new MethodSignature (mi.Name, mi.ReturnType, args);
+			MemberInfo [] list = FindMembers (
+				TypeBuilder.BaseType, MemberTypes.Method | MemberTypes.Property,
+				BindingFlags.Public | BindingFlags.Instance,
+				Method.method_signature_filter, ms);
+
+			if (list == null)
+				return false;
+			
+			DefineProxy (iface_type, (MethodInfo) list [0], mi, args);
+			return true;
+		}
+		
 		/// <summary>
 		///   Verifies that any pending abstract methods or interface methods
 		///   were implemented.
@@ -1524,6 +1607,9 @@ namespace Mono.CSharp {
 						continue;
 
 					if (type.IsInterface){
+						if (ParentImplements (type, mi))
+							continue;
+ 
 						string extra = "";
 						
 						if (pending_implementations [i].found [j])
@@ -1905,11 +1991,10 @@ namespace Mono.CSharp {
 		//  Returns the System.Type array for the parameters of this method
 		//
 		Type [] parameter_types;
-		static Type [] no_types = new Type [0];
 		public Type [] ParameterTypes (TypeContainer parent)
 		{
 			if (Parameters == null)
-				return no_types;
+				return TypeManager.NoTypes;
 			
 			if (parameter_types == null)
 				parameter_types = Parameters.GetParameterInfo (parent);
@@ -2080,7 +2165,7 @@ namespace Mono.CSharp {
 		///    This delegate is used to extract methods which have the
 		///    same signature as the argument
 		/// </summary>
-		static MemberFilter method_signature_filter;
+		public static MemberFilter method_signature_filter;
 		
 		static Method ()
 		{
@@ -2742,7 +2827,7 @@ namespace Mono.CSharp {
 		public Block           Get, Set;
 		public PropertyBuilder PropertyBuilder;
 		public Attributes OptAttributes;
-		MethodBuilder GetBuilder, SetBuilder;
+		public MethodBuilder GetBuilder, SetBuilder;
 
 		//
 		// The type, once we compute it.
@@ -3927,7 +4012,11 @@ namespace Mono.CSharp {
 		{
 			Name = name;
 			RetType = ret_type;
-			Parameters = parameters;
+
+			if (parameters == null)
+				Parameters = TypeManager.NoTypes;
+			else
+				Parameters = parameters;
 		}
 		
 		public override int GetHashCode ()

+ 6 - 1
mcs/mcs/compiler.csproj

@@ -21,7 +21,7 @@
             >
                 <Config
                     Name = "Debug"
-                    AllowUnsafeBlocks = "true"
+                    AllowUnsafeBlocks = "false"
                     BaseAddress = "285212672"
                     CheckForOverflowUnderflow = "false"
                     ConfigurationOverrideFile = ""
@@ -87,6 +87,11 @@
                     SubType = "Code"
                     BuildAction = "Compile"
                 />
+                <File
+                    RelPath = "cfold.cs"
+                    SubType = "Code"
+                    BuildAction = "Compile"
+                />
                 <File
                     RelPath = "class.cs"
                     SubType = "Code"

+ 14 - 6
mcs/mcs/constant.cs

@@ -17,12 +17,6 @@ namespace Mono.CSharp {
 	///   Base class for constants and literals.
 	/// </summary>
 	public abstract class Constant : Expression {
-
-		protected Constant ()
-		{
-			eclass = ExprClass.Value;
-		}
-
 		/// <remarks>
 		///   This is different from ToString in that ToString
 		///   is supposed to be there for debugging purposes,
@@ -160,6 +154,7 @@ namespace Mono.CSharp {
 		public BoolConstant (bool val)
 		{
 			type = TypeManager.bool_type;
+			eclass = ExprClass.Value;
 
 			Value = val;
 		}
@@ -190,6 +185,7 @@ namespace Mono.CSharp {
 		public ByteConstant (byte v)
 		{
 			type = TypeManager.byte_type;
+			eclass = ExprClass.Value;
 			Value = v;
 		}
 
@@ -245,6 +241,7 @@ namespace Mono.CSharp {
 		public CharConstant (char v)
 		{
 			type = TypeManager.char_type;
+			eclass = ExprClass.Value;
 			Value = v;
 		}
 
@@ -329,6 +326,7 @@ namespace Mono.CSharp {
 		public SByteConstant (sbyte v)
 		{
 			type = TypeManager.sbyte_type;
+			eclass = ExprClass.Value;
 			Value = v;
 		}
 
@@ -387,6 +385,7 @@ namespace Mono.CSharp {
 		public ShortConstant (short v)
 		{
 			type = TypeManager.short_type;
+			eclass = ExprClass.Value;
 			Value = v;
 		}
 
@@ -442,6 +441,7 @@ namespace Mono.CSharp {
 		public UShortConstant (ushort v)
 		{
 			type = TypeManager.ushort_type;
+			eclass = ExprClass.Value;
 			Value = v;
 		}
 
@@ -497,6 +497,7 @@ namespace Mono.CSharp {
 		public IntConstant (int v)
 		{
 			type = TypeManager.int32_type;
+			eclass = ExprClass.Value;
 			Value = v;
 		}
 
@@ -610,6 +611,7 @@ namespace Mono.CSharp {
 		public UIntConstant (uint v)
 		{
 			type = TypeManager.uint32_type;
+			eclass = ExprClass.Value;
 			Value = v;
 		}
 
@@ -665,6 +667,7 @@ namespace Mono.CSharp {
 		public LongConstant (long v)
 		{
 			type = TypeManager.int64_type;
+			eclass = ExprClass.Value;
 			Value = v;
 		}
 
@@ -730,6 +733,7 @@ namespace Mono.CSharp {
 		public ULongConstant (ulong v)
 		{
 			type = TypeManager.uint64_type;
+			eclass = ExprClass.Value;
 			Value = v;
 		}
 
@@ -787,6 +791,7 @@ namespace Mono.CSharp {
 		public FloatConstant (float v)
 		{
 			type = TypeManager.float_type;
+			eclass = ExprClass.Value;
 			Value = v;
 		}
 
@@ -837,6 +842,7 @@ namespace Mono.CSharp {
 		public DoubleConstant (double v)
 		{
 			type = TypeManager.double_type;
+			eclass = ExprClass.Value;
 			Value = v;
 		}
 
@@ -892,6 +898,7 @@ namespace Mono.CSharp {
 		public DecimalConstant (decimal d)
 		{
 			type = TypeManager.decimal_type;
+			eclass = ExprClass.Value;
 			Value = d;
 		}
 
@@ -917,6 +924,7 @@ namespace Mono.CSharp {
 		public StringConstant (string s)
 		{
 			type = TypeManager.string_type;
+			eclass = ExprClass.Value;
 			Value = s;
 		}
 

+ 1 - 1
mcs/mcs/cs-tokenizer.cs

@@ -1287,7 +1287,7 @@ namespace Mono.CSharp
 			val = null;
 			// optimization: eliminate col and implement #directive semantic correctly.
 			for (;(c = getChar ()) != -1; col++) {
-				if (is_identifier_start_character ((char) c)){
+				if (Char.IsLetter ((char)c) || c == '_'){
 					System.Text.StringBuilder id = new System.Text.StringBuilder ();
 					string ids;
 

+ 1 - 0
mcs/mcs/literal.cs

@@ -36,6 +36,7 @@ namespace Mono.CSharp {
 		{
 			if (Null != null)
 				throw new Exception ("More than one null has been created!");
+			eclass = ExprClass.Value;
 		}
 		
 		override public string AsString ()

+ 24 - 6
mcs/mcs/typemanager.cs

@@ -60,6 +60,8 @@ public class TypeManager {
 	static public Type methodimpl_attr_type;
 	static public Type param_array_type;
 	static public Type void_ptr_type;
+
+	static public Type [] NoTypes;
 	
 	//
 	// Internal, not really used outside
@@ -94,13 +96,13 @@ public class TypeManager {
 	//   (either because it is the default or the user used the
 	//   -r command line option)
 	// </remarks>
-	ArrayList assemblies;
+	Assembly [] assemblies;
 
 	// <remarks>
 	//  Keeps a list of module builders. We used this to do lookups
 	//  on the modulebuilder using GetType -- needed for arrays
 	// </remarks>
-	ArrayList modules;
+	ModuleBuilder [] modules;
 
 	// <remarks>
 	//   This is the type_cache from the assemblies to avoid
@@ -159,8 +161,8 @@ public class TypeManager {
 
 	public TypeManager ()
 	{
-		assemblies = new ArrayList ();
-		modules = new ArrayList ();
+		assemblies = null;
+		modules = null;
 		user_types = new ArrayList ();
 		types = new Hashtable ();
 		typecontainers = new Hashtable ();
@@ -176,6 +178,7 @@ public class TypeManager {
 		method_internal_params = new PtrHashtable ();
 		builder_to_container = new PtrHashtable ();
 		type_interface_cache = new PtrHashtable ();
+		NoTypes = new Type [0];
 	}
 
 	public void AddUserType (string name, TypeBuilder t)
@@ -248,7 +251,13 @@ public class TypeManager {
 	/// </summary>
 	public void AddAssembly (Assembly a)
 	{
-		assemblies.Add (a);
+		int top = assemblies != null ? assemblies.Length : 0;
+		Assembly [] n = new Assembly [top + 1];
+
+		if (assemblies != null)
+			assemblies.CopyTo (n, 0);
+		n [top] = a;
+		assemblies = n;
 	}
 
 	/// <summary>
@@ -256,7 +265,13 @@ public class TypeManager {
 	/// </summary>
 	public void AddModule (ModuleBuilder mb)
 	{
-		modules.Add (mb);
+		int top = modules != null ? modules.Length : 0;
+		ModuleBuilder [] n = new ModuleBuilder [top + 1];
+
+		if (modules != null)
+			modules.CopyTo (n, 0);
+		n [top] = mb;
+		modules = n;
 	}
 
 	/// <summary>
@@ -650,6 +665,9 @@ public class TypeManager {
 	/// </remarks>
 	static public bool RegisterMethod (MethodBase mb, InternalParameters ip, Type [] args)
 	{
+		if (args == null)
+			args = NoTypes;
+				
 		method_arguments.Add (mb, args);
 		method_internal_params.Add (mb, ip);
 		

+ 1 - 1
mcs/tests/makefile

@@ -11,7 +11,7 @@ TEST_SOURCES = \
 	test-41 test-42 test-43 test-44 test-45 test-46 test-47 test-48 test-49 test-50 \
 	test-51 test-52	test-53 test-54 test-55 test-56 test-57		test-59 	\
 	test-61	test-62 test-63	test-64 test-65 test-66 test-67 test-68 test-69 test-70	\
-	test-71 test-72 test-73 test-74 test-75		test-77 test-78 test-79
+	test-71 test-72 test-73 test-74 test-75		test-77 test-78 test-79 test-80
 
 UNSAFE_SOURCES = \
 	unsafe-1 unsafe-2

+ 32 - 0
mcs/tests/test-80.cs

@@ -0,0 +1,32 @@
+//
+// This test is used to check that we can actually use implementations
+// provided in our parent to interfaces declared afterwards.
+//
+
+using System;
+
+public interface A {
+ 	int Add (int a, int b);
+}
+
+public class X {
+	public int Add (int a, int b)
+	{
+		return a + b;
+	}
+}
+
+class Y : X, A {
+
+	static int Main ()
+	{
+		Y y = new Y ();
+		
+		if (y.Add (1, 1) != 2)
+			return 1;
+
+		Console.WriteLine ("parent interface implementation test passes");
+		return 0;
+	}
+	
+}