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