diff --git a/src/coreclr/System.Private.CoreLib/System.Private.CoreLib.csproj b/src/coreclr/System.Private.CoreLib/System.Private.CoreLib.csproj
index a4ddab439f6c07..854e13fedb8a97 100644
--- a/src/coreclr/System.Private.CoreLib/System.Private.CoreLib.csproj
+++ b/src/coreclr/System.Private.CoreLib/System.Private.CoreLib.csproj
@@ -254,7 +254,8 @@
-
+
+
diff --git a/src/coreclr/System.Private.CoreLib/src/System/ComAwareWeakReference.CoreCLR.cs b/src/coreclr/System.Private.CoreLib/src/System/ComAwareWeakReference.CoreCLR.cs
index de9aeddf403054..de9908401cba8b 100644
--- a/src/coreclr/System.Private.CoreLib/src/System/ComAwareWeakReference.CoreCLR.cs
+++ b/src/coreclr/System.Private.CoreLib/src/System/ComAwareWeakReference.CoreCLR.cs
@@ -10,46 +10,56 @@ namespace System
internal sealed partial class ComAwareWeakReference
{
[LibraryImport(RuntimeHelpers.QCall, EntryPoint = "ComWeakRefToObject")]
- private static partial void ComWeakRefToObject(IntPtr pComWeakRef, long wrapperId, ObjectHandleOnStack retRcw);
+ private static partial void ComWeakRefToObject(IntPtr pComWeakRef, ObjectHandleOnStack retRcw);
- internal static object? ComWeakRefToObject(IntPtr pComWeakRef, long wrapperId)
+ internal static object? ComWeakRefToObject(IntPtr pComWeakRef, object? context)
{
- object? retRcw = null;
- ComWeakRefToObject(pComWeakRef, wrapperId, ObjectHandleOnStack.Create(ref retRcw));
- return retRcw;
+#if FEATURE_COMINTEROP
+ if (context is null)
+ {
+ // This wrapper was not created by ComWrappers, so we try to rehydrate using built-in COM.
+ object? retRcw = null;
+ ComWeakRefToObject(pComWeakRef, ObjectHandleOnStack.Create(ref retRcw));
+ return retRcw;
+ }
+#endif // FEATURE_COMINTEROP
+
+ return ComWeakRefToComWrappersObject(pComWeakRef, context);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
internal static unsafe bool PossiblyComObject(object target)
{
- // see: syncblk.h
- const int IS_HASHCODE_BIT_NUMBER = 26;
- const int BIT_SBLK_IS_HASHCODE = 1 << IS_HASHCODE_BIT_NUMBER;
- const int BIT_SBLK_IS_HASH_OR_SYNCBLKINDEX = 0x08000000;
-
- fixed (byte* pRawData = &target.GetRawData())
- {
- // The header is 4 bytes before MT field on all architectures
- int header = *(int*)(pRawData - sizeof(IntPtr) - sizeof(int));
- // common case: target does not have a syncblock, so there is no interop info
- return (header & (BIT_SBLK_IS_HASH_OR_SYNCBLKINDEX | BIT_SBLK_IS_HASHCODE)) == BIT_SBLK_IS_HASH_OR_SYNCBLKINDEX;
- }
+#if FEATURE_COMINTEROP
+ return target is __ComObject || PossiblyComWrappersObject(target);
+#else // !FEATURE_COMINTEROP
+ // If we are not using built-in COM, then we can only be a ComWrappers object.
+ return PossiblyComWrappersObject(target);
+#endif // FEATURE_COMINTEROP
}
- [MethodImpl(MethodImplOptions.InternalCall)]
- internal static extern bool HasInteropInfo(object target);
-
[LibraryImport(RuntimeHelpers.QCall, EntryPoint = "ObjectToComWeakRef")]
- private static partial IntPtr ObjectToComWeakRef(ObjectHandleOnStack retRcw, out long wrapperId);
+ private static partial IntPtr ObjectToComWeakRef(ObjectHandleOnStack retRcw);
- internal static nint ObjectToComWeakRef(object target, out long wrapperId)
+ internal static nint ObjectToComWeakRef(object target, out object? context)
{
- if (HasInteropInfo(target))
+#if FEATURE_COMINTEROP
+ if (target is __ComObject)
+ {
+ // This object is using built-in COM, so use built-in COM to create the weak reference.
+ context = null;
+ return ObjectToComWeakRef(ObjectHandleOnStack.Create(ref target));
+ }
+#endif // FEATURE_COMINTEROP
+
+ if (PossiblyComWrappersObject(target))
{
- return ObjectToComWeakRef(ObjectHandleOnStack.Create(ref target), out wrapperId);
+ return ComWrappersObjectToComWeakRef(target, out context);
}
- wrapperId = 0;
+ // This object is not produced using built-in COM or ComWrappers
+ // or is an aggregated object, so we cannot create a weak reference.
+ context = null;
return IntPtr.Zero;
}
}
diff --git a/src/coreclr/System.Private.CoreLib/src/System/GC.CoreCLR.cs b/src/coreclr/System.Private.CoreLib/src/System/GC.CoreCLR.cs
index 184ce80f44b899..101fbfa7c6bc45 100644
--- a/src/coreclr/System.Private.CoreLib/src/System/GC.CoreCLR.cs
+++ b/src/coreclr/System.Private.CoreLib/src/System/GC.CoreCLR.cs
@@ -106,7 +106,7 @@ internal enum GC_ALLOC_FLAGS
private static partial long GetTotalMemory();
[LibraryImport(RuntimeHelpers.QCall, EntryPoint = "GCInterface_Collect")]
- private static partial void _Collect(int generation, int mode);
+ private static partial void _Collect(int generation, int mode, [MarshalAs(UnmanagedType.U1)] bool lowMemoryPressure);
[MethodImpl(MethodImplOptions.InternalCall)]
private static extern int GetMaxGeneration();
@@ -174,7 +174,7 @@ public static void Collect(int generation)
public static void Collect()
{
// -1 says to GC all generations.
- _Collect(-1, (int)InternalGCCollectionMode.Blocking);
+ _Collect(-1, (int)InternalGCCollectionMode.Blocking, lowMemoryPressure: false);
}
public static void Collect(int generation, GCCollectionMode mode)
@@ -189,6 +189,11 @@ public static void Collect(int generation, GCCollectionMode mode, bool blocking)
}
public static void Collect(int generation, GCCollectionMode mode, bool blocking, bool compacting)
+ {
+ Collect(generation, mode, blocking, compacting, lowMemoryPressure: false);
+ }
+
+ internal static void Collect(int generation, GCCollectionMode mode, bool blocking, bool compacting, bool lowMemoryPressure)
{
ArgumentOutOfRangeException.ThrowIfNegative(generation);
@@ -197,7 +202,6 @@ public static void Collect(int generation, GCCollectionMode mode, bool blocking,
throw new ArgumentOutOfRangeException(nameof(mode), SR.ArgumentOutOfRange_Enum);
}
-
int iInternalModes = 0;
if (mode == GCCollectionMode.Optimized)
@@ -222,7 +226,9 @@ public static void Collect(int generation, GCCollectionMode mode, bool blocking,
}
if (compacting)
+ {
iInternalModes |= (int)InternalGCCollectionMode.Compacting;
+ }
if (blocking)
{
@@ -233,7 +239,7 @@ public static void Collect(int generation, GCCollectionMode mode, bool blocking,
iInternalModes |= (int)InternalGCCollectionMode.NonBlocking;
}
- _Collect(generation, iInternalModes);
+ _Collect(generation, (int)iInternalModes, lowMemoryPressure);
}
public static int CollectionCount(int generation)
diff --git a/src/coreclr/System.Private.CoreLib/src/System/Runtime/InteropServices/ComWrappers.CoreCLR.cs b/src/coreclr/System.Private.CoreLib/src/System/Runtime/InteropServices/ComWrappers.CoreCLR.cs
new file mode 100644
index 00000000000000..5f89431729f0aa
--- /dev/null
+++ b/src/coreclr/System.Private.CoreLib/src/System/Runtime/InteropServices/ComWrappers.CoreCLR.cs
@@ -0,0 +1,119 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+
+using System.Threading;
+using System.Runtime.CompilerServices;
+using System.Collections.Generic;
+using System.Collections.Concurrent;
+
+namespace System.Runtime.InteropServices
+{
+ ///
+ /// Class for managing wrappers of COM IUnknown types.
+ ///
+ public abstract partial class ComWrappers
+ {
+ ///
+ /// Get the runtime provided IUnknown implementation.
+ ///
+ /// Function pointer to QueryInterface.
+ /// Function pointer to AddRef.
+ /// Function pointer to Release.
+ public static unsafe void GetIUnknownImpl(out IntPtr fpQueryInterface, out IntPtr fpAddRef, out IntPtr fpRelease)
+ => GetIUnknownImplInternal(out fpQueryInterface, out fpAddRef, out fpRelease);
+
+ [LibraryImport(RuntimeHelpers.QCall, EntryPoint = "ComWrappers_GetIUnknownImpl")]
+ [SuppressGCTransition]
+ private static partial void GetIUnknownImplInternal(out IntPtr fpQueryInterface, out IntPtr fpAddRef, out IntPtr fpRelease);
+
+ internal static IntPtr DefaultIUnknownVftblPtr { get; } = CreateDefaultIUnknownVftbl();
+ internal static IntPtr TaggedImplVftblPtr { get; } = CreateTaggedImplVftbl();
+ internal static IntPtr DefaultIReferenceTrackerTargetVftblPtr { get; } = CreateDefaultIReferenceTrackerTargetVftbl();
+
+ private static unsafe IntPtr CreateDefaultIUnknownVftbl()
+ {
+ IntPtr* vftbl = (IntPtr*)RuntimeHelpers.AllocateTypeAssociatedMemory(typeof(ComWrappers), 3 * sizeof(IntPtr));
+ GetIUnknownImpl(out vftbl[0], out vftbl[1], out vftbl[2]);
+ return (IntPtr)vftbl;
+ }
+
+ private static unsafe IntPtr CreateTaggedImplVftbl()
+ {
+ IntPtr* vftbl = (IntPtr*)RuntimeHelpers.AllocateTypeAssociatedMemory(typeof(ComWrappers), 4 * sizeof(IntPtr));
+ GetIUnknownImpl(out vftbl[0], out vftbl[1], out vftbl[2]);
+ vftbl[3] = GetTaggedImplCurrentVersion();
+ return (IntPtr)vftbl;
+ }
+
+ internal static int CallICustomQueryInterface(ManagedObjectWrapperHolder holder, ref Guid iid, out IntPtr ppObject)
+ {
+ if (holder.WrappedObject is ICustomQueryInterface customQueryInterface)
+ {
+ return (int)customQueryInterface.GetInterface(ref iid, out ppObject);
+ }
+
+ ppObject = IntPtr.Zero;
+ return -1; // See TryInvokeICustomQueryInterfaceResult
+ }
+
+ internal static IntPtr GetOrCreateComInterfaceForObjectWithGlobalMarshallingInstance(object obj)
+ {
+ try
+ {
+ return s_globalInstanceForMarshalling is null
+ ? IntPtr.Zero
+ : s_globalInstanceForMarshalling.GetOrCreateComInterfaceForObject(obj, CreateComInterfaceFlags.TrackerSupport);
+ }
+ catch (ArgumentException)
+ {
+ // We've failed to create a COM interface for the object.
+ // Fallback to built-in COM.
+ return IntPtr.Zero;
+ }
+ }
+
+ internal static object? GetOrCreateObjectForComInstanceWithGlobalMarshallingInstance(IntPtr comObject, CreateObjectFlags flags)
+ {
+ try
+ {
+ return s_globalInstanceForMarshalling?.GetOrCreateObjectForComInstance(comObject, flags);
+ }
+ catch (ArgumentNullException)
+ {
+ // We've failed to create a managed object for the COM instance.
+ // Fallback to built-in COM.
+ return null;
+ }
+ }
+
+ [LibraryImport(RuntimeHelpers.QCall, EntryPoint = "ComWrappers_GetIReferenceTrackerTargetVftbl")]
+ [SuppressGCTransition]
+ private static partial IntPtr GetDefaultIReferenceTrackerTargetVftbl();
+
+ private static IntPtr CreateDefaultIReferenceTrackerTargetVftbl()
+ => GetDefaultIReferenceTrackerTargetVftbl();
+
+ private static IntPtr GetTaggedImplCurrentVersion()
+ {
+ return GetTaggedImpl();
+ }
+
+ [LibraryImport(RuntimeHelpers.QCall, EntryPoint = "ComWrappers_GetTaggedImpl")]
+ [SuppressGCTransition]
+ private static partial IntPtr GetTaggedImpl();
+
+ internal sealed partial class ManagedObjectWrapperHolder
+ {
+ [LibraryImport(RuntimeHelpers.QCall, EntryPoint = "ComWrappers_RegisterIsRootedCallback")]
+ private static partial void RegisterIsRootedCallback();
+
+ private static IntPtr AllocateRefCountedHandle(ManagedObjectWrapperHolder holder)
+ {
+ return AllocateRefCountedHandle(ObjectHandleOnStack.Create(ref holder));
+ }
+
+ [LibraryImport(RuntimeHelpers.QCall, EntryPoint = "ComWrappers_AllocateRefCountedHandle")]
+ private static partial IntPtr AllocateRefCountedHandle(ObjectHandleOnStack obj);
+ }
+ }
+}
diff --git a/src/coreclr/System.Private.CoreLib/src/System/Runtime/InteropServices/ComWrappers.cs b/src/coreclr/System.Private.CoreLib/src/System/Runtime/InteropServices/ComWrappers.cs
deleted file mode 100644
index c7c78a7325f998..00000000000000
--- a/src/coreclr/System.Private.CoreLib/src/System/Runtime/InteropServices/ComWrappers.cs
+++ /dev/null
@@ -1,396 +0,0 @@
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
-
-using System;
-using System.Collections;
-using System.Diagnostics.CodeAnalysis;
-using System.Runtime.CompilerServices;
-using System.Runtime.Versioning;
-using System.Threading;
-
-namespace System.Runtime.InteropServices
-{
- ///
- /// Internal enumeration used by the runtime to indicate the scenario for which ComWrappers is being used.
- ///
- internal enum ComWrappersScenario
- {
- Instance = 0,
- TrackerSupportGlobalInstance = 1,
- MarshallingGlobalInstance = 2,
- }
-
- ///
- /// Class for managing wrappers of COM IUnknown types.
- ///
- public abstract partial class ComWrappers
- {
- ///
- /// Given a managed object, determine if it is a -created
- /// managed wrapper and if so, return the wrapped unmanaged pointer.
- ///
- /// A managed wrapper
- /// An unmanaged COM object
- /// True if the wrapper was resolved to an external COM object, otherwise false.
- ///
- /// If a COM object is returned, the caller is expected to call Release() on the object.
- /// This can be done through an API like .
- /// Since this API is required to interact directly with the external COM object, QueryInterface(),
- /// it is important for the caller to understand the COM object may have apartment affinity and therefore
- /// if the current thread is not in the correct apartment or the COM object is not a proxy this call may fail.
- ///
- public static bool TryGetComInstance(object obj, out IntPtr unknown)
- {
- if (obj == null)
- {
- unknown = IntPtr.Zero;
- return false;
- }
-
- return TryGetComInstanceInternal(ObjectHandleOnStack.Create(ref obj), out unknown);
- }
-
- [LibraryImport(RuntimeHelpers.QCall, EntryPoint = "ComWrappers_TryGetComInstance")]
- [return: MarshalAs(UnmanagedType.Bool)]
- private static partial bool TryGetComInstanceInternal(ObjectHandleOnStack wrapperMaybe, out IntPtr externalComObject);
-
- ///
- /// Given a COM object, determine if it is a -created
- /// unmanaged wrapper and if so, return the wrapped managed object.
- ///
- /// An unmanaged wrapper
- /// A managed object
- /// True if the wrapper was resolved to a managed object, otherwise false.
- public static bool TryGetObject(IntPtr unknown, [NotNullWhen(true)] out object? obj)
- {
- obj = null;
- if (unknown == IntPtr.Zero)
- {
- return false;
- }
-
- return TryGetObjectInternal(unknown, ObjectHandleOnStack.Create(ref obj));
- }
-
- [LibraryImport(RuntimeHelpers.QCall, EntryPoint = "ComWrappers_TryGetObject")]
- [return: MarshalAs(UnmanagedType.Bool)]
- private static partial bool TryGetObjectInternal(IntPtr wrapperMaybe, ObjectHandleOnStack instance);
-
- ///
- /// ABI for function dispatch of a COM interface.
- ///
- public partial struct ComInterfaceDispatch
- {
- ///
- /// Given a from a generated Vtable, convert to the target type.
- ///
- /// Desired type.
- /// Pointer supplied to Vtable function entry.
- /// Instance of type associated with dispatched function call.
- public static unsafe T GetInstance(ComInterfaceDispatch* dispatchPtr) where T : class
- {
- // See the dispatch section in the runtime for details on the masking below.
- long DispatchAlignmentThisPtr = sizeof(void*) == 8 ? 64 : 16; // Should be a power of 2.
- long DispatchThisPtrMask = ~(DispatchAlignmentThisPtr - 1);
- var comInstance = *(ComInterfaceInstance**)(((long)dispatchPtr) & DispatchThisPtrMask);
-
- return Unsafe.As(GCHandle.InternalGet(comInstance->GcHandle));
- }
-
- private struct ComInterfaceInstance
- {
- public IntPtr GcHandle;
- }
- }
-
- ///
- /// Globally registered instance of the ComWrappers class for reference tracker support.
- ///
- private static ComWrappers? s_globalInstanceForTrackerSupport;
-
- ///
- /// Globally registered instance of the ComWrappers class for marshalling.
- ///
- private static ComWrappers? s_globalInstanceForMarshalling;
-
- private static long s_instanceCounter;
- private readonly long id = Interlocked.Increment(ref s_instanceCounter);
-
- ///
- /// Create a COM representation of the supplied object that can be passed to a non-managed environment.
- ///
- /// The managed object to expose outside the .NET runtime.
- /// Flags used to configure the generated interface.
- /// The generated COM interface that can be passed outside the .NET runtime.
- ///
- /// If a COM representation was previously created for the specified using
- /// this instance, the previously created COM interface will be returned.
- /// If not, a new one will be created.
- ///
- public IntPtr GetOrCreateComInterfaceForObject(object instance, CreateComInterfaceFlags flags)
- {
- IntPtr ptr;
- if (!TryGetOrCreateComInterfaceForObjectInternal(this, instance, flags, out ptr))
- throw new ArgumentException(null, nameof(instance));
-
- return ptr;
- }
-
- ///
- /// Create a COM representation of the supplied object that can be passed to a non-managed environment.
- ///
- /// The implementation to use when creating the COM representation.
- /// The managed object to expose outside the .NET runtime.
- /// Flags used to configure the generated interface.
- /// The generated COM interface that can be passed outside the .NET runtime or IntPtr.Zero if it could not be created.
- /// Returns true if a COM representation could be created, false otherwise
- ///
- /// If is null, the global instance (if registered) will be used.
- ///
- private static bool TryGetOrCreateComInterfaceForObjectInternal(ComWrappers impl, object instance, CreateComInterfaceFlags flags, out IntPtr retValue)
- {
- ArgumentNullException.ThrowIfNull(instance);
-
- return TryGetOrCreateComInterfaceForObjectInternal(ObjectHandleOnStack.Create(ref impl), impl.id, ObjectHandleOnStack.Create(ref instance), flags, out retValue);
- }
-
- [LibraryImport(RuntimeHelpers.QCall, EntryPoint = "ComWrappers_TryGetOrCreateComInterfaceForObject")]
- [return: MarshalAs(UnmanagedType.Bool)]
- private static partial bool TryGetOrCreateComInterfaceForObjectInternal(ObjectHandleOnStack comWrappersImpl, long wrapperId, ObjectHandleOnStack instance, CreateComInterfaceFlags flags, out IntPtr retValue);
-
- // Called by the runtime to execute the abstract instance function
- internal static unsafe void* CallComputeVtables(ComWrappersScenario scenario, ComWrappers? comWrappersImpl, object obj, CreateComInterfaceFlags flags, out int count)
- {
- ComWrappers? impl = null;
- switch (scenario)
- {
- case ComWrappersScenario.Instance:
- impl = comWrappersImpl;
- break;
- case ComWrappersScenario.TrackerSupportGlobalInstance:
- impl = s_globalInstanceForTrackerSupport;
- break;
- case ComWrappersScenario.MarshallingGlobalInstance:
- impl = s_globalInstanceForMarshalling;
- break;
- }
-
- if (impl is null)
- {
- count = -1;
- return null;
- }
-
- return impl.ComputeVtables(obj, flags, out count);
- }
-
- ///
- /// Get the currently registered managed object or creates a new managed object and registers it.
- ///
- /// Object to import for usage into the .NET runtime.
- /// Flags used to describe the external object.
- /// Returns a managed object associated with the supplied external COM object.
- ///
- /// If a managed object was previously created for the specified
- /// using this instance, the previously created object will be returned.
- /// If not, a new one will be created.
- ///
- public object GetOrCreateObjectForComInstance(IntPtr externalComObject, CreateObjectFlags flags)
- {
- object? obj;
- if (!TryGetOrCreateObjectForComInstanceInternal(this, externalComObject, IntPtr.Zero, flags, null, out obj))
- throw new ArgumentNullException(nameof(externalComObject));
-
- return obj!;
- }
-
- // Called by the runtime to execute the abstract instance function.
- internal static object? CallCreateObject(ComWrappersScenario scenario, ComWrappers? comWrappersImpl, IntPtr externalComObject, CreateObjectFlags flags)
- {
- ComWrappers? impl = null;
- switch (scenario)
- {
- case ComWrappersScenario.Instance:
- impl = comWrappersImpl;
- break;
- case ComWrappersScenario.TrackerSupportGlobalInstance:
- impl = s_globalInstanceForTrackerSupport;
- break;
- case ComWrappersScenario.MarshallingGlobalInstance:
- impl = s_globalInstanceForMarshalling;
- break;
- }
-
- if (impl == null)
- return null;
-
- return impl.CreateObject(externalComObject, flags);
- }
-
- ///
- /// Get the currently registered managed object or uses the supplied managed object and registers it.
- ///
- /// Object to import for usage into the .NET runtime.
- /// Flags used to describe the external object.
- /// The to be used as the wrapper for the external object
- /// Returns a managed object associated with the supplied external COM object.
- ///
- /// If the instance already has an associated external object a will be thrown.
- ///
- public object GetOrRegisterObjectForComInstance(IntPtr externalComObject, CreateObjectFlags flags, object wrapper)
- {
- return GetOrRegisterObjectForComInstance(externalComObject, flags, wrapper, IntPtr.Zero);
- }
-
- ///
- /// Get the currently registered managed object or uses the supplied managed object and registers it.
- ///
- /// Object to import for usage into the .NET runtime.
- /// Flags used to describe the external object.
- /// The to be used as the wrapper for the external object
- /// Inner for COM aggregation scenarios
- /// Returns a managed object associated with the supplied external COM object.
- ///
- /// This method override is for registering an aggregated COM instance with its associated inner. The inner
- /// will be released when the associated wrapper is eventually freed. Note that it will be released on a thread
- /// in an unknown apartment state. If the supplied inner is not known to be a free-threaded instance then
- /// it is advised to not supply the inner.
- ///
- /// If the instance already has an associated external object a will be thrown.
- ///
- public object GetOrRegisterObjectForComInstance(IntPtr externalComObject, CreateObjectFlags flags, object wrapper, IntPtr inner)
- {
- ArgumentNullException.ThrowIfNull(wrapper);
-
- object? obj;
- if (!TryGetOrCreateObjectForComInstanceInternal(this, externalComObject, inner, flags, wrapper, out obj))
- throw new ArgumentNullException(nameof(externalComObject));
-
- return obj!;
- }
-
- ///
- /// Get the currently registered managed object or creates a new managed object and registers it.
- ///
- /// The implementation to use when creating the managed object.
- /// Object to import for usage into the .NET runtime.
- /// The inner instance if aggregation is involved
- /// Flags used to describe the external object.
- /// The to be used as the wrapper for the external object.
- /// The managed object associated with the supplied external COM object or null if it could not be created.
- /// Returns true if a managed object could be retrieved/created, false otherwise
- ///
- /// If is null, the global instance (if registered) will be used.
- ///
- private static bool TryGetOrCreateObjectForComInstanceInternal(
- ComWrappers impl,
- IntPtr externalComObject,
- IntPtr innerMaybe,
- CreateObjectFlags flags,
- object? wrapperMaybe,
- out object? retValue)
- {
- ArgumentNullException.ThrowIfNull(externalComObject);
-
- // If the inner is supplied the Aggregation flag should be set.
- if (innerMaybe != IntPtr.Zero && !flags.HasFlag(CreateObjectFlags.Aggregation))
- throw new InvalidOperationException(SR.InvalidOperation_SuppliedInnerMustBeMarkedAggregation);
-
- object? wrapperMaybeLocal = wrapperMaybe;
- retValue = null;
- return TryGetOrCreateObjectForComInstanceInternal(ObjectHandleOnStack.Create(ref impl), impl.id, externalComObject, innerMaybe, flags, ObjectHandleOnStack.Create(ref wrapperMaybeLocal), ObjectHandleOnStack.Create(ref retValue));
- }
-
- [LibraryImport(RuntimeHelpers.QCall, EntryPoint = "ComWrappers_TryGetOrCreateObjectForComInstance")]
- [return: MarshalAs(UnmanagedType.Bool)]
- private static partial bool TryGetOrCreateObjectForComInstanceInternal(ObjectHandleOnStack comWrappersImpl, long wrapperId, IntPtr externalComObject, IntPtr innerMaybe, CreateObjectFlags flags, ObjectHandleOnStack wrapper, ObjectHandleOnStack retValue);
-
- // Call to execute the virtual instance function
- internal static void CallReleaseObjects(ComWrappers? comWrappersImpl, IEnumerable objects)
- => (comWrappersImpl ?? s_globalInstanceForTrackerSupport!).ReleaseObjects(objects);
-
- ///
- /// Register a instance to be used as the global instance for reference tracker support.
- ///
- /// Instance to register
- ///
- /// This function can only be called a single time. Subsequent calls to this function will result
- /// in a being thrown.
- ///
- /// Scenarios where this global instance may be used are:
- /// * Object tracking via the and flags.
- ///
- public static void RegisterForTrackerSupport(ComWrappers instance)
- {
- ArgumentNullException.ThrowIfNull(instance);
-
- if (null != Interlocked.CompareExchange(ref s_globalInstanceForTrackerSupport, instance, null))
- {
- throw new InvalidOperationException(SR.InvalidOperation_ResetGlobalComWrappersInstance);
- }
-
- SetGlobalInstanceRegisteredForTrackerSupport(instance.id);
- }
-
-
- [LibraryImport(RuntimeHelpers.QCall, EntryPoint = "ComWrappers_SetGlobalInstanceRegisteredForTrackerSupport")]
- [SuppressGCTransition]
- private static partial void SetGlobalInstanceRegisteredForTrackerSupport(long id);
-
- ///
- /// Register a instance to be used as the global instance for marshalling in the runtime.
- ///
- /// Instance to register
- ///
- /// This function can only be called a single time. Subsequent calls to this function will result
- /// in a being thrown.
- ///
- /// Scenarios where this global instance may be used are:
- /// * Usage of COM-related Marshal APIs
- /// * P/Invokes with COM-related types
- /// * COM activation
- ///
- [SupportedOSPlatform("windows")]
- public static void RegisterForMarshalling(ComWrappers instance)
- {
- ArgumentNullException.ThrowIfNull(instance);
-
- if (null != Interlocked.CompareExchange(ref s_globalInstanceForMarshalling, instance, null))
- {
- throw new InvalidOperationException(SR.InvalidOperation_ResetGlobalComWrappersInstance);
- }
-
- // Indicate to the runtime that a global instance has been registered for marshalling.
- // This allows the native runtime know to call into the managed ComWrappers only if a
- // global instance is registered for marshalling.
- SetGlobalInstanceRegisteredForMarshalling(instance.id);
- }
-
- [LibraryImport(RuntimeHelpers.QCall, EntryPoint = "ComWrappers_SetGlobalInstanceRegisteredForMarshalling")]
- [SuppressGCTransition]
- private static partial void SetGlobalInstanceRegisteredForMarshalling(long id);
-
- ///
- /// Get the runtime provided IUnknown implementation.
- ///
- /// Function pointer to QueryInterface.
- /// Function pointer to AddRef.
- /// Function pointer to Release.
- public static void GetIUnknownImpl(out IntPtr fpQueryInterface, out IntPtr fpAddRef, out IntPtr fpRelease)
- => GetIUnknownImplInternal(out fpQueryInterface, out fpAddRef, out fpRelease);
-
- [LibraryImport(RuntimeHelpers.QCall, EntryPoint = "ComWrappers_GetIUnknownImpl")]
- private static partial void GetIUnknownImplInternal(out IntPtr fpQueryInterface, out IntPtr fpAddRef, out IntPtr fpRelease);
-
- internal static int CallICustomQueryInterface(object customQueryInterfaceMaybe, ref Guid iid, out IntPtr ppObject)
- {
- if (customQueryInterfaceMaybe is ICustomQueryInterface customQueryInterface)
- {
- return (int)customQueryInterface.GetInterface(ref iid, out ppObject);
- }
-
- ppObject = IntPtr.Zero;
- return -1; // See TryInvokeICustomQueryInterfaceResult
- }
- }
-}
diff --git a/src/coreclr/System.Private.CoreLib/src/System/Runtime/InteropServices/TrackerObjectManager.CoreCLR.cs b/src/coreclr/System.Private.CoreLib/src/System/Runtime/InteropServices/TrackerObjectManager.CoreCLR.cs
new file mode 100644
index 00000000000000..ac60cd56719b64
--- /dev/null
+++ b/src/coreclr/System.Private.CoreLib/src/System/Runtime/InteropServices/TrackerObjectManager.CoreCLR.cs
@@ -0,0 +1,45 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+
+using System;
+using System.Collections.Generic;
+using System.Runtime.CompilerServices;
+using System.Text;
+
+namespace System.Runtime.InteropServices
+{
+ internal static partial class TrackerObjectManager
+ {
+ private static bool HasReferenceTrackerManager
+ => HasReferenceTrackerManagerInternal();
+
+ [LibraryImport(RuntimeHelpers.QCall, EntryPoint = "TrackerObjectManager_HasReferenceTrackerManager")]
+ [SuppressGCTransition]
+ [return: MarshalAs(UnmanagedType.U1)]
+ private static partial bool HasReferenceTrackerManagerInternal();
+
+ [LibraryImport(RuntimeHelpers.QCall, EntryPoint = "TrackerObjectManager_TryRegisterReferenceTrackerManager")]
+ [SuppressGCTransition]
+ [return: MarshalAs(UnmanagedType.U1)]
+ private static partial bool TryRegisterReferenceTrackerManager(IntPtr referenceTrackerManager);
+
+ internal static bool IsGlobalPeggingEnabled
+ => IsGlobalPeggingEnabledInternal();
+
+ [LibraryImport(RuntimeHelpers.QCall, EntryPoint = "TrackerObjectManager_IsGlobalPeggingEnabled")]
+ [SuppressGCTransition]
+ [return: MarshalAs(UnmanagedType.U1)]
+ private static partial bool IsGlobalPeggingEnabledInternal();
+
+ private static void RegisterGCCallbacks()
+ {
+ // CoreCLR doesn't have GC callbacks, but we do need to register the GC handle set with the runtime for enumeration
+ // during GC.
+ GCHandleSet handleSet = s_referenceTrackerNativeObjectWrapperCache;
+ RegisterNativeObjectWrapperCache(ObjectHandleOnStack.Create(ref handleSet));
+ }
+
+ [LibraryImport(RuntimeHelpers.QCall, EntryPoint = "TrackerObjectManager_RegisterNativeObjectWrapperCache")]
+ private static partial void RegisterNativeObjectWrapperCache(ObjectHandleOnStack nativeObjectWrapperCache);
+ }
+}
diff --git a/src/coreclr/classlibnative/bcltype/objectnative.cpp b/src/coreclr/classlibnative/bcltype/objectnative.cpp
index 2a06cf22e737be..c9087be0db975f 100644
--- a/src/coreclr/classlibnative/bcltype/objectnative.cpp
+++ b/src/coreclr/classlibnative/bcltype/objectnative.cpp
@@ -45,24 +45,7 @@ FCIMPL1(INT32, ObjectNative::TryGetHashCode, Object* obj)
return 0;
OBJECTREF objRef = ObjectToOBJECTREF(obj);
- DWORD bits = objRef->GetHeader()->GetBits();
- if (bits & BIT_SBLK_IS_HASH_OR_SYNCBLKINDEX)
- {
- if (bits & BIT_SBLK_IS_HASHCODE)
- {
- // Common case: the object already has a hash code
- return bits & MASK_HASHCODE;
- }
- else
- {
- // We have a sync block index. This means if we already have a hash code,
- // it is in the sync block, otherwise we will return 0, which means "not set".
- SyncBlock *psb = objRef->PassiveGetSyncBlock();
- if (psb != NULL)
- return psb->GetHashCode();
- }
- }
- return 0;
+ return objRef->TryGetHashCode();
}
FCIMPLEND
diff --git a/src/coreclr/debug/daccess/dacimpl.h b/src/coreclr/debug/daccess/dacimpl.h
index f516c0eda6f200..ef4a8246374e56 100644
--- a/src/coreclr/debug/daccess/dacimpl.h
+++ b/src/coreclr/debug/daccess/dacimpl.h
@@ -1504,6 +1504,7 @@ class ClrDataAccess
BOOL DACIsComWrappersCCW(CLRDATA_ADDRESS ccwPtr);
TADDR DACGetManagedObjectWrapperFromCCW(CLRDATA_ADDRESS ccwPtr);
HRESULT DACTryGetComWrappersObjectFromCCW(CLRDATA_ADDRESS ccwPtr, OBJECTREF* objRef);
+ TADDR GetIdentityForManagedObjectWrapper(TADDR mow);
#endif
protected:
diff --git a/src/coreclr/debug/daccess/request.cpp b/src/coreclr/debug/daccess/request.cpp
index 96e38cc41b525f..99c157007ff20f 100644
--- a/src/coreclr/debug/daccess/request.cpp
+++ b/src/coreclr/debug/daccess/request.cpp
@@ -14,6 +14,7 @@
#include "typestring.h"
#include
#include
+#include
#ifdef FEATURE_COMINTEROP
#include
@@ -22,9 +23,6 @@
#ifdef FEATURE_COMWRAPPERS
#include
#include
-
-typedef DPTR(InteropLibInterface::ExternalObjectContextBase) PTR_ExternalObjectContext;
-typedef DPTR(InteropLib::ABI::ManagedObjectWrapperLayout) PTR_ManagedObjectWrapper;
#endif // FEATURE_COMWRAPPERS
#ifndef TARGET_UNIX
@@ -4433,6 +4431,7 @@ ErrExit: return hr;
HRESULT ClrDataAccess::DACTryGetComWrappersObjectFromCCW(CLRDATA_ADDRESS ccwPtr, OBJECTREF* objRef)
{
HRESULT hr = E_FAIL;
+ MOWHOLDERREF holder = NULL;
if (ccwPtr == 0 || objRef == NULL)
{
@@ -4447,7 +4446,9 @@ HRESULT ClrDataAccess::DACTryGetComWrappersObjectFromCCW(CLRDATA_ADDRESS ccwPtr,
goto ErrExit;
}
- *objRef = ObjectFromHandle(handle);
+ holder = (MOWHOLDERREF)ObjectFromHandle(handle);
+
+ *objRef = holder->_wrappedObject;
return S_OK;
@@ -5048,6 +5049,66 @@ HRESULT ClrDataAccess::GetBreakingChangeVersion(int* pVersion)
return S_OK;
}
+#ifdef FEATURE_COMWRAPPERS
+namespace
+{
+ typedef DPTR(InteropLib::ABI::ComInterfaceEntry) PTR_ComInterfaceEntry;
+
+ struct TargetManagedObjectWrapper : public InteropLib::ABI::ManagedObjectWrapperLayout
+ {
+ public:
+ InteropLib::Com::CreateComInterfaceFlagsEx GetFlags()
+ {
+ return _flags;
+ }
+
+ PTR_ComInterfaceEntry GetUserDefined(int32_t* pNumEntries)
+ {
+ return dac_cast((TADDR)_userDefined);
+ }
+
+ TADDR IndexIntoDispatchSection(int32_t index)
+ {
+ return (TADDR)InteropLib::ABI::IndexIntoDispatchSection(index, _dispatches);
+ }
+
+ TADDR GetRuntimeDefinedIUnknown()
+ {
+ return (TADDR)InteropLib::ABI::IndexIntoDispatchSection(_userDefinedCount, _dispatches);
+ }
+ };
+
+ typedef DPTR(TargetManagedObjectWrapper) PTR_ManagedObjectWrapper;
+}
+
+TADDR ClrDataAccess::GetIdentityForManagedObjectWrapper(TADDR mow)
+{
+ PTR_ManagedObjectWrapper pMOW = dac_cast(mow);
+ // Replicate the logic for ManagedObjectWrapper.As(IID_IUnknown)
+ if ((pMOW->GetFlags() & InteropLib::Com::CreateComInterfaceFlagsEx::CallerDefinedIUnknown) == InteropLib::Com::CreateComInterfaceFlagsEx::None)
+ {
+ // We have the standard IUnknown implementation, so grab it from its known location.
+ // The index returned from IndexIntoDispatchSection is in the target address space.
+ return pMOW->GetRuntimeDefinedIUnknown();
+ }
+
+ // We need to find the IUnknown interface pointer in the MOW.
+ int32_t userDefinedCount;
+ PTR_ComInterfaceEntry pUserDefined = pMOW->GetUserDefined(&userDefinedCount);
+ for (int32_t i = 0; i < userDefinedCount; i++)
+ {
+ if (pUserDefined[i].IID == IID_IUnknown)
+ {
+ // We found the IUnknown interface pointer.
+ // The index returned from IndexIntoDispatchSection is in the target address space.
+ return pMOW->IndexIntoDispatchSection(i);
+ }
+ }
+
+ return (TADDR)NULL;
+}
+#endif // FEATURE_COMWRAPPERS
+
HRESULT ClrDataAccess::GetObjectComWrappersData(CLRDATA_ADDRESS objAddr, CLRDATA_ADDRESS *rcw, unsigned int count, CLRDATA_ADDRESS *mowList, unsigned int *pNeeded)
{
#ifdef FEATURE_COMWRAPPERS
@@ -5062,6 +5123,10 @@ HRESULT ClrDataAccess::GetObjectComWrappersData(CLRDATA_ADDRESS objAddr, CLRDATA
}
SOSDacEnter();
+
+ // Default to having found no information.
+ HRESULT hr = S_FALSE;
+
if (pNeeded != NULL)
{
*pNeeded = 0;
@@ -5072,59 +5137,63 @@ HRESULT ClrDataAccess::GetObjectComWrappersData(CLRDATA_ADDRESS objAddr, CLRDATA
*rcw = 0;
}
- PTR_SyncBlock pSyncBlk = PTR_Object(TO_TADDR(objAddr))->PassiveGetSyncBlock();
- if (pSyncBlk != NULL)
+ FieldDesc* pRcwTableField = (&g_CoreLib)->GetField(FIELD__COMWRAPPERS__NAITVE_OBJECT_WRAPPER_TABLE);
+ CONDITIONAL_WEAK_TABLE_REF rcwTable = *(DPTR(CONDITIONAL_WEAK_TABLE_REF))PTR_TO_TADDR(pRcwTableField->GetStaticAddressHandle(pRcwTableField->GetBase()));
+ if (rcwTable != nullptr)
{
- PTR_InteropSyncBlockInfo pInfo = pSyncBlk->GetInteropInfoNoCreate();
- if (pInfo != NULL)
+ NATIVEOBJECTWRAPPERREF pNativeObjectWrapperRef = nullptr;
+ if (rcwTable->TryGetValue(OBJECTREF(TO_TADDR(objAddr)), &pNativeObjectWrapperRef))
{
- if (rcw != NULL)
- {
- *rcw = TO_TADDR(pInfo->m_externalComObjectContext);
- }
+ // Tag this RCW as a ComWrappers RCW.
+ *rcw = TO_CDADDR(dac_cast(pNativeObjectWrapperRef)) | 0x1;
+ hr = S_OK;
+ }
+ }
- DPTR(NewHolder) mapHolder(PTR_TO_MEMBER_TADDR(InteropSyncBlockInfo, pInfo, m_managedObjectComWrapperMap));
- DPTR(ManagedObjectComWrapperByIdMap *)ppMap(PTR_TO_MEMBER_TADDR(NewHolder, mapHolder, m_value));
- DPTR(ManagedObjectComWrapperByIdMap) pMap(TO_TADDR(*ppMap));
+ FieldDesc* pMowTableField = (&g_CoreLib)->GetField(FIELD__COMWRAPPERS__ALL_MANAGED_OBJECT_WRAPPER_TABLE);
+ CONDITIONAL_WEAK_TABLE_REF mowTable = *(DPTR(CONDITIONAL_WEAK_TABLE_REF))PTR_TO_TADDR(pMowTableField->GetStaticAddressHandle(pRcwTableField->GetBase()));
+ if (mowTable != nullptr)
+ {
+ OBJECTREF pAllManagedObjectWrapperRef = nullptr;
+ if (mowTable->TryGetValue(OBJECTREF(TO_TADDR(objAddr)), &pAllManagedObjectWrapperRef))
+ {
+ hr = S_OK;
- CQuickArrayList comWrappers;
- if (pMap != NULL)
+ // Read the list of MOWs into the provided buffer.
+ FieldDesc* pListItemsField = (&g_CoreLib)->GetField(FIELD__LISTGENERIC__ITEMS);
+ PTRARRAYREF pListItems = (PTRARRAYREF)pListItemsField->GetRefValue(pAllManagedObjectWrapperRef);
+ FieldDesc* pListSizeField = (&g_CoreLib)->GetField(FIELD__LISTGENERIC__SIZE);
+ int32_t listCount = pListSizeField->GetValue32(pAllManagedObjectWrapperRef);
+ if (listCount > 0 && pListItems != nullptr)
{
- ManagedObjectComWrapperByIdMap::Iterator iter = pMap->Begin();
- while (iter != pMap->End())
+ // The list is not empty, so we can return the MOWs.
+ if (pNeeded != NULL)
{
- comWrappers.Push(TO_CDADDR(iter->Value()));
- ++iter;
-
+ *pNeeded = (unsigned int)listCount;
}
- }
-
- if (pNeeded != NULL)
- {
- *pNeeded = (unsigned int)comWrappers.Size();
- }
- for (SIZE_T pos = 0; pos < comWrappers.Size(); ++pos)
- {
- if (pos >= count)
+ if (count < (unsigned int)listCount)
{
+ // Return S_FALSE if the buffer is too small.
hr = S_FALSE;
- break;
}
- mowList[pos] = comWrappers[pos];
+ for (unsigned int i = 0; i < count; i++)
+ {
+ MOWHOLDERREF pMOWRef = (MOWHOLDERREF)pListItems->GetAt(i);
+ PTR_ManagedObjectWrapper pMOW = PTR_ManagedObjectWrapper(dac_cast(pMOWRef->ManagedObjectWrapper));
+
+ // Now that we have the managed object wrapper, we need to figure out the COM identity of it.
+ TADDR pComIdentity = GetIdentityForManagedObjectWrapper(dac_cast(pMOW));
+
+ mowList[i] = TO_CDADDR(pComIdentity);
+ }
}
}
- else
- {
- hr = S_FALSE;
- }
- }
- else
- {
- hr = S_FALSE;
}
+ hr = S_FALSE;
+
SOSDacLeave();
return hr;
#else // FEATURE_COMWRAPPERS
@@ -5186,7 +5255,7 @@ HRESULT ClrDataAccess::GetComWrappersCCWData(CLRDATA_ADDRESS ccw, CLRDATA_ADDRES
if (refCount != NULL)
{
- *refCount = (int)pMOW->RefCount;
+ *refCount = (int)pMOW->GetRawRefCount();
}
}
else
@@ -5202,52 +5271,58 @@ HRESULT ClrDataAccess::GetComWrappersCCWData(CLRDATA_ADDRESS ccw, CLRDATA_ADDRES
#endif // FEATURE_COMWRAPPERS
}
-HRESULT ClrDataAccess::IsComWrappersRCW(CLRDATA_ADDRESS rcw, BOOL *isComWrappersRCW)
-{
#ifdef FEATURE_COMWRAPPERS
- if (rcw == 0)
- {
- return E_INVALIDARG;
- }
-
- SOSDacEnter();
-
- if (isComWrappersRCW != NULL)
+namespace
+{
+ BOOL IsComWrappersRCW(CLRDATA_ADDRESS rcw)
{
- PTR_ExternalObjectContext pRCW(TO_TADDR(rcw));
- BOOL stillValid = TRUE;
- if(pRCW->SyncBlockIndex >= SyncBlockCache::s_pSyncBlockCache->m_SyncTableSize)
+ if ((rcw & 1) == 0)
{
- stillValid = FALSE;
+ // We use the low bit of the RCW address to indicate that it is a ComWrappers RCW.
+ return FALSE;
}
- PTR_SyncBlock pSyncBlk = NULL;
- if (stillValid)
+ OBJECTREF nativeObjectWrapper = OBJECTREF(TO_TADDR(rcw & ~1));
+ if (nativeObjectWrapper == NULL)
{
- PTR_SyncTableEntry ste = PTR_SyncTableEntry(dac_cast(g_pSyncTable) + (sizeof(SyncTableEntry) * pRCW->SyncBlockIndex));
- pSyncBlk = ste->m_SyncBlock;
- if(pSyncBlk == NULL)
- {
- stillValid = FALSE;
- }
+ return FALSE;
}
- PTR_InteropSyncBlockInfo pInfo = NULL;
- if (stillValid)
+ if (nativeObjectWrapper->GetMethodTable() != (&g_CoreLib)->GetClass(CLASS__NATIVE_OBJECT_WRAPPER))
{
- pInfo = pSyncBlk->GetInteropInfoNoCreate();
- if(pInfo == NULL)
- {
- stillValid = FALSE;
- }
+ return FALSE;
}
- if (stillValid)
+ return TRUE;
+ }
+
+ TADDR GetComWrappersRCWIdentity(CLRDATA_ADDRESS rcw)
+ {
+ if ((rcw & 1) == 0)
{
- stillValid = TO_TADDR(pInfo->m_externalComObjectContext) == PTR_HOST_TO_TADDR(pRCW);
+ // We use the low bit of the RCW address to indicate that it is a ComWrappers RCW.
+ return (TADDR)NULL;
}
- *isComWrappersRCW = stillValid;
+ NATIVEOBJECTWRAPPERREF pNativeObjectWrapper = NATIVEOBJECTWRAPPERREF(TO_TADDR(rcw & ~1));
+ return pNativeObjectWrapper->GetExternalComObject();
+ }
+}
+#endif
+
+HRESULT ClrDataAccess::IsComWrappersRCW(CLRDATA_ADDRESS rcw, BOOL *isComWrappersRCW)
+{
+#ifdef FEATURE_COMWRAPPERS
+ if (rcw == 0)
+ {
+ return E_INVALIDARG;
+ }
+
+ SOSDacEnter();
+
+ if (isComWrappersRCW != NULL)
+ {
+ *isComWrappersRCW = ::IsComWrappersRCW(rcw);
hr = *isComWrappersRCW ? S_OK : S_FALSE;
}
@@ -5268,10 +5343,9 @@ HRESULT ClrDataAccess::GetComWrappersRCWData(CLRDATA_ADDRESS rcw, CLRDATA_ADDRES
SOSDacEnter();
- PTR_ExternalObjectContext pEOC(TO_TADDR(rcw));
if (identity != NULL)
{
- *identity = PTR_CDADDR(pEOC->Identity);
+ *identity = TO_CDADDR(GetComWrappersRCWIdentity(rcw));
}
SOSDacLeave();
diff --git a/src/coreclr/debug/ee/dactable.cpp b/src/coreclr/debug/ee/dactable.cpp
index 6dac100ffb39c4..80d1995acf8928 100644
--- a/src/coreclr/debug/ee/dactable.cpp
+++ b/src/coreclr/debug/ee/dactable.cpp
@@ -31,16 +31,19 @@ extern "C" void STDCALL ThePreStubPatchLabel(void);
#ifdef FEATURE_COMWRAPPERS
// Keep these forward declarations in sync with the method definitions in interop/comwrappers.cpp
-namespace ABI
+namespace InteropLib
{
- struct ComInterfaceDispatch;
+ namespace ABI
+ {
+ struct ComInterfaceDispatch;
+ }
}
HRESULT STDMETHODCALLTYPE ManagedObjectWrapper_QueryInterface(
- _In_ ABI::ComInterfaceDispatch* disp,
+ _In_ InteropLib::ABI::ComInterfaceDispatch* disp,
/* [in] */ REFIID riid,
/* [iid_is][out] */ _COM_Outptr_ void __RPC_FAR* __RPC_FAR* ppvObject);
HRESULT STDMETHODCALLTYPE TrackerTarget_QueryInterface(
- _In_ ABI::ComInterfaceDispatch* disp,
+ _In_ InteropLib::ABI::ComInterfaceDispatch* disp,
/* [in] */ REFIID riid,
/* [iid_is][out] */ _COM_Outptr_ void __RPC_FAR* __RPC_FAR* ppvObject);
diff --git a/src/coreclr/interop/comwrappers.cpp b/src/coreclr/interop/comwrappers.cpp
index 58b83368f7bf4b..05fb629cf2282f 100644
--- a/src/coreclr/interop/comwrappers.cpp
+++ b/src/coreclr/interop/comwrappers.cpp
@@ -11,7 +11,6 @@
#endif // _WIN32
using OBJECTHANDLE = InteropLib::OBJECTHANDLE;
-using AllocScenario = InteropLibImports::AllocScenario;
using TryInvokeICustomQueryInterfaceResult = InteropLibImports::TryInvokeICustomQueryInterfaceResult;
namespace ABI
@@ -44,133 +43,11 @@ namespace ABI
// See the dispatch section building API below for an example of how indexing works.
//--------------------------------------------------------------------------------
- struct ComInterfaceDispatch
- {
- const void* vtable;
- };
- ABI_ASSERT(sizeof(ComInterfaceDispatch) == sizeof(void*));
-
+ using InteropLib::ABI::ComInterfaceDispatch;
+ using InteropLib::ABI::ComInterfaceEntry;
using InteropLib::ABI::DispatchAlignmentThisPtr;
using InteropLib::ABI::DispatchThisPtrMask;
- ABI_ASSERT(sizeof(void*) < DispatchAlignmentThisPtr);
-
- const intptr_t AlignmentThisPtrMaxPadding = DispatchAlignmentThisPtr - sizeof(void*);
- const size_t EntriesPerThisPtr = (DispatchAlignmentThisPtr / sizeof(void*)) - 1;
-
- // Check if the instance can dispatch according to the ABI.
- bool IsAbleToDispatch(_In_ ComInterfaceDispatch* disp)
- {
- return (reinterpret_cast(disp) & DispatchThisPtrMask) != 0;
- }
-
- // Given the number of dispatch entries, compute the needed number of 'this' pointer entries.
- constexpr size_t ComputeThisPtrForDispatchSection(_In_ size_t dispatchCount)
- {
- return (dispatchCount / ABI::EntriesPerThisPtr) + ((dispatchCount % ABI::EntriesPerThisPtr) == 0 ? 0 : 1);
- }
-
- // Given a pointer and a padding allowance, attempt to find an offset into
- // the memory that is properly aligned for the dispatch section.
- char* AlignDispatchSection(_In_ char* section, _In_ intptr_t extraPadding)
- {
- _ASSERTE(section != nullptr);
-
- // If the dispatch section is not properly aligned by default, we
- // utilize the padding to make sure the dispatch section is aligned.
- while ((reinterpret_cast(section) % ABI::DispatchAlignmentThisPtr) != 0)
- {
- // Check if there is padding to attempt an alignment.
- if (extraPadding <= 0)
- return nullptr;
-
- extraPadding -= sizeof(void*);
-
-#ifdef _DEBUG
- // Poison unused portions of the section.
- ::memset(section, 0xff, sizeof(void*));
-#endif
-
- section += sizeof(void*);
- }
-
- return section;
- }
-
- struct ComInterfaceEntry
- {
- GUID IID;
- const void* Vtable;
- };
-
- struct EntrySet
- {
- const ComInterfaceEntry* start;
- int32_t count;
- };
-
- // Populate the dispatch section with the entry sets
- ComInterfaceDispatch* PopulateDispatchSection(
- _In_ void* thisPtr,
- _In_ void* dispatchSection,
- _In_ size_t entrySetCount,
- _In_ const EntrySet* entrySets)
- {
- // Define dispatch section iterator.
- const void** currDisp = reinterpret_cast(dispatchSection);
-
- // Keep rolling count of dispatch entries.
- int32_t dispCount = 0;
-
- // Iterate over all interface entry sets.
- const EntrySet* curr = entrySets;
- const EntrySet* end = entrySets + entrySetCount;
- for (; curr != end; ++curr)
- {
- const ComInterfaceEntry* currEntry = curr->start;
- int32_t entryCount = curr->count;
-
- // Update dispatch section with 'this' pointer and vtables.
- for (int32_t i = 0; i < entryCount; ++i, ++dispCount, ++currEntry)
- {
- // Insert the 'this' pointer at the appropriate locations
- // e.g.:
- // 32-bit | 64-bit
- // (0 * 4) % 16 = 0 | (0 * 8) % 64 = 0
- // (1 * 4) % 16 = 4 | (1 * 8) % 64 = 8
- // (2 * 4) % 16 = 8 | (2 * 8) % 64 = 16
- // (3 * 4) % 16 = 12 | ...
- // (4 * 4) % 16 = 0 | (7 * 8) % 64 = 56
- // (5 * 4) % 16 = 4 | (8 * 8) % 64 = 0
- //
- if (((dispCount * sizeof(void*)) % ABI::DispatchAlignmentThisPtr) == 0)
- {
- *currDisp++ = thisPtr;
- ++dispCount;
- }
-
- // Fill in the dispatch entry
- *currDisp++ = currEntry->Vtable;
- }
- }
-
- return reinterpret_cast(dispatchSection);
- }
-
- // Given the entry index, compute the dispatch index.
- ComInterfaceDispatch* IndexIntoDispatchSection(_In_ int32_t i, _In_ ComInterfaceDispatch* dispatches)
- {
- // Convert the supplied zero based index into what it represents as a count.
- const size_t count = static_cast(i) + 1;
-
- // Based on the supplied count, compute how many previous 'this' pointers would be
- // required in the dispatch section and add that to the supplied index to get the
- // index into the dispatch section.
- const size_t idx = ComputeThisPtrForDispatchSection(count) + i;
-
- ComInterfaceDispatch* disp = dispatches + idx;
- _ASSERTE(IsAbleToDispatch(disp));
- return disp;
- }
+ using InteropLib::ABI::IndexIntoDispatchSection;
// Given a dispatcher instance, return the associated ManagedObjectWrapper.
ManagedObjectWrapper* ToManagedObjectWrapper(_In_ ComInterfaceDispatch* disp)
@@ -242,7 +119,7 @@ HRESULT STDMETHODCALLTYPE TrackerTarget_QueryInterface(
// 1. Marked to Destroy - in this case it is unsafe to touch wrapper.
// 2. Object Handle target has been NULLed out by GC.
if (wrapper->IsMarkedToDestroy()
- || !InteropLibImports::HasValidTarget(wrapper->Target))
+ || !InteropLibImports::HasValidTarget(wrapper->GetTarget()))
{
// It is unsafe to proceed with a QueryInterface call. The MOW has been
// marked destroyed or the associated managed object has been collected.
@@ -338,6 +215,11 @@ namespace
static_assert(sizeof(ManagedObjectWrapper_IReferenceTrackerTargetImpl) == (7 * sizeof(void*)), "Unexpected vtable size");
}
+void const* ManagedObjectWrapper::GetIReferenceTrackerTargetImpl() noexcept
+{
+ return &ManagedObjectWrapper_IReferenceTrackerTargetImpl;
+}
+
namespace
{
// This IID represents an internal interface we define to tag any ManagedObjectWrappers we create.
@@ -355,22 +237,6 @@ namespace
{
return (version == (void*)&ITaggedImpl_IsCurrentVersion) ? S_OK : E_FAIL;
}
-
- // Hard-coded ManagedObjectWrapper tagged vtable.
- const struct
- {
- decltype(&ManagedObjectWrapper_QueryInterface) QueryInterface;
- decltype(&ManagedObjectWrapper_AddRef) AddRef;
- decltype(&ManagedObjectWrapper_Release) Release;
- decltype(&ITaggedImpl_IsCurrentVersion) IsCurrentVersion;
- } ManagedObjectWrapper_TaggedImpl {
- &ManagedObjectWrapper_QueryInterface,
- &ManagedObjectWrapper_AddRef,
- &ManagedObjectWrapper_Release,
- &ITaggedImpl_IsCurrentVersion,
- };
-
- static_assert(sizeof(ManagedObjectWrapper_TaggedImpl) == (4 * sizeof(void*)), "Unexpected vtable size");
}
void ManagedObjectWrapper::GetIUnknownImpl(
@@ -387,6 +253,11 @@ void ManagedObjectWrapper::GetIUnknownImpl(
*fpRelease = (void*)ManagedObjectWrapper_IUnknownImpl.Release;
}
+void const* ManagedObjectWrapper::GetTaggedCurrentVersionImpl() noexcept
+{
+ return reinterpret_cast(&ITaggedImpl_IsCurrentVersion);
+}
+
// The logic here should match code:ClrDataAccess::DACTryGetComWrappersObjectFromCCW in daccess/request.cpp
ManagedObjectWrapper* ManagedObjectWrapper::MapFromIUnknown(_In_ IUnknown* pUnk)
{
@@ -428,166 +299,35 @@ ManagedObjectWrapper* ManagedObjectWrapper::MapFromIUnknownWithQueryInterface(_I
return ABI::ToManagedObjectWrapper(disp);
}
-HRESULT ManagedObjectWrapper::Create(
- _In_ InteropLib::Com::CreateComInterfaceFlags flagsRaw,
- _In_ OBJECTHANDLE objectHandle,
- _In_ int32_t userDefinedCount,
- _In_ ABI::ComInterfaceEntry* userDefined,
- _Outptr_ ManagedObjectWrapper** mow)
+void* ManagedObjectWrapper::AsRuntimeDefined(_In_ REFIID riid)
{
- _ASSERTE(objectHandle != nullptr && mow != nullptr);
-
- auto flags = static_cast(flagsRaw);
- _ASSERTE((flags & CreateComInterfaceFlagsEx::InternalMask) == CreateComInterfaceFlagsEx::None);
-
- // Maximum number of runtime supplied vtables.
- ABI::ComInterfaceEntry runtimeDefinedLocal[3];
- int32_t runtimeDefinedCount = 0;
+ // The order of interface lookup here is important.
+ // See ComWrappers.CreateManagedObjectWrapper() for the expected order.
+ int i = _userDefinedCount;
- // Check if the caller will provide the IUnknown table.
- if ((flags & CreateComInterfaceFlagsEx::CallerDefinedIUnknown) == CreateComInterfaceFlagsEx::None)
+ if ((_flags & CreateComInterfaceFlagsEx::CallerDefinedIUnknown) == CreateComInterfaceFlagsEx::None)
{
- ABI::ComInterfaceEntry& curr = runtimeDefinedLocal[runtimeDefinedCount++];
- curr.IID = __uuidof(IUnknown);
- curr.Vtable = &ManagedObjectWrapper_IUnknownImpl;
- }
-
- // Check if the caller wants tracker support.
- if ((flags & CreateComInterfaceFlagsEx::TrackerSupport) == CreateComInterfaceFlagsEx::TrackerSupport)
- {
- ABI::ComInterfaceEntry& curr = runtimeDefinedLocal[runtimeDefinedCount++];
- curr.IID = IID_IReferenceTrackerTarget;
- curr.Vtable = &ManagedObjectWrapper_IReferenceTrackerTargetImpl;
- }
-
- // Always add the tagged interface. This is used to confirm at run-time with certainty
- // the wrapper is created by the ComWrappers API.
- {
- ABI::ComInterfaceEntry& curr = runtimeDefinedLocal[runtimeDefinedCount++];
- curr.IID = IID_TaggedImpl;
- curr.Vtable = &ManagedObjectWrapper_TaggedImpl;
- }
-
- _ASSERTE(runtimeDefinedCount <= static_cast(ARRAY_SIZE(runtimeDefinedLocal)));
-
- // Compute size for ManagedObjectWrapper instance.
- const size_t totalRuntimeDefinedSize = runtimeDefinedCount * sizeof(ABI::ComInterfaceEntry);
- const size_t totalDefinedCount = static_cast(runtimeDefinedCount) + userDefinedCount;
-
- // Compute the total entry size of dispatch section.
- const size_t totalDispatchSectionCount = ABI::ComputeThisPtrForDispatchSection(totalDefinedCount) + totalDefinedCount;
- const size_t totalDispatchSectionSize = totalDispatchSectionCount * sizeof(void*);
-
- // Allocate memory for the ManagedObjectWrapper.
- char* wrapperMem = (char*)InteropLibImports::MemAlloc(sizeof(ManagedObjectWrapper) + totalRuntimeDefinedSize + totalDispatchSectionSize + ABI::AlignmentThisPtrMaxPadding, AllocScenario::ManagedObjectWrapper);
- if (wrapperMem == nullptr)
- return E_OUTOFMEMORY;
-
- // Compute Runtime defined offset.
- char* runtimeDefinedOffset = wrapperMem + sizeof(ManagedObjectWrapper);
+ if (riid == IID_IUnknown)
+ {
+ return ABI::IndexIntoDispatchSection(i, _dispatches);
+ }
- // Copy in runtime supplied COM interface entries.
- ABI::ComInterfaceEntry* runtimeDefined = nullptr;
- if (0 < runtimeDefinedCount)
- {
- ::memcpy(runtimeDefinedOffset, runtimeDefinedLocal, totalRuntimeDefinedSize);
- runtimeDefined = reinterpret_cast(runtimeDefinedOffset);
+ ++i;
}
- // Compute the dispatch section offset and ensure it is aligned.
- char* dispatchSectionOffset = runtimeDefinedOffset + totalRuntimeDefinedSize;
- dispatchSectionOffset = ABI::AlignDispatchSection(dispatchSectionOffset, ABI::AlignmentThisPtrMaxPadding);
- if (dispatchSectionOffset == nullptr)
- return E_UNEXPECTED;
-
- // Define the sets for the tables to insert
- const ABI::EntrySet AllEntries[] =
+ if ((_flags & CreateComInterfaceFlagsEx::TrackerSupport) == CreateComInterfaceFlagsEx::TrackerSupport)
{
- { runtimeDefined, runtimeDefinedCount },
- { userDefined, userDefinedCount }
- };
-
- ABI::ComInterfaceDispatch* dispSection = ABI::PopulateDispatchSection(wrapperMem, dispatchSectionOffset, ARRAY_SIZE(AllEntries), AllEntries);
-
- ManagedObjectWrapper* wrapper = new (wrapperMem) ManagedObjectWrapper
+ if (riid == IID_IReferenceTrackerTarget)
{
- flags,
- objectHandle,
- runtimeDefinedCount,
- runtimeDefined,
- userDefinedCount,
- userDefined,
- dispSection
- };
-
- *mow = wrapper;
- return S_OK;
-}
-
-void ManagedObjectWrapper::Destroy(_In_ ManagedObjectWrapper* wrapper)
-{
- _ASSERTE(wrapper != nullptr);
- _ASSERTE(GetComCount(wrapper->_refCount) == 0);
+ return ABI::IndexIntoDispatchSection(i, _dispatches);
+ }
- // Attempt to set the destroyed bit.
- LONGLONG refCount;
- LONGLONG prev;
- do
- {
- prev = wrapper->_refCount;
- refCount = prev | DestroySentinel;
- } while (InterlockedCompareExchange64(&wrapper->_refCount, refCount, prev) != prev);
-
- // The destroy sentinel represents the bit that indicates the wrapper
- // should be destroyed. Since the reference count field (64-bit) holds
- // two counters we rely on the singular sentinel value - no other bits
- // in the 64-bit counter are set. If there are outstanding bits set it
- // indicates there are still outstanding references.
- if (refCount == DestroySentinel)
- {
- // Manually trigger the destructor since placement
- // new was used to allocate the object.
- wrapper->~ManagedObjectWrapper();
- InteropLibImports::MemFree(wrapper, AllocScenario::ManagedObjectWrapper);
+ ++i;
}
-}
-
-ManagedObjectWrapper::ManagedObjectWrapper(
- _In_ CreateComInterfaceFlagsEx flags,
- _In_ OBJECTHANDLE objectHandle,
- _In_ int32_t runtimeDefinedCount,
- _In_ const ABI::ComInterfaceEntry* runtimeDefined,
- _In_ int32_t userDefinedCount,
- _In_ const ABI::ComInterfaceEntry* userDefined,
- _In_ ABI::ComInterfaceDispatch* dispatches)
- : Target{ nullptr }
- , _refCount{ 1 }
- , _runtimeDefinedCount{ runtimeDefinedCount }
- , _userDefinedCount{ userDefinedCount }
- , _runtimeDefined{ runtimeDefined }
- , _userDefined{ userDefined }
- , _dispatches{ dispatches }
- , _flags{ flags }
-{
- bool wasSet = TrySetObjectHandle(objectHandle);
- _ASSERTE(wasSet);
-}
-
-ManagedObjectWrapper::~ManagedObjectWrapper()
-{
- // If the target isn't null, then release it.
- if (Target != nullptr)
- InteropLibImports::DeleteObjectInstanceHandle(Target);
-}
-void* ManagedObjectWrapper::AsRuntimeDefined(_In_ REFIID riid)
-{
- for (int32_t i = 0; i < _runtimeDefinedCount; ++i)
+ if (riid == IID_TaggedImpl)
{
- if (IsEqualGUID(_runtimeDefined[i].IID, riid))
- {
- return ABI::IndexIntoDispatchSection(i, _dispatches);
- }
+ return ABI::IndexIntoDispatchSection(i, _dispatches);
}
return nullptr;
@@ -599,7 +339,7 @@ void* ManagedObjectWrapper::AsUserDefined(_In_ REFIID riid)
{
if (IsEqualGUID(_userDefined[i].IID, riid))
{
- return ABI::IndexIntoDispatchSection(i + _runtimeDefinedCount, _dispatches);
+ return ABI::IndexIntoDispatchSection(i, _dispatches);
}
}
@@ -616,11 +356,6 @@ void* ManagedObjectWrapper::As(_In_ REFIID riid)
return typeMaybe;
}
-bool ManagedObjectWrapper::TrySetObjectHandle(_In_ OBJECTHANDLE objectHandle, _In_ OBJECTHANDLE current)
-{
- return (InterlockedCompareExchangePointer(&Target, objectHandle, current) == current);
-}
-
bool ManagedObjectWrapper::IsSet(_In_ CreateComInterfaceFlagsEx flag) const
{
return (_flags & flag) != CreateComInterfaceFlagsEx::None;
@@ -689,7 +424,13 @@ ULONG ManagedObjectWrapper::ReleaseFromReferenceTracker()
// If we observe the destroy sentinel, then this release
// must destroy the wrapper.
if (refCount == DestroySentinel)
- Destroy(this);
+ {
+ InteropLib::OBJECTHANDLE handle = InterlockedExchangePointer(&_target, nullptr);
+ if (handle != nullptr)
+ {
+ InteropLibImports::DestroyHandle(handle);
+ }
+ }
return GetTrackerCount(refCount);
}
@@ -720,7 +461,7 @@ HRESULT ManagedObjectWrapper::QueryInterface(
// Check if the managed object has implemented ICustomQueryInterface
if (!IsSet(CreateComInterfaceFlagsEx::LacksICustomQueryInterface))
{
- TryInvokeICustomQueryInterfaceResult result = InteropLibImports::TryInvokeICustomQueryInterface(Target, riid, ppvObject);
+ TryInvokeICustomQueryInterfaceResult result = InteropLibImports::TryInvokeICustomQueryInterface(GetTarget(), riid, ppvObject);
switch (result)
{
case TryInvokeICustomQueryInterfaceResult::Handled:
@@ -782,166 +523,7 @@ ULONG ManagedObjectWrapper::Release(void)
return GetComCount(::InterlockedDecrement64(&_refCount));
}
-namespace
-{
- const size_t LiveContextSentinel = 0x0a110ced;
- const size_t DeadContextSentinel = 0xdeaddead;
-}
-
-NativeObjectWrapperContext* NativeObjectWrapperContext::MapFromRuntimeContext(_In_ void* cxtMaybe)
-{
- _ASSERTE(cxtMaybe != nullptr);
-
- // Convert the supplied context
- char* cxtRaw = reinterpret_cast(cxtMaybe);
- cxtRaw -= sizeof(NativeObjectWrapperContext);
- NativeObjectWrapperContext* cxt = reinterpret_cast(cxtRaw);
-
-#ifdef _DEBUG
- _ASSERTE(cxt->_sentinel == LiveContextSentinel);
-#endif
-
- return cxt;
-}
-
-HRESULT NativeObjectWrapperContext::Create(
- _In_ IUnknown* external,
- _In_opt_ IUnknown* inner,
- _In_ InteropLib::Com::CreateObjectFlags flags,
- _In_ size_t runtimeContextSize,
- _Outptr_ NativeObjectWrapperContext** context)
+InteropLib::OBJECTHANDLE ManagedObjectWrapper::GetTarget() const
{
- _ASSERTE(external != nullptr && context != nullptr);
-
- HRESULT hr;
-
- ComHolder trackerObject;
- if (flags & InteropLib::Com::CreateObjectFlags_TrackerObject)
- {
- hr = external->QueryInterface(IID_IReferenceTracker, (void**)&trackerObject);
- if (SUCCEEDED(hr))
- RETURN_IF_FAILED(TrackerObjectManager::OnIReferenceTrackerFound(trackerObject));
- }
-
- // Allocate memory for the RCW
- char* cxtMem = (char*)InteropLibImports::MemAlloc(sizeof(NativeObjectWrapperContext) + runtimeContextSize, AllocScenario::NativeObjectWrapper);
- if (cxtMem == nullptr)
- return E_OUTOFMEMORY;
-
- void* runtimeContext = cxtMem + sizeof(NativeObjectWrapperContext);
-
- // Contract specifically requires zeroing out runtime context.
- ::memset(runtimeContext, 0, runtimeContextSize);
-
- NativeObjectWrapperContext* contextLocal = new (cxtMem) NativeObjectWrapperContext{ runtimeContext, trackerObject, inner };
-
- if (trackerObject != nullptr)
- {
- // Inform the tracker object manager
- _ASSERTE(flags & InteropLib::Com::CreateObjectFlags_TrackerObject);
- hr = TrackerObjectManager::AfterWrapperCreated(trackerObject);
- if (FAILED(hr))
- {
- Destroy(contextLocal);
- return hr;
- }
-
- // Aggregation with a tracker object must be "cleaned up".
- if (flags & InteropLib::Com::CreateObjectFlags_Aggregated)
- {
- _ASSERTE(inner != nullptr);
- contextLocal->HandleReferenceTrackerAggregation();
- }
- }
-
- *context = contextLocal;
- return S_OK;
-}
-
-void NativeObjectWrapperContext::Destroy(_In_ NativeObjectWrapperContext* wrapper)
-{
- _ASSERTE(wrapper != nullptr);
-
- // Manually trigger the destructor since placement
- // new was used to allocate the object.
- wrapper->~NativeObjectWrapperContext();
- InteropLibImports::MemFree(wrapper, AllocScenario::NativeObjectWrapper);
-}
-
-NativeObjectWrapperContext::NativeObjectWrapperContext(
- _In_ void* runtimeContext,
- _In_opt_ IReferenceTracker* trackerObject,
- _In_opt_ IUnknown* nativeObjectAsInner)
- : _trackerObject{ trackerObject }
- , _runtimeContext{ runtimeContext }
- , _trackerObjectDisconnected{ FALSE }
- , _trackerObjectState{ (trackerObject == nullptr ? TrackerObjectState::NotSet : TrackerObjectState::SetForRelease) }
- , _nativeObjectAsInner{ nativeObjectAsInner }
-#ifdef _DEBUG
- , _sentinel{ LiveContextSentinel }
-#endif
-{
- if (_trackerObjectState == TrackerObjectState::SetForRelease)
- (void)_trackerObject->AddRef();
-}
-
-NativeObjectWrapperContext::~NativeObjectWrapperContext()
-{
- DisconnectTracker();
-
- // If the inner was supplied, we need to release our reference.
- if (_nativeObjectAsInner != nullptr)
- (void)_nativeObjectAsInner->Release();
-
-#ifdef _DEBUG
- _sentinel = DeadContextSentinel;
-#endif
-}
-
-void* NativeObjectWrapperContext::GetRuntimeContext() const noexcept
-{
- return _runtimeContext;
-}
-
-IReferenceTracker* NativeObjectWrapperContext::GetReferenceTracker() const noexcept
-{
- return ((_trackerObjectState == TrackerObjectState::NotSet || _trackerObjectDisconnected) ? nullptr : _trackerObject);
-}
-
-// See TrackerObjectManager::AfterWrapperCreated() for AddRefFromTrackerSource() usage.
-// See NativeObjectWrapperContext::HandleReferenceTrackerAggregation() for additional
-// cleanup logistics.
-void NativeObjectWrapperContext::DisconnectTracker() noexcept
-{
- // Return if already disconnected or the tracker isn't set.
- if (FALSE != ::InterlockedCompareExchange((LONG*)&_trackerObjectDisconnected, TRUE, FALSE)
- || _trackerObjectState == TrackerObjectState::NotSet)
- {
- return;
- }
-
- _ASSERTE(_trackerObject != nullptr);
-
- // Always release the tracker source during a disconnect.
- // This to account for the implied IUnknown ownership by the runtime.
- (void)_trackerObject->ReleaseFromTrackerSource(); // IUnknown
-
- // Disconnect from the tracker.
- if (_trackerObjectState == TrackerObjectState::SetForRelease)
- {
- (void)_trackerObject->ReleaseFromTrackerSource(); // IReferenceTracker
- (void)_trackerObject->Release();
- }
-}
-
-void NativeObjectWrapperContext::HandleReferenceTrackerAggregation() noexcept
-{
- _ASSERTE(_trackerObjectState == TrackerObjectState::SetForRelease && _trackerObject != nullptr);
-
- // Aggregation with an IReferenceTracker instance creates an extra AddRef()
- // on the outer (e.g. MOW) so we clean up that issue here.
- _trackerObjectState = TrackerObjectState::SetNoRelease;
-
- (void)_trackerObject->ReleaseFromTrackerSource(); // IReferenceTracker
- (void)_trackerObject->Release();
+ return _target;
}
diff --git a/src/coreclr/interop/comwrappers.hpp b/src/coreclr/interop/comwrappers.hpp
index 47bf008ac50126..00ebfc39194b96 100644
--- a/src/coreclr/interop/comwrappers.hpp
+++ b/src/coreclr/interop/comwrappers.hpp
@@ -9,62 +9,14 @@
#include
#include "referencetrackertypes.hpp"
-#ifndef DEFINE_ENUM_FLAG_OPERATORS
-#define DEFINE_ENUM_FLAG_OPERATORS(ENUMTYPE) \
-extern "C++" { \
- inline ENUMTYPE operator | (ENUMTYPE a, ENUMTYPE b) { return ENUMTYPE(((int)a)|((int)b)); } \
- inline ENUMTYPE operator |= (ENUMTYPE &a, ENUMTYPE b) { return (ENUMTYPE &)(((int &)a) |= ((int)b)); } \
- inline ENUMTYPE operator & (ENUMTYPE a, ENUMTYPE b) { return ENUMTYPE(((int)a)&((int)b)); } \
- inline ENUMTYPE operator &= (ENUMTYPE &a, ENUMTYPE b) { return (ENUMTYPE &)(((int &)a) &= ((int)b)); } \
- inline ENUMTYPE operator ~ (ENUMTYPE a) { return (ENUMTYPE)(~((int)a)); } \
- inline ENUMTYPE operator ^ (ENUMTYPE a, ENUMTYPE b) { return ENUMTYPE(((int)a)^((int)b)); } \
- inline ENUMTYPE operator ^= (ENUMTYPE &a, ENUMTYPE b) { return (ENUMTYPE &)(((int &)a) ^= ((int)b)); } \
-}
-#endif
-
-enum class CreateComInterfaceFlagsEx : int32_t
-{
- None = InteropLib::Com::CreateComInterfaceFlags_None,
- CallerDefinedIUnknown = InteropLib::Com::CreateComInterfaceFlags_CallerDefinedIUnknown,
- TrackerSupport = InteropLib::Com::CreateComInterfaceFlags_TrackerSupport,
-
- // Highest bits are reserved for internal usage
- LacksICustomQueryInterface = 1 << 29,
- IsComActivated = 1 << 30,
- IsPegged = 1 << 31,
-
- InternalMask = IsPegged | IsComActivated | LacksICustomQueryInterface,
-};
-
-DEFINE_ENUM_FLAG_OPERATORS(CreateComInterfaceFlagsEx);
-
-// Forward declarations
-namespace ABI
-{
- struct ComInterfaceDispatch;
- struct ComInterfaceEntry;
-}
+using InteropLib::Com::CreateComInterfaceFlagsEx;
static constexpr size_t ManagedObjectWrapperRefCountOffset();
+static constexpr size_t ManagedObjectWrapperFlagsOffset();
// Class for wrapping a managed object and projecting it in a non-managed environment
-class ManagedObjectWrapper
+class ManagedObjectWrapper final : public InteropLib::ABI::ManagedObjectWrapperLayout
{
- friend constexpr size_t ManagedObjectWrapperRefCountOffset();
-public:
- Volatile Target;
-
-private:
- LONGLONG _refCount;
-
- const int32_t _runtimeDefinedCount;
- const int32_t _userDefinedCount;
- const ABI::ComInterfaceEntry* _runtimeDefined;
- const ABI::ComInterfaceEntry* _userDefined;
- ABI::ComInterfaceDispatch* _dispatches;
-
- Volatile _flags;
-
public: // static
// Get the implementation for IUnknown.
static void GetIUnknownImpl(
@@ -72,6 +24,10 @@ class ManagedObjectWrapper
_Out_ void** fpAddRef,
_Out_ void** fpRelease);
+ static void const* GetIReferenceTrackerTargetImpl() noexcept;
+
+ static void const* GetTaggedCurrentVersionImpl() noexcept;
+
// Convert the IUnknown if the instance is a ManagedObjectWrapper
// into a ManagedObjectWrapper, otherwise null.
static ManagedObjectWrapper* MapFromIUnknown(_In_ IUnknown* pUnk);
@@ -82,42 +38,17 @@ class ManagedObjectWrapper
// performing a QueryInterface() which may not always be possible.
// See implementation for more details.
static ManagedObjectWrapper* MapFromIUnknownWithQueryInterface(_In_ IUnknown* pUnk);
-
- // Create a ManagedObjectWrapper instance
- static HRESULT Create(
- _In_ InteropLib::Com::CreateComInterfaceFlags flags,
- _In_ InteropLib::OBJECTHANDLE objectHandle,
- _In_ int32_t userDefinedCount,
- _In_ ABI::ComInterfaceEntry* userDefined,
- _Outptr_ ManagedObjectWrapper** mow);
-
- // Destroy the instance
- static void Destroy(_In_ ManagedObjectWrapper* wrapper);
-
private:
- ManagedObjectWrapper(
- _In_ CreateComInterfaceFlagsEx flags,
- _In_ InteropLib::OBJECTHANDLE objectHandle,
- _In_ int32_t runtimeDefinedCount,
- _In_ const ABI::ComInterfaceEntry* runtimeDefined,
- _In_ int32_t userDefinedCount,
- _In_ const ABI::ComInterfaceEntry* userDefined,
- _In_ ABI::ComInterfaceDispatch* dispatches);
-
- ~ManagedObjectWrapper();
-
// Query the runtime defined tables.
void* AsRuntimeDefined(_In_ REFIID riid);
// Query the user defined tables.
void* AsUserDefined(_In_ REFIID riid);
-
public:
// N.B. Does not impact the reference count of the object.
void* As(_In_ REFIID riid);
// Attempt to set the target object handle based on an assumed current value.
- bool TrySetObjectHandle(_In_ InteropLib::OBJECTHANDLE objectHandle, _In_ InteropLib::OBJECTHANDLE current = nullptr);
bool IsSet(_In_ CreateComInterfaceFlagsEx flag) const;
void SetFlag(_In_ CreateComInterfaceFlagsEx flag);
void ResetFlag(_In_ CreateComInterfaceFlagsEx flag);
@@ -128,6 +59,8 @@ class ManagedObjectWrapper
// Check if the wrapper has been marked to be destroyed.
bool IsMarkedToDestroy() const;
+ InteropLib::OBJECTHANDLE GetTarget() const;
+
public: // IReferenceTrackerTarget
ULONG AddRefFromReferenceTracker();
ULONG ReleaseFromReferenceTracker();
@@ -142,82 +75,13 @@ class ManagedObjectWrapper
ULONG Release(void);
};
-// ABI contract. This below offset is assumed in managed code and the DAC.
-ABI_ASSERT(offsetof(ManagedObjectWrapper, Target) == 0);
-
-static constexpr size_t ManagedObjectWrapperRefCountOffset()
-{
- // _refCount is a private field and offsetof won't let you look at private fields.
- // To overcome, this function is a friend function of ManagedObjectWrapper.
- return offsetof(ManagedObjectWrapper, _refCount);
-}
-
-// ABI contract used by the DAC.
-ABI_ASSERT(offsetof(ManagedObjectWrapper, Target) == offsetof(InteropLib::ABI::ManagedObjectWrapperLayout, ManagedObject));
-ABI_ASSERT(ManagedObjectWrapperRefCountOffset() == offsetof(InteropLib::ABI::ManagedObjectWrapperLayout, RefCount));
-
-// State ownership mechanism.
-enum class TrackerObjectState
-{
- NotSet,
- SetNoRelease,
- SetForRelease,
-};
-
-// Class for connecting a native COM object to a managed object instance
-class NativeObjectWrapperContext
-{
- IReferenceTracker* _trackerObject;
- void* _runtimeContext;
- Volatile _trackerObjectDisconnected;
- TrackerObjectState _trackerObjectState;
- IUnknown* _nativeObjectAsInner;
-
-#ifdef _DEBUG
- size_t _sentinel;
-#endif
-public: // static
- // Convert a context pointer into a NativeObjectWrapperContext.
- static NativeObjectWrapperContext* MapFromRuntimeContext(_In_ void* cxt);
-
- // Create a NativeObjectWrapperContext instance
- static HRESULT Create(
- _In_ IUnknown* external,
- _In_opt_ IUnknown* nativeObjectAsInner,
- _In_ InteropLib::Com::CreateObjectFlags flags,
- _In_ size_t runtimeContextSize,
- _Outptr_ NativeObjectWrapperContext** context);
-
- // Destroy the instance
- static void Destroy(_In_ NativeObjectWrapperContext* wrapper);
-
-private:
- NativeObjectWrapperContext(_In_ void* runtimeContext, _In_opt_ IReferenceTracker* trackerObject, _In_opt_ IUnknown* nativeObjectAsInner);
- ~NativeObjectWrapperContext();
-
-public:
- // Get the associated runtime context for this context.
- void* GetRuntimeContext() const noexcept;
-
- // Get the IReferenceTracker instance.
- IReferenceTracker* GetReferenceTracker() const noexcept;
-
- // Disconnect reference tracker instance.
- void DisconnectTracker() noexcept;
-
-private:
- void HandleReferenceTrackerAggregation() noexcept;
-};
-
// Manage native object wrappers that support IReferenceTracker.
class TrackerObjectManager
{
public:
- // Called when an IReferenceTracker instance is found.
- static HRESULT OnIReferenceTrackerFound(_In_ IReferenceTracker* obj);
+ static bool HasReferenceTrackerManager();
- // Called after wrapper has been created.
- static HRESULT AfterWrapperCreated(_In_ IReferenceTracker* obj);
+ static bool TryRegisterReferenceTrackerManager(_In_ IReferenceTrackerManager* manager);
// Called before wrapper is about to be finalized (the same lifetime as short weak handle).
static HRESULT BeforeWrapperFinalized(_In_ IReferenceTracker* obj);
@@ -228,6 +92,8 @@ class TrackerObjectManager
// End the reference tracking process for external object.
static HRESULT EndReferenceTracking();
+
+ static HRESULT DetachNonPromotedObjects(_In_ InteropLibImports::RuntimeCallContext* cxt);
};
// Class used to hold COM objects (i.e. IUnknown base class)
diff --git a/src/coreclr/interop/inc/interoplib.h b/src/coreclr/interop/inc/interoplib.h
index 684283b7133bd7..e4a09fb84c64ee 100644
--- a/src/coreclr/interop/inc/interoplib.h
+++ b/src/coreclr/interop/inc/interoplib.h
@@ -17,48 +17,16 @@ namespace InteropLib
{
using OBJECTHANDLE = void*;
- namespace Com
+ namespace ABI
{
- // See CreateComInterfaceFlags in ComWrappers.cs
- enum CreateComInterfaceFlags
- {
- CreateComInterfaceFlags_None = 0,
- CreateComInterfaceFlags_CallerDefinedIUnknown = 1,
- CreateComInterfaceFlags_TrackerSupport = 2,
- };
-
- // Create an IUnknown instance that represents the supplied managed object instance.
- HRESULT CreateWrapperForObject(
- _In_ OBJECTHANDLE instance,
- _In_ INT32 vtableCount,
- _In_ void* vtables,
- _In_ enum CreateComInterfaceFlags flags,
- _Outptr_ IUnknown** wrapper) noexcept;
-
- // Destroy the supplied wrapper
- void DestroyWrapperForObject(_In_ void* wrapper) noexcept;
-
- // Check if a wrapper is considered a GC root.
- HRESULT IsWrapperRooted(_In_ IUnknown* wrapper) noexcept;
+ struct ManagedObjectWrapperLayout;
+ }
- // Get the object for the supplied wrapper
- HRESULT GetObjectForWrapper(_In_ IUnknown* wrapper, _Outptr_result_maybenull_ OBJECTHANDLE* object) noexcept;
+ namespace Com
+ {
+ bool IsRooted(_In_ ABI::ManagedObjectWrapperLayout* wrapper) noexcept;
HRESULT MarkComActivated(_In_ IUnknown* wrapper) noexcept;
- HRESULT IsComActivated(_In_ IUnknown* wrapper) noexcept;
-
- struct ExternalWrapperResult
- {
- // The returned context memory is guaranteed to be initialized to zero.
- void* Context;
-
- // See https://learn.microsoft.com/windows/win32/api/windows.ui.xaml.hosting.referencetracker/
- // for details.
- bool FromTrackerRuntime;
-
- // The supplied external object is wrapping a managed object.
- bool ManagedObjectWrapper;
- };
// See CreateObjectFlags in ComWrappers.cs
enum CreateObjectFlags
@@ -70,32 +38,21 @@ namespace InteropLib
CreateObjectFlags_Unwrap = 8,
};
- // Get the true identity and inner for the supplied IUnknown.
- HRESULT DetermineIdentityAndInnerForExternal(
- _In_ IUnknown* external,
- _In_ enum CreateObjectFlags flags,
- _Outptr_ IUnknown** identity,
- _Inout_ IUnknown** innerMaybe) noexcept;
-
- // Allocate a wrapper context for an external object.
- // The runtime supplies the external object, flags, and a memory
- // request in order to bring the object into the runtime.
- HRESULT CreateWrapperForExternal(
- _In_ IUnknown* external,
- _In_opt_ IUnknown* inner,
- _In_ enum CreateObjectFlags flags,
- _In_ size_t contextSize,
- _Out_ ExternalWrapperResult* result) noexcept;
-
- // Inform the wrapper it is being collected.
- void NotifyWrapperForExternalIsBeingCollected(_In_ void* context) noexcept;
-
- // Destroy the supplied wrapper.
- // Optionally notify the wrapper of collection at the same time.
- void DestroyWrapperForExternal(_In_ void* context, _In_ bool notifyIsBeingCollected = false) noexcept;
-
- // Separate the supplied wrapper from the tracker runtime.
- void SeparateWrapperFromTrackerRuntime(_In_ void* context) noexcept;
+ enum class CreateComInterfaceFlagsEx : int32_t
+ {
+ // Matches the managed definition of System.Runtime.InteropServices.CreateComInterfaceFlags
+ None = 0,
+ CallerDefinedIUnknown = 1,
+ TrackerSupport = 2,
+
+ // Highest bits are reserved for internal usage
+ LacksICustomQueryInterface = 1 << 29,
+ IsComActivated = 1 << 30,
+ IsPegged = 1 << 31,
+
+ InternalMask = IsPegged | IsComActivated | LacksICustomQueryInterface,
+ };
+
// Get internal interop IUnknown dispatch pointers.
void GetIUnknownImpl(
@@ -103,6 +60,8 @@ namespace InteropLib
_Out_ void** fpAddRef,
_Out_ void** fpRelease) noexcept;
+ void const* GetTaggedCurrentVersionImpl() noexcept;
+
// Begin the reference tracking process on external COM objects.
// This should only be called during a runtime's GC phase.
HRESULT BeginExternalObjectReferenceTracking(_In_ InteropLibImports::RuntimeCallContext* cxt) noexcept;
@@ -110,8 +69,35 @@ namespace InteropLib
// End the reference tracking process.
// This should only be called during a runtime's GC phase.
HRESULT EndExternalObjectReferenceTracking() noexcept;
+
+ // Detach non-promoted objects from the reference tracker.
+ // This should only be called during a runtime's GC phase.
+ HRESULT DetachNonPromotedObjects(_In_ InteropLibImports::RuntimeCallContext* cxt) noexcept;
+
+ // Get the vtable for IReferenceTrackerTarget
+ void const* GetIReferenceTrackerTargetVftbl() noexcept;
+
+ // Check if a ReferenceTrackerManager has been registered.
+ bool HasReferenceTrackerManager() noexcept;
+
+ // Register a ReferenceTrackerManager if one has not already been registered.
+ bool TryRegisterReferenceTrackerManager(void* manager) noexcept;
}
}
-#endif // _INTEROP_INC_INTEROPLIB_H_
+#ifndef DEFINE_ENUM_FLAG_OPERATORS
+#define DEFINE_ENUM_FLAG_OPERATORS(ENUMTYPE) \
+extern "C++" { \
+ inline ENUMTYPE operator | (ENUMTYPE a, ENUMTYPE b) { return ENUMTYPE(((int)a)|((int)b)); } \
+ inline ENUMTYPE operator |= (ENUMTYPE &a, ENUMTYPE b) { return (ENUMTYPE &)(((int &)a) |= ((int)b)); } \
+ inline ENUMTYPE operator & (ENUMTYPE a, ENUMTYPE b) { return ENUMTYPE(((int)a)&((int)b)); } \
+ inline ENUMTYPE operator &= (ENUMTYPE &a, ENUMTYPE b) { return (ENUMTYPE &)(((int &)a) &= ((int)b)); } \
+ inline ENUMTYPE operator ~ (ENUMTYPE a) { return (ENUMTYPE)(~((int)a)); } \
+ inline ENUMTYPE operator ^ (ENUMTYPE a, ENUMTYPE b) { return ENUMTYPE(((int)a)^((int)b)); } \
+ inline ENUMTYPE operator ^= (ENUMTYPE &a, ENUMTYPE b) { return (ENUMTYPE &)(((int &)a) ^= ((int)b)); } \
+}
+#endif
+
+DEFINE_ENUM_FLAG_OPERATORS(InteropLib::Com::CreateComInterfaceFlagsEx);
+#endif // _INTEROP_INC_INTEROPLIB_H_
diff --git a/src/coreclr/interop/inc/interoplibabi.h b/src/coreclr/interop/inc/interoplibabi.h
index 7789a68217b2be..217ecda8b73e28 100644
--- a/src/coreclr/interop/inc/interoplibabi.h
+++ b/src/coreclr/interop/inc/interoplibabi.h
@@ -5,27 +5,79 @@
#define _INTEROP_INC_INTEROPLIBABI_H_
#include
+#include
namespace InteropLib
{
namespace ABI
{
- // Updating this also requires updating ComInterfaceDispatch::GetInstance.
+ // The definitions in this file are constants and data structures that are shared between interoplib,
+ // the managed ComWrappers code, and the DAC's ComWrappers support.
+ // All constants, type layouts, and algorithms that calculate pointer offsets should be in this file
+ // and should have identical implementations with the managed ComWrappers code.
+
#ifdef HOST_64BIT
- const size_t DispatchAlignmentThisPtr = 64; // Should be a power of 2.
+ constexpr size_t DispatchAlignmentThisPtr = 64; // Should be a power of 2.
#else
- const size_t DispatchAlignmentThisPtr = 16; // Should be a power of 2.
+ constexpr size_t DispatchAlignmentThisPtr = 16; // Should be a power of 2.
#endif
- const intptr_t DispatchThisPtrMask = ~(DispatchAlignmentThisPtr - 1);
+ constexpr intptr_t DispatchThisPtrMask = ~(DispatchAlignmentThisPtr - 1);
+
+ static_assert(sizeof(void*) < DispatchAlignmentThisPtr, "DispatchAlignmentThisPtr must be larger than sizeof(void*).");
+
+ constexpr size_t EntriesPerThisPtr = (DispatchAlignmentThisPtr / sizeof(void*)) - 1;
+
+ struct ComInterfaceDispatch
+ {
+ const void* vtable;
+ };
+
+ static_assert(sizeof(ComInterfaceDispatch) == sizeof(void*), "ComInterfaceDispatch must be pointer-sized.");
+
+ struct ManagedObjectWrapperLayout;
+
+ struct InternalComInterfaceDispatch
+ {
+ private:
+ ManagedObjectWrapperLayout* _thisPtr;
+ public:
+ ComInterfaceDispatch _entries[EntriesPerThisPtr];
+ };
+
+ struct ComInterfaceEntry
+ {
+ GUID IID;
+ const void* Vtable;
+ };
// Managed object wrapper layout.
// This is designed to codify the binary layout.
struct ManagedObjectWrapperLayout
{
- PTR_VOID ManagedObject;
- long long RefCount;
+ public:
+ LONGLONG GetRawRefCount() const
+ {
+ return _refCount;
+ }
+
+ protected:
+ Volatile _target;
+ int64_t _refCount;
+
+ Volatile _flags;
+ int32_t _userDefinedCount;
+ ComInterfaceEntry* _userDefined;
+ InternalComInterfaceDispatch* _dispatches;
};
+
+ // Given the entry index, compute the dispatch index.
+ inline ComInterfaceDispatch* IndexIntoDispatchSection(int32_t i, InternalComInterfaceDispatch* dispatches)
+ {
+ InternalComInterfaceDispatch* dispatch = dispatches + i / EntriesPerThisPtr;
+ ComInterfaceDispatch* entries = dispatch->_entries;
+ return entries + (i % EntriesPerThisPtr);
+ }
}
}
diff --git a/src/coreclr/interop/inc/interoplibimports.h b/src/coreclr/interop/inc/interoplibimports.h
index 57824c36d78caa..a75252bf3019d8 100644
--- a/src/coreclr/interop/inc/interoplibimports.h
+++ b/src/coreclr/interop/inc/interoplibimports.h
@@ -8,45 +8,13 @@
namespace InteropLibImports
{
- enum class AllocScenario
- {
- ManagedObjectWrapper,
- NativeObjectWrapper,
- };
-
- // Allocate the given amount of memory.
- void* MemAlloc(_In_ size_t sizeInBytes, _In_ AllocScenario scenario) noexcept;
-
- // Free the previously allocated memory.
- void MemFree(_In_ void* mem, _In_ AllocScenario scenario) noexcept;
-
- // Add memory pressure to the runtime's GC calculations.
- HRESULT AddMemoryPressureForExternal(_In_ UINT64 memoryInBytes) noexcept;
-
- // Remove memory pressure from the runtime's GC calculations.
- HRESULT RemoveMemoryPressureForExternal(_In_ UINT64 memoryInBytes) noexcept;
-
- enum class GcRequest
- {
- Default,
- FullBlocking // This is an expensive GC request, akin to a Gen2/"stop the world" GC.
- };
-
- // Request a GC from the runtime.
- HRESULT RequestGarbageCollectionForExternal(_In_ GcRequest req) noexcept;
-
- // Wait for the runtime's finalizer to clean up objects.
- HRESULT WaitForRuntimeFinalizerForExternal() noexcept;
-
- // Release objects associated with the current thread.
- HRESULT ReleaseExternalObjectsFromCurrentThread() noexcept;
-
- // Delete Object instance handle.
- void DeleteObjectInstanceHandle(_In_ InteropLib::OBJECTHANDLE handle) noexcept;
-
// Check if Object instance handle still points at an Object.
bool HasValidTarget(_In_ InteropLib::OBJECTHANDLE handle) noexcept;
+ void DestroyHandle(_In_ InteropLib::OBJECTHANDLE handle) noexcept;
+
+ bool IsObjectPromoted(_In_ InteropLib::OBJECTHANDLE handle) noexcept;
+
// Get the current global pegging state.
bool GetGlobalPeggingState() noexcept;
@@ -54,26 +22,17 @@ namespace InteropLibImports
void SetGlobalPeggingState(_In_ bool state) noexcept;
// Get next External Object Context from the Runtime calling context.
- // S_OK - Context is valid.
- // S_FALSE - Iterator has reached end and context out parameter is set to NULL.
- HRESULT IteratorNext(
+ bool IteratorNext(
_In_ RuntimeCallContext* runtimeContext,
- _Outptr_result_maybenull_ void** extObjContext) noexcept;
+ _Outptr_result_maybenull_ void** trackerTarget,
+ _Outptr_result_maybenull_ InteropLib::OBJECTHANDLE* proxyObject) noexcept;
// Tell the runtime a reference path between the External Object Context and
// OBJECTHANDLE was found.
HRESULT FoundReferencePath(
_In_ RuntimeCallContext* runtimeContext,
- _In_ void* extObjContext,
- _In_ InteropLib::OBJECTHANDLE handle) noexcept;
-
- // Get or create an IReferenceTrackerTarget instance for the supplied
- // external object.
- HRESULT GetOrCreateTrackerTargetForExternal(
- _In_ IUnknown* externalComObject,
- _In_ InteropLib::Com::CreateObjectFlags externalObjectFlags,
- _In_ InteropLib::Com::CreateComInterfaceFlags trackerTargetFlags,
- _Outptr_ void** trackerTarget) noexcept;
+ _In_ InteropLib::OBJECTHANDLE sourceHandle,
+ _In_ InteropLib::OBJECTHANDLE targetHandle) noexcept;
// The enum describes the value of System.Runtime.InteropServices.CustomQueryInterfaceResult
// and the case where the object doesn't support ICustomQueryInterface.
diff --git a/src/coreclr/interop/interoplib.cpp b/src/coreclr/interop/interoplib.cpp
index 452df3cce39b79..b86842bcc3f0fe 100644
--- a/src/coreclr/interop/interoplib.cpp
+++ b/src/coreclr/interop/interoplib.cpp
@@ -3,6 +3,7 @@
#include "platform.h"
#include
+#include
#include
#ifdef FEATURE_COMWRAPPERS
@@ -18,65 +19,6 @@ namespace InteropLib
// Exposed COM related API
namespace Com
{
- HRESULT CreateWrapperForObject(
- _In_ OBJECTHANDLE instance,
- _In_ INT32 vtableCount,
- _In_ void* vtablesRaw,
- _In_ enum CreateComInterfaceFlags flags,
- _Outptr_ IUnknown** wrapper) noexcept
- {
- _ASSERTE(instance != nullptr && wrapper != nullptr);
-
- // Validate the supplied vtable data is valid with a
- // reasonable count.
- if ((vtablesRaw == nullptr && vtableCount != 0) || vtableCount < 0)
- return E_INVALIDARG;
-
- HRESULT hr;
-
- // Convert input to appropriate types.
- auto vtables = static_cast<::ABI::ComInterfaceEntry*>(vtablesRaw);
-
- ManagedObjectWrapper* mow;
- RETURN_IF_FAILED(ManagedObjectWrapper::Create(flags, instance, vtableCount, vtables, &mow));
-
- *wrapper = static_cast(mow->As(IID_IUnknown));
- return S_OK;
- }
-
- void DestroyWrapperForObject(_In_ void* wrapperMaybe) noexcept
- {
- ManagedObjectWrapper* wrapper = ManagedObjectWrapper::MapFromIUnknownWithQueryInterface(static_cast(wrapperMaybe));
-
- // A caller should not be destroying a wrapper without knowing if the wrapper is valid.
- _ASSERTE(wrapper != nullptr);
-
- ManagedObjectWrapper::Destroy(wrapper);
- }
-
- HRESULT IsWrapperRooted(_In_ IUnknown* wrapperMaybe) noexcept
- {
- ManagedObjectWrapper* wrapper = ManagedObjectWrapper::MapFromIUnknown(wrapperMaybe);
- if (wrapper == nullptr)
- return E_INVALIDARG;
-
- return wrapper->IsRooted() ? S_OK : S_FALSE;
- }
-
- HRESULT GetObjectForWrapper(_In_ IUnknown* wrapper, _Outptr_result_maybenull_ OBJECTHANDLE* object) noexcept
- {
- _ASSERTE(wrapper != nullptr && object != nullptr);
- *object = nullptr;
-
- // Attempt to get the managed object wrapper.
- ManagedObjectWrapper *mow = ManagedObjectWrapper::MapFromIUnknownWithQueryInterface(wrapper);
- if (mow == nullptr)
- return E_INVALIDARG;
-
- *object = mow->Target;
- return S_OK;
- }
-
HRESULT MarkComActivated(_In_ IUnknown* wrapperMaybe) noexcept
{
ManagedObjectWrapper* wrapper = ManagedObjectWrapper::MapFromIUnknownWithQueryInterface(wrapperMaybe);
@@ -87,143 +29,52 @@ namespace InteropLib
return S_OK;
}
- HRESULT IsComActivated(_In_ IUnknown* wrapperMaybe) noexcept
+ void GetIUnknownImpl(
+ _Out_ void** fpQueryInterface,
+ _Out_ void** fpAddRef,
+ _Out_ void** fpRelease) noexcept
{
- ManagedObjectWrapper* wrapper = ManagedObjectWrapper::MapFromIUnknownWithQueryInterface(wrapperMaybe);
- if (wrapper == nullptr)
- return E_INVALIDARG;
-
- return wrapper->IsSet(CreateComInterfaceFlagsEx::IsComActivated) ? S_OK : S_FALSE;
+ ManagedObjectWrapper::GetIUnknownImpl(fpQueryInterface, fpAddRef, fpRelease);
}
- HRESULT DetermineIdentityAndInnerForExternal(
- _In_ IUnknown* external,
- _In_ enum CreateObjectFlags flags,
- _Outptr_ IUnknown** identity,
- _Inout_ IUnknown** innerMaybe) noexcept
+ void const* GetTaggedCurrentVersionImpl() noexcept
{
- _ASSERTE(external != nullptr && identity != nullptr && innerMaybe != nullptr);
-
- IUnknown* checkForIdentity = external;
-
- // Check if the flags indicate we are creating
- // an object for an external IReferenceTracker instance
- // that we are aggregating with.
- bool refTrackerInnerScenario = (flags & CreateObjectFlags_TrackerObject)
- && (flags & CreateObjectFlags_Aggregated);
-
- ComHolder trackerObject;
- if (refTrackerInnerScenario)
- {
- // We are checking the supplied external value
- // for IReferenceTracker since in .NET 5 this could
- // actually be the inner and we want the true identity
- // not the inner . This is a trick since the only way
- // to get identity from an inner is through a non-IUnknown
- // interface QI. Once we have the IReferenceTracker
- // instance we can be sure the QI for IUnknown will really
- // be the true identity.
- HRESULT hr = external->QueryInterface(IID_IReferenceTracker, (void**)&trackerObject);
- if (SUCCEEDED(hr))
- checkForIdentity = trackerObject.p;
- }
-
- HRESULT hr;
-
- IUnknown* identityLocal;
- RETURN_IF_FAILED(checkForIdentity->QueryInterface(IID_IUnknown, (void **)&identityLocal));
-
- // Set the inner if scenario dictates an update.
- if (*innerMaybe == nullptr // User didn't supply inner - .NET 5 API scenario sanity check.
- && checkForIdentity != external // Target of check was changed - .NET 5 API scenario sanity check.
- && external != identityLocal // The supplied object doesn't match the computed identity.
- && refTrackerInnerScenario) // The appropriate flags were set.
- {
- *innerMaybe = external;
- }
-
- *identity = identityLocal;
- return S_OK;
+ return ManagedObjectWrapper::GetTaggedCurrentVersionImpl();
}
- HRESULT CreateWrapperForExternal(
- _In_ IUnknown* external,
- _In_opt_ IUnknown* inner,
- _In_ enum CreateObjectFlags flags,
- _In_ size_t contextSize,
- _Out_ ExternalWrapperResult* result) noexcept
+ HRESULT BeginExternalObjectReferenceTracking(_In_ RuntimeCallContext* cxt) noexcept
{
- _ASSERTE(external != nullptr && result != nullptr);
-
- HRESULT hr;
-
- NativeObjectWrapperContext* wrapperContext;
- RETURN_IF_FAILED(NativeObjectWrapperContext::Create(external, inner, flags, contextSize, &wrapperContext));
-
- result->Context = wrapperContext->GetRuntimeContext();
- result->FromTrackerRuntime = (wrapperContext->GetReferenceTracker() != nullptr);
- result->ManagedObjectWrapper = (ManagedObjectWrapper::MapFromIUnknownWithQueryInterface(external) != nullptr);
- return S_OK;
+ return TrackerObjectManager::BeginReferenceTracking(cxt);
}
- void NotifyWrapperForExternalIsBeingCollected(_In_ void* contextMaybe) noexcept
- {
- NativeObjectWrapperContext* context = NativeObjectWrapperContext::MapFromRuntimeContext(contextMaybe);
-
- // A caller should not be destroying a context without knowing if the context is valid.
- _ASSERTE(context != nullptr);
-
- // Check if the tracker object manager should be informed of collection.
- IReferenceTracker* trackerMaybe = context->GetReferenceTracker();
- if (trackerMaybe != nullptr)
- {
- // We only call this during a GC so ignore the failure as
- // there is no way we can handle it at this point.
- HRESULT hr = TrackerObjectManager::BeforeWrapperFinalized(trackerMaybe);
- _ASSERTE(SUCCEEDED(hr));
- (void)hr;
- }
+ HRESULT EndExternalObjectReferenceTracking() noexcept
+ {
+ return TrackerObjectManager::EndReferenceTracking();
}
- void DestroyWrapperForExternal(_In_ void* contextMaybe, _In_ bool notifyIsBeingCollected) noexcept
+ HRESULT DetachNonPromotedObjects(_In_ RuntimeCallContext* cxt) noexcept
{
- NativeObjectWrapperContext* context = NativeObjectWrapperContext::MapFromRuntimeContext(contextMaybe);
-
- // A caller should not be destroying a context without knowing if the context is valid.
- _ASSERTE(context != nullptr);
-
- if (notifyIsBeingCollected)
- NotifyWrapperForExternalIsBeingCollected(contextMaybe);
-
- NativeObjectWrapperContext::Destroy(context);
- }
+ return TrackerObjectManager::DetachNonPromotedObjects(cxt);
+ }
- void SeparateWrapperFromTrackerRuntime(_In_ void* contextMaybe) noexcept
+ void const* GetIReferenceTrackerTargetVftbl() noexcept
{
- NativeObjectWrapperContext* context = NativeObjectWrapperContext::MapFromRuntimeContext(contextMaybe);
-
- // A caller should not be separating a context without knowing if the context is valid.
- _ASSERTE(context != nullptr);
-
- context->DisconnectTracker();
+ return ManagedObjectWrapper::GetIReferenceTrackerTargetImpl();
}
- void GetIUnknownImpl(
- _Out_ void** fpQueryInterface,
- _Out_ void** fpAddRef,
- _Out_ void** fpRelease) noexcept
+ bool HasReferenceTrackerManager() noexcept
{
- ManagedObjectWrapper::GetIUnknownImpl(fpQueryInterface, fpAddRef, fpRelease);
+ return TrackerObjectManager::HasReferenceTrackerManager();
}
- HRESULT BeginExternalObjectReferenceTracking(_In_ RuntimeCallContext* cxt) noexcept
+ bool TryRegisterReferenceTrackerManager(_In_ void* manager) noexcept
{
- return TrackerObjectManager::BeginReferenceTracking(cxt);
+ return TrackerObjectManager::TryRegisterReferenceTrackerManager((IReferenceTrackerManager*)manager);
}
- HRESULT EndExternalObjectReferenceTracking() noexcept
+ bool IsRooted(InteropLib::ABI::ManagedObjectWrapperLayout* mow) noexcept
{
- return TrackerObjectManager::EndReferenceTracking();
+ return reinterpret_cast(mow)->IsRooted();
}
}
diff --git a/src/coreclr/interop/trackerobjectmanager.cpp b/src/coreclr/interop/trackerobjectmanager.cpp
index 0df78164906dcc..cc178d4187179b 100644
--- a/src/coreclr/interop/trackerobjectmanager.cpp
+++ b/src/coreclr/interop/trackerobjectmanager.cpp
@@ -9,148 +9,11 @@ using RuntimeCallContext = InteropLibImports::RuntimeCallContext;
namespace
{
- // 29a71c6a-3c42-4416-a39d-e2825a07a773
- const GUID IID_IReferenceTrackerHost = { 0x29a71c6a, 0x3c42, 0x4416, { 0xa3, 0x9d, 0xe2, 0x82, 0x5a, 0x7, 0xa7, 0x73} };
-
- // 3cf184b4-7ccb-4dda-8455-7e6ce99a3298
- const GUID IID_IReferenceTrackerManager = { 0x3cf184b4, 0x7ccb, 0x4dda, { 0x84, 0x55, 0x7e, 0x6c, 0xe9, 0x9a, 0x32, 0x98} };
-
// 04b3486c-4687-4229-8d14-505ab584dd88
const GUID IID_IFindReferenceTargetsCallback = { 0x04b3486c, 0x4687, 0x4229, { 0x8d, 0x14, 0x50, 0x5a, 0xb5, 0x84, 0xdd, 0x88} };
- // In order to minimize the impact of a constructor running on module load,
- // the HostServices class should have no instance fields.
- class HostServices : public IReferenceTrackerHost
- {
- public: // IReferenceTrackerHost
- STDMETHOD(DisconnectUnusedReferenceSources)(_In_ DWORD dwFlags);
- STDMETHOD(ReleaseDisconnectedReferenceSources)();
- STDMETHOD(NotifyEndOfReferenceTrackingOnThread)();
- STDMETHOD(GetTrackerTarget)(_In_ IUnknown* obj, _Outptr_ IReferenceTrackerTarget** ppNewReference);
- STDMETHOD(AddMemoryPressure)(_In_ UINT64 bytesAllocated);
- STDMETHOD(RemoveMemoryPressure)(_In_ UINT64 bytesAllocated);
-
- public: // IUnknown
- // Lifetime maintained by stack - we don't care about ref counts
- STDMETHOD_(ULONG, AddRef)() { return 1; }
- STDMETHOD_(ULONG, Release)() { return 1; }
-
- STDMETHOD(QueryInterface)(
- /* [in] */ REFIID riid,
- /* [iid_is][out] */ _COM_Outptr_ void __RPC_FAR* __RPC_FAR* ppvObject)
- {
- if (ppvObject == nullptr)
- return E_POINTER;
-
- if (IsEqualIID(riid, IID_IReferenceTrackerHost))
- {
- *ppvObject = static_cast(this);
- }
- else if (IsEqualIID(riid, IID_IUnknown))
- {
- *ppvObject = static_cast(this);
- }
- else
- {
- *ppvObject = nullptr;
- return E_NOINTERFACE;
- }
-
- (void)AddRef();
- return S_OK;
- }
- };
-
- // Global instance of host services.
- HostServices g_HostServicesInstance;
-
- // Defined in windows.ui.xaml.hosting.referencetracker.h.
- enum XAML_REFERENCETRACKER_DISCONNECT
- {
- // Indicates the disconnect is during a suspend and a GC can be trigger.
- XAML_REFERENCETRACKER_DISCONNECT_SUSPEND = 0x00000001
- };
-
- STDMETHODIMP HostServices::DisconnectUnusedReferenceSources(_In_ DWORD flags)
- {
- InteropLibImports::GcRequest type = InteropLibImports::GcRequest::Default;
-
- // Request a "stop the world" GC when a suspend is occurring.
- if (flags & XAML_REFERENCETRACKER_DISCONNECT_SUSPEND)
- type = InteropLibImports::GcRequest::FullBlocking;
-
- return InteropLibImports::RequestGarbageCollectionForExternal(type);
- }
-
- STDMETHODIMP HostServices::ReleaseDisconnectedReferenceSources()
- {
- // We'd like to call InteropLibImports::WaitForRuntimeFinalizerForExternal() here, but this could
- // lead to deadlock if the finalizer thread is trying to get back to this thread, because we are
- // not pumping anymore. Disable this for now. See: https://github.com/dotnet/runtime/issues/109538.
- return S_OK;
- }
-
- STDMETHODIMP HostServices::NotifyEndOfReferenceTrackingOnThread()
- {
- return InteropLibImports::ReleaseExternalObjectsFromCurrentThread();
- }
-
- // Creates a proxy object (managed object wrapper) that points to the given IUnknown.
- // The proxy represents the following:
- // 1. Has a managed reference pointing to the external object
- // and therefore forms a cycle that can be resolved by GC.
- // 2. Forwards data binding requests.
- //
- // For example:
- //
- // Grid <---- NoCW Grid <-------- NoCW
- // | ^ | ^
- // | | Becomes | |
- // v | v |
- // Rectangle Rectangle ----->Proxy
- //
- // Arguments
- // obj - An IUnknown* where a NoCW points to (Grid, in this case)
- // Notes:
- // 1. We can either create a new NoCW or get back an old one from the cache.
- // 2. This obj could be a regular tracker runtime object for data binding.
- // ppNewReference - The IReferenceTrackerTarget* for the proxy created
- // The tracker runtime will call IReferenceTrackerTarget to establish a reference.
- //
- STDMETHODIMP HostServices::GetTrackerTarget(_In_ IUnknown* obj, _Outptr_ IReferenceTrackerTarget** ppNewReference)
- {
- if (obj == nullptr || ppNewReference == nullptr)
- return E_INVALIDARG;
-
- HRESULT hr;
-
- // QI for IUnknown to get the identity unknown
- ComHolder identity;
- RETURN_IF_FAILED(obj->QueryInterface(IID_IUnknown, (void**)&identity));
-
- // Get or create an existing implementation for this external.
- ComHolder target;
- RETURN_IF_FAILED(InteropLibImports::GetOrCreateTrackerTargetForExternal(
- identity,
- InteropLib::Com::CreateObjectFlags_TrackerObject,
- InteropLib::Com::CreateComInterfaceFlags_TrackerSupport,
- (void**)&target));
-
- return target->QueryInterface(IID_IReferenceTrackerTarget, (void**)ppNewReference);
- }
-
- STDMETHODIMP HostServices::AddMemoryPressure(_In_ UINT64 bytesAllocated)
- {
- return InteropLibImports::AddMemoryPressureForExternal(bytesAllocated);
- }
-
- STDMETHODIMP HostServices::RemoveMemoryPressure(_In_ UINT64 bytesAllocated)
- {
- return InteropLibImports::RemoveMemoryPressureForExternal(bytesAllocated);
- }
-
VolatilePtr s_TrackerManager; // The one and only Tracker Manager instance
- Volatile s_HasTrackingStarted = FALSE;
+ Volatile s_HasTrackingStarted = false;
// Indicates if walking the external objects is needed.
// (i.e. Have any IReferenceTracker instances been found?)
@@ -160,17 +23,17 @@ namespace
}
// Callback implementation of IFindReferenceTargetsCallback
- class FindDependentWrappersCallback : public IFindReferenceTargetsCallback
+ class FindDependentWrappersCallback final : public IFindReferenceTargetsCallback
{
- NativeObjectWrapperContext* _nowCxt;
+ OBJECTHANDLE _sourceHandle;
RuntimeCallContext* _runtimeCallCxt;
public:
- FindDependentWrappersCallback(_In_ NativeObjectWrapperContext* nowCxt, _In_ RuntimeCallContext* runtimeCallCxt)
- : _nowCxt{ nowCxt }
+ FindDependentWrappersCallback(_In_ OBJECTHANDLE sourceHandle, _In_ RuntimeCallContext* runtimeCallCxt)
+ : _sourceHandle{ sourceHandle }
, _runtimeCallCxt{ runtimeCallCxt }
{
- _ASSERTE(_nowCxt != nullptr && runtimeCallCxt != nullptr);
+ _ASSERTE(_sourceHandle != nullptr && runtimeCallCxt != nullptr);
}
STDMETHOD(FoundTrackerTarget)(_In_ IReferenceTrackerTarget* target)
@@ -189,8 +52,8 @@ namespace
// Notify the runtime a reference path was found.
RETURN_IF_FAILED(InteropLibImports::FoundReferencePath(
_runtimeCallCxt,
- _nowCxt->GetRuntimeContext(),
- mow->Target));
+ _sourceHandle,
+ mow->GetTarget()));
return S_OK;
}
@@ -229,24 +92,19 @@ namespace
{
_ASSERTE(cxt != nullptr);
- BOOL walkFailed = FALSE;
- HRESULT hr;
+ bool walkFailed = false;
+ HRESULT hr = S_OK;
- void* extObjContext = nullptr;
- while (S_OK == (hr = InteropLibImports::IteratorNext(cxt, &extObjContext)))
+ IReferenceTracker* trackerTarget = nullptr;
+ OBJECTHANDLE proxyObject = nullptr;
+ while (InteropLibImports::IteratorNext(cxt, (void**)&trackerTarget, &proxyObject))
{
- _ASSERTE(extObjContext != nullptr);
-
- NativeObjectWrapperContext* nowc = NativeObjectWrapperContext::MapFromRuntimeContext(extObjContext);
-
- // Check if the object is a tracker object.
- IReferenceTracker* trackerMaybe = nowc->GetReferenceTracker();
- if (trackerMaybe == nullptr)
+ if (trackerTarget == nullptr)
continue;
// Ask the tracker instance to find all reference targets.
- FindDependentWrappersCallback cb{ nowc, cxt };
- hr = trackerMaybe->FindTrackerTargets(&cb);
+ FindDependentWrappersCallback cb{ proxyObject, cxt };
+ hr = trackerTarget->FindTrackerTargets(&cb);
if (FAILED(hr))
break;
}
@@ -254,58 +112,26 @@ namespace
if (FAILED(hr))
{
// Remember the fact that we've failed and stop walking
- walkFailed = TRUE;
+ walkFailed = true;
InteropLibImports::SetGlobalPeggingState(true);
}
_ASSERTE(s_TrackerManager != nullptr);
- (void)s_TrackerManager->FindTrackerTargetsCompleted(walkFailed);
+ (void)s_TrackerManager->FindTrackerTargetsCompleted(walkFailed ? TRUE : FALSE);
return hr;
}
}
-HRESULT TrackerObjectManager::OnIReferenceTrackerFound(_In_ IReferenceTracker* obj)
+bool TrackerObjectManager::HasReferenceTrackerManager()
{
- _ASSERTE(obj != nullptr);
- if (s_TrackerManager != nullptr)
- return S_OK;
-
- // Retrieve IReferenceTrackerManager
- HRESULT hr;
- ComHolder trackerManager;
- RETURN_IF_FAILED(obj->GetReferenceTrackerManager(&trackerManager));
-
- ComHolder hostServices;
- RETURN_IF_FAILED(g_HostServicesInstance.QueryInterface(IID_IReferenceTrackerHost, (void**)&hostServices));
-
- // Attempt to set the tracker instance.
- if (InterlockedCompareExchangePointer((void**)&s_TrackerManager, trackerManager.p, nullptr) == nullptr)
- {
- (void)trackerManager.Detach(); // Ownership has been transferred
- RETURN_IF_FAILED(s_TrackerManager->SetReferenceTrackerHost(hostServices));
- }
-
- return S_OK;
+ return s_TrackerManager != nullptr;
}
-HRESULT TrackerObjectManager::AfterWrapperCreated(_In_ IReferenceTracker* obj)
+bool TrackerObjectManager::TryRegisterReferenceTrackerManager(_In_ IReferenceTrackerManager* manager)
{
- _ASSERTE(obj != nullptr);
-
- HRESULT hr;
-
- // Notify tracker runtime that we've created a new wrapper for this object.
- // To avoid surprises, we should notify them before we fire the first AddRefFromTrackerSource.
- RETURN_IF_FAILED(obj->ConnectFromTrackerSource());
-
- // Send out AddRefFromTrackerSource callbacks to notify tracker runtime we've done AddRef()
- // for certain interfaces. We should do this *after* we made a AddRef() because we should never
- // be in a state where report refs > actual refs
- RETURN_IF_FAILED(obj->AddRefFromTrackerSource()); // IUnknown
- RETURN_IF_FAILED(obj->AddRefFromTrackerSource()); // IReferenceTracker
-
- return S_OK;
+ _ASSERTE(manager != nullptr);
+ return InterlockedCompareExchangePointer((void**)&s_TrackerManager, manager, nullptr) == nullptr;
}
HRESULT TrackerObjectManager::BeforeWrapperFinalized(_In_ IReferenceTracker* obj)
@@ -332,10 +158,10 @@ HRESULT TrackerObjectManager::BeginReferenceTracking(_In_ RuntimeCallContext* cx
HRESULT hr;
- _ASSERTE(s_HasTrackingStarted == FALSE);
+ _ASSERTE(s_HasTrackingStarted == false);
_ASSERTE(InteropLibImports::GetGlobalPeggingState());
- s_HasTrackingStarted = TRUE;
+ s_HasTrackingStarted = true;
// Let the tracker runtime know we are about to walk external objects so that
// they can lock their reference cache. Note that the tracker runtime doesn't need to
@@ -356,7 +182,7 @@ HRESULT TrackerObjectManager::BeginReferenceTracking(_In_ RuntimeCallContext* cx
HRESULT TrackerObjectManager::EndReferenceTracking()
{
- if (s_HasTrackingStarted != TRUE
+ if (s_HasTrackingStarted != true
|| !ShouldWalkExternalObjects())
return S_FALSE;
@@ -372,7 +198,31 @@ HRESULT TrackerObjectManager::EndReferenceTracking()
_ASSERTE(SUCCEEDED(hr));
InteropLibImports::SetGlobalPeggingState(true);
- s_HasTrackingStarted = FALSE;
+ s_HasTrackingStarted = false;
return hr;
}
+
+HRESULT TrackerObjectManager::DetachNonPromotedObjects(_In_ RuntimeCallContext* cxt)
+{
+ _ASSERTE(cxt != nullptr);
+
+ HRESULT hr;
+ IReferenceTracker* trackerTarget = nullptr;
+ OBJECTHANDLE proxyObject = NULL;
+ while (InteropLibImports::IteratorNext(cxt, (void**)&trackerTarget, &proxyObject))
+ {
+ if (trackerTarget == nullptr)
+ continue;
+
+ if (proxyObject == nullptr)
+ continue;
+
+ if (!InteropLibImports::IsObjectPromoted(proxyObject))
+ {
+ RETURN_IF_FAILED(BeforeWrapperFinalized(trackerTarget));
+ }
+ }
+
+ return S_OK;
+}
diff --git a/src/coreclr/nativeaot/System.Private.CoreLib/src/System.Private.CoreLib.csproj b/src/coreclr/nativeaot/System.Private.CoreLib/src/System.Private.CoreLib.csproj
index d7f5454259ee61..f687c6bb354546 100644
--- a/src/coreclr/nativeaot/System.Private.CoreLib/src/System.Private.CoreLib.csproj
+++ b/src/coreclr/nativeaot/System.Private.CoreLib/src/System.Private.CoreLib.csproj
@@ -158,6 +158,7 @@
+
@@ -168,7 +169,6 @@
-
@@ -277,9 +277,6 @@
Interop\Windows\Ole32\Interop.CoGetApartmentType.cs
-
- Interop\Windows\Ole32\Interop.CoGetContextToken.cs
-
Interop\Windows\OleAut32\Interop.VariantClear.cs
@@ -575,11 +572,7 @@
-
+
diff --git a/src/coreclr/nativeaot/System.Private.CoreLib/src/System/GC.NativeAot.cs b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/GC.NativeAot.cs
index 67d09f8b246a6d..6f6aec5df683aa 100644
--- a/src/coreclr/nativeaot/System.Private.CoreLib/src/System/GC.NativeAot.cs
+++ b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/GC.NativeAot.cs
@@ -141,6 +141,11 @@ public static void Collect(int generation, GCCollectionMode mode, bool blocking)
}
public static void Collect(int generation, GCCollectionMode mode, bool blocking, bool compacting)
+ {
+ Collect(generation, mode, blocking, compacting, lowMemoryPressure: false);
+ }
+
+ internal static void Collect(int generation, GCCollectionMode mode, bool blocking, bool compacting, bool lowMemoryPressure)
{
ArgumentOutOfRangeException.ThrowIfNegative(generation);
@@ -186,7 +191,7 @@ public static void Collect(int generation, GCCollectionMode mode, bool blocking,
iInternalModes |= (int)InternalGCCollectionMode.NonBlocking;
}
- RuntimeImports.RhCollect(generation, (InternalGCCollectionMode)iInternalModes);
+ RuntimeImports.RhCollect(generation, (InternalGCCollectionMode)iInternalModes, lowMemoryPressure);
}
///
diff --git a/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Runtime/InteropServices/ComAwareWeakReference.NativeAot.cs b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Runtime/InteropServices/ComAwareWeakReference.NativeAot.cs
new file mode 100644
index 00000000000000..6e630e096fd762
--- /dev/null
+++ b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Runtime/InteropServices/ComAwareWeakReference.NativeAot.cs
@@ -0,0 +1,27 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+
+using System;
+using System.Runtime.CompilerServices;
+
+namespace System
+{
+ internal sealed partial class ComAwareWeakReference
+ {
+ internal static unsafe object? ComWeakRefToObject(IntPtr pComWeakRef, object? context)
+ {
+ return ComWeakRefToComWrappersObject(pComWeakRef, context);
+ }
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ internal static unsafe bool PossiblyComObject(object target)
+ {
+ return PossiblyComWrappersObject(target);
+ }
+
+ internal static unsafe IntPtr ObjectToComWeakRef(object target, out object? context)
+ {
+ return ComWrappersObjectToComWeakRef(target, out context);
+ }
+ }
+}
diff --git a/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Runtime/InteropServices/ComWrappers.NativeAot.cs b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Runtime/InteropServices/ComWrappers.NativeAot.cs
index 88f392363573e0..0cc40f0f46c894 100644
--- a/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Runtime/InteropServices/ComWrappers.NativeAot.cs
+++ b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Runtime/InteropServices/ComWrappers.NativeAot.cs
@@ -18,1461 +18,42 @@ namespace System.Runtime.InteropServices
///
public abstract partial class ComWrappers
{
- private const int TrackerRefShift = 32;
- private const ulong TrackerRefCounter = 1UL << TrackerRefShift;
- private const ulong DestroySentinel = 0x0000000080000000UL;
- private const ulong TrackerRefCountMask = 0xffffffff00000000UL;
- private const ulong ComRefCountMask = 0x000000007fffffffUL;
- private const int COR_E_ACCESSING_CCW = unchecked((int)0x80131544);
-
- internal static IntPtr DefaultIUnknownVftblPtr { get; } = CreateDefaultIUnknownVftbl();
- internal static IntPtr TaggedImplVftblPtr { get; } = CreateTaggedImplVftbl();
- internal static IntPtr DefaultIReferenceTrackerTargetVftblPtr { get; } = CreateDefaultIReferenceTrackerTargetVftbl();
-
- internal static readonly Guid IID_IUnknown = new Guid(0x00000000, 0x0000, 0x0000, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46);
- internal static readonly Guid IID_IReferenceTrackerTarget = new Guid(0x64bd43f8, 0xbfee, 0x4ec4, 0xb7, 0xeb, 0x29, 0x35, 0x15, 0x8d, 0xae, 0x21);
- internal static readonly Guid IID_TaggedImpl = new Guid(0x5c13e51c, 0x4f32, 0x4726, 0xa3, 0xfd, 0xf3, 0xed, 0xd6, 0x3d, 0xa3, 0xa0);
- internal static readonly Guid IID_IReferenceTracker = new Guid(0x11D3B13A, 0x180E, 0x4789, 0xA8, 0xBE, 0x77, 0x12, 0x88, 0x28, 0x93, 0xE6);
- internal static readonly Guid IID_IReferenceTrackerHost = new Guid(0x29a71c6a, 0x3c42, 0x4416, 0xa3, 0x9d, 0xe2, 0x82, 0x5a, 0x7, 0xa7, 0x73);
- internal static readonly Guid IID_IReferenceTrackerManager = new Guid(0x3cf184b4, 0x7ccb, 0x4dda, 0x84, 0x55, 0x7e, 0x6c, 0xe9, 0x9a, 0x32, 0x98);
- internal static readonly Guid IID_IFindReferenceTargetsCallback = new Guid(0x04b3486c, 0x4687, 0x4229, 0x8d, 0x14, 0x50, 0x5a, 0xb5, 0x84, 0xdd, 0x88);
-
- private static readonly Guid IID_IInspectable = new Guid(0xAF86E2E0, 0xB12D, 0x4c6a, 0x9C, 0x5A, 0xD7, 0xAA, 0x65, 0x10, 0x1E, 0x90);
- private static readonly Guid IID_IWeakReferenceSource = new Guid(0x00000038, 0, 0, 0xC0, 0, 0, 0, 0, 0, 0, 0x46);
-
- private static readonly ConditionalWeakTable