From 03b76e1ca9fda3737f5fcf8d572980b6e5f051a9 Mon Sep 17 00:00:00 2001 From: Manodasan Wignarajah Date: Fri, 11 Feb 2022 00:58:07 -0800 Subject: [PATCH 1/8] Experiment with removing Expression.Lamda --- src/WinRT.Runtime/ComWrappersSupport.cs | 8 ++- src/WinRT.Runtime/ComWrappersSupport.net5.cs | 58 ++++++++----------- .../Projections/IDictionary.net5.cs | 4 +- .../Projections/IEnumerable.net5.cs | 2 + src/WinRT.Runtime/Projections/IList.net5.cs | 4 +- .../Projections/IReadOnlyDictionary.net5.cs | 4 +- .../Projections/IReadOnlyList.net5.cs | 11 +++- 7 files changed, 50 insertions(+), 41 deletions(-) diff --git a/src/WinRT.Runtime/ComWrappersSupport.cs b/src/WinRT.Runtime/ComWrappersSupport.cs index 138feb00a..674154584 100644 --- a/src/WinRT.Runtime/ComWrappersSupport.cs +++ b/src/WinRT.Runtime/ComWrappersSupport.cs @@ -357,9 +357,11 @@ private static Func CreateCustomTypeMappingFactory(Type cu throw new MissingMethodException(); } - var parms = new[] { Expression.Parameter(typeof(IInspectable), "obj") }; - return Expression.Lambda>( - Expression.Call(fromAbiMethod, Expression.Property(parms[0], "ThisPtr")), parms).Compile(); + var fromAbiMethodFunc = (Func) fromAbiMethod.CreateDelegate(typeof(Func)); + return (IInspectable obj) => fromAbiMethodFunc(obj.ThisPtr); + // var parms = new[] { Expression.Parameter(typeof(IInspectable), "obj") }; + // return Expression.Lambda>( + // Expression.Call(fromAbiMethod, Expression.Property(parms[0], "ThisPtr")), parms).Compile(); } internal static Func CreateTypedRcwFactory(Type implementationType, string runtimeClassName = null) diff --git a/src/WinRT.Runtime/ComWrappersSupport.net5.cs b/src/WinRT.Runtime/ComWrappersSupport.net5.cs index 33e2ba119..06a2f5263 100644 --- a/src/WinRT.Runtime/ComWrappersSupport.net5.cs +++ b/src/WinRT.Runtime/ComWrappersSupport.net5.cs @@ -221,56 +221,46 @@ public static void InitializeComWrappers(ComWrappers wrappers = null) private static Func CreateFactoryForImplementationType(string runtimeClassName, Type implementationType) { - ParameterExpression[] parms = new[] { Expression.Parameter(typeof(IInspectable), "inspectable") }; - if (implementationType.IsGenericType) { var genericType = implementationType.GetGenericTypeDefinition(); + + Type genericImplType = null; if (genericType == typeof(IList<>)) { - return Expression.Lambda>( - Expression.New(typeof(IListImpl<>).MakeGenericType(new[] { implementationType.GetGenericArguments()[0] }).GetConstructor(BindingFlags.NonPublic | BindingFlags.CreateInstance | BindingFlags.Instance, null, new[] { typeof(IObjectReference) }, null), - Expression.Property(parms[0], nameof(WinRT.IInspectable.ObjRef))), - parms).Compile(); + genericImplType = typeof(IListImpl<>); } - if (genericType == typeof(IDictionary<,>)) + else if (genericType == typeof(IDictionary<,>)) { - return Expression.Lambda>( - Expression.New(typeof(IDictionaryImpl<,>).MakeGenericType(new[] { implementationType.GetGenericArguments()[0], implementationType.GetGenericArguments()[1] }).GetConstructor(BindingFlags.NonPublic | BindingFlags.CreateInstance | BindingFlags.Instance, null, new[] { typeof(IObjectReference) }, null), - Expression.Property(parms[0], nameof(WinRT.IInspectable.ObjRef))), - parms).Compile(); + genericImplType = typeof(IDictionaryImpl<,>); } - if (genericType == typeof(IReadOnlyDictionary<,>)) + else if (genericType == typeof(IReadOnlyDictionary<,>)) { - return Expression.Lambda>( - Expression.New(typeof(IReadOnlyDictionaryImpl<,>).MakeGenericType(new[] { implementationType.GetGenericArguments()[0], implementationType.GetGenericArguments()[1] }).GetConstructor(BindingFlags.NonPublic | BindingFlags.CreateInstance | BindingFlags.Instance, null, new[] { typeof(IObjectReference) }, null), - Expression.Property(parms[0], nameof(WinRT.IInspectable.ObjRef))), - parms).Compile(); + genericImplType = typeof(IReadOnlyDictionaryImpl<,>); } - if (genericType == typeof(IReadOnlyList<>)) + else if (genericType == typeof(IReadOnlyList<>)) { - return Expression.Lambda>( - Expression.New(typeof(IReadOnlyListImpl<>).MakeGenericType(new[] { implementationType.GetGenericArguments()[0] }).GetConstructor(BindingFlags.NonPublic | BindingFlags.CreateInstance | BindingFlags.Instance, null, new[] { typeof(IObjectReference) }, null), - Expression.Property(parms[0], nameof(WinRT.IInspectable.ObjRef))), - parms).Compile(); - } - if (genericType == typeof(IEnumerable<>)) + genericImplType = typeof(IReadOnlyListImpl<>); + } + else if (genericType == typeof(IEnumerable<>)) { - return Expression.Lambda>( - Expression.New(typeof(IEnumerableImpl<>).MakeGenericType(new[] { implementationType.GetGenericArguments()[0] }).GetConstructor(BindingFlags.NonPublic | BindingFlags.CreateInstance | BindingFlags.Instance, null, new[] { typeof(IObjectReference) }, null), - Expression.Property(parms[0], nameof(WinRT.IInspectable.ObjRef))), - parms).Compile(); - } + genericImplType = typeof(IEnumerableImpl<>); + } + + if (genericImplType != null) + { + var createRcw = genericImplType.MakeGenericType(implementationType.GetGenericArguments()).GetMethod("CreateRcw", BindingFlags.Public | BindingFlags.Static, null, new[] { typeof(IInspectable) }, null); + return (Func)createRcw.CreateDelegate(typeof(Func)); + } } + if (implementationType.IsInterface) { return obj => obj; - } - - return Expression.Lambda>( - Expression.New(implementationType.GetConstructor(BindingFlags.NonPublic | BindingFlags.CreateInstance | BindingFlags.Instance, null, new[] { typeof(IObjectReference) }, null), - Expression.Property(parms[0], nameof(WinRT.IInspectable.ObjRef))), - parms).Compile(); + } + + var constructor = implementationType.GetConstructor(BindingFlags.NonPublic | BindingFlags.CreateInstance | BindingFlags.Instance, null, new[] { typeof(IObjectReference) }, null); + return (IInspectable obj) => constructor.Invoke(new[] { obj.ObjRef }); } } diff --git a/src/WinRT.Runtime/Projections/IDictionary.net5.cs b/src/WinRT.Runtime/Projections/IDictionary.net5.cs index a7b2d300d..c8c33011f 100644 --- a/src/WinRT.Runtime/Projections/IDictionary.net5.cs +++ b/src/WinRT.Runtime/Projections/IDictionary.net5.cs @@ -44,7 +44,9 @@ internal IDictionaryImpl(IObjectReference _inner) { this._inner = _inner; this._lookupCache = new Dictionary(); - } + } + + public static IDictionaryImpl CreateRcw(IInspectable obj) => new(obj.ObjRef); private volatile IObjectReference __iDictionaryObjRef; private IObjectReference Make_IDictionaryObjRef() diff --git a/src/WinRT.Runtime/Projections/IEnumerable.net5.cs b/src/WinRT.Runtime/Projections/IEnumerable.net5.cs index 48a84c8af..11eebe83d 100644 --- a/src/WinRT.Runtime/Projections/IEnumerable.net5.cs +++ b/src/WinRT.Runtime/Projections/IEnumerable.net5.cs @@ -74,6 +74,8 @@ internal IEnumerableImpl(IObjectReference _inner) this._inner = _inner; } + public static IEnumerableImpl CreateRcw(IInspectable obj) => new(obj.ObjRef); + private volatile IObjectReference __iEnumerableObjRef; private IObjectReference Make_IEnumerableObjRef() { diff --git a/src/WinRT.Runtime/Projections/IList.net5.cs b/src/WinRT.Runtime/Projections/IList.net5.cs index a989accb5..acaa95655 100644 --- a/src/WinRT.Runtime/Projections/IList.net5.cs +++ b/src/WinRT.Runtime/Projections/IList.net5.cs @@ -62,7 +62,9 @@ private IObjectReference Make_IEnumerableObjRef() internal IListImpl(IObjectReference _inner) { this._inner = _inner; - } + } + + public static IListImpl CreateRcw(IInspectable obj) => new(obj.ObjRef); public T this[int index] { diff --git a/src/WinRT.Runtime/Projections/IReadOnlyDictionary.net5.cs b/src/WinRT.Runtime/Projections/IReadOnlyDictionary.net5.cs index f2d7eddbb..672c692bf 100644 --- a/src/WinRT.Runtime/Projections/IReadOnlyDictionary.net5.cs +++ b/src/WinRT.Runtime/Projections/IReadOnlyDictionary.net5.cs @@ -37,7 +37,9 @@ internal sealed class IReadOnlyDictionaryImpl : IReadOnlyDictionary, internal IReadOnlyDictionaryImpl(IObjectReference _inner) { this._inner = _inner; - } + } + + public static IReadOnlyDictionaryImpl CreateRcw(IInspectable obj) => new(obj.ObjRef); private volatile IObjectReference __iReadOnlyDictionaryObjRef; private IObjectReference Make_IDictionaryObjRef() diff --git a/src/WinRT.Runtime/Projections/IReadOnlyList.net5.cs b/src/WinRT.Runtime/Projections/IReadOnlyList.net5.cs index 8bfb99245..596d0198e 100644 --- a/src/WinRT.Runtime/Projections/IReadOnlyList.net5.cs +++ b/src/WinRT.Runtime/Projections/IReadOnlyList.net5.cs @@ -50,7 +50,9 @@ private IObjectReference Make_IEnumerableObjRef() internal IReadOnlyListImpl(IObjectReference _inner) { this._inner = _inner; - } + } + + public static IReadOnlyListImpl CreateRcw(IInspectable obj) => new(obj.ObjRef); IObjectReference IWinRTObject.NativeObject => _inner; @@ -332,6 +334,7 @@ public unsafe struct Vftbl public static Guid PIID = GuidGenerator.CreateIID(typeof(IReadOnlyList)); private static readonly Type GetAt_0_Type = Expression.GetDelegateType(new Type[] { typeof(void*), typeof(uint), Marshaler.AbiType.MakeByRefType(), typeof(int) }); private static readonly Type IndexOf_2_Type = Expression.GetDelegateType(new Type[] { typeof(void*), Marshaler.AbiType, typeof(uint).MakeByRefType(), typeof(byte).MakeByRefType(), typeof(int) }); +// private static readonly Type GetAt_0_Type2 = typeof(IReadOnlyList_Delegates<>).MakeGenericType(Marshaler.AbiType).GetMethod("GetAt_0"); internal unsafe Vftbl(IntPtr thisPtr) : this() { @@ -504,5 +507,11 @@ public static ObjectReference ObjRefFromAbi(IntPtr thisPtr) static class IReadOnlyList_Delegates { public unsafe delegate int GetMany_3(IntPtr thisPtr, uint startIndex, int __itemsSize, IntPtr items, out uint __return_value__); + } + + internal static class IReadOnlyList_Delegates + { + public unsafe delegate int GetAt_0(IntPtr thisPtr, uint index, out TAbi __return_value__); + public unsafe delegate int IndexOf_2(IntPtr thisPtr, TAbi value, out uint index, out byte __return_value__); } } From 3223dbab00f8fc7687ffa4d61f39e37e50569698 Mon Sep 17 00:00:00 2001 From: Manodasan Wignarajah Date: Tue, 15 Feb 2022 02:42:46 -0800 Subject: [PATCH 2/8] Remove uses of Linq expressions to improve performance --- src/WinRT.Runtime/ComWrappersSupport.cs | 56 +++++-------- src/WinRT.Runtime/Marshalers.cs | 83 +++++-------------- .../Projections/Bindable.net5.cs | 4 +- .../Projections/IReadOnlyList.net5.cs | 7 -- .../Projections/IReferenceArray.net5.cs | 22 ++++- .../IReferenceArray.netstandard2.0.cs | 6 ++ 6 files changed, 69 insertions(+), 109 deletions(-) diff --git a/src/WinRT.Runtime/ComWrappersSupport.cs b/src/WinRT.Runtime/ComWrappersSupport.cs index 674154584..ae7b3cb00 100644 --- a/src/WinRT.Runtime/ComWrappersSupport.cs +++ b/src/WinRT.Runtime/ComWrappersSupport.cs @@ -260,7 +260,7 @@ internal static (InspectableInfo inspectableInfo, List interf } if (type.FullName.StartsWith("ABI.", StringComparison.Ordinal)) - { + { type = Projections.FindCustomPublicTypeForAbiType(type) ?? type.Assembly.GetType(type.FullName.Substring("ABI.".Length)) ?? type; } @@ -280,59 +280,44 @@ private static bool IsAbiNullableDelegate(Type implementationType) } private static bool IsIReferenceArray(Type implementationType) - { - return implementationType.FullName.StartsWith("Windows.Foundation.IReferenceArray`1", StringComparison.Ordinal); + { + return implementationType.IsGenericType && implementationType.GetGenericTypeDefinition() == typeof(Windows.Foundation.IReferenceArray<>); } private static Func CreateKeyValuePairFactory(Type type) { - var parms = new[] { Expression.Parameter(typeof(IInspectable), "obj") }; - return Expression.Lambda>( - Expression.Call(type.GetHelperType().GetMethod("CreateRcw", BindingFlags.Public | BindingFlags.Static), - parms), parms).Compile(); + var createRcwFunc = (Func) type.GetHelperType().GetMethod("CreateRcw", BindingFlags.Public | BindingFlags.Static). + CreateDelegate(typeof(Func)); + return createRcwFunc; } internal static Func CreateDelegateFactory(Type type) { return DelegateFactoryCache.GetOrAdd(type, (type) => { - var parms = new[] { Expression.Parameter(typeof(IntPtr), "ptr") }; - return Expression.Lambda>( - Expression.Call(type.GetHelperType().GetMethod("CreateRcw", BindingFlags.Public | BindingFlags.Static), - parms), parms).Compile(); + var createRcwFunc = (Func)type.GetHelperType().GetMethod("CreateRcw", BindingFlags.Public | BindingFlags.Static). + CreateDelegate(typeof(Func)); + return createRcwFunc; }); } private static Func CreateNullableTFactory(Type implementationType) - { - Type helperType = implementationType.GetHelperType(); - - ParameterExpression[] parms = new[] { Expression.Parameter(typeof(IInspectable), "inspectable") }; - return Expression.Lambda>( - Expression.Convert(Expression.Call(helperType.GetMethod("GetValue", BindingFlags.Static | BindingFlags.NonPublic), - parms), typeof(object)), parms).Compile(); + { + var getValueMethod = implementationType.GetHelperType().GetMethod("GetValue", BindingFlags.Static | BindingFlags.NonPublic); + return (IInspectable obj) => getValueMethod.Invoke(null, new[] { obj }); } private static Func CreateAbiNullableTFactory(Type implementationType) - { - ParameterExpression[] parms = new[] { Expression.Parameter(typeof(IInspectable), "inspectable") }; - return Expression.Lambda>( - Expression.Convert(Expression.Call(implementationType.GetMethod("GetValue", BindingFlags.Static | BindingFlags.NonPublic), - parms), typeof(object)), parms).Compile(); + { + var getValueMethod = implementationType.GetMethod("GetValue", BindingFlags.Static | BindingFlags.NonPublic); + return (IInspectable obj) => getValueMethod.Invoke(null, new[] { obj }); } private static Func CreateArrayFactory(Type implementationType) - { - Type helperType = implementationType.GetHelperType(); - Type vftblType = helperType.FindVftblType(); - - ParameterExpression[] parms = new[] { Expression.Parameter(typeof(IInspectable), "inspectable") }; - var createInterfaceInstanceExpression = Expression.New(helperType.GetConstructor(new[] { typeof(ObjectReference<>).MakeGenericType(vftblType) }), - Expression.Call(parms[0], - typeof(IInspectable).GetMethod(nameof(IInspectable.As)).MakeGenericMethod(vftblType))); - - return Expression.Lambda>( - Expression.Property(createInterfaceInstanceExpression, "Value"), parms).Compile(); + { + var getValueFunc = (Func)implementationType.GetHelperType().GetMethod("GetValue", BindingFlags.Static | BindingFlags.NonPublic). + CreateDelegate(typeof(Func)); + return getValueFunc; } // This is used to hold the reference to the native value type object (IReference) until the actual value in it (boxed as an object) gets cleaned up by GC @@ -359,9 +344,6 @@ private static Func CreateCustomTypeMappingFactory(Type cu var fromAbiMethodFunc = (Func) fromAbiMethod.CreateDelegate(typeof(Func)); return (IInspectable obj) => fromAbiMethodFunc(obj.ThisPtr); - // var parms = new[] { Expression.Parameter(typeof(IInspectable), "obj") }; - // return Expression.Lambda>( - // Expression.Call(fromAbiMethod, Expression.Property(parms[0], "ThisPtr")), parms).Compile(); } internal static Func CreateTypedRcwFactory(Type implementationType, string runtimeClassName = null) diff --git a/src/WinRT.Runtime/Marshalers.cs b/src/WinRT.Runtime/Marshalers.cs index 122238718..bc307afde 100644 --- a/src/WinRT.Runtime/Marshalers.cs +++ b/src/WinRT.Runtime/Marshalers.cs @@ -441,27 +441,21 @@ class MarshalGeneric protected static readonly Type HelperType = typeof(T).GetHelperType(); protected static readonly Type AbiType = typeof(T).GetAbiType(); protected static readonly Type MarshalerType = typeof(T).GetMarshalerType(); - internal static readonly Type MarshalerArrayType = typeof(T).GetMarshalerArrayType(); public static readonly Func CreateMarshaler = (T value) => CreateMarshalerLazy.Value(value); private static readonly Lazy> CreateMarshalerLazy = new(BindCreateMarshaler); private static Func BindCreateMarshaler() { - var parms = new[] { Expression.Parameter(typeof(T), "arg") }; - return Expression.Lambda>( - Expression.Convert(Expression.Call(HelperType.GetMethod("CreateMarshaler", BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static), parms), - typeof(object)), parms).Compile(); + var createMarshaler = HelperType.GetMethod("CreateMarshaler", BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static); + return (T arg) => createMarshaler.Invoke(null, new object[] { arg }); } public static readonly Func GetAbi = (object objRef) => GetAbiLazy.Value(objRef); private static readonly Lazy> GetAbiLazy = new(BindGetAbi); private static Func BindGetAbi() { - var parms = new[] { Expression.Parameter(typeof(object), "arg") }; - return Expression.Lambda>( - Expression.Convert(Expression.Call(HelperType.GetMethod("GetAbi", BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static), - new[] { Expression.Convert(parms[0], MarshalerType) }), - typeof(object)), parms).Compile(); + var getAbi = HelperType.GetMethod("GetAbi", BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static); + return (object arg) => getAbi.Invoke(null, new[] { arg }); } public static readonly Action CopyAbi = (object box, IntPtr dest) => CopyAbiLazy.Value(box, dest); @@ -470,30 +464,23 @@ private static Action BindCopyAbi() { var copyAbi = HelperType.GetMethod("CopyAbi", BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static); if (copyAbi == null) return null; - var parms = new[] { Expression.Parameter(typeof(object), "arg"), Expression.Parameter(typeof(IntPtr), "dest") }; - return Expression.Lambda>( - Expression.Call(copyAbi, - new Expression[] { Expression.Convert(parms[0], MarshalerType), parms[1] }), parms).Compile(); + return (object arg, IntPtr dest) => copyAbi.Invoke(null, new[] { arg, dest }); } public static readonly Func FromAbi = (object box) => FromAbiLazy.Value(box); private static readonly Lazy> FromAbiLazy = new(BindFromAbi); private static Func BindFromAbi() { - var parms = new[] { Expression.Parameter(typeof(object), "arg") }; - return Expression.Lambda>( - Expression.Call(HelperType.GetMethod("FromAbi", BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static), - new[] { Expression.Convert(parms[0], AbiType) }), parms).Compile(); + var fromAbi = HelperType.GetMethod("FromAbi", BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static); + return (object arg) => (T)fromAbi.Invoke(null, new[] { arg }); } public static readonly Func FromManaged = (T value) => FromManagedLazy.Value(value); private static readonly Lazy> FromManagedLazy = new(BindFromManaged); private static Func BindFromManaged() { - var parms = new[] { Expression.Parameter(typeof(T), "arg") }; - return Expression.Lambda>( - Expression.Convert(Expression.Call(HelperType.GetMethod("FromManaged", BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static), parms), - typeof(object)), parms).Compile(); + var fromManaged = HelperType.GetMethod("FromManaged", BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static); + return (T arg) => fromManaged.Invoke(null, new object[] { arg }); } public static readonly Action CopyManaged = (T value, IntPtr dest) => CopyManagedLazy.Value(value, dest); @@ -502,19 +489,15 @@ private static Action BindCopyManaged() { var copyManaged = HelperType.GetMethod("CopyManaged", BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static); if (copyManaged == null) return null; - var parms = new[] { Expression.Parameter(typeof(T), "arg"), Expression.Parameter(typeof(IntPtr), "dest") }; - return Expression.Lambda>( - Expression.Call(copyManaged, parms), parms).Compile(); + return (T arg, IntPtr dest) => copyManaged.Invoke(null, new object[] { arg, dest }); } public static readonly Action DisposeMarshaler = (object objRef) => DisposeMarshalerLazy.Value(objRef); private static readonly Lazy> DisposeMarshalerLazy = new(BindDisposeMarshaler); private static Action BindDisposeMarshaler() { - var parms = new[] { Expression.Parameter(typeof(object), "arg") }; - return Expression.Lambda>( - Expression.Call(HelperType.GetMethod("DisposeMarshaler", BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static), - new[] { Expression.Convert(parms[0], MarshalerType) }), parms).Compile(); + var disposeMarshaler = HelperType.GetMethod("DisposeMarshaler", BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static); + return (object arg) => disposeMarshaler.Invoke(null, new [] { arg }); } internal static readonly Action DisposeAbi = (object box) => DisposeAbiLazy.Value(box); @@ -523,9 +506,7 @@ private static Action BindDisposeAbi() { var disposeAbi = HelperType.GetMethod("DisposeAbi", BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static); if (disposeAbi == null) return null; - var parms = new[] { Expression.Parameter(typeof(object), "arg") }; - return Expression.Lambda>( - Expression.Call(disposeAbi, new[] { Expression.Convert(parms[0], AbiType) }), parms).Compile(); + return (object arg) => disposeAbi.Invoke(null, new[] { arg }); } internal static readonly Func CreateMarshalerArray = (T[] array) => CreateMarshalerArrayLazy.Value(array); @@ -534,9 +515,7 @@ private static Func BindCreateMarshalerArray() { var createMarshalerArray = HelperType.GetMethod("CreateMarshalerArray", BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static); if (createMarshalerArray == null) return null; - var parms = new[] { Expression.Parameter(typeof(T[]), "arg") }; - return Expression.Lambda>( - Expression.Convert(Expression.Call(createMarshalerArray, parms), typeof(object)), parms).Compile(); + return (T[] arg) => createMarshalerArray.Invoke(null, new object[] { arg }); } internal static readonly Func GetAbiArray = (object box) => GetAbiArrayLazy.Value(box); @@ -545,9 +524,7 @@ private static Func BindCreateMarshalerArray() { var getAbiArray = HelperType.GetMethod("GetAbiArray", BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static); if (getAbiArray == null) return null; - var parms = new[] { Expression.Parameter(typeof(object), "arg") }; - return Expression.Lambda>( - Expression.Convert(Expression.Call(getAbiArray, parms), typeof((int, IntPtr))), parms).Compile(); + return (object arg) => ((int, IntPtr))getAbiArray.Invoke(null, new object[] { arg }); } internal static readonly Func FromAbiArray = (object box) => FromAbiArrayLazy.Value(box); @@ -556,9 +533,7 @@ private static Func BindFromAbiArray() { var fromAbiArray = HelperType.GetMethod("FromAbiArray", BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static); if (fromAbiArray == null) return null; - var parms = new[] { Expression.Parameter(typeof(object), "arg") }; - return Expression.Lambda>( - Expression.Call(fromAbiArray, parms), parms).Compile(); + return (object arg) => (T[])fromAbiArray.Invoke(null, new[] { arg }); } internal static readonly Func FromManagedArray = (T[] array) => FromManagedArrayLazy.Value(array); @@ -567,9 +542,7 @@ private static Func BindFromAbiArray() { var fromManagedArray = HelperType.GetMethod("FromManagedArray", BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static); if (fromManagedArray == null) return null; - var parms = new[] { Expression.Parameter(typeof(T[]), "arg") }; - return Expression.Lambda>( - Expression.Convert(Expression.Call(fromManagedArray, parms), typeof((int, IntPtr))), parms).Compile(); + return (T[] arg) => ((int, IntPtr))fromManagedArray.Invoke(null, new object[] { arg }); } internal static readonly Action DisposeMarshalerArray = (object box) => DisposeMarshalerArrayLazy.Value(box); @@ -578,9 +551,7 @@ private static Action BindDisposeMarshalerArray() { var disposeMarshalerArray = HelperType.GetMethod("DisposeMarshalerArray", BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static); if (disposeMarshalerArray == null) return null; - var parms = new[] { Expression.Parameter(typeof(object), "arg") }; - return Expression.Lambda>( - Expression.Call(disposeMarshalerArray, Expression.Convert(parms[0], MarshalerArrayType)), parms).Compile(); + return (object arg) => disposeMarshalerArray.Invoke(null, new object[] { arg }); } internal static readonly Action DisposeAbiArray = (object box) => DisposeAbiArrayLazy.Value(box); @@ -589,9 +560,7 @@ private static Action BindDisposeAbiArray() { var disposeAbiArray = HelperType.GetMethod("DisposeAbiArray", BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static); if (disposeAbiArray == null) return null; - var parms = new[] { Expression.Parameter(typeof(object), "arg") }; - return Expression.Lambda>( - Expression.Call(disposeAbiArray, parms), parms).Compile(); + return (object arg) => disposeAbiArray.Invoke(null, new object[] { arg }); } private static unsafe void CopyManagedFallback(T value, IntPtr dest) @@ -1090,11 +1059,8 @@ public static unsafe void CopyManaged(T value, IntPtr dest) private static Func BindToAbi() { - var parms = new[] { Expression.Parameter(typeof(T), "arg") }; - return Expression.Lambda>( - Expression.MakeMemberAccess( - Expression.Convert(parms[0], HelperType), - HelperType.GetField("_obj", BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.DeclaredOnly)), parms).Compile(); + var objField = HelperType.GetField("_obj", BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.DeclaredOnly); + return (T arg) => (IObjectReference) objField.GetValue(arg); } private static Func BindCreateMarshaler() @@ -1137,11 +1103,8 @@ public static IObjectReference CreateMarshaler(T o, Guid iid, bool unwrapObje Type helperType = Projections.FindCustomHelperTypeMapping(publicType, true); if (helperType != null) { - var parms = new[] { Expression.Parameter(typeof(object), "arg") }; - var createMarshaler = Expression.Lambda>( - Expression.Call(helperType.GetMethod("CreateMarshaler", BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static), - new[] { Expression.Convert(parms[0], publicType) }), parms).Compile(); - return createMarshaler(o); + var createMarshaler = helperType.GetMethod("CreateMarshaler", BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static); + return (IObjectReference) createMarshaler.Invoke(null, new[] { (object) o }); } return ComWrappersSupport.CreateCCWForObject(o, iid); diff --git a/src/WinRT.Runtime/Projections/Bindable.net5.cs b/src/WinRT.Runtime/Projections/Bindable.net5.cs index 0c8fa77bb..2e5663cce 100644 --- a/src/WinRT.Runtime/Projections/Bindable.net5.cs +++ b/src/WinRT.Runtime/Projections/Bindable.net5.cs @@ -434,9 +434,7 @@ public AdaptiveFromAbiHelper(Type runtimeType, IWinRTObject winRTObject) if(enumGenericType != null) { var getEnumerator = enumGenericType.GetMethod("GetEnumerator"); - var obj = Expression.Variable(typeof(IWinRTObject)); - _enumerator = Expression.Lambda>( - Expression.Call(Expression.Convert(obj, runtimeType), getEnumerator), obj).Compile(); + _enumerator = (IWinRTObject obj) => (global::System.Collections.IEnumerator)getEnumerator.Invoke(obj, null); } } diff --git a/src/WinRT.Runtime/Projections/IReadOnlyList.net5.cs b/src/WinRT.Runtime/Projections/IReadOnlyList.net5.cs index 596d0198e..c0a4ae11a 100644 --- a/src/WinRT.Runtime/Projections/IReadOnlyList.net5.cs +++ b/src/WinRT.Runtime/Projections/IReadOnlyList.net5.cs @@ -334,7 +334,6 @@ public unsafe struct Vftbl public static Guid PIID = GuidGenerator.CreateIID(typeof(IReadOnlyList)); private static readonly Type GetAt_0_Type = Expression.GetDelegateType(new Type[] { typeof(void*), typeof(uint), Marshaler.AbiType.MakeByRefType(), typeof(int) }); private static readonly Type IndexOf_2_Type = Expression.GetDelegateType(new Type[] { typeof(void*), Marshaler.AbiType, typeof(uint).MakeByRefType(), typeof(byte).MakeByRefType(), typeof(int) }); -// private static readonly Type GetAt_0_Type2 = typeof(IReadOnlyList_Delegates<>).MakeGenericType(Marshaler.AbiType).GetMethod("GetAt_0"); internal unsafe Vftbl(IntPtr thisPtr) : this() { @@ -508,10 +507,4 @@ static class IReadOnlyList_Delegates { public unsafe delegate int GetMany_3(IntPtr thisPtr, uint startIndex, int __itemsSize, IntPtr items, out uint __return_value__); } - - internal static class IReadOnlyList_Delegates - { - public unsafe delegate int GetAt_0(IntPtr thisPtr, uint index, out TAbi __return_value__); - public unsafe delegate int IndexOf_2(IntPtr thisPtr, TAbi value, out uint index, out byte __return_value__); - } } diff --git a/src/WinRT.Runtime/Projections/IReferenceArray.net5.cs b/src/WinRT.Runtime/Projections/IReferenceArray.net5.cs index aaf1cc4ff..a4d0d2c14 100644 --- a/src/WinRT.Runtime/Projections/IReferenceArray.net5.cs +++ b/src/WinRT.Runtime/Projections/IReferenceArray.net5.cs @@ -83,6 +83,24 @@ public static object FromAbi(IntPtr ptr) return wrapper.Value; } + internal static unsafe object GetValue(IInspectable inspectable) + { + IntPtr referenceArrayPtr = IntPtr.Zero; + int __retval_length = default; + IntPtr __retval_data = default; + try + { + ExceptionHelpers.ThrowExceptionForHR(Marshal.QueryInterface(inspectable.ThisPtr, ref PIID, out referenceArrayPtr)); + ExceptionHelpers.ThrowExceptionForHR((*(delegate* unmanaged[Stdcall]**)referenceArrayPtr)[6](referenceArrayPtr, &__retval_length, &__retval_data)); + return Marshaler.FromAbiArray((__retval_length, __retval_data)); + } + finally + { + Marshaler.DisposeAbiArray((__retval_length, __retval_data)); + Marshal.Release(referenceArrayPtr); + } + } + public static unsafe void CopyManaged(object o, IntPtr dest) { using var objRef = CreateMarshaler(o); @@ -108,7 +126,7 @@ public unsafe struct Vftbl { internal IInspectable.Vftbl IInspectableVftbl; internal void* _get_Value_0; - internal delegate* unmanaged[Stdcall] GetValue_0 { get => (delegate* unmanaged[Stdcall])_get_Value_0; set => _get_Value_0 = (void*)value; } + internal delegate* unmanaged[Stdcall] GetValue_0 { get => (delegate* unmanaged[Stdcall])_get_Value_0; set => _get_Value_0 = (void*)value; } public static Guid PIID = GuidGenerator.CreateIID(typeof(IReferenceArray)); @@ -143,7 +161,7 @@ public unsafe T[] Value int __retval_length = default; IntPtr __retval_data = default; try - { + { global::WinRT.ExceptionHelpers.ThrowExceptionForHR(_obj.Vftbl.GetValue_0(ThisPtr, out __retval_length, out __retval_data)); return Marshaler.FromAbiArray((__retval_length, __retval_data)); } diff --git a/src/WinRT.Runtime/Projections/IReferenceArray.netstandard2.0.cs b/src/WinRT.Runtime/Projections/IReferenceArray.netstandard2.0.cs index 01fb0dafe..e9a236e69 100644 --- a/src/WinRT.Runtime/Projections/IReferenceArray.netstandard2.0.cs +++ b/src/WinRT.Runtime/Projections/IReferenceArray.netstandard2.0.cs @@ -83,6 +83,12 @@ public static object FromAbi(IntPtr ptr) var vftblT = new Vftbl(ptr); var wrapper = new IReferenceArray(ObjectReference.FromAbi(ptr, vftblT)); return wrapper.Value; + } + + internal static object GetValue(IInspectable inspectable) + { + var array = new IReferenceArray(inspectable.ObjRef); + return array.Value; } public static unsafe void CopyManaged(object o, IntPtr dest) From 7e0bb9359b3444e75a73dc79cb0ead3d1936b955 Mon Sep 17 00:00:00 2001 From: Manodasan Wignarajah Date: Tue, 15 Feb 2022 12:33:29 -0800 Subject: [PATCH 3/8] Fix IID optimization for certain scenarios --- src/cswinrt/code_writers.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/cswinrt/code_writers.h b/src/cswinrt/code_writers.h index ac1117fcb..adffd8fb3 100644 --- a/src/cswinrt/code_writers.h +++ b/src/cswinrt/code_writers.h @@ -2028,14 +2028,14 @@ private IObjectReference Make__%() else if (distance(ifaceType.GenericParam()) == 0) { - w.write(R"(global::System.Threading.Interlocked.CompareExchange(ref __%, ((IWinRTObject)this).NativeObject.As(GuidGenerator.GetIID(typeof(%).FindHelperType())), null);)", + w.write(R"(global::System.Threading.Interlocked.CompareExchange(ref __%, ((IWinRTObject)this).NativeObject.As(GuidGenerator.GetIID(typeof(%).GetHelperType())), null);)", objrefname, bind(semantics, typedef_name_type::Projected, false) ); } else { - w.write(R"(global::System.Threading.Interlocked.CompareExchange(ref __%, (IObjectReference)typeof(IObjectReference).GetMethod("As", Type.EmptyTypes).MakeGenericMethod(typeof(%).FindHelperType().FindVftblType()).Invoke(((IWinRTObject)this).NativeObject, null), null);)", + w.write(R"(global::System.Threading.Interlocked.CompareExchange(ref __%, (IObjectReference)typeof(IObjectReference).GetMethod("As", Type.EmptyTypes).MakeGenericMethod(typeof(%).GetHelperType().FindVftblType()).Invoke(((IWinRTObject)this).NativeObject, null), null);)", objrefname, bind(semantics, typedef_name_type::Projected, false)); } From ff6a447f9633640ebbc7c7fc7523f143210f54d8 Mon Sep 17 00:00:00 2001 From: Manodasan Wignarajah Date: Tue, 15 Feb 2022 18:45:43 -0800 Subject: [PATCH 4/8] IID optimization by reordering logic --- src/WinRT.Runtime/GuidGenerator.cs | 43 +++++++++++++++--------------- 1 file changed, 22 insertions(+), 21 deletions(-) diff --git a/src/WinRT.Runtime/GuidGenerator.cs b/src/WinRT.Runtime/GuidGenerator.cs index 70ca1ed8a..f87bd7f05 100644 --- a/src/WinRT.Runtime/GuidGenerator.cs +++ b/src/WinRT.Runtime/GuidGenerator.cs @@ -32,7 +32,17 @@ public static Guid GetIID(Type type) } public static string GetSignature(Type type) - { + { + if (type == typeof(object)) + { + return "cinterface(IInspectable)"; + } + + if (type == typeof(string)) + { + return "string"; + } + var helperType = type.FindHelperType(); if (helperType != null) { @@ -43,18 +53,6 @@ public static string GetSignature(Type type) } } - type = type.IsInterface ? (type.GetAuthoringMetadataType() ?? type) : type; - if (type == typeof(object)) - { - return "cinterface(IInspectable)"; - } - - if (type.IsGenericType) - { - var args = type.GetGenericArguments().Select(t => GetSignature(t)); - return "pinterface({" + GetGUID(type) + "};" + String.Join(";", args) + ")"; - } - if (type.IsValueType) { switch (type.Name) @@ -88,20 +86,23 @@ public static string GetSignature(Type type) } } } + + type = type.IsInterface ? (type.GetAuthoringMetadataType() ?? type) : type; - if (type == typeof(string)) + if (type.IsGenericType) { - return "string"; - } - - if (Projections.TryGetDefaultInterfaceTypeForRuntimeClassType(type, out Type iface)) + var args = type.GetGenericArguments().Select(t => GetSignature(t)); + return "pinterface({" + GetGUID(type) + "};" + String.Join(";", args) + ")"; + } + + if (type.IsDelegate()) { - return "rc(" + type.FullName + ";" + GetSignature(iface) + ")"; + return "delegate({" + GetGUID(type) + "})"; } - if (type.IsDelegate()) + if (type.IsClass && Projections.TryGetDefaultInterfaceTypeForRuntimeClassType(type, out Type iface)) { - return "delegate({" + GetGUID(type) + "})"; + return "rc(" + type.FullName + ";" + GetSignature(iface) + ")"; } return "{" + type.GUID.ToString() + "}"; From 19b4d13382f362caa1808779f58e2dc68b3ed148 Mon Sep 17 00:00:00 2001 From: Manodasan Wignarajah Date: Fri, 18 Feb 2022 18:33:53 -0800 Subject: [PATCH 5/8] Remove a couple more .GUID calls to reduce GetCustomAttribute --- src/WinRT.Runtime/Interop/IUnknownVftbl.cs | 2 +- src/WinRT.Runtime/Interop/IWeakReferenceSource.net5.cs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/WinRT.Runtime/Interop/IUnknownVftbl.cs b/src/WinRT.Runtime/Interop/IUnknownVftbl.cs index 40e498278..24103d54e 100644 --- a/src/WinRT.Runtime/Interop/IUnknownVftbl.cs +++ b/src/WinRT.Runtime/Interop/IUnknownVftbl.cs @@ -24,7 +24,7 @@ unsafe struct IUnknownVftbl public static IUnknownVftbl AbiToProjectionVftbl => ComWrappersSupport.IUnknownVftbl; public static IntPtr AbiToProjectionVftblPtr => ComWrappersSupport.IUnknownVftblPtr; - internal static readonly Guid IID = new(0, 0, 0, 0xC0, 0, 0, 0, 0, 0, 0, 0x46); + internal static readonly Guid IID = InterfaceIIDs.IUnknown_IID; // Avoids boxing when using default Equals. internal bool Equals(IUnknownVftbl other) diff --git a/src/WinRT.Runtime/Interop/IWeakReferenceSource.net5.cs b/src/WinRT.Runtime/Interop/IWeakReferenceSource.net5.cs index 99d9eaebc..d0597618c 100644 --- a/src/WinRT.Runtime/Interop/IWeakReferenceSource.net5.cs +++ b/src/WinRT.Runtime/Interop/IWeakReferenceSource.net5.cs @@ -92,7 +92,7 @@ static class IWeakReferenceSourceMethods [Guid("00000038-0000-0000-C000-000000000046")] internal unsafe interface IWeakReferenceSource : global::WinRT.Interop.IWeakReferenceSource { - internal static readonly Guid IID = new(0x00000038, 0, 0, 0xC0, 0, 0, 0, 0, 0, 0, 0x46); + internal static readonly Guid IID = InterfaceIIDs.IWeakReferenceSource_IID; public static IntPtr AbiToProjectionVftablePtr; static unsafe IWeakReferenceSource() From 240d2bc04100f2732941bd7a8101db27c7719f32 Mon Sep 17 00:00:00 2001 From: Manodasan Wignarajah Date: Fri, 18 Feb 2022 18:34:26 -0800 Subject: [PATCH 6/8] Add missed change --- src/cswinrt/strings/WinRT.cs | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/cswinrt/strings/WinRT.cs b/src/cswinrt/strings/WinRT.cs index b3bba5ca0..04385c322 100644 --- a/src/cswinrt/strings/WinRT.cs +++ b/src/cswinrt/strings/WinRT.cs @@ -466,7 +466,7 @@ private Cache Update(IWeakReference target, int index, System.WeakReference GetState(int index) // If target no longer exists, destroy cache lock (this) { - using var resolved = this.target.Resolve(typeof(IUnknownVftbl).GUID); + using var resolved = this.target.Resolve(InterfaceIIDs.IUnknown_IID); if (resolved == null) { return null; @@ -522,7 +522,7 @@ public static void Create(IObjectReference obj, int index, System.WeakReference< return; } #else - int hr = obj.TryAs(typeof(IWeakReferenceSource).GUID, out var weakRefSource); + int hr = obj.TryAs(InterfaceIIDs.IWeakReferenceSource_IID, out var weakRefSource); if (hr != 0) { return; @@ -850,6 +850,8 @@ private void RemoveEventHandlerNoLock(EventRegistrationToken token) internal static class InterfaceIIDs { internal static readonly Guid IInspectable_IID = new(0xAF86E2E0, 0xB12D, 0x4c6a, 0x9C, 0x5A, 0xD7, 0xAA, 0x65, 0x10, 0x1E, 0x90); + internal static readonly Guid IUnknown_IID = new(0, 0, 0, 0xC0, 0, 0, 0, 0, 0, 0, 0x46); + internal static readonly Guid IWeakReferenceSource_IID = new(0x00000038, 0, 0, 0xC0, 0, 0, 0, 0, 0, 0, 0x46); } } From 6265a1cb27a71233f10c5225c2047e9e5ae7cd74 Mon Sep 17 00:00:00 2001 From: Manodasan Wignarajah Date: Fri, 18 Feb 2022 18:34:45 -0800 Subject: [PATCH 7/8] Reduce cost of Nullable value types from other projections. --- src/WinRT.Runtime/Projections/Nullable.cs | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/src/WinRT.Runtime/Projections/Nullable.cs b/src/WinRT.Runtime/Projections/Nullable.cs index f537d6d81..e0b6c367d 100644 --- a/src/WinRT.Runtime/Projections/Nullable.cs +++ b/src/WinRT.Runtime/Projections/Nullable.cs @@ -132,10 +132,22 @@ public Nullable(ObjectReference obj) _obj = obj; } - internal static T GetValue(IInspectable inspectable) + internal static unsafe T GetValue(IInspectable inspectable) { - var nullable = new Nullable(inspectable.ObjRef); - return nullable.Value; + IntPtr nullablePtr = IntPtr.Zero; + var __params = new object[] { IntPtr.Zero, null }; + try + { + ExceptionHelpers.ThrowExceptionForHR(Marshal.QueryInterface(inspectable.ThisPtr, ref PIID, out nullablePtr)); + __params[0] = nullablePtr; + Marshal.GetDelegateForFunctionPointer((*(IntPtr**)nullablePtr)[6], Vftbl.get_Value_0_Type).DynamicInvokeAbi(__params); + return Marshaler.FromAbi(__params[1]); + } + finally + { + Marshaler.DisposeAbi(__params[1]); + Marshal.Release(nullablePtr); + } } public unsafe T Value From bf6035c61ee70ed412675ed5c0eccb3b3ca4e8f4 Mon Sep 17 00:00:00 2001 From: Manodasan Wignarajah Date: Mon, 21 Feb 2022 00:03:09 -0800 Subject: [PATCH 8/8] Remove unnecessary property --- src/cswinrt/code_writers.h | 47 ++++++++++++++++++++------------------ 1 file changed, 25 insertions(+), 22 deletions(-) diff --git a/src/cswinrt/code_writers.h b/src/cswinrt/code_writers.h index adffd8fb3..991e6bdbd 100644 --- a/src/cswinrt/code_writers.h +++ b/src/cswinrt/code_writers.h @@ -2012,44 +2012,47 @@ ComWrappersSupport.RegisterObjectForInterface(this, ThisPtr); } auto objrefname = bind(semantics); + bool useInner = replaceDefaultByInner && has_attribute(ii, "Windows.Foundation.Metadata", "DefaultAttribute") && distance(ifaceType.GenericParam()) == 0; - w.write(R"( + if (!useInner) + { + w.write(R"( private volatile IObjectReference __%; private IObjectReference Make__%() { )", objrefname, objrefname); - - if (replaceDefaultByInner && has_attribute(ii, "Windows.Foundation.Metadata", "DefaultAttribute") && distance(ifaceType.GenericParam()) == 0) - { - w.write(R"(global::System.Threading.Interlocked.CompareExchange(ref __%, _inner, null);)", objrefname); - } - else if (distance(ifaceType.GenericParam()) == 0) - { - w.write(R"(global::System.Threading.Interlocked.CompareExchange(ref __%, ((IWinRTObject)this).NativeObject.As(GuidGenerator.GetIID(typeof(%).GetHelperType())), null);)", - objrefname, - bind(semantics, typedef_name_type::Projected, false) - ); - } - else - { - w.write(R"(global::System.Threading.Interlocked.CompareExchange(ref __%, (IObjectReference)typeof(IObjectReference).GetMethod("As", Type.EmptyTypes).MakeGenericMethod(typeof(%).GetHelperType().FindVftblType()).Invoke(((IWinRTObject)this).NativeObject, null), null);)", - objrefname, - bind(semantics, typedef_name_type::Projected, false)); - } + if (distance(ifaceType.GenericParam()) == 0) + { - w.write(R"( - return __%; + w.write(R"(global::System.Threading.Interlocked.CompareExchange(ref __%, ((IWinRTObject)this).NativeObject.As(GuidGenerator.GetIID(typeof(%).GetHelperType())), null);)", + objrefname, + bind(semantics, typedef_name_type::Projected, false) + ); + } + else + { + w.write(R"(global::System.Threading.Interlocked.CompareExchange(ref __%, (IObjectReference)typeof(IObjectReference).GetMethod("As", Type.EmptyTypes).MakeGenericMethod(typeof(%).GetHelperType().FindVftblType()).Invoke(((IWinRTObject)this).NativeObject, null), null);)", + objrefname, + bind(semantics, typedef_name_type::Projected, false)); + } + + w.write(R"( +return __%; } private IObjectReference % => __% ?? Make__%(); - )", objrefname, objrefname, objrefname, objrefname); + } + else + { + w.write(R"(private IObjectReference % => _inner;)", objrefname); + } }); } }