Interfaces support - initial patch.
Implementation as described in
http://www.research.ibm.com/people/d/dgrove/papers/oopsla01.pdf
ITable with 5 slots is created before TypeInfo. Conflict resolution
stubs are generated with the class code.
Index: Kernel/Tests/CS/Interface.cs
===================================================================
--- Kernel/Tests/CS/Interface.cs	(wersja 815)
+++ Kernel/Tests/CS/Interface.cs	(kopia robocza)
@@ -8,10 +8,8 @@
 //  with Classpath Linking Exception for Libraries
 //
 
-#define NO_INTERFACE_SUPPORT
 namespace SharpOS.Kernel.Tests.CS {
 	public class Interface {
-#if !NO_INTERFACE_SUPPORT
 		private interface Iface1 {
 			int GetNumber ();
 			int Get100 ();
@@ -19,6 +17,9 @@
 			{
 				get;
 			}
+			void Key1_3();
+			void Key1_4();
+			void Key2_0();
 		}
 
 		private interface Iface2 {
@@ -52,6 +53,10 @@
 			{
 				return 69;
 			}
+
+			public void Key1_3() {}
+			public void Key1_4() {}
+			public void Key2_0() {}
 		}
 
 		public static uint CMPGetProperty ()
@@ -85,11 +90,5 @@
 
 			return 0;
 		}
-#else
-		public static uint CMPImplement ()
-		{
-			return 0;
-		}
-#endif
 	}
 }
Index: Kernel/Core/Korlib/Runtime/VTable.cs
===================================================================
--- Kernel/Core/Korlib/Runtime/VTable.cs	(wersja 815)
+++ Kernel/Core/Korlib/Runtime/VTable.cs	(kopia robocza)
@@ -16,5 +16,6 @@
 	internal class VTable : InternalSystem.Object {
 		internal TypeInfo Type;
 		internal uint Size;
+		internal ITable Itable; 
 	}
 }
Index: Kernel/Core/Korlib/Runtime/ITable.cs
===================================================================
--- Kernel/Core/Korlib/Runtime/ITable.cs	(wersja 0)
+++ Kernel/Core/Korlib/Runtime/ITable.cs	(wersja 0)
@@ -0,0 +1,18 @@
+//
+// (C) 2006-2007 The SharpOS Project Team (http://www.sharpos.org)
+//
+// Authors:
+//	Stanisław Pitucha <[EMAIL PROTECTED]>
+//
+// Licensed under the terms of the GNU GPL v3,
+//  with Classpath Linking Exception for Libraries
+//
+
+using System.Runtime.InteropServices;
+
+namespace SharpOS.Korlib.Runtime {
+	[SharpOS.AOT.Attributes.ITable]
+	[StructLayout (LayoutKind.Sequential)]
+	internal class ITable : InternalSystem.Object {
+	}
+}
Index: AOT/Core/X86/Assembly.cs
===================================================================
--- AOT/Core/X86/Assembly.cs	(wersja 815)
+++ AOT/Core/X86/Assembly.cs	(kopia robocza)
@@ -4,6 +4,7 @@
 // Authors:
 //	Mircea-Cristian Racasan <[EMAIL PROTECTED]>
 //	William Lahti <[EMAIL PROTECTED]>
+//	Stanisław Pitucha <[EMAIL PROTECTED]>
 //
 // Licensed under the terms of the GNU GPL v3,
 //  with Classpath Linking Exception for Libraries
@@ -72,7 +73,11 @@
 		internal const string HELPER_LSAR = "LSAR";
 		internal const string HELPER_LMUL = "LMUL";
 
+		const string IMT_LABEL = "{0} IMTstub{1}";
+		const string IMT_RANGE_LABEL = "{0} IMTstub{1} {2}_{3}";
+
 		#region RUNTIME
+		const string ITABLE_LABEL = "{0} ITable";
 		const string VTABLE_LABEL = "{0} VTable";
 		const string TYPE_INFO_LABEL = "{0} TypeInfo";
 		#endregion
@@ -1123,6 +1128,11 @@
 			return string.Format (VTABLE_LABEL, value);
 		}
 
