Skip to content

Commit fd8933a

Browse files
authored
Share implementation of ComWrappers between CoreCLR and NativeAOT (#113907)
1 parent 33b5215 commit fd8933a

File tree

59 files changed

+3828
-6003
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

59 files changed

+3828
-6003
lines changed

src/coreclr/System.Private.CoreLib/System.Private.CoreLib.csproj

+2-1
Original file line numberDiff line numberDiff line change
@@ -254,7 +254,8 @@
254254
<Compile Include="src\System\RuntimeType.GenericCache.cs" />
255255
</ItemGroup>
256256
<ItemGroup Condition="'$(FeatureComWrappers)' == 'true'">
257-
<Compile Include="$(BclSourcesRoot)\System\Runtime\InteropServices\ComWrappers.cs" />
257+
<Compile Include="$(BclSourcesRoot)\System\Runtime\InteropServices\ComWrappers.CoreCLR.cs" />
258+
<Compile Include="$(BclSourcesRoot)\System\Runtime\InteropServices\TrackerObjectManager.CoreCLR.cs" />
258259
</ItemGroup>
259260
<ItemGroup Condition="'$(FeatureCominterop)' == 'true'">
260261
<Compile Include="$(CommonPath)System\Runtime\InteropServices\IDispatch.cs">

src/coreclr/System.Private.CoreLib/src/System/ComAwareWeakReference.CoreCLR.cs

+35-25
Original file line numberDiff line numberDiff line change
@@ -10,46 +10,56 @@ namespace System
1010
internal sealed partial class ComAwareWeakReference
1111
{
1212
[LibraryImport(RuntimeHelpers.QCall, EntryPoint = "ComWeakRefToObject")]
13-
private static partial void ComWeakRefToObject(IntPtr pComWeakRef, long wrapperId, ObjectHandleOnStack retRcw);
13+
private static partial void ComWeakRefToObject(IntPtr pComWeakRef, ObjectHandleOnStack retRcw);
1414

15-
internal static object? ComWeakRefToObject(IntPtr pComWeakRef, long wrapperId)
15+
internal static object? ComWeakRefToObject(IntPtr pComWeakRef, object? context)
1616
{
17-
object? retRcw = null;
18-
ComWeakRefToObject(pComWeakRef, wrapperId, ObjectHandleOnStack.Create(ref retRcw));
19-
return retRcw;
17+
#if FEATURE_COMINTEROP
18+
if (context is null)
19+
{
20+
// This wrapper was not created by ComWrappers, so we try to rehydrate using built-in COM.
21+
object? retRcw = null;
22+
ComWeakRefToObject(pComWeakRef, ObjectHandleOnStack.Create(ref retRcw));
23+
return retRcw;
24+
}
25+
#endif // FEATURE_COMINTEROP
26+
27+
return ComWeakRefToComWrappersObject(pComWeakRef, context);
2028
}
2129

2230
[MethodImpl(MethodImplOptions.AggressiveInlining)]
2331
internal static unsafe bool PossiblyComObject(object target)
2432
{
25-
// see: syncblk.h
26-
const int IS_HASHCODE_BIT_NUMBER = 26;
27-
const int BIT_SBLK_IS_HASHCODE = 1 << IS_HASHCODE_BIT_NUMBER;
28-
const int BIT_SBLK_IS_HASH_OR_SYNCBLKINDEX = 0x08000000;
29-
30-
fixed (byte* pRawData = &target.GetRawData())
31-
{
32-
// The header is 4 bytes before MT field on all architectures
33-
int header = *(int*)(pRawData - sizeof(IntPtr) - sizeof(int));
34-
// common case: target does not have a syncblock, so there is no interop info
35-
return (header & (BIT_SBLK_IS_HASH_OR_SYNCBLKINDEX | BIT_SBLK_IS_HASHCODE)) == BIT_SBLK_IS_HASH_OR_SYNCBLKINDEX;
36-
}
33+
#if FEATURE_COMINTEROP
34+
return target is __ComObject || PossiblyComWrappersObject(target);
35+
#else // !FEATURE_COMINTEROP
36+
// If we are not using built-in COM, then we can only be a ComWrappers object.
37+
return PossiblyComWrappersObject(target);
38+
#endif // FEATURE_COMINTEROP
3739
}
3840

39-
[MethodImpl(MethodImplOptions.InternalCall)]
40-
internal static extern bool HasInteropInfo(object target);
41-
4241
[LibraryImport(RuntimeHelpers.QCall, EntryPoint = "ObjectToComWeakRef")]
43-
private static partial IntPtr ObjectToComWeakRef(ObjectHandleOnStack retRcw, out long wrapperId);
42+
private static partial IntPtr ObjectToComWeakRef(ObjectHandleOnStack retRcw);
4443

45-
internal static nint ObjectToComWeakRef(object target, out long wrapperId)
44+
internal static nint ObjectToComWeakRef(object target, out object? context)
4645
{
47-
if (HasInteropInfo(target))
46+
#if FEATURE_COMINTEROP
47+
if (target is __ComObject)
48+
{
49+
// This object is using built-in COM, so use built-in COM to create the weak reference.
50+
context = null;
51+
return ObjectToComWeakRef(ObjectHandleOnStack.Create(ref target));
52+
}
53+
#endif // FEATURE_COMINTEROP
54+
55+
if (PossiblyComWrappersObject(target))
4856
{
49-
return ObjectToComWeakRef(ObjectHandleOnStack.Create(ref target), out wrapperId);
57+
return ComWrappersObjectToComWeakRef(target, out context);
5058
}
5159

52-
wrapperId = 0;
60+
// This object is not produced using built-in COM or ComWrappers
61+
// or is an aggregated object, so we cannot create a weak reference.
62+
context = null;
5363
return IntPtr.Zero;
5464
}
5565
}

src/coreclr/System.Private.CoreLib/src/System/GC.CoreCLR.cs

+10-4
Original file line numberDiff line numberDiff line change
@@ -106,7 +106,7 @@ internal enum GC_ALLOC_FLAGS
106106
private static partial long GetTotalMemory();
107107

108108
[LibraryImport(RuntimeHelpers.QCall, EntryPoint = "GCInterface_Collect")]
109-
private static partial void _Collect(int generation, int mode);
109+
private static partial void _Collect(int generation, int mode, [MarshalAs(UnmanagedType.U1)] bool lowMemoryPressure);
110110

111111
[MethodImpl(MethodImplOptions.InternalCall)]
112112
private static extern int GetMaxGeneration();
@@ -174,7 +174,7 @@ public static void Collect(int generation)
174174
public static void Collect()
175175
{
176176
// -1 says to GC all generations.
177-
_Collect(-1, (int)InternalGCCollectionMode.Blocking);
177+
_Collect(-1, (int)InternalGCCollectionMode.Blocking, lowMemoryPressure: false);
178178
}
179179

180180
public static void Collect(int generation, GCCollectionMode mode)
@@ -189,6 +189,11 @@ public static void Collect(int generation, GCCollectionMode mode, bool blocking)
189189
}
190190

