Skip to content

Commit

Permalink
CreateObject microbenchmark optimizations (#1010)
Browse files Browse the repository at this point in the history
* Fix benchmarks and optimizations to CreateObject code path

* Minor changes based on rosyln analyzer suggestions.

* Microbenchmark optimizations

* Update marshalers to use finally to catch issues in cleanup

* PR feedback.

* Replace Guid.TryParse
  • Loading branch information
manodasanW authored Oct 11, 2021
1 parent bd25372 commit a32c457
Show file tree
Hide file tree
Showing 17 changed files with 171 additions and 133 deletions.
7 changes: 4 additions & 3 deletions src/Benchmarks/Benchmarks.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -16,14 +16,15 @@
</PropertyGroup>

<ItemGroup>
<PackageReference Include="BenchmarkDotNet" Version="0.12.1" />
<PackageReference Include="BenchmarkDotNet" Version="0.13.1" />
<PackageReference Include="BenchmarkDotNet.Diagnostics.Windows" Version="0.13.1" />
<PackageReference Include="Microsoft.Windows.SDK.Contracts" Version="10.0.18362.2005" Condition="$(UseWinmd) == true"/>
<PackageReference Include="System.Runtime.CompilerServices.Unsafe" Version="4.5.3" Condition="$(UseWinmd) == false"/>
</ItemGroup>

<ItemGroup>
<Reference Include="$(MSBuildThisFileDirectory)..\Projections\Windows\bin\x64\Release\$(BenchmarkTargetFramework)\Microsoft.Windows.SDK.NET.dll"></Reference>
<Reference Include="$(MSBuildThisFileDirectory)..\Projections\Benchmark\bin\x64\Release\$(BenchmarkTargetFramework)\Benchmark.dll"></Reference>
<Reference Include="$(MSBuildThisFileDirectory)..\Projections\Windows\bin\x64\Release\$(BenchmarkTargetFramework)\Microsoft.Windows.SDK.NET.dll" Condition="$(UseWinmd) == false"></Reference>
<Reference Include="$(MSBuildThisFileDirectory)..\Projections\Benchmark\bin\x64\Release\$(BenchmarkTargetFramework)\Benchmark.dll" Condition="$(UseWinmd) == false"></Reference>

<ProjectReference Include="..\Projections\Windows\Windows.csproj" Condition="$(UseWinmd) == false And $(IsDotnetBuild) == false" />
<ProjectReference Include="..\Projections\Benchmark\Benchmark.csproj" Condition="$(UseWinmd) == false And $(IsDotnetBuild) == false" />
Expand Down
2 changes: 1 addition & 1 deletion src/WinRT.Runtime/AgileReference.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ namespace WinRT
{
public class AgileReference : IDisposable
{
private readonly static Guid CLSID_StdGlobalInterfaceTable = Guid.Parse("00000323-0000-0000-c000-000000000046");
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 IntPtr _cookie;
Expand Down
67 changes: 33 additions & 34 deletions src/WinRT.Runtime/ComWrappersSupport.cs
Original file line number Diff line number Diff line change
Expand Up @@ -63,49 +63,48 @@ public static IObjectReference GetObjectReferenceForInterface(IntPtr externalCom
return null;
}

using var unknownRef = ObjectReference<IUnknownVftbl>.FromAbi(externalComObject);
var unknownRef = ObjectReference<IUnknownVftbl>.FromAbi(externalComObject);

if (IsFreeThreaded())
if (IsFreeThreaded(unknownRef))
{
return unknownRef.As<IUnknownVftbl>();
return unknownRef;
}
else
{
return new ObjectReferenceWithContext<IUnknownVftbl>(
unknownRef.GetRef(),
Context.GetContextCallback(),
Context.GetContextToken());
using (unknownRef)
{
return new ObjectReferenceWithContext<IUnknownVftbl>(
unknownRef.GetRef(),
Context.GetContextCallback(),
Context.GetContextToken());
}
}

// If we are free threaded, we do not need to keep track of context.
// This can either be if the object implements IAgileObject or the free threaded marshaler.
unsafe bool IsFreeThreaded()
{
if (unknownRef.TryAs<IUnknownVftbl>(typeof(ABI.WinRT.Interop.IAgileObject.Vftbl).GUID, out var agileRef) >= 0)
{
agileRef.Dispose();
return true;
}
else if (unknownRef.TryAs<ABI.WinRT.Interop.IMarshal.Vftbl>(out var marshalRef) >= 0)
{
try
{
Guid iid_IUnknown = typeof(IUnknownVftbl).GUID;
Guid iid_unmarshalClass;
var marshaler = new ABI.WinRT.Interop.IMarshal(marshalRef);
marshaler.GetUnmarshalClass(&iid_IUnknown, IntPtr.Zero, MSHCTX.InProc, IntPtr.Zero, MSHLFLAGS.Normal, &iid_unmarshalClass);
if (iid_unmarshalClass == ABI.WinRT.Interop.IMarshal.IID_InProcFreeThreadedMarshaler.Value)
{
return true;
}
}
finally
{
marshalRef.Dispose();
}
}
return false;
}
unsafe static bool IsFreeThreaded(IObjectReference unknownRef)
{
if (unknownRef.TryAs(ABI.WinRT.Interop.IAgileObject.IID, out var agilePtr) >= 0)
{
Marshal.Release(agilePtr);
return true;
}
else if (unknownRef.TryAs<ABI.WinRT.Interop.IMarshal.Vftbl>(ABI.WinRT.Interop.IMarshal.IID, out var marshalRef) >= 0)
{
using (marshalRef)
{
Guid iid_IUnknown = IUnknownVftbl.IID;
Guid iid_unmarshalClass;
Marshal.ThrowExceptionForHR(marshalRef.Vftbl.GetUnmarshalClass_0(
marshalRef.ThisPtr, &iid_IUnknown, IntPtr.Zero, MSHCTX.InProc, IntPtr.Zero, MSHLFLAGS.Normal, &iid_unmarshalClass));
if (iid_unmarshalClass == ABI.WinRT.Interop.IMarshal.IID_InProcFreeThreadedMarshaler.Value)
{
return true;
}
}
}
return false;
}
}

public static void RegisterProjectionAssembly(Assembly assembly) => TypeNameSupport.RegisterProjectionAssembly(assembly);
Expand Down
8 changes: 4 additions & 4 deletions src/WinRT.Runtime/ComWrappersSupport.net5.cs
Original file line number Diff line number Diff line change
Expand Up @@ -229,7 +229,7 @@ public unsafe static void Init(
// otherwise the new instance will be used. Since the inner was composed
// it should answer immediately without going through the outer. Either way
// the reference count will go to the new instance.
Guid iid = typeof(IReferenceTrackerVftbl).GUID;
Guid iid = IReferenceTrackerVftbl.IID;
int hr = Marshal.QueryInterface(objRef.ThisPtr, ref iid, out referenceTracker);
if (hr != 0)
{
Expand Down Expand Up @@ -330,7 +330,7 @@ public unsafe static void Init(IObjectReference objRef, bool addRefFromTrackerSo
{
if (objRef.ReferenceTrackerPtr == IntPtr.Zero)
{
Guid iid = typeof(IReferenceTrackerVftbl).GUID;
Guid iid = IReferenceTrackerVftbl.IID;
int hr = Marshal.QueryInterface(objRef.ThisPtr, ref iid, out var referenceTracker);
if (hr == 0)
{
Expand Down Expand Up @@ -434,7 +434,7 @@ private static unsafe bool IsRuntimeImplementedRCW(Type objType)

private static object CreateObject(IObjectReference objRef)
{
if (objRef.TryAs<IInspectable.Vftbl>(out var inspectableRef) == 0)
if (objRef.TryAs<IInspectable.Vftbl>(IInspectable.IID, out var inspectableRef) == 0)
{
IInspectable inspectable = new IInspectable(inspectableRef);

Expand All @@ -448,7 +448,7 @@ private static object CreateObject(IObjectReference objRef)

return ComWrappersSupport.GetTypedRcwFactory(runtimeClassName)(inspectable);
}
else if (objRef.TryAs<ABI.WinRT.Interop.IWeakReference.Vftbl>(out var weakRef) == 0)
else if (objRef.TryAs<ABI.WinRT.Interop.IWeakReference.Vftbl>(ABI.WinRT.Interop.IWeakReference.IID, out var weakRef) == 0)
{
// IWeakReference is IUnknown-based, so implementations of it may not (and likely won't) implement
// IInspectable. As a result, we need to check for them explicitly.
Expand Down
2 changes: 1 addition & 1 deletion src/WinRT.Runtime/Context.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ static class Context
[DllImport("api-ms-win-core-com-l1-1-0.dll")]
private static extern int CoGetObjectContext(ref Guid riid, out IntPtr ppv);

private static readonly Guid IID_ICallbackWithNoReentrancyToApplicationSTA = Guid.Parse("0A299774-3E4E-FC42-1D9D-72CEE105CA57");
private static readonly Guid IID_ICallbackWithNoReentrancyToApplicationSTA = new(0x0A299774, 0x3E4E, 0xFC42, 0x1D, 0x9D, 0x72, 0xCE, 0xE1, 0x05, 0xCA, 0x57);

public static IntPtr GetContextCallback()
{
Expand Down
40 changes: 22 additions & 18 deletions src/WinRT.Runtime/ExceptionHelpers.cs
Original file line number Diff line number Diff line change
Expand Up @@ -56,30 +56,34 @@ static ExceptionHelpers()
setRestrictedErrorInfo = Platform.GetProcAddress<SetRestrictedErrorInfo>(winRTErrorModule);
}
}
}

public static void ThrowExceptionForHR(int hr)
{
if (hr < 0)
{
Throw(hr);
}

static void Throw(int hr)
{
Exception ex = GetExceptionForHR(hr, useGlobalErrorState: true, out bool restoredExceptionFromGlobalState);
if (restoredExceptionFromGlobalState)
{
ExceptionDispatchInfo.Capture(ex).Throw();
}
else
{
throw ex;
}
}
}

public static void ThrowExceptionForHR(int hr)
{
Exception ex = GetExceptionForHR(hr, useGlobalErrorState: true, out bool restoredExceptionFromGlobalState);
if (restoredExceptionFromGlobalState)
{
ExceptionDispatchInfo.Capture(ex).Throw();
}
else if (ex is object)
{
throw ex;
}
}

public static Exception GetExceptionForHR(int hr) => GetExceptionForHR(hr, false, out _);
public static Exception GetExceptionForHR(int hr) => hr >= 0 ? null : GetExceptionForHR(hr, false, out _);

private static Exception GetExceptionForHR(int hr, bool useGlobalErrorState, out bool restoredExceptionFromGlobalState)
{
restoredExceptionFromGlobalState = false;
if (hr >= 0)
{
return null;
}

ObjectReference<ABI.WinRT.Interop.IErrorInfo.Vftbl> iErrorInfo = null;
IObjectReference restrictedErrorInfoToSave = null;
Expand Down
4 changes: 2 additions & 2 deletions src/WinRT.Runtime/GuidGenerator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ public static string GetSignature(Type type)
var sigMethod = helperType.GetMethod("GetGuidSignature", BindingFlags.Static | BindingFlags.Public);
if (sigMethod != null)
{
return (string)sigMethod.Invoke(null, new Type[] { });
return (string)sigMethod.Invoke(null, null);
}
}

Expand Down Expand Up @@ -128,7 +128,7 @@ private static Guid encode_guid(Span<byte> data)
#endif
}

private static Guid wrt_pinterface_namespace = new Guid("d57af411-737b-c042-abae-878b1e16adee");
private readonly static Guid wrt_pinterface_namespace = new(0xd57af411, 0x737b, 0xc042, 0xab, 0xae, 0x87, 0x8b, 0x1e, 0x16, 0xad, 0xee);

public static Guid CreateIID(Type type)
{
Expand Down
4 changes: 3 additions & 1 deletion src/WinRT.Runtime/IInspectable.cs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,9 @@ public enum TrustLevel
[ObjectReferenceWrapper(nameof(_obj))]
[Guid("AF86E2E0-B12D-4c6a-9C5A-D7AA65101E90")]
public partial class IInspectable
{
{
internal static readonly Guid IID = new(0xAF86E2E0, 0xB12D, 0x4c6a, 0x9C, 0x5A, 0xD7, 0xAA, 0x65, 0x10, 0x1E, 0x90);

[Guid("AF86E2E0-B12D-4c6a-9C5A-D7AA65101E90")]
public unsafe struct Vftbl
{
Expand Down
4 changes: 2 additions & 2 deletions src/WinRT.Runtime/Interop/IAgileReference.net5.cs
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,8 @@ internal interface IAgileReference
[WindowsRuntimeType]
[Guid("94ea2b94-e9cc-49e0-c0ff-ee64ca8f5b90")]
public interface IAgileObject
{
public static readonly Guid IID = Guid.Parse("94ea2b94-e9cc-49e0-c0ff-ee64ca8f5b90");
{
public static readonly Guid IID = new(0x94ea2b94, 0xe9cc, 0x49e0, 0xc0, 0xff, 0xee, 0x64, 0xca, 0x8f, 0x5b, 0x90);
}

[WindowsRuntimeType]
Expand Down
6 changes: 4 additions & 2 deletions src/WinRT.Runtime/Interop/IAgileReference.netstandard2.0.cs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ internal interface IAgileReference
[WindowsRuntimeType]
[Guid("94ea2b94-e9cc-49e0-c0ff-ee64ca8f5b90")]
public interface IAgileObject
{
{
}

[WindowsRuntimeType]
Expand Down Expand Up @@ -113,7 +113,9 @@ public IObjectReference Resolve(Guid riid)

[Guid("94ea2b94-e9cc-49e0-c0ff-ee64ca8f5b90")]
public class IAgileObject : global::WinRT.Interop.IAgileObject
{
{
internal static readonly Guid IID = new(0x94ea2b94, 0xe9cc, 0x49e0, 0xc0, 0xff, 0xee, 0x64, 0xca, 0x8f, 0x5b, 0x90);

[Guid("94ea2b94-e9cc-49e0-c0ff-ee64ca8f5b90")]
public struct Vftbl
{
Expand Down
4 changes: 3 additions & 1 deletion src/WinRT.Runtime/Interop/IMarshal.cs
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,9 @@ namespace ABI.WinRT.Interop
{
[Guid("00000003-0000-0000-c000-000000000046")]
internal class IMarshal
{
{
internal static readonly Guid IID = new(0x00000003, 0, 0, 0xc0, 0, 0, 0, 0, 0, 0, 0x46);

[DllImport("api-ms-win-core-com-l1-1-0.dll")]
private static extern int CoCreateFreeThreadedMarshaler(IntPtr outer, out IntPtr marshalerPtr);

Expand Down
2 changes: 2 additions & 0 deletions src/WinRT.Runtime/Interop/IReferenceTracker.cs
Original file line number Diff line number Diff line change
Expand Up @@ -16,5 +16,7 @@ internal unsafe struct IReferenceTrackerVftbl
private void* _ReleaseFromTrackerSource_5;
public delegate* unmanaged[Stdcall]<IntPtr, int> ReleaseFromTrackerSource { get => (delegate* unmanaged[Stdcall]<IntPtr, int>)_ReleaseFromTrackerSource_5; set => _ReleaseFromTrackerSource_5 = (void*)value; }
private void* _PegFromTrackerSource_6;

internal static readonly Guid IID = new(0x11D3B13A, 0x180E, 0x4789, 0xA8, 0xBE, 0x77, 0x12, 0x88, 0x28, 0x93, 0xE6);
}
}
4 changes: 3 additions & 1 deletion src/WinRT.Runtime/Interop/IUnknownVftbl.cs
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@ public unsafe struct IUnknownVftbl
public delegate* unmanaged[Stdcall]<IntPtr, uint> Release { get => (delegate* unmanaged[Stdcall]<IntPtr, uint>)_Release; set => _Release = (void*)value; }

public static IUnknownVftbl AbiToProjectionVftbl => ComWrappersSupport.IUnknownVftbl;
public static IntPtr AbiToProjectionVftblPtr => ComWrappersSupport.IUnknownVftblPtr;
public static IntPtr AbiToProjectionVftblPtr => ComWrappersSupport.IUnknownVftblPtr;

internal static readonly Guid IID = new(0, 0, 0, 0xC0, 0, 0, 0, 0, 0, 0, 0x46);
}
}
4 changes: 3 additions & 1 deletion src/WinRT.Runtime/Interop/IWeakReferenceSource.net5.cs
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,9 @@ private static int Do_Abi_GetWeakReference(IntPtr thisPtr, IntPtr* weakReference
[DynamicInterfaceCastableImplementation]
[Guid("00000037-0000-0000-C000-000000000046")]
internal unsafe interface IWeakReference : global::WinRT.Interop.IWeakReference
{
{
internal static readonly Guid IID = new(0x00000037, 0, 0, 0xC0, 0, 0, 0, 0, 0, 0, 0x46);

[Guid("00000037-0000-0000-C000-000000000046")]
public struct Vftbl
{
Expand Down
Loading

0 comments on commit a32c457

Please sign in to comment.