+		public string GetITableLabel (string value)
+		{
+			return string.Format (ITABLE_LABEL, value);
+		}
+
 		public string GetTypeInfoLabel (string value)
 		{
 			return string.Format (TYPE_INFO_LABEL, value);
@@ -1158,6 +1168,13 @@
 				if (_class.IsInternal)
 					continue;
 
+				if (_class.IsInterface) {
+					AddTypeInfoFields(_class);
+					continue;
+				}
+
+				AddITableFields (_class);
+
 				string typeInfoLabel = AddTypeInfoFields (_class);
 
 				AddVTableFields (_class, typeInfoLabel);
@@ -1309,12 +1326,43 @@
 
 			// VTable Size Field
 			this.DATA ((uint) _class.Size);
+			
+			// ITable pointer
+			this.ADDRESSOF (this.GetITableLabel(_class.TypeFullName));
 
 			// Virtual Methods
-			foreach (Method method in _class.VirtualMethods)
-				this.ADDRESSOF (method.AssemblyLabel);
+			foreach (Method method in _class.VirtualMethods) {
+				// add only non-interface methods to vtable
+				if (method.InterfaceMethodNumber == -1) {
+					this.ADDRESSOF (method.AssemblyLabel);
+				}
+			}
 		}
 
+		private void AddITableFields (Class _class)
+		{
+			this.ALIGN (OBJECT_ALIGNMENT);
+
+			// Writing the Runtime ITable instances
+			string label = this.GetITableLabel (_class.TypeFullName);
+			this.AddSymbol (new COFF.Label (label));
+			this.LABEL (label);
+
+			// Type Info Object Header
+			this.AddObjectFields (this.engine.ITableClass.TypeFullName);
+
+			for (int key = 0; key < Method.IMTSize; ++key) {
+				List<Method> m = _class.GetInterfaceEntries(key);
+				if (m == null) {
+					this.DATA((uint) 0);
+				} else if (m.Count == 1) {
+					this.ADDRESSOF (m[0].AssemblyLabel);
+				} else {
+					this.ADDRESSOF (String.Format(IMT_LABEL, _class, key));
+				}
+			}
+		}
+
 		private string AddTypeInfoFields (Class _class)
 		{
 			this.ALIGN (OBJECT_ALIGNMENT);
@@ -1385,7 +1433,55 @@
 					this.DATA (kvp.Value [x]);
 			}
 		}
+		
+		private void GenerateConflictStubPart (Class _class, int key, List<Method> methods, int rangeStart, int rangeEnd)
+		{
+			// only one element - just jump to that method
+			if (rangeStart == rangeEnd) {
+				this.JMP (methods[rangeStart].AssemblyLabel);
+			} else { // many elements - divide and generate stub parts
+				int divide = (rangeEnd - rangeStart)/2 + rangeStart;
+				string greaterBranchLabel = String.Format(IMT_RANGE_LABEL, _class, key, divide+1, rangeEnd);
 
+				this.CMP (R32.ECX, (uint)methods[divide].InterfaceMethodNumber);
+				this.JG (greaterBranchLabel);
+				// needed interface number is lower than middle element
+				GenerateConflictStubPart (_class, key, methods, rangeStart, divide);
+				this.LABEL (greaterBranchLabel);
+				// needed interface number is higher than middle element
+				GenerateConflictStubPart (_class, key, methods, divide + 1, rangeEnd);
+			}
+		}
+
+		private void GenerateConflictStub (Class _class, int key)
+		{
+			List<Method> entries = _class.GetInterfaceEntries (key);
+			entries.Sort (delegate (Method a, Method b) {
+				return Comparer<int>.Default.Compare (a.InterfaceMethodNumber, b.InterfaceMethodNumber);
+			});
+
+			string fullname = String.Format(IMT_LABEL, _class, key);
+			this.ALIGN (Assembly.ALIGNMENT);
+
+			this.AddSymbol (new COFF.Function (fullname));
+
+			this.LABEL (fullname);
+			GenerateConflictStubPart (_class, key, entries, 0, entries.Count-1);
+		}
+
+		private void GenerateIMTHelpers(Class _class) {
+			if (!_class.IsClass)
+				return;
+
+			if ((_class.ClassDefinition as TypeDefinition).Interfaces.Count > 0) {
+				for (int i = 0; i < Method.IMTSize; ++i) {
+					List<Method> entries = _class.GetInterfaceEntries (i);
+					if (entries != null && entries.Count > 1)
+						GenerateConflictStub (_class, i);
+				}
+			}
+		}
+
 		/// <summary>
 		/// Encodes the specified engine.
 		/// </summary>
