Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improve non agile object performance #1106

Merged
merged 8 commits into from
Feb 16, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
66 changes: 66 additions & 0 deletions src/Benchmarks/NonAgileObjectPerf.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
using BenchmarkDotNet.Attributes;
using System.Threading;

namespace Benchmarks
{
[MemoryDiagnoser]
public class NonAgileObjectPerf
{
AutoResetEvent createObject;
AutoResetEvent exitThread;
AutoResetEvent objectCreated;
Thread staThread;
private volatile Windows.UI.Popups.PopupMenu nonAgileObject;

[GlobalSetup]
public void Setup()
{
createObject = new AutoResetEvent(false);
exitThread = new AutoResetEvent(false);
objectCreated = new AutoResetEvent(false);
staThread = new Thread(new ThreadStart(ObjectAllocationLoop));
staThread.SetApartmentState(ApartmentState.STA);
staThread.Start();
}

[GlobalCleanup]
public void Cleanup()
{
exitThread.Set();
createObject.Set();
}

private void ObjectAllocationLoop()
{
while (createObject.WaitOne() && !exitThread.WaitOne(1))
{
createObject.Reset();
nonAgileObject = new Windows.UI.Popups.PopupMenu();
CallObject();
objectCreated.Set();
}
}

private int CallObject()
{
return nonAgileObject.Commands.Count;
}

[Benchmark]
public void ConstructAndQueryNonAgileObject()
{
createObject.Set();
objectCreated.WaitOne();
CallObject();
objectCreated.Reset();
}

[Benchmark]
public void ConstructNonAgileObject()
{
createObject.Set();
objectCreated.WaitOne();
objectCreated.Reset();
}
}
}
15 changes: 7 additions & 8 deletions src/WinRT.Runtime/AgileReference.cs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ class AgileReference : IDisposable
{
private readonly static Guid CLSID_StdGlobalInterfaceTable = new(0x00000323, 0, 0, 0xc0, 0, 0, 0, 0, 0, 0, 0x46);
private readonly static Lazy<IGlobalInterfaceTable> Git = new Lazy<IGlobalInterfaceTable>(() => GetGitTable());
private readonly IAgileReference _agileReference;
private readonly IObjectReference _agileReference;
private readonly IntPtr _cookie;
private bool disposed;

Expand All @@ -35,12 +35,8 @@ public unsafe AgileReference(IObjectReference instance)
0 /*AGILEREFERENCE_DEFAULT*/,
ref iid,
instance.ThisPtr,
&agileReference));
#if NET
_agileReference = (IAgileReference)new SingleInterfaceOptimizedObject(typeof(IAgileReference), ObjectReference<ABI.WinRT.Interop.IAgileReference.Vftbl>.Attach(ref agileReference));
#else
_agileReference = ABI.WinRT.Interop.IAgileReference.FromAbi(agileReference).AsType<ABI.WinRT.Interop.IAgileReference>();
#endif
&agileReference));
_agileReference = ObjectReference<IUnknownVftbl>.Attach(ref agileReference);
}
catch(TypeLoadException)
{
Expand All @@ -51,7 +47,10 @@ public unsafe AgileReference(IObjectReference instance)
MarshalInterface<IAgileReference>.DisposeAbi(agileReference);
}
}
public IObjectReference Get() => _cookie == IntPtr.Zero ? _agileReference?.Resolve(IUnknownVftbl.IID) : Git.Value?.GetInterfaceFromGlobal(_cookie, IUnknownVftbl.IID);

public IObjectReference Get() => _cookie == IntPtr.Zero ? ABI.WinRT.Interop.IAgileReferenceMethods.Resolve(_agileReference, IUnknownVftbl.IID) : Git.Value?.GetInterfaceFromGlobal(_cookie, IUnknownVftbl.IID);

internal ObjectReference<T> Get<T>(Guid iid) => _cookie == IntPtr.Zero ? ABI.WinRT.Interop.IAgileReferenceMethods.Resolve<T>(_agileReference, iid) : Git.Value?.GetInterfaceFromGlobal(_cookie, IUnknownVftbl.IID)?.As<T>(iid);

