From 005c2a31256cb7b2899746e6242be0e67df8d3e6 Mon Sep 17 00:00:00 2001 From: Joshua Larkin <70237359+j0shuams@users.noreply.github.com> Date: Mon, 24 Jan 2022 14:02:15 -0800 Subject: [PATCH 1/7] CompareExchange --- src/WinRT.Runtime/ObjectReference.cs | 40 ++++++++++++++++++++++------ 1 file changed, 32 insertions(+), 8 deletions(-) diff --git a/src/WinRT.Runtime/ObjectReference.cs b/src/WinRT.Runtime/ObjectReference.cs index 1db4fdd18..6a7af3aff 100644 --- a/src/WinRT.Runtime/ObjectReference.cs +++ b/src/WinRT.Runtime/ObjectReference.cs @@ -448,8 +448,28 @@ internal sealed class ObjectReferenceWithContext : ObjectReference { private readonly IntPtr _contextCallbackPtr; private readonly IntPtr _contextToken; - private readonly Lazy>> _cachedContext; - private readonly Lazy _agileReference; + + private volatile ConcurrentDictionary> __cachedContext; + private ConcurrentDictionary> _cachedContext => __cachedContext ?? Make_CachedContext(); + private ConcurrentDictionary> Make_CachedContext() + { + global::System.Threading.Interlocked.CompareExchange(ref __cachedContext, new(), null); + return __cachedContext; + } + + private volatile AgileReference __agileReference; + private AgileReference _agileReference => __agileReference ?? Make_AgileReference(); + private AgileReference Make_AgileReference() + { + // Might need to wrap these into a lambda and call it in the CompareExchange + AgileReference agileReference = null; + Context.CallInContext(_contextCallbackPtr, _contextToken, InitAgileReference, null); + void InitAgileReference() { agileReference = new AgileReference(this); } + + global::System.Threading.Interlocked.CompareExchange(ref __agileReference, agileReference, null); + return __agileReference; + } + private readonly Guid _iid; internal ObjectReferenceWithContext(IntPtr thisPtr, IntPtr contextCallbackPtr, IntPtr contextToken) @@ -457,7 +477,8 @@ internal ObjectReferenceWithContext(IntPtr thisPtr, IntPtr contextCallbackPtr, I { _contextCallbackPtr = contextCallbackPtr; _contextToken = contextToken; - _cachedContext = new Lazy>>(); + // _cachedContext = new Lazy>>(); + /* _agileReference = new Lazy(() => { AgileReference agileReference = null; Context.CallInContext(_contextCallbackPtr, _contextToken, InitAgileReference, null); @@ -468,6 +489,7 @@ void InitAgileReference() agileReference = new AgileReference(this); } }); + */ } internal ObjectReferenceWithContext(IntPtr thisPtr, IntPtr contextCallbackPtr, IntPtr contextToken, Guid iid) @@ -475,7 +497,8 @@ internal ObjectReferenceWithContext(IntPtr thisPtr, IntPtr contextCallbackPtr, I { _contextCallbackPtr = contextCallbackPtr; _contextToken = contextToken; - _cachedContext = new Lazy>>(); + // _cachedContext = new Lazy>>(); + /* _agileReference = new Lazy(() => { AgileReference agileReference = null; Context.CallInContext(_contextCallbackPtr, _contextToken, InitAgileReference, null); @@ -486,6 +509,7 @@ void InitAgileReference() agileReference = new AgileReference(this); } }); + */ _iid = iid; } @@ -524,11 +548,11 @@ private ObjectReference GetCurrentContext() return null; } - return _cachedContext.Value.GetOrAdd(currentContext, CreateForCurrentContext); + return _cachedContext.GetOrAdd(currentContext, CreateForCurrentContext); ObjectReference CreateForCurrentContext(IntPtr _) { - var agileReference = _agileReference.Value; + var agileReference = _agileReference; // We may fail to switch context and thereby not get an agile reference. // In these cases, fallback to using the current context. if (agileReference == null) @@ -550,9 +574,9 @@ ObjectReference CreateForCurrentContext(IntPtr _) protected override unsafe void Release() { - if (_cachedContext.IsValueCreated) + if (_cachedContext != null) { - _cachedContext.Value.Clear(); + _cachedContext.Clear(); } Context.CallInContext(_contextCallbackPtr, _contextToken, base.Release, ReleaseWithoutContext); From 9782d5f7317fd119e78903d8f32c9e34ab681a0d Mon Sep 17 00:00:00 2001 From: Manodasan Wignarajah Date: Wed, 9 Feb 2022 00:47:01 -0800 Subject: [PATCH 2/7] Add benchark for non agile objects --- src/Benchmarks/NonAgileObjectPerf.cs | 61 ++++++++++++++++++++++++++++ 1 file changed, 61 insertions(+) create mode 100644 src/Benchmarks/NonAgileObjectPerf.cs diff --git a/src/Benchmarks/NonAgileObjectPerf.cs b/src/Benchmarks/NonAgileObjectPerf.cs new file mode 100644 index 000000000..a2f4d1dc0 --- /dev/null +++ b/src/Benchmarks/NonAgileObjectPerf.cs @@ -0,0 +1,61 @@ +using BenchmarkDotNet.Attributes; +using System; +using System.Collections.Generic; +using System.Text; +using System.Threading; + +namespace Benchmarks +{ + [MemoryDiagnoser] + public class NonAgileObjectPerf + { + AutoResetEvent createObject; + AutoResetEvent exitThread; + AutoResetEvent objectCreated; + Thread staThread; + private 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(); + _ = nonAgileObject.Commands.Count; + objectCreated.Set(); + } + } + + private int CallObject() + { + return nonAgileObject.Commands.Count; + } + + [Benchmark] + public void ConstructAndQueryNonAgileObject() + { + createObject.Set(); + objectCreated.WaitOne(); + CallObject(); + objectCreated.Reset(); + } + } +} From ba850906898c38fc13b52d088b0bea206fde91d5 Mon Sep 17 00:00:00 2001 From: Manodasan Wignarajah Date: Wed, 9 Feb 2022 01:07:23 -0800 Subject: [PATCH 3/7] Add another benchmark and cleanup code --- src/Benchmarks/NonAgileObjectPerf.cs | 11 +++++-- src/WinRT.Runtime/ObjectReference.cs | 44 +++++----------------------- 2 files changed, 15 insertions(+), 40 deletions(-) diff --git a/src/Benchmarks/NonAgileObjectPerf.cs b/src/Benchmarks/NonAgileObjectPerf.cs index a2f4d1dc0..29cbedda9 100644 --- a/src/Benchmarks/NonAgileObjectPerf.cs +++ b/src/Benchmarks/NonAgileObjectPerf.cs @@ -1,7 +1,4 @@ using BenchmarkDotNet.Attributes; -using System; -using System.Collections.Generic; -using System.Text; using System.Threading; namespace Benchmarks @@ -57,5 +54,13 @@ public void ConstructAndQueryNonAgileObject() CallObject(); objectCreated.Reset(); } + + [Benchmark] + public void ConstructNonAgileObject() + { + createObject.Set(); + objectCreated.WaitOne(); + objectCreated.Reset(); + } } } diff --git a/src/WinRT.Runtime/ObjectReference.cs b/src/WinRT.Runtime/ObjectReference.cs index 6a7af3aff..1950bc380 100644 --- a/src/WinRT.Runtime/ObjectReference.cs +++ b/src/WinRT.Runtime/ObjectReference.cs @@ -450,7 +450,7 @@ internal sealed class ObjectReferenceWithContext : ObjectReference private readonly IntPtr _contextToken; private volatile ConcurrentDictionary> __cachedContext; - private ConcurrentDictionary> _cachedContext => __cachedContext ?? Make_CachedContext(); + private ConcurrentDictionary> CachedContext => __cachedContext ?? Make_CachedContext(); private ConcurrentDictionary> Make_CachedContext() { global::System.Threading.Interlocked.CompareExchange(ref __cachedContext, new(), null); @@ -458,10 +458,9 @@ private ConcurrentDictionary> Make_CachedContext() } private volatile AgileReference __agileReference; - private AgileReference _agileReference => __agileReference ?? Make_AgileReference(); + private AgileReference AgileReference => __agileReference ?? Make_AgileReference(); private AgileReference Make_AgileReference() { - // Might need to wrap these into a lambda and call it in the CompareExchange AgileReference agileReference = null; Context.CallInContext(_contextCallbackPtr, _contextToken, InitAgileReference, null); void InitAgileReference() { agileReference = new AgileReference(this); } @@ -477,40 +476,11 @@ internal ObjectReferenceWithContext(IntPtr thisPtr, IntPtr contextCallbackPtr, I { _contextCallbackPtr = contextCallbackPtr; _contextToken = contextToken; - // _cachedContext = new Lazy>>(); - /* - _agileReference = new Lazy(() => { - AgileReference agileReference = null; - Context.CallInContext(_contextCallbackPtr, _contextToken, InitAgileReference, null); - return agileReference; - - void InitAgileReference() - { - agileReference = new AgileReference(this); - } - }); - */ } internal ObjectReferenceWithContext(IntPtr thisPtr, IntPtr contextCallbackPtr, IntPtr contextToken, Guid iid) - : base(thisPtr) + : this(thisPtr, contextCallbackPtr, contextToken) { - _contextCallbackPtr = contextCallbackPtr; - _contextToken = contextToken; - // _cachedContext = new Lazy>>(); - /* - _agileReference = new Lazy(() => { - AgileReference agileReference = null; - Context.CallInContext(_contextCallbackPtr, _contextToken, InitAgileReference, null); - return agileReference; - - void InitAgileReference() - { - agileReference = new AgileReference(this); - } - }); - */ - _iid = iid; } @@ -548,11 +518,11 @@ private ObjectReference GetCurrentContext() return null; } - return _cachedContext.GetOrAdd(currentContext, CreateForCurrentContext); + return CachedContext.GetOrAdd(currentContext, CreateForCurrentContext); ObjectReference CreateForCurrentContext(IntPtr _) { - var agileReference = _agileReference; + var agileReference = AgileReference; // We may fail to switch context and thereby not get an agile reference. // In these cases, fallback to using the current context. if (agileReference == null) @@ -574,9 +544,9 @@ ObjectReference CreateForCurrentContext(IntPtr _) protected override unsafe void Release() { - if (_cachedContext != null) + if (__cachedContext != null) { - _cachedContext.Clear(); + CachedContext.Clear(); } Context.CallInContext(_contextCallbackPtr, _contextToken, base.Release, ReleaseWithoutContext); From 41a69e530fd5f8f7a5b60fe6a015fc43242eb50d Mon Sep 17 00:00:00 2001 From: Manodasan Wignarajah Date: Wed, 9 Feb 2022 12:56:10 -0800 Subject: [PATCH 4/7] Minor changes --- src/Benchmarks/NonAgileObjectPerf.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Benchmarks/NonAgileObjectPerf.cs b/src/Benchmarks/NonAgileObjectPerf.cs index 29cbedda9..a945e409d 100644 --- a/src/Benchmarks/NonAgileObjectPerf.cs +++ b/src/Benchmarks/NonAgileObjectPerf.cs @@ -10,7 +10,7 @@ public class NonAgileObjectPerf AutoResetEvent exitThread; AutoResetEvent objectCreated; Thread staThread; - private Windows.UI.Popups.PopupMenu nonAgileObject; + private volatile Windows.UI.Popups.PopupMenu nonAgileObject; [GlobalSetup] public void Setup() @@ -36,7 +36,7 @@ private void ObjectAllocationLoop() { createObject.Reset(); nonAgileObject = new Windows.UI.Popups.PopupMenu(); - _ = nonAgileObject.Commands.Count; + CallObject(); objectCreated.Set(); } } From e95a87aed5ea4341ba6d742ef725262bb82118fe Mon Sep 17 00:00:00 2001 From: Manodasan Wignarajah Date: Thu, 10 Feb 2022 00:57:27 -0800 Subject: [PATCH 5/7] Agile reference optimizations --- src/WinRT.Runtime/AgileReference.cs | 15 +- .../Interop/IAgileReference.net5.cs | 148 ++++++++---------- .../Interop/IAgileReference.netstandard2.0.cs | 55 +++++-- src/WinRT.Runtime/ObjectReference.cs | 27 ++-- 4 files changed, 135 insertions(+), 110 deletions(-) diff --git a/src/WinRT.Runtime/AgileReference.cs b/src/WinRT.Runtime/AgileReference.cs index 41c992a2c..efffe18a8 100644 --- a/src/WinRT.Runtime/AgileReference.cs +++ b/src/WinRT.Runtime/AgileReference.cs @@ -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 Git = new Lazy(() => GetGitTable()); - private readonly IAgileReference _agileReference; + private readonly IObjectReference _agileReference; private readonly IntPtr _cookie; private bool disposed; @@ -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.Attach(ref agileReference)); -#else - _agileReference = ABI.WinRT.Interop.IAgileReference.FromAbi(agileReference).AsType(); -#endif + &agileReference)); + _agileReference = ObjectReference.Attach(ref agileReference); } catch(TypeLoadException) { @@ -51,7 +47,10 @@ public unsafe AgileReference(IObjectReference instance) MarshalInterface.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 Get(Guid iid) => _cookie == IntPtr.Zero ? ABI.WinRT.Interop.IAgileReferenceMethods.Resolve(_agileReference, iid) : Git.Value?.GetInterfaceFromGlobal(_cookie, IUnknownVftbl.IID)?.As(iid); protected virtual void Dispose(bool disposing) { diff --git a/src/WinRT.Runtime/Interop/IAgileReference.net5.cs b/src/WinRT.Runtime/Interop/IAgileReference.net5.cs index a860fc784..2ebcdb9ea 100644 --- a/src/WinRT.Runtime/Interop/IAgileReference.net5.cs +++ b/src/WinRT.Runtime/Interop/IAgileReference.net5.cs @@ -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] @@ -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] Resolve { get => (delegate* unmanaged[Stdcall])_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]**)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)&Do_Abi_Resolve -#endif - }; - AbiToProjectionVftablePtr = Marshal.AllocHGlobal(Marshal.SizeOf()); - 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(thisPtr).Resolve(*riid); - *objectReference = _objectReference?.GetRef() ?? IntPtr.Zero; - } - catch (Exception __exception__) - { - return __exception__.HResult; - } - return 0; + MarshalInspectable.DisposeAbi(ptr); } - } - - public static ObjectReference FromAbi(IntPtr thisPtr) => ObjectReference.FromAbi(thisPtr); + } + + public static unsafe ObjectReference Resolve(IObjectReference _obj, Guid riid) + { + if (_obj == null) return null; - IObjectReference global::WinRT.Interop.IAgileReference.Resolve(Guid riid) - { - var _obj = ((ObjectReference)((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]**)ThisPtr)[3]( + ThisPtr, &riid, &ptr)); try { - return ComWrappersSupport.GetObjectReferenceForInterface(ptr); + return ComWrappersSupport.GetObjectReferenceForInterface(ptr); } finally { MarshalInspectable.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*)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(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()); - 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 FromAbi(IntPtr thisPtr) => ObjectReference.FromAbi(thisPtr); - } [Guid("00000146-0000-0000-C000-000000000046")] diff --git a/src/WinRT.Runtime/Interop/IAgileReference.netstandard2.0.cs b/src/WinRT.Runtime/Interop/IAgileReference.netstandard2.0.cs index 872b82b8e..1052770e2 100644 --- a/src/WinRT.Runtime/Interop/IAgileReference.netstandard2.0.cs +++ b/src/WinRT.Runtime/Interop/IAgileReference.netstandard2.0.cs @@ -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] @@ -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]**)ThisPtr)[3]( + ThisPtr, &riid, &ptr)); + try + { + return ComWrappersSupport.GetObjectReferenceForInterface(ptr); + } + finally + { + MarshalInspectable.DisposeAbi(ptr); + } + } + + public static unsafe ObjectReference Resolve(IObjectReference _obj, Guid riid) + { + if (_obj == null) return null; + + var ThisPtr = _obj.ThisPtr; + IntPtr ptr = IntPtr.Zero; + ExceptionHelpers.ThrowExceptionForHR((*(delegate* unmanaged[Stdcall]**)ThisPtr)[3]( + ThisPtr, &riid, &ptr)); + try + { + return ComWrappersSupport.GetObjectReferenceForInterface(ptr); + } + finally + { + MarshalInspectable.DisposeAbi(ptr); + } + } + } [Guid("C03F6A43-65A4-9818-987E-E0B810D2A6F2")] internal sealed unsafe class IAgileReference : global::WinRT.Interop.IAgileReference @@ -104,16 +143,8 @@ public IAgileReference(ObjectReference obj) public IObjectReference Resolve(Guid riid) { - ExceptionHelpers.ThrowExceptionForHR(_obj.Vftbl.Resolve(ThisPtr, ref riid, out IntPtr ptr)); - try - { - return ComWrappersSupport.GetObjectReferenceForInterface(ptr); - } - finally - { - MarshalInspectable.DisposeAbi(ptr); - } - } + return IAgileReferenceMethods.Resolve(_obj, riid); + } } [Guid("94ea2b94-e9cc-49e0-c0ff-ee64ca8f5b90")] diff --git a/src/WinRT.Runtime/ObjectReference.cs b/src/WinRT.Runtime/ObjectReference.cs index 1950bc380..f20e65f42 100644 --- a/src/WinRT.Runtime/ObjectReference.cs +++ b/src/WinRT.Runtime/ObjectReference.cs @@ -457,16 +457,22 @@ private ConcurrentDictionary> Make_CachedContext() return __cachedContext; } + // Agile reference can be null, so whether it is set is tracked separately. + private volatile bool _agileReferenceSet; private volatile AgileReference __agileReference; - private AgileReference AgileReference => __agileReference ?? Make_AgileReference(); + private AgileReference AgileReference => _agileReferenceSet ? __agileReference : Make_AgileReference(); private AgileReference Make_AgileReference() { - AgileReference agileReference = null; - Context.CallInContext(_contextCallbackPtr, _contextToken, InitAgileReference, null); - void InitAgileReference() { agileReference = new AgileReference(this); } + Context.CallInContext(_contextCallbackPtr, _contextToken, InitAgileReference, null); - global::System.Threading.Interlocked.CompareExchange(ref __agileReference, agileReference, null); - return __agileReference; + // Set after CallInContext callback given callback can fail to occur. + _agileReferenceSet = true; + return __agileReference; + + void InitAgileReference() + { + global::System.Threading.Interlocked.CompareExchange(ref __agileReference, new AgileReference(this), null); + } } private readonly Guid _iid; @@ -530,20 +536,21 @@ ObjectReference CreateForCurrentContext(IntPtr _) return null; } - using var referenceInContext = agileReference.Get(); if (_iid == Guid.Empty) - { + { + using var referenceInContext = agileReference.Get(); return referenceInContext.TryAs(out var objRef) >= 0 ? objRef : null; } else - { - return referenceInContext.TryAs(_iid, out var objRef) >= 0 ? objRef : null; + { + return agileReference.Get(_iid); } } } protected override unsafe void Release() { + // Don't initialize cached context by calling through property if it is already null. if (__cachedContext != null) { CachedContext.Clear(); From 7c36c9857137ac052cd96e68572b64735167783e Mon Sep 17 00:00:00 2001 From: Manodasan Wignarajah Date: Thu, 10 Feb 2022 01:01:19 -0800 Subject: [PATCH 6/7] Variable rename --- src/WinRT.Runtime/ObjectReference.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/WinRT.Runtime/ObjectReference.cs b/src/WinRT.Runtime/ObjectReference.cs index f20e65f42..9b2760d2b 100644 --- a/src/WinRT.Runtime/ObjectReference.cs +++ b/src/WinRT.Runtime/ObjectReference.cs @@ -458,15 +458,15 @@ private ConcurrentDictionary> Make_CachedContext() } // Agile reference can be null, so whether it is set is tracked separately. - private volatile bool _agileReferenceSet; + private volatile bool _isAgileReferenceSet; private volatile AgileReference __agileReference; - private AgileReference AgileReference => _agileReferenceSet ? __agileReference : Make_AgileReference(); + private AgileReference AgileReference => _isAgileReferenceSet ? __agileReference : Make_AgileReference(); private AgileReference Make_AgileReference() { Context.CallInContext(_contextCallbackPtr, _contextToken, InitAgileReference, null); // Set after CallInContext callback given callback can fail to occur. - _agileReferenceSet = true; + _isAgileReferenceSet = true; return __agileReference; void InitAgileReference() From 8aa1ba5ec14eabb88459e25ec8ea4acac380901e Mon Sep 17 00:00:00 2001 From: Manodasan Wignarajah Date: Tue, 15 Feb 2022 19:45:54 -0800 Subject: [PATCH 7/7] Add back fallback --- src/WinRT.Runtime/ObjectReference.cs | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/src/WinRT.Runtime/ObjectReference.cs b/src/WinRT.Runtime/ObjectReference.cs index 9b2760d2b..592006146 100644 --- a/src/WinRT.Runtime/ObjectReference.cs +++ b/src/WinRT.Runtime/ObjectReference.cs @@ -536,14 +536,21 @@ ObjectReference CreateForCurrentContext(IntPtr _) return null; } - if (_iid == Guid.Empty) + try { - using var referenceInContext = agileReference.Get(); - return referenceInContext.TryAs(out var objRef) >= 0 ? objRef : null; + if (_iid == Guid.Empty) + { + return agileReference.Get(GuidGenerator.GetIID(typeof(T))); + } + else + { + return agileReference.Get(_iid); + } } - else + catch (Exception) { - return agileReference.Get(_iid); + // Fallback to using the current context in case of error. + return null; } } }