@@ -1415,6 +1511,12 @@
 			this.engine.Dump.Section (DumpSection.MethodEncode);
 
 			foreach (Class _class in engine) {
+				// interfaces don't have method bodies
+				if (_class.IsInterface)
+					continue;
+				
+				GenerateIMTHelpers(_class);
+				
 				foreach (Method method in _class) {
 					this.engine.Dump.MethodEncode (method);
 
Index: AOT/Core/X86/IR.cs
===================================================================
--- AOT/Core/X86/IR.cs	(wersja 815)
+++ AOT/Core/X86/IR.cs	(kopia robocza)
@@ -3,6 +3,7 @@
 //
 // Authors:
 //	Mircea-Cristian Racasan <[EMAIL PROTECTED]>
+//	Stanisław Pitucha <[EMAIL PROTECTED]>
 //
 // Licensed under the terms of the GNU GPL v3,
 //  with Classpath Linking Exception for Libraries
@@ -60,14 +61,31 @@
 				else
 					this.assembly.MOV (R32.EAX, new DWordMemory (this.GetAddress (_this)));
 
-				int address = this.assembly.Engine.VTableSize + this.assembly.IntSize * call.Method.VirtualSlot;
+				if (call.Method.InterfaceMethodNumber == -1) {
+					// Do a normal vtable call
+					int address = this.assembly.Engine.VTableSize + this.assembly.IntSize * call.Method.VirtualSlot;
 
-				// Get the Object's VTable
-				this.assembly.MOV (R32.EAX, new DWordMemory (null, R32.EAX, null, 0));
+					// Get the Object's VTable
+					this.assembly.MOV (R32.EAX, new DWordMemory (null, R32.EAX, null, 0));
 				
-				// Call virtual method using the table in the Object's VTable
-				this.assembly.CALL (new DWordMemory (null, R32.EAX, null, 0, address));
+					// Call virtual method using the table in the Object's VTable
+					this.assembly.CALL (new DWordMemory (null, R32.EAX, null, 0, address));
+				} else {
+					// Do a IMT lookup call for interface method
+					int address = this.assembly.IntSize * (call.Method.InterfaceMethodKey + 2);
 
+					// Get the Object's VTable
+					this.assembly.MOV (R32.EAX, new DWordMemory (null, R32.EAX, null, 0));
+				
+					// Get the Object's ITable
+					this.assembly.MOV (R32.EAX, new DWordMemory (null, R32.EAX, null, 0, this.assembly.IntSize * 4));
+
+					// IMT key in case call hits a colision resolving stub
+					this.assembly.MOV (R32.ECX, (uint) call.Method.InterfaceMethodNumber);
+
+					// Call virtual method using the table in the Object's ITable
+					this.assembly.CALL (new DWordMemory (null, R32.EAX, null, 0, address));
+				}
 			} else
 				assembly.CALL (call.Method.AssemblyLabel);
 
@@ -104,7 +122,7 @@
 					break;
 
 				default:
-					throw new NotImplementedEngineException ();
+					throw new NotImplementedEngineException ("Call assignee handling.");
 				}
 			}
 		}
@@ -691,7 +709,7 @@
 				break;
 
 			default:
-				throw new NotImplementedEngineException ();
+				throw new NotImplementedEngineException ("LDC of " + assignee.InternalType + " not supported yet");
 			}
 		}
 
Index: AOT/Core/X86/AddressOf.cs
===================================================================
--- AOT/Core/X86/AddressOf.cs	(wersja 815)
+++ AOT/Core/X86/AddressOf.cs	(kopia robocza)
@@ -37,5 +37,13 @@
 				return this.addressOfLabel;
 			}
 		}
+
+		public override string Parameters
+		{
+			get
+			{
+				return string.Format ("DD 0x{0:X8} ; Address of {1}", this.value, AddressOfLabel);
+			}
+		}
 	}
 }