protected virtual void Dispose(bool disposing)
{
Expand Down
148 changes: 68 additions & 80 deletions src/WinRT.Runtime/Interop/IAgileReference.net5.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ namespace WinRT.Interop
[Guid("C03F6A43-65A4-9818-987E-E0B810D2A6F2")]
internal interface IAgileReference
{
IObjectReference Resolve(Guid riid);
IObjectReference Resolve(Guid riid);
}

[WindowsRuntimeType]
Expand All @@ -37,107 +37,95 @@ internal interface IGlobalInterfaceTable

namespace ABI.WinRT.Interop
{
using global::WinRT;

[DynamicInterfaceCastableImplementation]
[Guid("C03F6A43-65A4-9818-987E-E0B810D2A6F2")]
internal unsafe interface IAgileReference : global::WinRT.Interop.IAgileReference
{
[Guid("C03F6A43-65A4-9818-987E-E0B810D2A6F2")]
public struct Vftbl
using global::WinRT;

internal static class IAgileReferenceMethods
{
public static unsafe IObjectReference Resolve(IObjectReference _obj, Guid riid)
{
public global::WinRT.Interop.IUnknownVftbl IUnknownVftbl;
private void* _Resolve;
public delegate* unmanaged[Stdcall]<IntPtr, ref Guid, out IntPtr, int> Resolve { get => (delegate* unmanaged[Stdcall]<IntPtr, ref Guid, out IntPtr, int>)_Resolve; set => _Resolve = value; }

public static readonly Vftbl AbiToProjectionVftable;
public static readonly IntPtr AbiToProjectionVftablePtr;
if (_obj == null) return null;

#if !NET
public delegate int ResolveDelegate(IntPtr thisPtr, Guid* riid, IntPtr* objectReference);
private static readonly Delegate[] DelegateCache = new Delegate[1];
#endif
static Vftbl()
var ThisPtr = _obj.ThisPtr;
IntPtr ptr = IntPtr.Zero;
ExceptionHelpers.ThrowExceptionForHR((*(delegate* unmanaged[Stdcall]<IntPtr, Guid*, IntPtr*, int>**)ThisPtr)[3](
ThisPtr, &riid, &ptr));
try
{
AbiToProjectionVftable = new Vftbl
{
IUnknownVftbl = global::WinRT.Interop.IUnknownVftbl.AbiToProjectionVftbl,
#if !NET
_Resolve = Marshal.GetFunctionPointerForDelegate(DelegateCache[0] = new ResolveDelegate(Do_Abi_Resolve)).ToPointer(),
#else
_Resolve = (delegate* unmanaged<IntPtr, Guid*, IntPtr*, int>)&Do_Abi_Resolve
#endif
};
AbiToProjectionVftablePtr = Marshal.AllocHGlobal(Marshal.SizeOf<Vftbl>());
Marshal.StructureToPtr(AbiToProjectionVftable, AbiToProjectionVftablePtr, false);
return ComWrappersSupport.GetObjectReferenceForInterface(ptr);
}

#if NET
[UnmanagedCallersOnly]
#endif
private static int Do_Abi_Resolve(IntPtr thisPtr, Guid* riid, IntPtr* objectReference)
finally
{
IObjectReference _objectReference = default;

*objectReference = default;

try
{
_objectReference = global::WinRT.ComWrappersSupport.FindObject<global::WinRT.Interop.IAgileReference>(thisPtr).Resolve(*riid);
*objectReference = _objectReference?.GetRef() ?? IntPtr.Zero;
}
catch (Exception __exception__)
{
return __exception__.HResult;
}
return 0;
MarshalInspectable<object>.DisposeAbi(ptr);
}
}

public static ObjectReference<Vftbl> FromAbi(IntPtr thisPtr) => ObjectReference<Vftbl>.FromAbi(thisPtr);
}

public static unsafe ObjectReference<T> Resolve<T>(IObjectReference _obj, Guid riid)
{
if (_obj == null) return null;

IObjectReference global::WinRT.Interop.IAgileReference.Resolve(Guid riid)
{
var _obj = ((ObjectReference<Vftbl>)((IWinRTObject)this).GetObjectReferenceForType(typeof(global::WinRT.Interop.IAgileReference).TypeHandle));
var ThisPtr = _obj.ThisPtr;

ExceptionHelpers.ThrowExceptionForHR(_obj.Vftbl.Resolve(ThisPtr, ref riid, out IntPtr ptr));
IntPtr ptr = IntPtr.Zero;
ExceptionHelpers.ThrowExceptionForHR((*(delegate* unmanaged[Stdcall]<IntPtr, Guid*, IntPtr*, int>**)ThisPtr)[3](
ThisPtr, &riid, &ptr));
try
{
return ComWrappersSupport.GetObjectReferenceForInterface(ptr);
return ComWrappersSupport.GetObjectReferenceForInterface<T>(ptr);
}
finally
{
MarshalInspectable<object>.DisposeAbi(ptr);
}
}
}

[DynamicInterfaceCastableImplementation]
[Guid("C03F6A43-65A4-9818-987E-E0B810D2A6F2")]
internal unsafe interface IAgileReference : global::WinRT.Interop.IAgileReference
{
public static IntPtr AbiToProjectionVftablePtr;
static unsafe IAgileReference()
{
AbiToProjectionVftablePtr = ComWrappersSupport.AllocateVtableMemory(typeof(IAgileReference), sizeof(global::WinRT.Interop.IUnknownVftbl) + sizeof(IntPtr) * 1);
*(global::WinRT.Interop.IUnknownVftbl*)AbiToProjectionVftablePtr = global::WinRT.Interop.IUnknownVftbl.AbiToProjectionVftbl;
((delegate* unmanaged<IntPtr, Guid*, IntPtr*, int>*)AbiToProjectionVftablePtr)[3] = &Do_Abi_Resolve;
}

[UnmanagedCallersOnly]
private static int Do_Abi_Resolve(IntPtr thisPtr, Guid* riid, IntPtr* objectReference)
{
IObjectReference _objectReference = default;

*objectReference = default;

try
{
_objectReference = global::WinRT.ComWrappersSupport.FindObject<global::WinRT.Interop.IAgileReference>(thisPtr).Resolve(*riid);
*objectReference = _objectReference?.GetRef() ?? IntPtr.Zero;
}
catch (Exception __exception__)
{
return __exception__.HResult;
}
return 0;
}

IObjectReference global::WinRT.Interop.IAgileReference.Resolve(Guid riid)
{
var _obj = ((IWinRTObject)this).GetObjectReferenceForType(typeof(global::WinRT.Interop.IAgileReference).TypeHandle);
return IAgileReferenceMethods.Resolve(_obj, riid);
}
}

[DynamicInterfaceCastableImplementation]
[Guid("94ea2b94-e9cc-49e0-c0ff-ee64ca8f5b90")]
interface IAgileObject : global::WinRT.Interop.IAgileObject
{
[Guid("94ea2b94-e9cc-49e0-c0ff-ee64ca8f5b90")]
public struct Vftbl
{
public global::WinRT.Interop.IUnknownVftbl IUnknownVftbl;

public static readonly Vftbl AbiToProjectionVftable;
public static readonly IntPtr AbiToProjectionVftablePtr;

static Vftbl()
{
AbiToProjectionVftable = new Vftbl
{
IUnknownVftbl = global::WinRT.Interop.IUnknownVftbl.AbiToProjectionVftbl,
};
AbiToProjectionVftablePtr = Marshal.AllocHGlobal(Marshal.SizeOf<Vftbl>());
Marshal.StructureToPtr(AbiToProjectionVftable, AbiToProjectionVftablePtr, false);
}
{
public static IntPtr AbiToProjectionVftablePtr;
static unsafe IAgileObject()
{
AbiToProjectionVftablePtr = ComWrappersSupport.AllocateVtableMemory(typeof(IAgileObject), sizeof(global::WinRT.Interop.IUnknownVftbl));
*(global::WinRT.Interop.IUnknownVftbl*)AbiToProjectionVftablePtr = global::WinRT.Interop.IUnknownVftbl.AbiToProjectionVftbl;
}

public static ObjectReference<Vftbl> FromAbi(IntPtr thisPtr) => ObjectReference<Vftbl>.FromAbi(thisPtr);

}

[Guid("00000146-0000-0000-C000-000000000046")]
Expand Down
55 changes: 43 additions & 12 deletions src/WinRT.Runtime/Interop/IAgileReference.netstandard2.0.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ namespace WinRT.Interop
[Guid("C03F6A43-65A4-9818-987E-E0B810D2A6F2")]
internal interface IAgileReference
{
IObjectReference Resolve(Guid riid);
IObjectReference Resolve(Guid riid);
}

[WindowsRuntimeType]
Expand All @@ -36,7 +36,46 @@ internal interface IGlobalInterfaceTable

namespace ABI.WinRT.Interop
{
using global::WinRT;
using global::WinRT;

internal static class IAgileReferenceMethods
{
public static unsafe IObjectReference Resolve(IObjectReference _obj, Guid riid)
{
if (_obj == null) return null;

var ThisPtr = _obj.ThisPtr;
IntPtr ptr = IntPtr.Zero;
ExceptionHelpers.ThrowExceptionForHR((*(delegate* unmanaged[Stdcall]<IntPtr, Guid*, IntPtr*, int>**)ThisPtr)[3](
ThisPtr, &riid, &ptr));
try
{
return ComWrappersSupport.GetObjectReferenceForInterface(ptr);
}
finally
{
MarshalInspectable<object>.DisposeAbi(ptr);
}
}

public static unsafe ObjectReference<T> Resolve<T>(IObjectReference _obj, Guid riid)
{
if (_obj == null) return null;

var ThisPtr = _obj.ThisPtr;
IntPtr ptr = IntPtr.Zero;
ExceptionHelpers.ThrowExceptionForHR((*(delegate* unmanaged[Stdcall]<IntPtr, Guid*, IntPtr*, int>**)ThisPtr)[3](
ThisPtr, &riid, &ptr));
try
{
return ComWrappersSupport.GetObjectReferenceForInterface<T>(ptr);
}
finally
{
MarshalInspectable<object>.DisposeAbi(ptr);
}
}
}

[Guid("C03F6A43-65A4-9818-987E-E0B810D2A6F2")]
internal sealed unsafe class IAgileReference : global::WinRT.Interop.IAgileReference
Expand Down Expand Up @@ -104,16 +143,8 @@ public IAgileReference(ObjectReference<Vftbl> obj)

public IObjectReference Resolve(Guid riid)
{
ExceptionHelpers.ThrowExceptionForHR(_obj.Vftbl.Resolve(ThisPtr, ref riid, out IntPtr ptr));
try
{
return ComWrappersSupport.GetObjectReferenceForInterface(ptr);
}
finally
{
MarshalInspectable<object>.DisposeAbi(ptr);
}
}
return IAgileReferenceMethods.Resolve(_obj, riid);
}
}

[Guid("94ea2b94-e9cc-49e0-c0ff-ee64ca8f5b90")]
Expand Down
Loading