191191
public static void Collect(int generation, GCCollectionMode mode, bool blocking, bool compacting)
192+
{
193+
Collect(generation, mode, blocking, compacting, lowMemoryPressure: false);
194+
}
195+
196+
internal static void Collect(int generation, GCCollectionMode mode, bool blocking, bool compacting, bool lowMemoryPressure)
192197
{
193198
ArgumentOutOfRangeException.ThrowIfNegative(generation);
194199

@@ -197,7 +202,6 @@ public static void Collect(int generation, GCCollectionMode mode, bool blocking,
197202
throw new ArgumentOutOfRangeException(nameof(mode), SR.ArgumentOutOfRange_Enum);
198203
}
199204

200-
201205
int iInternalModes = 0;
202206

203207
if (mode == GCCollectionMode.Optimized)
@@ -222,7 +226,9 @@ public static void Collect(int generation, GCCollectionMode mode, bool blocking,
222226
}
223227

224228
if (compacting)
229+
{
225230
iInternalModes |= (int)InternalGCCollectionMode.Compacting;
231+
}
226232

227233
if (blocking)
228234
{
@@ -233,7 +239,7 @@ public static void Collect(int generation, GCCollectionMode mode, bool blocking,
233239
iInternalModes |= (int)InternalGCCollectionMode.NonBlocking;
234240
}
235241

236-
_Collect(generation, iInternalModes);
242+
_Collect(generation, (int)iInternalModes, lowMemoryPressure);
237243
}
238244

239245
public static int CollectionCount(int generation)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,119 @@
1+
// Licensed to the .NET Foundation under one or more agreements.
2+
// The .NET Foundation licenses this file to you under the MIT license.
3+
4+
using System.Threading;
5+
using System.Runtime.CompilerServices;
6+
using System.Collections.Generic;
7+
using System.Collections.Concurrent;
8+
9+
namespace System.Runtime.InteropServices
10+
{
11+
/// <summary>
12+
/// Class for managing wrappers of COM IUnknown types.
13+
/// </summary>
14+
public abstract partial class ComWrappers
15+
{
16+
/// <summary>
17+
/// Get the runtime provided IUnknown implementation.
18+
/// </summary>
19+
/// <param name="fpQueryInterface">Function pointer to QueryInterface.</param>
20+
/// <param name="fpAddRef">Function pointer to AddRef.</param>
21+
/// <param name="fpRelease">Function pointer to Release.</param>
22+
public static unsafe void GetIUnknownImpl(out IntPtr fpQueryInterface, out IntPtr fpAddRef, out IntPtr fpRelease)
23+
=> GetIUnknownImplInternal(out fpQueryInterface, out fpAddRef, out fpRelease);
24+
25+
[LibraryImport(RuntimeHelpers.QCall, EntryPoint = "ComWrappers_GetIUnknownImpl")]
26+
[SuppressGCTransition]
27+
private static partial void GetIUnknownImplInternal(out IntPtr fpQueryInterface, out IntPtr fpAddRef, out IntPtr fpRelease);
28+
29+
internal static IntPtr DefaultIUnknownVftblPtr { get; } = CreateDefaultIUnknownVftbl();
30+
internal static IntPtr TaggedImplVftblPtr { get; } = CreateTaggedImplVftbl();
31+
internal static IntPtr DefaultIReferenceTrackerTargetVftblPtr { get; } = CreateDefaultIReferenceTrackerTargetVftbl();
32+
33+
private static unsafe IntPtr CreateDefaultIUnknownVftbl()
34+
{
35+
IntPtr* vftbl = (IntPtr*)RuntimeHelpers.AllocateTypeAssociatedMemory(typeof(ComWrappers), 3 * sizeof(IntPtr));
36+
GetIUnknownImpl(out vftbl[0], out vftbl[1], out vftbl[2]);
37+
return (IntPtr)vftbl;
38+
}
39+
40+
private static unsafe IntPtr CreateTaggedImplVftbl()
41+
{
42+
IntPtr* vftbl = (IntPtr*)RuntimeHelpers.AllocateTypeAssociatedMemory(typeof(ComWrappers), 4 * sizeof(IntPtr));
43+
GetIUnknownImpl(out vftbl[0], out vftbl[1], out vftbl[2]);
44+
vftbl[3] = GetTaggedImplCurrentVersion();
45+
return (IntPtr)vftbl;
46+
}
47+
48+
internal static int CallICustomQueryInterface(ManagedObjectWrapperHolder holder, ref Guid iid, out IntPtr ppObject)
49+
{
50+
if (holder.WrappedObject is ICustomQueryInterface customQueryInterface)
51+
{
52+
return (int)customQueryInterface.GetInterface(ref iid, out ppObject);
53+
}
54+
55+
ppObject = IntPtr.Zero;
56+
return -1; // See TryInvokeICustomQueryInterfaceResult
57+
}
58+
59+
internal static IntPtr GetOrCreateComInterfaceForObjectWithGlobalMarshallingInstance(object obj)
60+
{
61+
try
62+
{
63+
return s_globalInstanceForMarshalling is null
64+
? IntPtr.Zero
65+
: s_globalInstanceForMarshalling.GetOrCreateComInterfaceForObject(obj, CreateComInterfaceFlags.TrackerSupport);
66+
}
67+
catch (ArgumentException)
68+
{
69+
// We've failed to create a COM interface for the object.
70+
// Fallback to built-in COM.
71+
return IntPtr.Zero;
72+
}
73+
}
74+
75+
internal static object? GetOrCreateObjectForComInstanceWithGlobalMarshallingInstance(IntPtr comObject, CreateObjectFlags flags)
76+
{
77+
try
78+
{
79+
return s_globalInstanceForMarshalling?.GetOrCreateObjectForComInstance(comObject, flags);
80+
}
81+
catch (ArgumentNullException)
82+
{
83+
// We've failed to create a managed object for the COM instance.
84+
// Fallback to built-in COM.
85+
return null;
86+
}
87+
}
88+
89+
[LibraryImport(RuntimeHelpers.QCall, EntryPoint = "ComWrappers_GetIReferenceTrackerTargetVftbl")]
90+
[SuppressGCTransition]
91+
private static partial IntPtr GetDefaultIReferenceTrackerTargetVftbl();
92+
93+
private static IntPtr CreateDefaultIReferenceTrackerTargetVftbl()
94+
=> GetDefaultIReferenceTrackerTargetVftbl();
95+
96+
private static IntPtr GetTaggedImplCurrentVersion()
97+
{
98+
return GetTaggedImpl();
99+
}
100+
101+
[LibraryImport(RuntimeHelpers.QCall, EntryPoint = "ComWrappers_GetTaggedImpl")]
102+
[SuppressGCTransition]
103+
private static partial IntPtr GetTaggedImpl();
104+
105+
internal sealed partial class ManagedObjectWrapperHolder
106+
{
107+
[LibraryImport(RuntimeHelpers.QCall, EntryPoint = "ComWrappers_RegisterIsRootedCallback")]
108+
private static partial void RegisterIsRootedCallback();
109+
110+
private static IntPtr AllocateRefCountedHandle(ManagedObjectWrapperHolder holder)
111+
{
112+
return AllocateRefCountedHandle(ObjectHandleOnStack.Create(ref holder));
113+
}
114+
115+
[LibraryImport(RuntimeHelpers.QCall, EntryPoint = "ComWrappers_AllocateRefCountedHandle")]
116+
private static partial IntPtr AllocateRefCountedHandle(ObjectHandleOnStack obj);
117+
}
118+
}
119+
}

0 commit comments

Comments
 (0)