\ brakuje znaku końca linii na końcu pliku 
Index: AOT/Core/Attributes/ITableAttribute.cs
===================================================================
--- AOT/Core/Attributes/ITableAttribute.cs	(wersja 0)
+++ AOT/Core/Attributes/ITableAttribute.cs	(wersja 0)
@@ -0,0 +1,22 @@
+// 
+// (C) 2006-2007 The SharpOS Project Team (http://www.sharpos.org)
+//
+// Authors:
+//	Stanislaw Pitucha <[EMAIL PROTECTED]>
+//
+// Licensed under the terms of the GNU GPL v3,
+//  with Classpath Linking Exception for Libraries
+//
+
+using System;
+using System.Text;
+using SharpOS.AOT;
+
+namespace SharpOS.AOT.Attributes {
+	/// <summary>
+	/// Used to mark the class that will be used as the itable in every object.
+	/// </summary>
+	[AttributeUsage (AttributeTargets.Class)]
+	public sealed class ITableAttribute : Attribute {
+	}
+}
Index: AOT/Core/IR/Method.cs
===================================================================
--- AOT/Core/IR/Method.cs	(wersja 815)
+++ AOT/Core/IR/Method.cs	(kopia robocza)
@@ -5,6 +5,7 @@
 //	Mircea-Cristian Racasan <[EMAIL PROTECTED]>
 //	William Lahti <[EMAIL PROTECTED]>
 //	Bruce Markham <[EMAIL PROTECTED]>
+//	Stanisław Pitucha <[EMAIL PROTECTED]>
 //
 // Licensed under the terms of the GNU GPL v3,
 //  with Classpath Linking Exception for Libraries
@@ -187,6 +188,30 @@
 			this.methodDefinition = methodDefinition;
 		}
 
+		public const byte IMTSize = 5;
+
+		public void AssignInterfaceMethodNumber() {
+			if (interfaceMethodNumber != -1)
+				throw new EngineException("Interface number already assigned to " + this.MethodFullName);
+
+			interfaceMethodNumber = interfaceMethodCount;
+			interfaceMethodCount++;
+		}
+		
+		static private int interfaceMethodCount = 0;
+		private int interfaceMethodNumber = -1;
+		
+		public int InterfaceMethodNumber
+		{
+			get { return interfaceMethodNumber; }
+			set { interfaceMethodNumber = value; }
+		}
+		
+		public int InterfaceMethodKey
+		{
+			get { return interfaceMethodNumber % IMTSize; }
+		}
+
 		/// <summary>
 		/// Dumps a representation of the blocks that comprise this method
 		/// </summary>
Index: AOT/Core/IR/Class.cs
===================================================================
--- AOT/Core/IR/Class.cs	(wersja 815)
+++ AOT/Core/IR/Class.cs	(kopia robocza)
@@ -3,6 +3,7 @@
 //
 // Authors:
 //	Mircea-Cristian Racasan <[EMAIL PROTECTED]>
+//	Stanisław Pitucha <[EMAIL PROTECTED]>
 //
 // Licensed under the terms of the GNU GPL v3,
 //  with Classpath Linking Exception for Libraries
@@ -80,10 +81,15 @@
 
 						this.internalType = Operands.InternalType.O;
 					}
+					
+					if (typeDefinition.IsInterface) {
+						this.isInterface = true;
+					}
 
-					if (this.TypeFullName != Mono.Cecil.Constants.Object)
+					if (this.TypeFullName != Mono.Cecil.Constants.Object && !this.isInterface)
 						this._base = this.engine.GetClass (typeDefinition.BaseType);
 					
+					this.MarkInterfaceMethods ();
 					this.AddVirtualMethods (this.virtualMethods);
 
 				} else if (step == 1) {
@@ -99,7 +105,7 @@
 						}
 					}
 				} else
-					throw new NotImplementedEngineException ();
+					throw new NotImplementedEngineException ("Getting size of " + this);
 
 			} else if (this.classDefinition is TypeSpecification) {
 				if (step == 0) {
@@ -210,6 +216,20 @@
 			}
 		}
 
+		private bool isInterface = false;
+
+		/// <summary>
+		/// Gets a value indicating whether this instance is interface.
+		/// </summary>
+		/// <value><c>true</c> if this instance is interface; otherwise, <c>false</c>.</value>
+		public bool IsInterface
+		{
+			get
+			{
+				return isInterface;
+			}
+		}
+		
 		private bool hasExplicitLayout = false;
 
 		/// <summary>
@@ -546,7 +566,8 @@
 					}
 
 				} else if (this.IsValueType
-						|| this.IsClass) {
+						|| this.IsClass
+						|| this.IsInterface) {
 					result = this.BaseSize;
 
 					if (this.hasExplicitLayout) {
@@ -626,5 +647,50 @@
 				}
 			}
 		}
