Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
42 commits
Select commit Hold shift + click to select a range
d673663
Various fixes to get tests passing
jkoritzinsky Feb 18, 2025
9b32654
Remove wrapper ID as a concept entirely
jkoritzinsky Mar 26, 2025
2abcf60
Add #if around built-in COM in the weakref support.
jkoritzinsky Mar 26, 2025
5b08974
Check for aggregation before getting a com weak ref for a ComWrappers…
jkoritzinsky Mar 26, 2025
8feaa8c
Make static now that we don't track an instance id
jkoritzinsky Mar 26, 2025
d045004
Various build fixes
jkoritzinsky Mar 27, 2025
095d924
Encapsulate the Target member
jkoritzinsky Mar 27, 2025
5c93a50
More fixes
jkoritzinsky Mar 27, 2025
045aae9
Add missing cast
jkoritzinsky Mar 27, 2025
dbd8533
TADDR cast for null
jkoritzinsky Mar 28, 2025
64b5e41
Fix defines
jkoritzinsky Mar 28, 2025
fe7d853
QI for identity is done in the managed code now, so we can skip the Q…
jkoritzinsky Mar 28, 2025
6b8913f
Fix ifdefs
jkoritzinsky Mar 28, 2025
4a09807
Fix calling the ComWrappers API when in a ComWrappers scenario.
jkoritzinsky Mar 31, 2025
9a0ee83
Merge branch 'shared-comwrappers' of github.com:jkoritzinsky/runtime …
jkoritzinsky Mar 31, 2025
a6b7513
fix arguments
jkoritzinsky Apr 2, 2025
a4c8b8d
Handle ArgumentException for global marshalling instance.
jkoritzinsky Apr 7, 2025
cee2e71
Fix fallback for RCW case as well
jkoritzinsky Apr 9, 2025
f6439f2
Fix COM Activation
jkoritzinsky Apr 10, 2025
0ec2e6b
Various PR feedback
jkoritzinsky Apr 10, 2025
6da9c57
Update src/coreclr/vm/interoplibinterface_shared.cpp
jkoritzinsky Apr 10, 2025
9dfcdff
Fix lifetime issue with the DAC (and provide a mechanism that we can …
jkoritzinsky Apr 11, 2025
d8605e7
PR feedback
jkoritzinsky Apr 11, 2025
1ae095f
Various PR feedback
jkoritzinsky Apr 11, 2025
ce21cc3
Merge branch 'main' of https://github.com/dotnet/runtime into shared-…
jkoritzinsky Apr 11, 2025
c8d0277
Use the pre-init pattern for all vtables on NativeAOT.
jkoritzinsky Apr 12, 2025
b123e15
PR feedback
jkoritzinsky Apr 14, 2025
8816f51
Reimplement ComWrappers diagnostics on top of the ConditionalWeakTabl…
jkoritzinsky May 1, 2025
fb8bf7d
PR feedback
jkoritzinsky May 1, 2025
ccac105
Add message for static-assert
jkoritzinsky May 1, 2025
960508d
Merge remote-tracking branch 'dotnet/main' into shared-comwrappers
jkoritzinsky May 2, 2025
0437a73
Refactor reading into a ManagedObjectWrapper to avoid friend classes
jkoritzinsky May 2, 2025
36c2e9a
Wrap in ifdef for correctness
jkoritzinsky May 2, 2025
7f080f7
Add validation that the vtable layouts are preinitialized and guard t…
jkoritzinsky May 6, 2025
62c3141
PR feedback and fix ifdefs for syncblk cleanup
jkoritzinsky May 7, 2025
3d94abb
Fix ifdef
jkoritzinsky May 7, 2025
03c9120
Fix null return
jkoritzinsky May 8, 2025
72fea93
Fix weak reference detection of comwrappers
jkoritzinsky May 9, 2025
566b5c9
Don't check the sync-block, just do a type check
jkoritzinsky May 9, 2025
61a7062
Merge branch 'shared-comwrappers' of https://github.com/jkoritzinsky/…
jkoritzinsky May 9, 2025
1dd8f71
Add ifdef
jkoritzinsky May 9, 2025
1f225f3
Remove FCall class def
jkoritzinsky May 9, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -254,7 +254,8 @@
<Compile Include="src\System\RuntimeType.GenericCache.cs" />
</ItemGroup>
<ItemGroup Condition="'$(FeatureComWrappers)' == 'true'">
<Compile Include="$(BclSourcesRoot)\System\Runtime\InteropServices\ComWrappers.cs" />
<Compile Include="$(BclSourcesRoot)\System\Runtime\InteropServices\ComWrappers.CoreCLR.cs" />
<Compile Include="$(BclSourcesRoot)\System\Runtime\InteropServices\TrackerObjectManager.CoreCLR.cs" />
</ItemGroup>
<ItemGroup Condition="'$(FeatureCominterop)' == 'true'">
<Compile Include="$(CommonPath)System\Runtime\InteropServices\IDispatch.cs">
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
}
Expand Down
14 changes: 10 additions & 4 deletions src/coreclr/System.Private.CoreLib/src/System/GC.CoreCLR.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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();
Expand Down Expand Up @@ -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)
Expand All @@ -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);

Expand All @@ -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)
Expand All @@ -222,7 +226,9 @@ public static void Collect(int generation, GCCollectionMode mode, bool blocking,
}

if (compacting)
{
iInternalModes |= (int)InternalGCCollectionMode.Compacting;
}

if (blocking)
{
Expand All @@ -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)
Expand Down
Original file line number Diff line number Diff line change
@@ -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
{
/// <summary>
/// Class for managing wrappers of COM IUnknown types.
/// </summary>
public abstract partial class ComWrappers
{
/// <summary>
/// Get the runtime provided IUnknown implementation.
/// </summary>
/// <param name="fpQueryInterface">Function pointer to QueryInterface.</param>
/// <param name="fpAddRef">Function pointer to AddRef.</param>
/// <param name="fpRelease">Function pointer to Release.</param>
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);
}
}
}
Loading
Loading