+
+		public List<Method> GetInterfaceEntries (int key) {
+			return interfaceMethodsEntries[key];
+		}
+
+		private List<Method>[] interfaceMethodsEntries = new List<Method>[Method.IMTSize];
+
+		private void AddMethodToIMT (Method method) {
+			int key = method.InterfaceMethodKey;
+	
+			if (interfaceMethodsEntries [key] == null)
+				interfaceMethodsEntries [key] = new List<Method> ();
+	
+			interfaceMethodsEntries[key].Add (method);
+		}
+		
+		/// <summary>
+		/// Marks all methods with correct IMT numbers if they are interface implementation 
+		/// </summary>
+		/// <returns></returns>
+		private void MarkInterfaceMethods ()
+		{
+			foreach (Method method in this.methods) {
+				// was implementation explicit?
+				MethodDefinition methodDef = method.MethodDefinition as MethodDefinition;
+				if (methodDef.Overrides.Count > 0) {
+					foreach (MethodReference origReference in methodDef.Overrides) {
+						Method orig = engine.GetMethod (origReference);
+						method.InterfaceMethodNumber = orig.InterfaceMethodNumber;
+						AddMethodToIMT(method);
+					}
+				} else { // was implementation implicit?
+					foreach (TypeReference iface in (this.ClassDefinition as TypeDefinition).Interfaces) {
+						Class ifaceClass = engine.GetClass (iface);
+						Method orig = ifaceClass.methods.Find (delegate (Method m) { return m.ID==method.ID; });
+						if (orig!=null) {
+							method.InterfaceMethodNumber = orig.InterfaceMethodNumber;
+							AddMethodToIMT(method);
+							break;
+						}
+					}
+				}
+				// or it's not interface method
+			}
+		}
 	}
 }
Index: AOT/Core/IR/Engine.cs
===================================================================
--- AOT/Core/IR/Engine.cs	(wersja 815)
+++ AOT/Core/IR/Engine.cs	(kopia robocza)
@@ -5,6 +5,7 @@
 //	Mircea-Cristian Racasan <[EMAIL PROTECTED]>
 //	William Lahti <[EMAIL PROTECTED]>
 //	Bruce Markham <[EMAIL PROTECTED]>
+//	Stanisław Pitucha <[EMAIL PROTECTED]>
 //
 // Licensed under the terms of the GNU GPL v3,
 //  with Classpath Linking Exception for Libraries
@@ -257,6 +258,22 @@
 			}
 		}
 
+		Class itableClass = null;
+
+		/// <summary>
+		/// Gets the Class object representing the kernel type
+		/// used to store itable information. In the SharpOS
+		/// kernel this type is SharpOS.Korlib.Runtime.ITable.
+		/// </summary>
+		/// <value>The ITable class in the kernel.</value>
+		public Class ITableClass
+		{
+			get
+			{
+				return itableClass;
+			}
+		}
+
 		Class typeInfoClass = null;
 
 		/// <summary>
@@ -907,7 +924,7 @@
 				Class _class = new Class (this, type);
 
 				if (this.classesDictionary.ContainsKey (_class.TypeFullName))
-					throw new NotImplementedEngineException ();
+					throw new NotImplementedEngineException ("Already contains " + _class.TypeFullName);
 
 				this.classes.Add (_class);
 				this.classesDictionary [_class.TypeFullName] = _class;
@@ -978,8 +995,22 @@
 							throw new EngineException ("More than one class was tagged as TypeInfo Class.");
 
 						this.typeInfoClass = _class;
+					} else if (customAttribute.Constructor.DeclaringType.FullName ==
+							typeof (SharpOS.AOT.Attributes.ITableAttribute).FullName) {
+
+						if (this.itableClass != null)
+							throw new EngineException ("More than one class was tagged as ITable Class.");
+
+						this.itableClass = _class;
 					} 
 				}
+
+				// assigning interface method uids
+				if (_class.IsInterface) {
+					foreach (Method _method in _class.VirtualMethods) {
+						_method.AssignInterfaceMethodNumber();
+					}
+				}
 			}
 
 			// 2nd Step Post Processing
-------------------------------------------------------------------------
This SF.net email is sponsored by: Microsoft
Defy all challenges. Microsoft(R) Visual Studio 2008.
http://clk.atdmt.com/MRT/go/vse0120000070mrt/direct/01/
_______________________________________________
SharpOS-Developers mailing list
SharpOS-Developers@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/sharpos-developers

Reply via email to