diff --git a/src/coreclr/System.Private.CoreLib/System.Private.CoreLib.csproj b/src/coreclr/System.Private.CoreLib/System.Private.CoreLib.csproj
index 76870f0bf9472..ed5b3314da9c3 100644
--- a/src/coreclr/System.Private.CoreLib/System.Private.CoreLib.csproj
+++ b/src/coreclr/System.Private.CoreLib/System.Private.CoreLib.csproj
@@ -133,6 +133,7 @@
+
@@ -244,8 +245,6 @@
-
-
diff --git a/src/coreclr/System.Private.CoreLib/src/System/ComAwareWeakReference.CoreCLR.cs b/src/coreclr/System.Private.CoreLib/src/System/ComAwareWeakReference.CoreCLR.cs
new file mode 100644
index 0000000000000..de9aeddf40305
--- /dev/null
+++ b/src/coreclr/System.Private.CoreLib/src/System/ComAwareWeakReference.CoreCLR.cs
@@ -0,0 +1,57 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+
+#if FEATURE_COMINTEROP || FEATURE_COMWRAPPERS
+namespace System
+{
+ internal sealed partial class ComAwareWeakReference
+ {
+ [LibraryImport(RuntimeHelpers.QCall, EntryPoint = "ComWeakRefToObject")]
+ private static partial void ComWeakRefToObject(IntPtr pComWeakRef, long wrapperId, ObjectHandleOnStack retRcw);
+
+ internal static object? ComWeakRefToObject(IntPtr pComWeakRef, long wrapperId)
+ {
+ object? retRcw = null;
+ ComWeakRefToObject(pComWeakRef, wrapperId, ObjectHandleOnStack.Create(ref retRcw));
+ return retRcw;
+ }
+
+ [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;
+ }
+ }
+
+ [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);
+
+ internal static nint ObjectToComWeakRef(object target, out long wrapperId)
+ {
+ if (HasInteropInfo(target))
+ {
+ return ObjectToComWeakRef(ObjectHandleOnStack.Create(ref target), out wrapperId);
+ }
+
+ wrapperId = 0;
+ return IntPtr.Zero;
+ }
+ }
+}
+#endif
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 bfb289a665104..d1f54004b9dcd 100644
--- a/src/coreclr/System.Private.CoreLib/src/System/GC.CoreCLR.cs
+++ b/src/coreclr/System.Private.CoreLib/src/System/GC.CoreCLR.cs
@@ -305,7 +305,7 @@ public static void KeepAlive(object? obj)
//
public static int GetGeneration(WeakReference wo)
{
- int result = GetGenerationWR(wo.m_handle);
+ int result = GetGenerationWR(wo.WeakHandle);
KeepAlive(wo);
return result;
}
diff --git a/src/coreclr/System.Private.CoreLib/src/System/Runtime/InteropServices/GCHandle.CoreCLR.cs b/src/coreclr/System.Private.CoreLib/src/System/Runtime/InteropServices/GCHandle.CoreCLR.cs
index 8597e5c6ed80e..b84be38d886fc 100644
--- a/src/coreclr/System.Private.CoreLib/src/System/Runtime/InteropServices/GCHandle.CoreCLR.cs
+++ b/src/coreclr/System.Private.CoreLib/src/System/Runtime/InteropServices/GCHandle.CoreCLR.cs
@@ -8,7 +8,7 @@ namespace System.Runtime.InteropServices
public partial struct GCHandle
{
[MethodImpl(MethodImplOptions.InternalCall)]
- private static extern IntPtr InternalAlloc(object? value, GCHandleType type);
+ internal static extern IntPtr InternalAlloc(object? value, GCHandleType type);
[MethodImpl(MethodImplOptions.InternalCall)]
internal static extern void InternalFree(IntPtr handle);
diff --git a/src/coreclr/System.Private.CoreLib/src/System/WeakReference.CoreCLR.cs b/src/coreclr/System.Private.CoreLib/src/System/WeakReference.CoreCLR.cs
deleted file mode 100644
index 0deef24348dd5..0000000000000
--- a/src/coreclr/System.Private.CoreLib/src/System/WeakReference.CoreCLR.cs
+++ /dev/null
@@ -1,52 +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.Runtime.Serialization;
-using System.Runtime.CompilerServices;
-using System.Diagnostics;
-
-namespace System
-{
- public partial class WeakReference : ISerializable
- {
- // If you fix bugs here, please fix them in WeakReference at the same time.
-
- // This field is not a regular GC handle. It can have a special values that are used to prevent a race condition between setting the target and finalization.
- internal IntPtr m_handle;
-
- // Determines whether or not this instance of WeakReference still refers to an object
- // that has not been collected.
- //
- public extern virtual bool IsAlive
- {
- [MethodImpl(MethodImplOptions.InternalCall)]
- get;
- }
-
- // Gets the Object stored in the handle if it's accessible.
- // Or sets it.
- //
- public extern virtual object? Target
- {
- [MethodImpl(MethodImplOptions.InternalCall)]
- get;
- [MethodImpl(MethodImplOptions.InternalCall)]
- set;
- }
-
- // Free all system resources associated with this reference.
- //
- // Note: The WeakReference finalizer is not actually run, but
- // treated specially in gc.cpp's ScanForFinalization
- // This is needed for subclasses deriving from WeakReference, however.
- // Additionally, there may be some cases during shutdown when we run this finalizer.
- [MethodImpl(MethodImplOptions.InternalCall)]
- extern ~WeakReference();
-
- [MethodImpl(MethodImplOptions.InternalCall)]
- private extern void Create(object? target, bool trackResurrection);
-
- [MethodImpl(MethodImplOptions.InternalCall)]
- private extern bool IsTrackResurrection();
- }
-}
diff --git a/src/coreclr/System.Private.CoreLib/src/System/WeakReference.T.CoreCLR.cs b/src/coreclr/System.Private.CoreLib/src/System/WeakReference.T.CoreCLR.cs
deleted file mode 100644
index dd5f0d900d3a2..0000000000000
--- a/src/coreclr/System.Private.CoreLib/src/System/WeakReference.T.CoreCLR.cs
+++ /dev/null
@@ -1,46 +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.Diagnostics.CodeAnalysis;
-using System.Runtime.Serialization;
-using System.Runtime.CompilerServices;
-
-namespace System
-{
- public sealed partial class WeakReference : ISerializable
- where T : class?
- {
- // This field is not a regular GC handle. It can have a special values that are used to prevent a race condition between setting the target and finalization.
- internal IntPtr m_handle;
-
- public void SetTarget(T target)
- {
- this.Target = target;
- }
-
- // This is property for better debugging experience (VS debugger shows values of properties when you hover over the variables)
- [MaybeNull]
- private extern T Target
- {
- [MethodImpl(MethodImplOptions.InternalCall)]
- get;
- [MethodImpl(MethodImplOptions.InternalCall)]
- set;
- }
-
- // Free all system resources associated with this reference.
- //
- // Note: The WeakReference finalizer is not usually run, but
- // treated specially in gc.cpp's ScanForFinalization
- // This is needed for subclasses deriving from WeakReference, however.
- // Additionally, there may be some cases during shutdown when we run this finalizer.
- [MethodImpl(MethodImplOptions.InternalCall)]
- extern ~WeakReference();
-
- [MethodImpl(MethodImplOptions.InternalCall)]
- private extern void Create(T target, bool trackResurrection);
-
- [MethodImpl(MethodImplOptions.InternalCall)]
- private extern bool IsTrackResurrection();
- }
-}
diff --git a/src/coreclr/debug/daccess/daccess.cpp b/src/coreclr/debug/daccess/daccess.cpp
index bb476fa8145aa..b77e0312e239f 100644
--- a/src/coreclr/debug/daccess/daccess.cpp
+++ b/src/coreclr/debug/daccess/daccess.cpp
@@ -7858,10 +7858,6 @@ void CALLBACK DacHandleWalker::EnumCallbackSOS(PTR_UNCHECKED_OBJECTREF handle, u
data.Type = param->Type;
if (param->Type == HNDTYPE_DEPENDENT)
data.Secondary = GetDependentHandleSecondary(handle.GetAddr()).GetAddr();
-#ifdef FEATURE_COMINTEROP
- else if (param->Type == HNDTYPE_WEAK_NATIVE_COM)
- data.Secondary = HndGetHandleExtraInfo(handle.GetAddr());
-#endif // FEATURE_COMINTEROP
else
data.Secondary = 0;
data.AppDomain = param->AppDomain;
diff --git a/src/coreclr/debug/daccess/dacdbiimpl.cpp b/src/coreclr/debug/daccess/dacdbiimpl.cpp
index acf458a39d2be..3ba32fb341e70 100644
--- a/src/coreclr/debug/daccess/dacdbiimpl.cpp
+++ b/src/coreclr/debug/daccess/dacdbiimpl.cpp
@@ -7601,10 +7601,6 @@ UINT32 DacRefWalker::GetHandleWalkerMask()
if ((mHandleMask & CorHandleWeakRefCount) || (mHandleMask & CorHandleStrongRefCount))
result |= (1 << HNDTYPE_REFCOUNTED);
#endif // FEATURE_COMINTEROP || FEATURE_COMWRAPPERS || FEATURE_OBJCMARSHAL
-#if defined(FEATURE_COMINTEROP) || defined(FEATURE_COMWRAPPERS)
- if (mHandleMask & CorHandleWeakNativeCom)
- result |= (1 << HNDTYPE_WEAK_NATIVE_COM);
-#endif // FEATURE_COMINTEROP || FEATURE_COMWRAPPERS
if (mHandleMask & CorHandleStrongDependent)
result |= (1 << HNDTYPE_DEPENDENT);
@@ -7778,11 +7774,6 @@ void CALLBACK DacHandleWalker::EnumCallbackDac(PTR_UNCHECKED_OBJECTREF handle, u
data.i64ExtraData = refCnt;
break;
#endif // FEATURE_COMINTEROP || FEATURE_COMWRAPPERS || FEATURE_OBJCMARSHAL
-#if defined(FEATURE_COMINTEROP) || defined(FEATURE_COMWRAPPERS)
- case HNDTYPE_WEAK_NATIVE_COM:
- data.dwType = (DWORD)CorHandleWeakNativeCom;
- break;
-#endif // FEATURE_COMINTEROP || FEATURE_COMWRAPPERS
case HNDTYPE_DEPENDENT:
data.dwType = (DWORD)CorHandleStrongDependent;
diff --git a/src/coreclr/debug/daccess/request.cpp b/src/coreclr/debug/daccess/request.cpp
index 88c1c03d695f9..e65ce43c40ef6 100644
--- a/src/coreclr/debug/daccess/request.cpp
+++ b/src/coreclr/debug/daccess/request.cpp
@@ -3210,9 +3210,6 @@ HRESULT ClrDataAccess::GetHandleEnum(ISOSHandleEnum **ppHandleEnum)
#if defined(FEATURE_COMINTEROP) || defined(FEATURE_COMWRAPPERS) || defined(FEATURE_OBJCMARSHAL)
HNDTYPE_REFCOUNTED,
#endif // FEATURE_COMINTEROP || FEATURE_COMWRAPPERS || FEATURE_OBJCMARSHAL
-#if defined(FEATURE_COMINTEROP) || defined(FEATURE_COMWRAPPERS)
- HNDTYPE_WEAK_NATIVE_COM
-#endif // FEATURE_COMINTEROP
};
return GetHandleEnumForTypes(types, ARRAY_SIZE(types), ppHandleEnum);
@@ -3251,9 +3248,6 @@ HRESULT ClrDataAccess::GetHandleEnumForGC(unsigned int gen, ISOSHandleEnum **ppH
#if defined(FEATURE_COMINTEROP) || defined(FEATURE_COMWRAPPERS) || defined(FEATURE_OBJCMARSHAL)
HNDTYPE_REFCOUNTED,
#endif // FEATURE_COMINTEROP || FEATURE_COMWRAPPERS || FEATURE_OBJCMARSHAL
-#if defined(FEATURE_COMINTEROP) || defined(FEATURE_COMWRAPPERS)
- HNDTYPE_WEAK_NATIVE_COM
-#endif // FEATURE_COMINTEROP || FEATURE_COMWRAPPERS
};
DacHandleWalker *walker = new DacHandleWalker();
diff --git a/src/coreclr/gc/gcinterface.h b/src/coreclr/gc/gcinterface.h
index 5dddd893c39dd..7e8c1b5665fac 100644
--- a/src/coreclr/gc/gcinterface.h
+++ b/src/coreclr/gc/gcinterface.h
@@ -465,6 +465,10 @@ typedef enum
* code holding onto a native weak reference can always access an RCW to the
* underlying COM object as long as it has not been released by all of its strong
* references.
+ *
+ * NOTE: HNDTYPE_WEAK_NATIVE_COM is no longer used in the VM starting .NET 8
+ * but we are keeping it here for backward compatibility purposes"
+ *
*/
HNDTYPE_WEAK_NATIVE_COM = 9
} HandleType;
diff --git a/src/coreclr/inc/dacvars.h b/src/coreclr/inc/dacvars.h
index 13642fe1ab6c9..b1d915efb6f7e 100644
--- a/src/coreclr/inc/dacvars.h
+++ b/src/coreclr/inc/dacvars.h
@@ -162,6 +162,9 @@ DEFINE_DACVAR(UNKNOWN_POINTER_TYPE, dac__g_pThreadClass, ::g_pThreadClass)
DEFINE_DACVAR(UNKNOWN_POINTER_TYPE, dac__g_pPredefinedArrayTypes, ::g_pPredefinedArrayTypes)
DEFINE_DACVAR(UNKNOWN_POINTER_TYPE, dac__g_TypedReferenceMT, ::g_TypedReferenceMT)
+DEFINE_DACVAR(UNKNOWN_POINTER_TYPE, dac__g_pWeakReferenceClass, ::g_pWeakReferenceClass)
+DEFINE_DACVAR(UNKNOWN_POINTER_TYPE, dac__g_pWeakReferenceOfTClass, ::g_pWeakReferenceOfTClass)
+
#ifdef FEATURE_COMINTEROP
DEFINE_DACVAR(UNKNOWN_POINTER_TYPE, dac__g_pBaseCOMObject, ::g_pBaseCOMObject)
#endif
diff --git a/src/coreclr/nativeaot/Runtime/ObjectLayout.h b/src/coreclr/nativeaot/Runtime/ObjectLayout.h
index 78ba3a925e825..9aeaf7903da67 100644
--- a/src/coreclr/nativeaot/Runtime/ObjectLayout.h
+++ b/src/coreclr/nativeaot/Runtime/ObjectLayout.h
@@ -136,5 +136,5 @@ static uintptr_t const MAX_STRING_LENGTH = 0x3FFFFFDF;
class WeakReference : public Object
{
public:
- uintptr_t m_HandleAndKind;
+ uintptr_t m_taggedHandle;
};
diff --git a/src/coreclr/nativeaot/Runtime/gcrhenv.cpp b/src/coreclr/nativeaot/Runtime/gcrhenv.cpp
index ec3f1be198f8e..ead3936f3bdf0 100644
--- a/src/coreclr/nativeaot/Runtime/gcrhenv.cpp
+++ b/src/coreclr/nativeaot/Runtime/gcrhenv.cpp
@@ -1181,10 +1181,15 @@ bool GCToEEInterface::EagerFinalized(Object* obj)
// Managed code should not be running.
ASSERT(GCHeapUtilities::GetGCHeap()->IsGCInProgressHelper());
+ // the lowermost 1 bit is reserved for storing additional info about the handle
+ const uintptr_t HandleTagBits = 1;
+
WeakReference* weakRefObj = (WeakReference*)obj;
- OBJECTHANDLE handle = (OBJECTHANDLE)(weakRefObj->m_HandleAndKind & ~(uintptr_t)1);
- HandleType handleType = (weakRefObj->m_HandleAndKind & 1) ? HandleType::HNDTYPE_WEAK_LONG : HandleType::HNDTYPE_WEAK_SHORT;
- weakRefObj->m_HandleAndKind &= (uintptr_t)1;
+ OBJECTHANDLE handle = (OBJECTHANDLE)(weakRefObj->m_taggedHandle & ~HandleTagBits);
+ _ASSERTE((weakRefObj->m_taggedHandle & 2) == 0);
+ HandleType handleType = (weakRefObj->m_taggedHandle & 1) ? HandleType::HNDTYPE_WEAK_LONG : HandleType::HNDTYPE_WEAK_SHORT;
+ // keep the bit that indicates whether this reference was tracking resurrection, clear the rest.
+ weakRefObj->m_taggedHandle &= HandleTagBits;
GCHandleUtilities::GetGCHandleManager()->DestroyHandleOfType(handle, handleType);
return true;
}
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 d32fb80194b10..8cfeb0ceaaa2c 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
@@ -169,6 +169,7 @@
+
diff --git a/src/coreclr/nativeaot/System.Private.CoreLib/src/System/ComAwareWeakReference.NativeAot.cs b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/ComAwareWeakReference.NativeAot.cs
new file mode 100644
index 0000000000000..d97196a7e31ca
--- /dev/null
+++ b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/ComAwareWeakReference.NativeAot.cs
@@ -0,0 +1,31 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+
+using System;
+
+#if FEATURE_COMINTEROP || FEATURE_COMWRAPPERS
+namespace System
+{
+ internal sealed partial class ComAwareWeakReference
+ {
+ internal static object? ComWeakRefToObject(IntPtr pComWeakRef, long wrapperId)
+ {
+ // NativeAOT support for COM WeakReference is NYI
+ throw new NotImplementedException();
+ }
+
+ internal static bool PossiblyComObject(object target)
+ {
+ // NativeAOT support for COM WeakReference is NYI
+ return false;
+ }
+
+ internal static IntPtr ObjectToComWeakRef(object target, out long wrapperId)
+ {
+ // NativeAOT support for COM WeakReference is NYI
+ wrapperId = 0;
+ return 0;
+ }
+ }
+}
+#endif
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 eff2963059a1d..ec433c0a1ee15 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
@@ -86,7 +86,9 @@ public static int GetGeneration(WeakReference wo)
{
// note - this throws an NRE if given a null weak reference. This isn't
// documented, but it's the behavior of Desktop and CoreCLR.
- object? obj = RuntimeImports.RhHandleGet(wo.Handle);
+ object? obj = RuntimeImports.RhHandleGet(wo.WeakHandle);
+ KeepAlive(wo);
+
if (obj == null)
{
throw new ArgumentNullException(nameof(wo));
diff --git a/src/coreclr/vm/appdomain.cpp b/src/coreclr/vm/appdomain.cpp
index 76421d72dfce7..fe4e901de5719 100644
--- a/src/coreclr/vm/appdomain.cpp
+++ b/src/coreclr/vm/appdomain.cpp
@@ -1384,6 +1384,9 @@ void SystemDomain::LoadBaseSystemClasses()
g_pThreadClass = CoreLibBinder::GetClass(CLASS__THREAD);
+ g_pWeakReferenceClass = CoreLibBinder::GetClass(CLASS__WEAKREFERENCE);
+ g_pWeakReferenceOfTClass = CoreLibBinder::GetClass(CLASS__WEAKREFERENCEGENERIC);
+
#ifdef FEATURE_COMINTEROP
if (g_pConfig->IsBuiltInCOMSupported())
{
diff --git a/src/coreclr/vm/appdomain.hpp b/src/coreclr/vm/appdomain.hpp
index ecf13313bef38..0dbff5efbf6b7 100644
--- a/src/coreclr/vm/appdomain.hpp
+++ b/src/coreclr/vm/appdomain.hpp
@@ -1064,12 +1064,6 @@ class BaseDomain
WRAPPER_NO_CONTRACT;
return ::CreateRefcountedHandle(m_handleStore, object);
}
-
- OBJECTHANDLE CreateNativeComWeakHandle(OBJECTREF object, NativeComWeakHandleInfo* pComWeakHandleInfo)
- {
- WRAPPER_NO_CONTRACT;
- return ::CreateNativeComWeakHandle(m_handleStore, object, pComWeakHandleInfo);
- }
#endif // FEATURE_COMINTEROP || FEATURE_COMWRAPPERS
OBJECTHANDLE CreateVariableHandle(OBJECTREF object, UINT type)
diff --git a/src/coreclr/vm/corelib.h b/src/coreclr/vm/corelib.h
index 1a7d26e42dc51..9f97a8001cec5 100644
--- a/src/coreclr/vm/corelib.h
+++ b/src/coreclr/vm/corelib.h
@@ -939,11 +939,12 @@ DEFINE_METHOD(GC, KEEP_ALIVE, KeepAlive,
DEFINE_METHOD(GC, COLLECT, Collect, SM_RetVoid)
DEFINE_METHOD(GC, WAIT_FOR_PENDING_FINALIZERS, WaitForPendingFinalizers, SM_RetVoid)
-DEFINE_CLASS_U(System, WeakReference, WeakReferenceObject)
-DEFINE_FIELD_U(m_handle, WeakReferenceObject, m_Handle)
+DEFINE_CLASS_U(System, WeakReference, WeakReferenceObject)
+DEFINE_FIELD_U(_taggedHandle, WeakReferenceObject, m_taggedHandle)
DEFINE_CLASS(WEAKREFERENCE, System, WeakReference)
+DEFINE_CLASS(WEAKREFERENCEGENERIC, System, WeakReference`1)
-DEFINE_CLASS_U(Threading, WaitHandle, WaitHandleBase)
+DEFINE_CLASS_U(Threading, WaitHandle, WaitHandleBase)
DEFINE_FIELD_U(_waitHandle, WaitHandleBase, m_safeHandle)
DEFINE_CLASS(DEBUGGER, Diagnostics, Debugger)
diff --git a/src/coreclr/vm/ecalllist.h b/src/coreclr/vm/ecalllist.h
index e000939d2c5a7..80c652acb2879 100644
--- a/src/coreclr/vm/ecalllist.h
+++ b/src/coreclr/vm/ecalllist.h
@@ -664,27 +664,13 @@ FCFuncStart(gGCHandleFuncs)
FCFuncElement("InternalCompareExchange", MarshalNative::GCHandleInternalCompareExchange)
FCFuncEnd()
-
FCFuncStart(gStreamFuncs)
FCFuncElement("HasOverriddenBeginEndRead", StreamNative::HasOverriddenBeginEndRead)
FCFuncElement("HasOverriddenBeginEndWrite", StreamNative::HasOverriddenBeginEndWrite)
FCFuncEnd()
-FCFuncStart(gWeakReferenceFuncs)
- FCFuncElement("Create", WeakReferenceNative::Create)
- FCFuncElement("Finalize", WeakReferenceNative::Finalize)
- FCFuncElement("get_Target", WeakReferenceNative::GetTarget)
- FCFuncElement("set_Target", WeakReferenceNative::SetTarget)
- FCFuncElement("get_IsAlive", WeakReferenceNative::IsAlive)
- FCFuncElement("IsTrackResurrection", WeakReferenceNative::IsTrackResurrection)
-FCFuncEnd()
-
-FCFuncStart(gWeakReferenceOfTFuncs)
- FCFuncElement("Create", WeakReferenceOfTNative::Create)
- FCFuncElement("Finalize", WeakReferenceOfTNative::Finalize)
- FCFuncElement("get_Target", WeakReferenceOfTNative::GetTarget)
- FCFuncElement("set_Target", WeakReferenceOfTNative::SetTarget)
- FCFuncElement("IsTrackResurrection", WeakReferenceOfTNative::IsTrackResurrection)
+FCFuncStart(gComAwareWeakReferenceFuncs)
+ FCFuncElement("HasInteropInfo", ComAwareWeakReferenceNative::HasInteropInfo)
FCFuncEnd()
#ifdef FEATURE_COMINTEROP
@@ -724,6 +710,7 @@ FCClassElement("Array", "System", gArrayFuncs)
FCClassElement("AssemblyLoadContext", "System.Runtime.Loader", gAssemblyLoadContextFuncs)
FCClassElement("Buffer", "System", gBufferFuncs)
FCClassElement("CastHelpers", "System.Runtime.CompilerServices", gCastHelpers)
+FCClassElement("ComAwareWeakReference", "System", gComAwareWeakReferenceFuncs)
FCClassElement("CompatibilitySwitch", "System.Runtime.Versioning", gCompatibilitySwitchFuncs)
FCClassElement("CustomAttribute", "System.Reflection", gCOMCustomAttributeFuncs)
FCClassElement("CustomAttributeEncodedArgument", "System.Reflection", gCustomAttributeEncodedArgument)
@@ -787,8 +774,6 @@ FCClassElement("ValueType", "System", gValueTypeFuncs)
FCClassElement("Variant", "System", gVariantFuncs)
#endif
FCClassElement("WaitHandle", "System.Threading", gWaitHandleFuncs)
-FCClassElement("WeakReference", "System", gWeakReferenceFuncs)
-FCClassElement("WeakReference`1", "System", gWeakReferenceOfTFuncs)
#undef FCFuncElement
#undef FCFuncElementSig
diff --git a/src/coreclr/vm/gcenv.ee.cpp b/src/coreclr/vm/gcenv.ee.cpp
index 4b9442184d9af..677f67bef5229 100644
--- a/src/coreclr/vm/gcenv.ee.cpp
+++ b/src/coreclr/vm/gcenv.ee.cpp
@@ -1094,8 +1094,8 @@ void GCToEEInterface::HandleFatalError(unsigned int exitCode)
bool GCToEEInterface::EagerFinalized(Object* obj)
{
MethodTable* pMT = obj->GetGCSafeMethodTable();
- if (pMT == pWeakReferenceMT ||
- pMT->GetCanonicalMethodTable() == pWeakReferenceOfTCanonMT)
+ if (pMT == g_pWeakReferenceClass ||
+ pMT->HasSameTypeDefAs(g_pWeakReferenceOfTClass))
{
FinalizeWeakReference(obj);
return true;
diff --git a/src/coreclr/vm/gcenv.ee.standalone.cpp b/src/coreclr/vm/gcenv.ee.standalone.cpp
index 9ad0c4c380e7a..6a73fca18f2ce 100644
--- a/src/coreclr/vm/gcenv.ee.standalone.cpp
+++ b/src/coreclr/vm/gcenv.ee.standalone.cpp
@@ -17,12 +17,6 @@
#include "genanalysis.h"
#include "eventpipeadapter.h"
-// the method table for the WeakReference class
-extern MethodTable* pWeakReferenceMT;
-
-// The canonical method table for WeakReference
-extern MethodTable* pWeakReferenceOfTCanonMT;
-
// Finalizes a weak reference directly.
extern void FinalizeWeakReference(Object* obj);
diff --git a/src/coreclr/vm/gcenv.ee.static.cpp b/src/coreclr/vm/gcenv.ee.static.cpp
index ab8a3f22f8cb8..9648ede32cf9e 100644
--- a/src/coreclr/vm/gcenv.ee.static.cpp
+++ b/src/coreclr/vm/gcenv.ee.static.cpp
@@ -17,12 +17,6 @@
#include "genanalysis.h"
#include "eventpipeadapter.h"
-// the method table for the WeakReference class
-extern MethodTable* pWeakReferenceMT;
-
-// The canonical method table for WeakReference
-extern MethodTable* pWeakReferenceOfTCanonMT;
-
// Finalizes a weak reference directly.
extern void FinalizeWeakReference(Object* obj);
diff --git a/src/coreclr/vm/gchandleutilities.h b/src/coreclr/vm/gchandleutilities.h
index 0aa4f1ded95ac..2dc3a1059d6e7 100644
--- a/src/coreclr/vm/gchandleutilities.h
+++ b/src/coreclr/vm/gchandleutilities.h
@@ -197,29 +197,6 @@ inline OBJECTHANDLE CreateGlobalRefcountedHandle(OBJECTREF object)
return CreateGlobalHandleCommon(object, HNDTYPE_REFCOUNTED);
}
-// Special handle creation convenience functions
-
-#if defined(FEATURE_COMINTEROP) || defined(FEATURE_COMWRAPPERS)
-
-struct NativeComWeakHandleInfo
-{
- IWeakReference *WeakReference;
- INT64 WrapperId;
-};
-
-inline OBJECTHANDLE CreateNativeComWeakHandle(IGCHandleStore* store, OBJECTREF object, NativeComWeakHandleInfo* pComWeakHandleInfo)
-{
- OBJECTHANDLE hnd = store->CreateHandleWithExtraInfo(OBJECTREFToObject(object), HNDTYPE_WEAK_NATIVE_COM, (void*)pComWeakHandleInfo);
- if (!hnd)
- {
- COMPlusThrowOM();
- }
-
- DiagHandleCreated(hnd, object);
- return hnd;
-}
-#endif // FEATURE_COMINTEROP || FEATURE_COMWRAPPERS
-
// Creates a variable-strength handle
inline OBJECTHANDLE CreateVariableHandle(IGCHandleStore* store, OBJECTREF object, uint32_t type)
{
@@ -368,35 +345,6 @@ inline void DestroyTypedHandle(OBJECTHANDLE handle)
GCHandleUtilities::GetGCHandleManager()->DestroyHandleOfUnknownType(handle);
}
-#if defined(FEATURE_COMINTEROP) || defined(FEATURE_COMWRAPPERS)
-inline void DestroyNativeComWeakHandle(OBJECTHANDLE handle)
-{
- CONTRACTL
- {
- NOTHROW;
- GC_NOTRIGGER;
- MODE_ANY;
- CAN_TAKE_LOCK;
- }
- CONTRACTL_END;
-
- // Delete the COM info and release the weak reference if we have one. We're assuming that
- // this will not reenter the runtime, since if we are pointing at a managed object, we should
- // not be using HNDTYPE_WEAK_NATIVE_COM but rather HNDTYPE_WEAK_SHORT or HNDTYPE_WEAK_LONG.
- void* pExtraInfo = GCHandleUtilities::GetGCHandleManager()->GetExtraInfoFromHandle(handle);
- NativeComWeakHandleInfo* comWeakHandleInfo = reinterpret_cast(pExtraInfo);
- if (comWeakHandleInfo != nullptr)
- {
- _ASSERTE(comWeakHandleInfo->WeakReference != nullptr);
- comWeakHandleInfo->WeakReference->Release();
- delete comWeakHandleInfo;
- }
-
- DiagHandleDestroyed(handle);
- GCHandleUtilities::GetGCHandleManager()->DestroyHandleOfType(handle, HNDTYPE_WEAK_NATIVE_COM);
-}
-#endif // FEATURE_COMINTEROP || FEATURE_COMWRAPPERS
-
// Handle holders/wrappers
#ifndef FEATURE_NATIVEAOT
diff --git a/src/coreclr/vm/marshalnative.cpp b/src/coreclr/vm/marshalnative.cpp
index 2e245082e6629..dadb391fc225e 100644
--- a/src/coreclr/vm/marshalnative.cpp
+++ b/src/coreclr/vm/marshalnative.cpp
@@ -465,7 +465,7 @@ FCIMPL2(LPVOID, MarshalNative::GCHandleInternalAlloc, Object *obj, int type)
OBJECTREF objRef(obj);
- assert(type >= HNDTYPE_WEAK_SHORT && type <= HNDTYPE_WEAK_NATIVE_COM);
+ assert(type >= HNDTYPE_WEAK_SHORT && type <= HNDTYPE_SIZEDREF);
if (CORProfilerTrackGC())
{
diff --git a/src/coreclr/vm/object.h b/src/coreclr/vm/object.h
index 1b7f140aae89f..d608fe0493a55 100644
--- a/src/coreclr/vm/object.h
+++ b/src/coreclr/vm/object.h
@@ -1546,7 +1546,7 @@ class AssemblyNameBaseObject : public Object
class WeakReferenceObject : public Object
{
public:
- Volatile m_Handle;
+ uintptr_t m_taggedHandle;
};
#ifdef USE_CHECKED_OBJECTREFS
@@ -1567,8 +1567,6 @@ typedef REF ASSEMBLYLOADCONTEXTREF;
typedef REF ASSEMBLYNAMEREF;
-typedef REF WEAKREFERENCEREF;
-
inline ARG_SLOT ObjToArgSlot(OBJECTREF objRef)
{
LIMITED_METHOD_CONTRACT;
@@ -1612,10 +1610,6 @@ typedef PTR_AssemblyBaseObject ASSEMBLYREF;
typedef PTR_AssemblyLoadContextBaseObject ASSEMBLYLOADCONTEXTREF;
typedef PTR_AssemblyNameBaseObject ASSEMBLYNAMEREF;
-#ifndef DACCESS_COMPILE
-typedef WeakReferenceObject* WEAKREFERENCEREF;
-#endif // #ifndef DACCESS_COMPILE
-
#define ObjToArgSlot(objref) ((ARG_SLOT)(SIZE_T)(objref))
#define ArgSlotToObj(s) ((OBJECTREF)(SIZE_T)(s))
diff --git a/src/coreclr/vm/qcallentrypoints.cpp b/src/coreclr/vm/qcallentrypoints.cpp
index 9a7518fe1b97a..e35425fede0be 100644
--- a/src/coreclr/vm/qcallentrypoints.cpp
+++ b/src/coreclr/vm/qcallentrypoints.cpp
@@ -317,6 +317,10 @@ static const Entry s_QCall[] =
#if defined(FEATURE_COMINTEROP)
DllImportEntry(InterfaceMarshaler__ClearNative)
#endif
+#if defined(FEATURE_COMINTEROP) || defined(FEATURE_COMWRAPPERS)
+ DllImportEntry(ComWeakRefToObject)
+ DllImportEntry(ObjectToComWeakRef)
+#endif
};
const void* QCallResolveDllImport(const char* name)
diff --git a/src/coreclr/vm/runtimehandles.cpp b/src/coreclr/vm/runtimehandles.cpp
index bc22a1890f9f9..239b7ee006034 100644
--- a/src/coreclr/vm/runtimehandles.cpp
+++ b/src/coreclr/vm/runtimehandles.cpp
@@ -983,7 +983,7 @@ extern "C" PVOID QCALLTYPE QCall_GetGCHandleForTypeHandle(QCall::TypeHandle pTyp
GCX_COOP();
TypeHandle th = pTypeHandle.AsTypeHandle();
- assert(handleType >= HNDTYPE_WEAK_SHORT && handleType <= HNDTYPE_WEAK_NATIVE_COM);
+ assert(handleType >= HNDTYPE_WEAK_SHORT && handleType <= HNDTYPE_SIZEDREF);
objHandle = AppDomain::GetCurrentDomain()->CreateTypedHandle(NULL, static_cast(handleType));
th.GetLoaderAllocator()->RegisterHandleForCleanup(objHandle);
diff --git a/src/coreclr/vm/vars.cpp b/src/coreclr/vm/vars.cpp
index edeff0074da90..85737057d2f9c 100644
--- a/src/coreclr/vm/vars.cpp
+++ b/src/coreclr/vm/vars.cpp
@@ -71,6 +71,9 @@ GPTR_IMPL(MethodTable, g_pFreeObjectMethodTable);
GPTR_IMPL(MethodTable, g_TypedReferenceMT);
+GPTR_IMPL(MethodTable, g_pWeakReferenceClass);
+GPTR_IMPL(MethodTable, g_pWeakReferenceOfTClass);
+
#ifdef FEATURE_COMINTEROP
GPTR_IMPL(MethodTable, g_pBaseCOMObject);
#endif
diff --git a/src/coreclr/vm/vars.hpp b/src/coreclr/vm/vars.hpp
index ccccb411fc2ef..dd92ee7b12fde 100644
--- a/src/coreclr/vm/vars.hpp
+++ b/src/coreclr/vm/vars.hpp
@@ -360,7 +360,6 @@ GPTR_DECL(MethodTable, g_pThreadAbortExceptionClass);
GPTR_DECL(MethodTable, g_pOutOfMemoryExceptionClass);
GPTR_DECL(MethodTable, g_pStackOverflowExceptionClass);
GPTR_DECL(MethodTable, g_pExecutionEngineExceptionClass);
-GPTR_DECL(MethodTable, g_pThreadAbortExceptionClass);
GPTR_DECL(MethodTable, g_pDelegateClass);
GPTR_DECL(MethodTable, g_pMulticastDelegateClass);
GPTR_DECL(MethodTable, g_pFreeObjectMethodTable);
@@ -370,6 +369,9 @@ GPTR_DECL(MethodTable, g_pThreadClass);
GPTR_DECL(MethodTable, g_TypedReferenceMT);
+GPTR_DECL(MethodTable, g_pWeakReferenceClass);
+GPTR_DECL(MethodTable, g_pWeakReferenceOfTClass);
+
#ifdef FEATURE_COMINTEROP
GPTR_DECL(MethodTable, g_pBaseCOMObject);
#endif
diff --git a/src/coreclr/vm/weakreferencenative.cpp b/src/coreclr/vm/weakreferencenative.cpp
index 946ce8d6675db..f9a7b9a6bfc01 100644
--- a/src/coreclr/vm/weakreferencenative.cpp
+++ b/src/coreclr/vm/weakreferencenative.cpp
@@ -10,1031 +10,171 @@
#include "common.h"
-#include "gchandleutilities.h"
#include "weakreferencenative.h"
-#include "typestring.h"
-#include "threadsuspend.h"
#include "interoplibinterface.h"
-//************************************************************************
-
-// We use several special values of the handle to track extra state without increasing the instance size.
-const LPVOID specialWeakReferenceHandles[3] = { 0, 0, 0 };
-
-// SPECIAL_HANDLE_SPINLOCK is used to implement spinlock that protects against races between setting the target and finalization
-#define SPECIAL_HANDLE_SPINLOCK ((OBJECTHANDLE)(&specialWeakReferenceHandles[0]))
-
-// SPECIAL_HANDLE_FINALIZED is used to track the original type of the handle so that IsTrackResurrection keeps working on finalized
-// objects for backward compatibility.
-#define SPECIAL_HANDLE_FINALIZED_SHORT ((OBJECTHANDLE)(&specialWeakReferenceHandles[1]))
-#define SPECIAL_HANDLE_FINALIZED_LONG ((OBJECTHANDLE)(&specialWeakReferenceHandles[2]))
-
-#define IS_SPECIAL_HANDLE(h) ((size_t)(h) - (size_t)(&specialWeakReferenceHandles) < sizeof(specialWeakReferenceHandles))
-
-//
-// A WeakReference instance can hold one of three types of handles - short or long weak handles,
-// or a native COM weak reference handle. The native COM weak reference handle has the extra capability
-// of recreating an RCW for a COM object which is still alive even though the previous RCW had
-// been collected. In order to differentiate this type of handle from the standard weak handles,
-// the bottom bit is stolen.
-//
-// Note that the bit is stolen only in the local copy of the object handle, held in the m_handle
-// field of the weak reference object. The handle in the handle table itself does not have its
-// bottom bit stolen, and requires using HandleFetchType to determine what type it is. The bit
-// is strictly a performance optimization for the weak reference implementation, and it is
-// responsible for setting up the bit as it needs and ensuring that it is cleared whenever an
-// object handle leaves the weak reference code, for instance to interact with the handle table
-// or diagnostics tools.
-//
-// The following functions are to set, test, and unset that bit before the handle is used.
-//
-
-// Determine if an object handle is a native COM weak reference handle
-bool IsNativeComWeakReferenceHandle(OBJECTHANDLE handle)
-{
- STATIC_CONTRACT_LEAF;
- return (reinterpret_cast(handle) & 0x1) != 0x0;
-}
-
-// Mark an object handle as being a native COM weak reference handle
-OBJECTHANDLE SetNativeComWeakReferenceHandle(OBJECTHANDLE handle)
-{
- STATIC_CONTRACT_LEAF;
-
- _ASSERTE(!IsNativeComWeakReferenceHandle(handle));
- return reinterpret_cast(reinterpret_cast(handle) | 0x1);
-}
-
-// Get the object handle value even if the object is a native COM weak reference
-OBJECTHANDLE GetHandleValue(OBJECTHANDLE handle)
-{
- STATIC_CONTRACT_LEAF;
- UINT_PTR mask = ~(static_cast(0x1));
- return reinterpret_cast(reinterpret_cast(handle) & mask);
-}
-
-FORCEINLINE OBJECTHANDLE AcquireWeakHandleSpinLock(WEAKREFERENCEREF pThis);
-FORCEINLINE void ReleaseWeakHandleSpinLock(WEAKREFERENCEREF pThis, OBJECTHANDLE newHandle);
-
-struct WeakHandleSpinLockHolder
-{
- OBJECTHANDLE RawHandle;
- OBJECTHANDLE Handle;
- WEAKREFERENCEREF* pWeakReference;
-
- WeakHandleSpinLockHolder(OBJECTHANDLE rawHandle, WEAKREFERENCEREF* weakReference)
- : RawHandle(rawHandle), Handle(GetHandleValue(rawHandle)), pWeakReference(weakReference)
- {
- STATIC_CONTRACT_LEAF;
- }
-
- ~WeakHandleSpinLockHolder()
- {
- WRAPPER_NO_CONTRACT;
- ReleaseWeakHandleSpinLock(*pWeakReference, RawHandle);
- }
-
-private:
- WeakHandleSpinLockHolder(const WeakHandleSpinLockHolder& other);
- WeakHandleSpinLockHolder& operator=(const WeakHandleSpinLockHolder& other);
-};
-
-#if defined(FEATURE_COMINTEROP) || defined(FEATURE_COMWRAPPERS)
-
-// Get the native COM information for the object underlying an RCW if applicable. If the incoming object cannot
-// use a native COM weak reference, nullptr is returned. Otherwise, a new NativeComWeakHandleInfo containing an
-// AddRef-ed IWeakReference* for the COM object underlying the RCW is returned.
-//
-// In order to qualify to be used with a HNDTYPE_WEAK_NATIVE_COM, the incoming object must:
-// * be an RCW
-// * not be an aggregated RCW
-// * respond to a QI for IWeakReferenceSource
-// * succeed when asked for an IWeakReference*
-//
-// Note that *pObject should be GC protected on the way into this method
-NativeComWeakHandleInfo* GetComWeakReferenceInfo(OBJECTREF* pObject)
+// This entrypoint is used for eager finalization by the GC.
+void FinalizeWeakReference(Object* obj)
{
CONTRACTL
{
- THROWS;
- GC_TRIGGERS;
- MODE_COOPERATIVE;
- PRECONDITION(CheckPointer(pObject));
+ NOTHROW;
+ GC_NOTRIGGER;
}
CONTRACTL_END;
- if (*pObject == NULL)
- {
- return nullptr;
- }
-
- ASSERT_PROTECTED(pObject);
-
- MethodTable* pMT = (*pObject)->GetMethodTable();
-
- SafeComHolder pWeakReferenceSource(nullptr);
- INT64 wrapperId = ComWrappersNative::InvalidWrapperId;
-
- // If the object is not an RCW, then we do not want to use a native COM weak reference to it
- // If the object is a managed type deriving from a COM type, then we also do not want to use a native COM
- // weak reference to it. (Otherwise, we'll wind up resolving IWeakReference-s back into the CLR
- // when we don't want to have reentrancy).
-#ifdef FEATURE_COMINTEROP
- if (pMT->IsComObjectType()
- && (pMT == g_pBaseCOMObject || !pMT->IsExtensibleRCW()))
- {
- pWeakReferenceSource = reinterpret_cast(GetComIPFromObjectRef(pObject, IID_IWeakReferenceSource, false /* throwIfNoComIP */));
- }
- else
-#endif
- {
-#ifdef FEATURE_COMWRAPPERS
- bool isAggregated = false;
- pWeakReferenceSource = reinterpret_cast(ComWrappersNative::GetIdentityForObject(pObject, IID_IWeakReferenceSource, &wrapperId, &isAggregated));
- if (isAggregated)
- {
- // If the RCW is an aggregated RCW, then the managed object cannot be recreated from the IUnknown as the outer IUnknown wraps the managed object.
- // In this case, don't create a weak reference backed by a COM weak reference.
- pWeakReferenceSource = nullptr;
- }
-#endif
- }
+ // Eager finalization happens while scanning for unmarked finalizable objects
+ // after marking strongly reachable and prior to marking dependent and long weak handles.
+ // Managed code should not be running.
+ _ASSERTE(GCHeapUtilities::IsGCInProgress());
- if (pWeakReferenceSource == nullptr)
- {
- return nullptr;
- }
+ // the lowermost 2 bits are reserved for storing additional info about the handle
+ // we can use these bits because handle is at least 4 byte aligned
+ const uintptr_t HandleTagBits = 3;
- GCX_PREEMP();
- SafeComHolderPreemp pWeakReference;
- if (FAILED(pWeakReferenceSource->GetWeakReference(&pWeakReference)))
- {
- return nullptr;
- }
+ WeakReferenceObject* weakRefObj = (WeakReferenceObject*)obj;
+ OBJECTHANDLE handle = (OBJECTHANDLE)(weakRefObj->m_taggedHandle & ~HandleTagBits);
+ HandleType handleType = (weakRefObj->m_taggedHandle & 2) ?
+ HandleType::HNDTYPE_STRONG :
+ (weakRefObj->m_taggedHandle & 1) ?
+ HandleType::HNDTYPE_WEAK_LONG :
+ HandleType::HNDTYPE_WEAK_SHORT;
- NewHolder info = new NativeComWeakHandleInfo { pWeakReference.GetValue(), wrapperId };
- pWeakReference.SuppressRelease();
- return info.Extract();
+ // keep the bit that indicates whether this reference was tracking resurrection, clear the rest.
+ weakRefObj->m_taggedHandle &= (uintptr_t)1;
+ GCHandleUtilities::GetGCHandleManager()->DestroyHandleOfType(handle, handleType);
}
-// Given an object handle that stores a native COM weak reference, attempt to create an RCW
-// and store it back in the handle, returning the RCW. If the underlying native COM object
-// is not alive, then the result is NULL.
-//
-// In order to create a new RCW, we must:
-// * Have an m_handle of HNDTYPE_WEAK_NATIVE_COM (ie the bottom bit of m_handle is set)
-// * Have stored an IWeakReference* in the handle extra info when setting up the handle
-// (see GetComWeakReference)
-// * The IWeakReference* must respond to a Resolve request for IID_IInspectable
-// *
-NOINLINE Object* LoadComWeakReferenceTarget(WEAKREFERENCEREF weakReference, TypeHandle targetType, LPVOID __me)
-{
- CONTRACTL
- {
- FCALL_CHECK;
- PRECONDITION(weakReference != NULL);
- }
- CONTRACTL_END;
-
- struct
- {
- WEAKREFERENCEREF weakReference;
- OBJECTREF rcw;
- OBJECTREF target;
- } gc;
- gc.weakReference = weakReference;
- gc.rcw = NULL;
- gc.target = NULL;
-
- FC_INNER_PROLOG_NO_ME_SETUP();
- HELPER_METHOD_FRAME_BEGIN_RET_ATTRIB_PROTECT(Frame::FRAME_ATTR_EXACT_DEPTH|Frame::FRAME_ATTR_CAPTURE_DEPTH_2, gc);
-
- // Acquire the spin lock to get the IWeakReference* associated with the weak reference. We will then need to
- // release the lock while resolving the IWeakReference* since we need to enter preemptive mode while calling out
- // to COM to resolve the object and we don't want to do that while holding the lock. If we wind up being able
- // to geenrate a new RCW, we'll reacquire the lock to save the RCW in the handle.
- //
- // Since we're acquiring and releasing the lock multiple times, we need to check the handle state each time we
- // reacquire the lock to make sure that another thread hasn't reassigned the target of the handle or finalized it
- SafeComHolder pComWeakReference = nullptr;
- INT64 wrapperId = ComWrappersNative::InvalidWrapperId;
- {
- WeakHandleSpinLockHolder handle(AcquireWeakHandleSpinLock(gc.weakReference), &gc.weakReference);
- GCX_NOTRIGGER();
+#if defined(FEATURE_COMINTEROP) || defined(FEATURE_COMWRAPPERS)
- // Make sure that while we were not holding the spin lock, another thread did not change the target of
- // this weak reference. Only fetch the IWeakReference* if we still have a valid handle holding a NULL object
- // and the handle is still a HNDTYPE_WEAK_NATIVE_COM type handle.
- if ((handle.Handle != NULL) && !IS_SPECIAL_HANDLE(handle.Handle))
- {
- if (*(Object **)(handle.Handle) != NULL)
- {
- // While we released the spin lock, another thread already set a new target for the weak reference.
- // We don't want to replace it with an RCW that we fetch, so save it to return as the object the
- // weak reference is targeting.
- gc.target = ObjectToOBJECTREF(*(Object **)(handle.Handle));
- }
- else if(IsNativeComWeakReferenceHandle(handle.RawHandle))
- {
- _ASSERTE(GCHandleUtilities::GetGCHandleManager()->HandleFetchType(handle.Handle) == HNDTYPE_WEAK_NATIVE_COM);
+// static
+extern "C" void QCALLTYPE ComWeakRefToObject(IWeakReference* pComWeakReference, INT64 wrapperId, QCall::ObjectHandleOnStack retRcw)
+{
+ QCALL_CONTRACT;
+ BEGIN_QCALL;
- // Retrieve the associated IWeakReference* for this weak reference. Add a reference to it while we release
- // the spin lock so that another thread doesn't release it out from underneath us.
- //
- // Setting pComWeakReference will claim that it triggers a GC, however that's not true in this case because
- // it's always set to NULL here and there's nothing for it to release.
- _ASSERTE(pComWeakReference.IsNull());
- CONTRACT_VIOLATION(GCViolation);
- IGCHandleManager *mgr = GCHandleUtilities::GetGCHandleManager();
- NativeComWeakHandleInfo* comWeakHandleInfo = reinterpret_cast(mgr->GetExtraInfoFromHandle(handle.Handle));
- if (comWeakHandleInfo != nullptr)
- {
- wrapperId = comWeakHandleInfo->WrapperId;
- pComWeakReference = comWeakHandleInfo->WeakReference;
- pComWeakReference->AddRef();
- }
- }
- }
- }
+ _ASSERTE(pComWeakReference != nullptr);
// If the weak reference was in a state that it had an IWeakReference* for us to use, then we need to find the IUnknown
- // identity of the underlying COM object (assuming that object is still alive). This work is done without holding the
- // spin lock since it will call out to arbitrary code and as such we need to switch to preemptive mode.
+ // identity of the underlying COM object (assuming that object is still alive).
SafeComHolder pTargetIdentity = nullptr;
- if (pComWeakReference != nullptr)
- {
- _ASSERTE(gc.target == NULL);
-
- GCX_PREEMP();
- // Using the IWeakReference*, get ahold of the target native COM object's IInspectable*. If this resolve fails, then we
- // assume that the underlying native COM object is no longer alive, and thus we cannot create a new RCW for it.
- SafeComHolderPreemp pTarget = nullptr;
- if (SUCCEEDED(pComWeakReference->Resolve(IID_IInspectable, &pTarget)))
+ // Using the IWeakReference*, get ahold of the target native COM object's IInspectable*. If this resolve fails, then we
+ // assume that the underlying native COM object is no longer alive, and thus we cannot create a new RCW for it.
+ SafeComHolderPreemp pTarget = nullptr;
+ if (SUCCEEDED(pComWeakReference->Resolve(IID_IInspectable, &pTarget)))
+ {
+ if (!pTarget.IsNull())
{
- if (!pTarget.IsNull())
- {
- // Get the IUnknown identity for the underlying object
- SafeQueryInterfacePreemp(pTarget, IID_IUnknown, &pTargetIdentity);
- }
+ // Get the IUnknown identity for the underlying object
+ SafeQueryInterfacePreemp(pTarget, IID_IUnknown, &pTargetIdentity);
}
}
// If we were able to get an IUnknown identity for the object, then we can find or create an associated RCW for it.
if (!pTargetIdentity.IsNull())
{
+ GCX_COOP();
+ OBJECTREF rcwRef = NULL;
+ GCPROTECT_BEGIN(rcwRef);
+
if (wrapperId != ComWrappersNative::InvalidWrapperId)
{
// Try the global COM wrappers
if (GlobalComWrappersForTrackerSupport::IsRegisteredInstance(wrapperId))
{
- (void)GlobalComWrappersForTrackerSupport::TryGetOrCreateObjectForComInstance(pTargetIdentity, &gc.rcw);
+ (void)GlobalComWrappersForTrackerSupport::TryGetOrCreateObjectForComInstance(pTargetIdentity, &rcwRef);
}
else if (GlobalComWrappersForMarshalling::IsRegisteredInstance(wrapperId))
{
- (void)GlobalComWrappersForMarshalling::TryGetOrCreateObjectForComInstance(pTargetIdentity, ObjFromComIP::NONE, &gc.rcw);
+ (void)GlobalComWrappersForMarshalling::TryGetOrCreateObjectForComInstance(pTargetIdentity, ObjFromComIP::NONE, &rcwRef);
}
}
#ifdef FEATURE_COMINTEROP
else
{
// If the original RCW was not created through ComWrappers, fall back to the built-in system.
- GetObjectRefFromComIP(&gc.rcw, pTargetIdentity);
+ GetObjectRefFromComIP(&rcwRef, pTargetIdentity);
}
#endif // FEATURE_COMINTEROP
+ GCPROTECT_END();
+ retRcw.Set(rcwRef);
}
- // If we were able to get an RCW, then we need to reacquire the spin lock and store the RCW in the handle. Note that
- // it's possible that another thread has acquired the spin lock and set the target of the weak reference while we were
- // building the RCW. In that case, we will defer to the hadle that the other thread set, and let the RCW die.
- if (gc.rcw != NULL)
- {
- // Make sure the type we got back from the native COM object is compatible with the type the managed
- // weak reference expects. (For instance, in the WeakReference case, the returned type
- // had better be compatible with T).
- TypeHandle rcwType(gc.rcw->GetMethodTable());
- if (!rcwType.CanCastTo(targetType))
- {
- SString weakReferenceTypeName;
- TypeString::AppendType(weakReferenceTypeName, targetType, TypeString::FormatNamespace | TypeString::FormatFullInst | TypeString::FormatAssembly);
-
- SString resolvedTypeName;
- TypeString::AppendType(resolvedTypeName, rcwType, TypeString::FormatNamespace | TypeString::FormatFullInst | TypeString::FormatAssembly);
-
- COMPlusThrow(kInvalidCastException, IDS_EE_NATIVE_COM_WEAKREF_BAD_TYPE, weakReferenceTypeName.GetUnicode(), resolvedTypeName.GetUnicode());
- }
-
- WeakHandleSpinLockHolder handle(AcquireWeakHandleSpinLock(gc.weakReference), &gc.weakReference);
- GCX_NOTRIGGER();
-
-
- // Now that we've reacquired the lock, see if the handle is still empty. If so, then save the RCW as the new target of the handle.
- if ((handle.Handle != NULL) && !IS_SPECIAL_HANDLE(handle.Handle))
- {
- _ASSERTE(gc.target == NULL);
- gc.target = ObjectToOBJECTREF(*(Object **)(handle.Handle));
-
- if (gc.target == NULL)
- {
- StoreObjectInHandle(handle.Handle, gc.rcw);
- gc.target = gc.rcw;
- }
- }
- }
-
- HELPER_METHOD_FRAME_END();
- FC_INNER_EPILOG();
-
- return OBJECTREFToObject(gc.target);
+ END_QCALL;
+ return;
}
-#endif // FEATURE_COMINTEROP || FEATURE_COMWRAPPERS
-
-//************************************************************************
-
-//
-// Spinlock implemented by overloading the WeakReference::m_Handle field that protects against races between setting
-// the target and finalization
-//
-
-NOINLINE OBJECTHANDLE AcquireWeakHandleSpinLockSpin(WEAKREFERENCEREF pThis)
+// static
+extern "C" IWeakReference * QCALLTYPE ObjectToComWeakRef(QCall::ObjectHandleOnStack obj, INT64* pWrapperId)
{
- CONTRACTL
- {
- NOTHROW;
- GC_NOTRIGGER;
- }
- CONTRACTL_END;
+ QCALL_CONTRACT;
- DWORD dwSwitchCount = 0;
- YieldProcessorNormalizationInfo normalizationInfo;
+ IWeakReference* pWeakReference = nullptr;
+ BEGIN_QCALL;
- //
- // Boilerplate spinning logic stolen from other locks
- //
- for (;;)
- {
- if (g_SystemInfo.dwNumberOfProcessors > 1)
- {
- DWORD spincount = g_SpinConstants.dwInitialDuration;
-
- for (;;)
- {
- YieldProcessorNormalizedForPreSkylakeCount(normalizationInfo, spincount);
-
- OBJECTHANDLE handle = InterlockedExchangeT(&pThis->m_Handle, SPECIAL_HANDLE_SPINLOCK);
- if (handle != SPECIAL_HANDLE_SPINLOCK)
- return handle;
-
- spincount *= g_SpinConstants.dwBackoffFactor;
- if (spincount > g_SpinConstants.dwMaximumDuration)
- {
- break;
- }
- }
- }
-
- __SwitchToThread(0, ++dwSwitchCount);
-
- OBJECTHANDLE handle = InterlockedExchangeT(&pThis->m_Handle, SPECIAL_HANDLE_SPINLOCK);
- if (handle != SPECIAL_HANDLE_SPINLOCK)
- return handle;
- }
-}
-
-FORCEINLINE OBJECTHANDLE AcquireWeakHandleSpinLock(WEAKREFERENCEREF pThis)
-{
- CONTRACTL
- {
- NOTHROW;
- GC_NOTRIGGER;
- }
- CONTRACTL_END;
-
- OBJECTHANDLE handle = InterlockedExchangeT(&pThis->m_Handle, SPECIAL_HANDLE_SPINLOCK);
- if (handle != SPECIAL_HANDLE_SPINLOCK)
- return handle;
- return AcquireWeakHandleSpinLockSpin(pThis);
-}
-
-FORCEINLINE void ReleaseWeakHandleSpinLock(WEAKREFERENCEREF pThis, OBJECTHANDLE newHandle)
-{
- LIMITED_METHOD_CONTRACT;
-
- _ASSERTE(newHandle != SPECIAL_HANDLE_SPINLOCK);
- pThis->m_Handle = newHandle;
-}
-
-//************************************************************************
-
-MethodTable *pWeakReferenceMT = NULL;
-MethodTable *pWeakReferenceOfTCanonMT = NULL;
-
-//************************************************************************
-
-FCIMPL3(void, WeakReferenceNative::Create, WeakReferenceObject * pThisUNSAFE, Object * pTargetUNSAFE, CLR_BOOL trackResurrection)
-{
- FCALL_CONTRACT;
-
- struct
- {
- WEAKREFERENCEREF pThis;
- OBJECTREF pTarget;
- } gc;
-
- gc.pThis = WEAKREFERENCEREF(pThisUNSAFE);
- gc.pTarget = OBJECTREF(pTargetUNSAFE);
-
- HELPER_METHOD_FRAME_BEGIN_PROTECT(gc);
-
- if (gc.pThis == NULL)
- COMPlusThrow(kNullReferenceException);
-
- if (pWeakReferenceMT == NULL)
- pWeakReferenceMT = CoreLibBinder::GetClass(CLASS__WEAKREFERENCE);
-
- _ASSERTE(gc.pThis->GetMethodTable()->CanCastToClass(pWeakReferenceMT));
-
- // Create the handle.
-#if defined(FEATURE_COMINTEROP) || defined(FEATURE_COMWRAPPERS)
- NativeComWeakHandleInfo *comWeakHandleInfo = nullptr;
- if (gc.pTarget != NULL)
- {
- SyncBlock *pSyncBlock = gc.pTarget->PassiveGetSyncBlock();
- if (pSyncBlock != nullptr && pSyncBlock->GetInteropInfoNoCreate() != nullptr)
- {
- comWeakHandleInfo = GetComWeakReferenceInfo(&gc.pTarget);
- }
- }
-
- if (comWeakHandleInfo != nullptr)
- {
- NewHolder infoHolder(comWeakHandleInfo);
- gc.pThis->m_Handle = SetNativeComWeakReferenceHandle(GetAppDomain()->CreateNativeComWeakHandle(gc.pTarget, infoHolder));
- infoHolder.SuppressRelease();
- }
- else
-#endif // FEATURE_COMINTEROP || FEATURE_COMWRAPPERS
- {
- gc.pThis->m_Handle = GetAppDomain()->CreateTypedHandle(gc.pTarget,
- trackResurrection ? HNDTYPE_WEAK_LONG : HNDTYPE_WEAK_SHORT);
- }
-
- HELPER_METHOD_FRAME_END();
-}
-FCIMPLEND
-
-FCIMPL3(void, WeakReferenceOfTNative::Create, WeakReferenceObject * pThisUNSAFE, Object * pTargetUNSAFE, CLR_BOOL trackResurrection)
-{
- FCALL_CONTRACT;
-
- struct
- {
- WEAKREFERENCEREF pThis;
- OBJECTREF pTarget;
- } gc;
-
- gc.pThis = WEAKREFERENCEREF(pThisUNSAFE);
- gc.pTarget = OBJECTREF(pTargetUNSAFE);
-
- HELPER_METHOD_FRAME_BEGIN_PROTECT(gc);
-
- if (gc.pThis == NULL)
- COMPlusThrow(kNullReferenceException);
-
- if (pWeakReferenceOfTCanonMT == NULL)
- pWeakReferenceOfTCanonMT = gc.pThis->GetMethodTable()->GetCanonicalMethodTable();
-
- _ASSERTE(gc.pThis->GetMethodTable()->GetCanonicalMethodTable() == pWeakReferenceOfTCanonMT);
-
-#if defined(FEATURE_COMINTEROP) || defined(FEATURE_COMWRAPPERS)
- NativeComWeakHandleInfo *comWeakHandleInfo = nullptr;
- if (gc.pTarget != NULL)
- {
- SyncBlock *pSyncBlock = gc.pTarget->PassiveGetSyncBlock();
- if (pSyncBlock != nullptr && pSyncBlock->GetInteropInfoNoCreate() != nullptr)
- {
- comWeakHandleInfo = GetComWeakReferenceInfo(&gc.pTarget);
- }
- }
-
- if (comWeakHandleInfo != nullptr)
- {
- NewHolder infoHolder(comWeakHandleInfo);
- gc.pThis->m_Handle = SetNativeComWeakReferenceHandle(GetAppDomain()->CreateNativeComWeakHandle(gc.pTarget, infoHolder));
- infoHolder.SuppressRelease();
- }
- else
-#endif // FEATURE_COMINTEROP || FEATURE_COMWRAPPERS
- {
- gc.pThis->m_Handle = GetAppDomain()->CreateTypedHandle(gc.pTarget,
- trackResurrection ? HNDTYPE_WEAK_LONG : HNDTYPE_WEAK_SHORT);
- }
-
- HELPER_METHOD_FRAME_END();
-}
-FCIMPLEND
-
-//************************************************************************
-
-// This entrypoint is also used for direct finalization by the GC. Note that we cannot depend on the runtime being suspended
-// when this is called because of background GC. Background GC is going to call this method while user managed code is running.
-void FinalizeWeakReference(Object * obj)
-{
- CONTRACTL
- {
- NOTHROW;
- GC_NOTRIGGER;
- }
- CONTRACTL_END;
-
- WEAKREFERENCEREF pThis((WeakReferenceObject *)(obj));
-
- // The suspension state of the runtime must be prevented from changing while in this function in order for this to be safe.
- OBJECTHANDLE handle = ThreadSuspend::SysIsSuspended() ? pThis->m_Handle.LoadWithoutBarrier() : AcquireWeakHandleSpinLock(pThis);
- OBJECTHANDLE handleToDestroy = NULL;
- bool isWeakNativeComHandle = false;
+ *pWrapperId = ComWrappersNative::InvalidWrapperId;
+ SafeComHolder pWeakReferenceSource(nullptr);
+ _ASSERTE(obj.m_ppObject != nullptr);
- // Check for not yet constructed or already finalized handle
- if ((handle != NULL) && !IS_SPECIAL_HANDLE(handle))
{
- handleToDestroy = GetHandleValue(handle);
+ // COM helpers assume COOP mode and the arguments are protected refs.
+ GCX_COOP();
+ OBJECTREF objRef = obj.Get();
+ GCPROTECT_BEGIN(objRef);
- // Cache the old handle value
- HandleType handleType = GCHandleUtilities::GetGCHandleManager()->HandleFetchType(handleToDestroy);
-#if defined(FEATURE_COMINTEROP) || defined(FEATURE_COMWRAPPERS)
- _ASSERTE(handleType == HNDTYPE_WEAK_LONG || handleType == HNDTYPE_WEAK_SHORT || handleType == HNDTYPE_WEAK_NATIVE_COM);
- isWeakNativeComHandle = handleType == HNDTYPE_WEAK_NATIVE_COM;
-#else // !FEATURE_COMINTEROP && !FEATURE_COMWRAPPERS
- _ASSERTE(handleType == HNDTYPE_WEAK_LONG || handleType == HNDTYPE_WEAK_SHORT);
-#endif // FEATURE_COMINTEROP || FEATURE_COMWRAPPERS
-
- handle = (handleType == HNDTYPE_WEAK_LONG) ?
- SPECIAL_HANDLE_FINALIZED_LONG : SPECIAL_HANDLE_FINALIZED_SHORT;
- }
-
- // Release the spin lock
- // This is necessary even when the spin lock is not acquired
- // (i.e. When ThreadSuspend::SysIsSuspended() == true)
- // so that the new handle value is set.
- ReleaseWeakHandleSpinLock(pThis, handle);
-
- if (handleToDestroy != NULL)
- {
-#if defined(FEATURE_COMINTEROP) || defined(FEATURE_COMWRAPPERS)
- if (isWeakNativeComHandle)
+ // If the object is not an RCW, then we do not want to use a native COM weak reference to it
+ // If the object is a managed type deriving from a COM type, then we also do not want to use a native COM
+ // weak reference to it. (Otherwise, we'll wind up resolving IWeakReference-s back into the CLR
+ // when we don't want to have reentrancy).
+#ifdef FEATURE_COMINTEROP
+ MethodTable* pMT = objRef->GetMethodTable();
+ if (pMT->IsComObjectType()
+ && (pMT == g_pBaseCOMObject || !pMT->IsExtensibleRCW()))
{
- DestroyNativeComWeakHandle(handleToDestroy);
+ pWeakReferenceSource = reinterpret_cast(GetComIPFromObjectRef(&objRef, IID_IWeakReferenceSource, false /* throwIfNoComIP */));
}
else
-#endif // FEATURE_COMINTEROP || FEATURE_COMWRAPPERS
- {
- DestroyTypedHandle(handleToDestroy);
- }
- }
-}
-
-FCIMPL1(void, WeakReferenceNative::Finalize, WeakReferenceObject * pThis)
-{
- FCALL_CONTRACT;
-
- HELPER_METHOD_FRAME_BEGIN_NOPOLL();
-
- if (pThis == NULL)
- {
- FCUnique(0x1);
- COMPlusThrow(kNullReferenceException);
- }
-
- FinalizeWeakReference(pThis);
-
- HELPER_METHOD_FRAME_END_POLL();
-}
-FCIMPLEND
-
-FCIMPL1(void, WeakReferenceOfTNative::Finalize, WeakReferenceObject * pThis)
-{
- FCALL_CONTRACT;
-
- HELPER_METHOD_FRAME_BEGIN_NOPOLL();
-
- if (pThis == NULL)
- COMPlusThrow(kNullReferenceException);
-
- FinalizeWeakReference(pThis);
-
- HELPER_METHOD_FRAME_END_POLL();
-}
-FCIMPLEND
-
-//************************************************************************
-
-#include
-
-static FORCEINLINE OBJECTREF GetWeakReferenceTarget(WEAKREFERENCEREF pThis)
-{
- CONTRACTL
- {
- NOTHROW;
- GC_NOTRIGGER;
- MODE_COOPERATIVE;
- }
- CONTRACTL_END;
-
- OBJECTHANDLE rawHandle = pThis->m_Handle.LoadWithoutBarrier();
- OBJECTHANDLE handle = GetHandleValue(rawHandle);
-
- if (handle == NULL)
- return NULL;
-
- // Try a speculative lock-free read first
- if (rawHandle != SPECIAL_HANDLE_SPINLOCK)
- {
- //
- // There is a theoretic chance that the speculative lock-free read may AV while reading the value
- // of freed handle if the handle table decides to release the memory that the handle lives in.
- // It is not exploitable security issue because of we will fail fast on the AV. It is denial of service only.
- // Non-malicious user code will never hit.
- //
- // We had this theoretical bug in there since forever. Fixing it by always taking the lock would
- // degrade the performance critical weak handle getter several times. The right fix may be
- // to ensure that handle table memory is released only if the runtime is suspended.
- //
- Object * pSpeculativeTarget = VolatileLoad((Object **)(handle));
-
- //
- // We want to ensure that the handle was still alive when we fetched the target,
- // so we double check m_handle here. Note that the reading of the handle
- // value has to take memory barrier for this to work, but reading of m_handle does not.
- //
- if (rawHandle == pThis->m_Handle.LoadWithoutBarrier())
- {
- return OBJECTREF(pSpeculativeTarget);
- }
- }
-
-
- rawHandle = AcquireWeakHandleSpinLock(pThis);
- GCX_NOTRIGGER();
-
- handle = GetHandleValue(rawHandle);
- OBJECTREF pTarget = OBJECTREF(*(Object **)(handle));
-
- ReleaseWeakHandleSpinLock(pThis, rawHandle);
-
- return pTarget;
-}
-
-FCIMPL1(Object *, WeakReferenceNative::GetTarget, WeakReferenceObject * pThisUNSAFE)
-{
- FCALL_CONTRACT;
-
- WEAKREFERENCEREF pThis(pThisUNSAFE);
- if (pThis == NULL)
- {
- FCUnique(0x1);
- FCThrow(kNullReferenceException);
- }
-
- OBJECTREF pTarget = GetWeakReferenceTarget(pThis);
-
-#if defined(FEATURE_COMINTEROP) || defined(FEATURE_COMWRAPPERS)
- // If we found an object, or we're not a native COM weak reference, then we're done. Othewrise
- // we can try to create a new RCW to the underlying native COM object if it's still alive.
- if (pTarget != NULL || !IsNativeComWeakReferenceHandle(pThis->m_Handle))
- {
- FC_GC_POLL_AND_RETURN_OBJREF(pTarget);
- }
-
- FC_INNER_RETURN(Object*, LoadComWeakReferenceTarget(pThis, g_pObjectClass, GetEEFuncEntryPointMacro(WeakReferenceNative::GetTarget)));
-#else // !FEATURE_COMINTEROP && !FEATURE_COMWRAPPERS
- FC_GC_POLL_AND_RETURN_OBJREF(pTarget);
-#endif // FEATURE_COMINTEROP || FEATURE_COMWRAPPERS
-}
-FCIMPLEND
-
-FCIMPL1(Object *, WeakReferenceOfTNative::GetTarget, WeakReferenceObject * pThisUNSAFE)
-{
- FCALL_CONTRACT;
-
- WEAKREFERENCEREF pThis(pThisUNSAFE);
- if (pThis == NULL)
- {
- FCThrow(kNullReferenceException);
- }
-
- OBJECTREF pTarget = GetWeakReferenceTarget(pThis);
-
-
-#if defined(FEATURE_COMINTEROP) || defined(FEATURE_COMWRAPPERS)
- // If we found an object, or we're not a native COM weak reference, then we're done. Othewrise
- // we can try to create a new RCW to the underlying native COM object if it's still alive.
- if (pTarget != NULL || !IsNativeComWeakReferenceHandle(pThis->m_Handle))
- {
- FC_GC_POLL_AND_RETURN_OBJREF(pTarget);
- }
-
- FC_INNER_RETURN(Object*, LoadComWeakReferenceTarget(pThis, pThis->GetMethodTable()->GetInstantiation()[0], GetEEFuncEntryPointMacro(WeakReferenceOfTNative::GetTarget)));
-#else // !FEATURE_COMINTEROP && !FEATURE_COMWRAPPERS
- FC_GC_POLL_AND_RETURN_OBJREF(pTarget);
-#endif // FEATURE_COMINTEROP || FEATURE_COMWRAPPERS
-}
-FCIMPLEND
-
-FCIMPL1(FC_BOOL_RET, WeakReferenceNative::IsAlive, WeakReferenceObject * pThisUNSAFE)
-{
- FCALL_CONTRACT;
-
- WEAKREFERENCEREF pThis(pThisUNSAFE);
- if (pThis == NULL)
- {
- FCThrow(kNullReferenceException);
- }
-
- BOOL fRet = GetWeakReferenceTarget(pThis) != NULL;
-
- FC_GC_POLL_RET();
-
- FC_RETURN_BOOL(fRet);
-}
-FCIMPLEND
-
-#include
-
-//************************************************************************
-
-#include
-
-// Slow path helper for setting the target of a weak reference. This code is used if a native COM weak reference might
-// be required.
-NOINLINE void SetWeakReferenceTarget(WEAKREFERENCEREF weakReference, OBJECTREF target, LPVOID __me)
-{
- FCALL_CONTRACT;
-
- FC_INNER_PROLOG_NO_ME_SETUP();
- HELPER_METHOD_FRAME_BEGIN_ATTRIB_2(Frame::FRAME_ATTR_EXACT_DEPTH|Frame::FRAME_ATTR_CAPTURE_DEPTH_2, target, weakReference);
-
-#if defined(FEATURE_COMINTEROP) || defined(FEATURE_COMWRAPPERS)
- NewHolder comWeakHandleInfo(GetComWeakReferenceInfo(&target));
-#endif // FEATURE_COMINTEROP || FEATURE_COMWRAPPERS
-
- WeakHandleSpinLockHolder handle(AcquireWeakHandleSpinLock(weakReference), &weakReference);
- GCX_NOTRIGGER();
-
-#if defined(FEATURE_COMINTEROP) || defined(FEATURE_COMWRAPPERS)
- //
- // We have four combinations to handle here
- //
- // Existing target is a GC object, new target is a GC object:
- // * Just store the new object in the handle
- //
- // Existing target is native COM weak reference, new target is native COM weak reference:
- // * Release the existing IWeakReference*
- // * Store the new IWeakReference*
- // * Store the new object in the handle
- //
- // Existing target is native COM weak reference, new target is GC:
- // * Release the existing IWeakReference*
- // * Store null to the IWeakReference* field
- // * Store the new object in the handle
- //
- // Existing target is GC, new target is native COM weak reference:
- // * Destroy the existing handle
- // * Allocate a new native COM weak handle for the new target
- //
-
- if (IsNativeComWeakReferenceHandle(handle.RawHandle))
- {
- // If the existing reference is a native COM weak reference, we need to delete its native COM info
- // and update it with the new native COM info. If the incoming object is not an RCW that can use
- // IWeakReference, then comWeakHandleInfo will be null. Therefore, no matter what the incoming
- // object type is, we can unconditionally store comWeakHandleInfo to the object handle's extra data.
- IGCHandleManager *mgr = GCHandleUtilities::GetGCHandleManager();
- NativeComWeakHandleInfo* existingInfo = reinterpret_cast(mgr->GetExtraInfoFromHandle(handle.Handle));
- mgr->SetExtraInfoForHandle(handle.Handle, HNDTYPE_WEAK_NATIVE_COM, reinterpret_cast(comWeakHandleInfo.GetValue()));
- StoreObjectInHandle(handle.Handle, target);
-
- if (existingInfo != nullptr)
- {
- _ASSERTE(existingInfo->WeakReference != nullptr);
- existingInfo->WeakReference->Release();
- delete existingInfo;
- }
- }
- else if (comWeakHandleInfo != nullptr)
- {
- // The existing handle is not a native COM weak reference, but we need to store the new object in
- // a native COM weak reference. Therefore we need to destroy the old handle and create a new native COM
- // handle. The new handle needs to be allocated first to prevent the weak reference from holding
- // a destroyed handle if we fail to allocate the new one.
- _ASSERTE(!IsNativeComWeakReferenceHandle(handle.RawHandle));
- OBJECTHANDLE previousHandle = handle.RawHandle;
-
- handle.Handle = GetAppDomain()->CreateNativeComWeakHandle(target, comWeakHandleInfo);
- handle.RawHandle = SetNativeComWeakReferenceHandle(handle.Handle);
-
- DestroyTypedHandle(previousHandle);
- }
- else
-#endif // FEATURE_COMINTEROP || FEATURE_COMWRAPPERS
- {
- StoreObjectInHandle(handle.Handle, target);
- }
-
-#if defined(FEATURE_COMINTEROP) || defined(FEATURE_COMWRAPPERS)
- comWeakHandleInfo.SuppressRelease();
-#endif // FEATURE_COMINTEROP || FEATURE_COMWRAPPERS
-
- HELPER_METHOD_FRAME_END();
- FC_INNER_EPILOG();
-}
-
-FCIMPL2(void, WeakReferenceNative::SetTarget, WeakReferenceObject * pThisUNSAFE, Object * pTargetUNSAFE)
-{
- FCALL_CONTRACT;
-
- WEAKREFERENCEREF pThis(pThisUNSAFE);
- OBJECTREF pTarget(pTargetUNSAFE);
-
- if (pThis == NULL)
- {
- FCUnique(0x1);
- FCThrowVoid(kNullReferenceException);
- }
-
- bool storedObject = false;
-
- OBJECTHANDLE handle = AcquireWeakHandleSpinLock(pThis);
- {
- if (handle == NULL || IS_SPECIAL_HANDLE(handle))
- {
- ReleaseWeakHandleSpinLock(pThis, handle);
- FCThrowResVoid(kInvalidOperationException, W("InvalidOperation_HandleIsNotInitialized"));
- }
-
- // Switch to no-trigger after the handle was validate. FCThrow triggers.
- GCX_NOTRIGGER();
-
- // If the existing handle is a GC weak handle and the new target is not an RCW, then
- // we can avoid setting up a helper method frame and just reset the handle directly.
- if (!IsNativeComWeakReferenceHandle(handle))
- {
- if (pTarget == NULL || !pTarget->GetMethodTable()->IsComObjectType())
- {
- StoreObjectInHandle(handle, pTarget);
- storedObject = true;
- }
- }
-
- // SetWeakReferenceTarget will reacquire the spinlock after setting up a helper method frame. This allows
- // the frame setup to throw without worrying about leaking the spinlock, and allows the epilog to be cleanly
- // walked by the epilog decoder.
- ReleaseWeakHandleSpinLock(pThis, handle);
- }
-
- // If we reset the handle directly, then early out before setting up a helper method frame
- if (storedObject)
- {
- FC_GC_POLL();
- return;
- }
-
- FC_INNER_RETURN_VOID(SetWeakReferenceTarget(pThis, pTarget, GetEEFuncEntryPointMacro(WeakReferenceNative::SetTarget)));
-}
-FCIMPLEND
-
-FCIMPL2(void, WeakReferenceOfTNative::SetTarget, WeakReferenceObject * pThisUNSAFE, Object * pTargetUNSAFE)
-{
- FCALL_CONTRACT;
-
- WEAKREFERENCEREF pThis(pThisUNSAFE);
- OBJECTREF pTarget(pTargetUNSAFE);
-
- if (pThis == NULL)
- {
- FCThrowVoid(kNullReferenceException);
- }
-
- bool storedObject = false;
-
- OBJECTHANDLE handle = AcquireWeakHandleSpinLock(pThis);
- {
- if (handle == NULL || IS_SPECIAL_HANDLE(handle))
- {
- ReleaseWeakHandleSpinLock(pThis, handle);
- FCThrowResVoid(kInvalidOperationException, W("InvalidOperation_HandleIsNotInitialized"));
- }
-
- // Switch to no-trigger after the handle was validate. FCThrow triggers.
- GCX_NOTRIGGER();
-
- // If the existing handle is a GC weak handle and the new target is not an RCW, then
- // we can avoid setting up a helper method frame and just reset the handle directly.
- if (!IsNativeComWeakReferenceHandle(handle))
+#endif
{
- if (pTarget == NULL || !pTarget->GetMethodTable()->IsComObjectType())
+#ifdef FEATURE_COMWRAPPERS
+ bool isAggregated = false;
+ pWeakReferenceSource = reinterpret_cast(ComWrappersNative::GetIdentityForObject(&objRef, IID_IWeakReferenceSource, pWrapperId, &isAggregated));
+ if (isAggregated)
{
- StoreObjectInHandle(handle, pTarget);
- storedObject = true;
+ // If the RCW is an aggregated RCW, then the managed object cannot be recreated from the IUnknown as the outer IUnknown wraps the managed object.
+ // In this case, don't create a weak reference backed by a COM weak reference.
+ pWeakReferenceSource = nullptr;
}
+#endif
}
- // SetWeakReferenceTarget will reacquire the spinlock after setting up a helper method frame. This allows
- // the frame setup to throw without worrying about leaking the spinlock, and allows the epilog to be cleanly
- // walked by the epilog decoder.
- ReleaseWeakHandleSpinLock(pThis, handle);
- }
-
- // If we reset the handle directly, then early out before setting up a helper method frame
- if (storedObject)
- {
- FC_GC_POLL();
- return;
- }
-
- FC_INNER_RETURN_VOID(SetWeakReferenceTarget(pThis, pTarget, GetEEFuncEntryPointMacro(WeakReferenceOfTNative::SetTarget)));
-}
-FCIMPLEND
-
-#include
-
-//************************************************************************
-
-FCIMPL1(FC_BOOL_RET, WeakReferenceNative::IsTrackResurrection, WeakReferenceObject * pThisUNSAFE)
-{
- FCALL_CONTRACT;
-
- WEAKREFERENCEREF pThis(pThisUNSAFE);
-
- if (pThis == NULL)
- {
- FCUnique(0x1);
- FCThrow(kNullReferenceException);
+ GCPROTECT_END();
}
- BOOL trackResurrection = FALSE;
- OBJECTHANDLE handle = AcquireWeakHandleSpinLock(pThis);
+ if (pWeakReferenceSource != nullptr)
{
- GCX_NOTRIGGER();
-
- if (handle == NULL)
+ SafeComHolderPreemp weakReferenceHolder;
+ if (!FAILED(pWeakReferenceSource->GetWeakReference(&weakReferenceHolder)))
{
- trackResurrection = FALSE;
+ weakReferenceHolder.SuppressRelease();
+ pWeakReference = weakReferenceHolder.GetValue();
}
- else
- if (IS_SPECIAL_HANDLE(handle))
- {
- trackResurrection = (handle == SPECIAL_HANDLE_FINALIZED_LONG);
- }
- else
- {
- trackResurrection = GCHandleUtilities::GetGCHandleManager()->HandleFetchType(GetHandleValue(handle)) == HNDTYPE_WEAK_LONG;
- }
-
- ReleaseWeakHandleSpinLock(pThis, handle);
}
- FC_GC_POLL_RET();
- FC_RETURN_BOOL(trackResurrection);
+ END_QCALL;
+ return pWeakReference;
}
-FCIMPLEND
-FCIMPL1(FC_BOOL_RET, WeakReferenceOfTNative::IsTrackResurrection, WeakReferenceObject * pThisUNSAFE)
+FCIMPL1(FC_BOOL_RET, ComAwareWeakReferenceNative::HasInteropInfo, Object* pObject)
{
FCALL_CONTRACT;
+ _ASSERTE(pObject != nullptr);
- WEAKREFERENCEREF pThis(pThisUNSAFE);
-
- if (pThis == NULL)
- {
- FCThrow(kNullReferenceException);
- }
-
- BOOL trackResurrection = FALSE;
- OBJECTHANDLE handle = AcquireWeakHandleSpinLock(pThis);
- {
- GCX_NOTRIGGER();
-
- if (handle == NULL)
- {
- trackResurrection = FALSE;
- }
- else
- if (IS_SPECIAL_HANDLE(handle))
- {
- trackResurrection = (handle == SPECIAL_HANDLE_FINALIZED_LONG);
- }
- else
- {
- trackResurrection = GCHandleUtilities::GetGCHandleManager()->HandleFetchType(GetHandleValue(handle)) == HNDTYPE_WEAK_LONG;
- }
-
- ReleaseWeakHandleSpinLock(pThis, handle);
- }
-
- FC_GC_POLL_RET();
- FC_RETURN_BOOL(trackResurrection);
+ SyncBlock* pSyncBlock = pObject->PassiveGetSyncBlock();
+ _ASSERTE(pSyncBlock != nullptr);
+ return pSyncBlock->GetInteropInfoNoCreate() != nullptr;
}
FCIMPLEND
-//************************************************************************
+#endif // FEATURE_COMINTEROP || FEATURE_COMWRAPPERS
diff --git a/src/coreclr/vm/weakreferencenative.h b/src/coreclr/vm/weakreferencenative.h
index 387d6df2e2524..0586d730f6a03 100644
--- a/src/coreclr/vm/weakreferencenative.h
+++ b/src/coreclr/vm/weakreferencenative.h
@@ -11,31 +11,17 @@
#ifndef _WEAKREFERENCENATIVE_H
#define _WEAKREFERENCENATIVE_H
-//
-// The implementations of WeakReferenceNative and WeakReferenceOfTNative are identical, but the managed signatures
-// are different. WeakReferenceOfTNative has strongly typed signatures. It is necessary for correct security transparancy
-// annotations without compromising inlining (security critical code cannot be inlined into security neutral code).
-//
+#if defined(FEATURE_COMINTEROP) || defined(FEATURE_COMWRAPPERS)
-class WeakReferenceNative
+class ComAwareWeakReferenceNative
{
public:
- static FCDECL3(void, Create, WeakReferenceObject * pThis, Object * pTarget, CLR_BOOL trackResurrection);
- static FCDECL1(void, Finalize, WeakReferenceObject * pThis);
- static FCDECL1(Object *, GetTarget, WeakReferenceObject * pThis);
- static FCDECL2(void, SetTarget, WeakReferenceObject * pThis, Object * pTarget);
- static FCDECL1(FC_BOOL_RET, IsTrackResurrection, WeakReferenceObject * pThis);
- static FCDECL1(FC_BOOL_RET, IsAlive, WeakReferenceObject * pThis);
+ static FCDECL1(FC_BOOL_RET, HasInteropInfo, Object* pObject);
};
-class WeakReferenceOfTNative
-{
-public:
- static FCDECL3(void, Create, WeakReferenceObject * pThis, Object * pTarget, CLR_BOOL trackResurrection);
- static FCDECL1(void, Finalize, WeakReferenceObject * pThis);
- static FCDECL1(Object *, GetTarget, WeakReferenceObject * pThis);
- static FCDECL2(void, SetTarget, WeakReferenceObject * pThis, Object * pTarget);
- static FCDECL1(FC_BOOL_RET, IsTrackResurrection, WeakReferenceObject * pThis);
-};
+extern "C" void QCALLTYPE ComWeakRefToObject(IWeakReference * pComWeakReference, INT64 wrapperId, QCall::ObjectHandleOnStack retRcw);
+extern "C" IWeakReference * QCALLTYPE ObjectToComWeakRef(QCall::ObjectHandleOnStack obj, INT64* wrapperId);
+
+#endif // FEATURE_COMINTEROP || FEATURE_COMWRAPPERS
#endif // _WEAKREFERENCENATIVE_H
diff --git a/src/libraries/System.Private.CoreLib/src/System.Private.CoreLib.Shared.projitems b/src/libraries/System.Private.CoreLib/src/System.Private.CoreLib.Shared.projitems
index 2cdc6ee9731c4..887350b088693 100644
--- a/src/libraries/System.Private.CoreLib/src/System.Private.CoreLib.Shared.projitems
+++ b/src/libraries/System.Private.CoreLib/src/System.Private.CoreLib.Shared.projitems
@@ -1193,6 +1193,7 @@
+
Common\Interop\Interop.Calendar.cs
@@ -2478,4 +2479,4 @@
-
+
\ No newline at end of file
diff --git a/src/libraries/System.Private.CoreLib/src/System/ComAwareWeakReference.cs b/src/libraries/System.Private.CoreLib/src/System/ComAwareWeakReference.cs
new file mode 100644
index 0000000000000..c6e7698c5768c
--- /dev/null
+++ b/src/libraries/System.Private.CoreLib/src/System/ComAwareWeakReference.cs
@@ -0,0 +1,183 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+
+using System.Diagnostics;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+using System.Threading;
+
+#if FEATURE_COMINTEROP || FEATURE_COMWRAPPERS
+
+using static System.WeakReferenceHandleTags;
+
+namespace System
+{
+ internal sealed partial class ComAwareWeakReference
+ {
+ // _weakHandle is effectively readonly.
+ // the only place where we change it after construction is in finalizer.
+ private nint _weakHandle;
+ private ComInfo? _comInfo;
+
+ internal sealed class ComInfo
+ {
+ // _pComWeakRef is effectively readonly.
+ // the only place where we change it after construction is in finalizer.
+ private IntPtr _pComWeakRef;
+ private readonly long _wrapperId;
+
+ internal object? ResolveTarget()
+ {
+ return ComWeakRefToObject(_pComWeakRef, _wrapperId);
+ }
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ internal static ComInfo? FromObject(object? target)
+ {
+ if (target == null || !PossiblyComObject(target))
+ return null;
+
+ return FromObjectSlow(target);
+ }
+
+ [MethodImpl(MethodImplOptions.NoInlining)]
+ private static unsafe ComInfo? FromObjectSlow(object target)
+ {
+ IntPtr pComWeakRef = ObjectToComWeakRef(target, out long wrapperId);
+ if (pComWeakRef == 0)
+ return null;
+
+ try
+ {
+ return new ComInfo(pComWeakRef, wrapperId);
+ }
+ catch (OutOfMemoryException)
+ {
+ // we did not create an object, so ComInfo finalizer will not run
+ Marshal.Release(pComWeakRef);
+ throw;
+ }
+ }
+
+ private ComInfo(IntPtr pComWeakRef, long wrapperId)
+ {
+ Debug.Assert(pComWeakRef != IntPtr.Zero);
+ _pComWeakRef = pComWeakRef;
+ _wrapperId = wrapperId;
+ }
+
+ ~ComInfo()
+ {
+ Marshal.Release(_pComWeakRef);
+ // our use pattern guarantees that the instance is not reachable after this.
+ // clear the pointer just in case that gets somehow broken.
+ _pComWeakRef = 0;
+ }
+ }
+
+ private ComAwareWeakReference(nint weakHandle)
+ {
+ Debug.Assert(weakHandle != 0);
+ _weakHandle = weakHandle;
+ }
+
+ ~ComAwareWeakReference()
+ {
+ GCHandle.InternalFree(_weakHandle);
+ // our use pattern guarantees that the instance is not reachable after this.
+ // clear the pointer just in case that gets somehow broken.
+ _weakHandle = 0;
+ }
+
+ private void SetTarget(object? target, ComInfo? comInfo)
+ {
+ // NOTE: ComAwareWeakReference is an internal implementation detail and
+ // instances are never exposed publicly, thus we can use "this" for locking
+ lock (this)
+ {
+ GCHandle.InternalSet(_weakHandle, target);
+ _comInfo = comInfo;
+ }
+ }
+
+ internal object? Target => GCHandle.InternalGet(_weakHandle) ?? RehydrateTarget();
+
+ private object? RehydrateTarget()
+ {
+ object? target = null;
+ lock (this)
+ {
+ if (_comInfo != null)
+ {
+ // check if the target is still null
+ target = GCHandle.InternalGet(_weakHandle);
+ if (target == null)
+ {
+ // resolve and reset
+ target = _comInfo.ResolveTarget();
+ if (target != null)
+ GCHandle.InternalSet(_weakHandle, target);
+ }
+ }
+ }
+
+ return target;
+ }
+
+ private static ComAwareWeakReference EnsureComAwareReference(ref nint taggedHandle)
+ {
+ nint current = taggedHandle;
+ if ((current & ComAwareBit) == 0)
+ {
+ ComAwareWeakReference newRef = new ComAwareWeakReference(taggedHandle & ~HandleTagBits);
+ nint newHandle = GCHandle.InternalAlloc(newRef, GCHandleType.Normal);
+ nint newTaggedHandle = newHandle | ComAwareBit | (taggedHandle & TracksResurrectionBit);
+ if (Interlocked.CompareExchange(ref taggedHandle, newTaggedHandle, current) == current)
+ {
+ // success.
+ return newRef;
+ }
+
+ // someone beat us to it. (this is rare)
+ GCHandle.InternalFree(newHandle);
+ GC.SuppressFinalize(newRef);
+ }
+
+ return Unsafe.As(GCHandle.InternalGet(taggedHandle & ~HandleTagBits));
+ }
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ internal static object? GetTarget(nint taggedHandle)
+ {
+ Debug.Assert((taggedHandle & ComAwareBit) != 0);
+ return Unsafe.As(GCHandle.InternalGet(taggedHandle & ~HandleTagBits)).Target;
+ }
+
+ internal static nint GetWeakHandle(nint taggedHandle)
+ {
+ Debug.Assert((taggedHandle & ComAwareBit) != 0);
+ return Unsafe.As(GCHandle.InternalGet(taggedHandle & ~HandleTagBits))._weakHandle;
+ }
+
+ [MethodImpl(MethodImplOptions.NoInlining)]
+ internal static void SetTarget(ref nint taggedHandle, object? target, ComInfo? comInfo)
+ {
+ ComAwareWeakReference comAwareRef = comInfo != null ?
+ EnsureComAwareReference(ref taggedHandle) :
+ Unsafe.As(GCHandle.InternalGet(taggedHandle & ~HandleTagBits));
+
+ comAwareRef.SetTarget(target, comInfo);
+ }
+
+ [MethodImpl(MethodImplOptions.NoInlining)]
+ internal static void SetComInfoInConstructor(ref nint taggedHandle, ComInfo comInfo)
+ {
+ Debug.Assert((taggedHandle & ComAwareBit) == 0);
+ ComAwareWeakReference comAwareRef = new ComAwareWeakReference(taggedHandle & ~HandleTagBits);
+ nint newHandle = GCHandle.InternalAlloc(comAwareRef, GCHandleType.Normal);
+ taggedHandle = newHandle | ComAwareBit | (taggedHandle & TracksResurrectionBit);
+ comAwareRef._comInfo = comInfo;
+ }
+ }
+}
+#endif
diff --git a/src/libraries/System.Private.CoreLib/src/System/WeakReference.T.cs b/src/libraries/System.Private.CoreLib/src/System/WeakReference.T.cs
index 3d48ec61d811b..36cb48135dd89 100644
--- a/src/libraries/System.Private.CoreLib/src/System/WeakReference.T.cs
+++ b/src/libraries/System.Private.CoreLib/src/System/WeakReference.T.cs
@@ -7,6 +7,8 @@
using System.Diagnostics.CodeAnalysis;
using System.Diagnostics;
+using static System.WeakReferenceHandleTags;
+
namespace System
{
[Serializable]
@@ -15,23 +17,15 @@ namespace System
public sealed partial class WeakReference : ISerializable
where T : class?
{
- // If you fix bugs here, please fix them in WeakReference at the same time.
+ // If you fix bugs here, please fix them in WeakReference at the same time.
// Most methods using the handle should use GC.KeepAlive(this) to avoid potential handle recycling
// attacks (i.e. if the WeakReference instance is finalized away underneath you when you're still
// handling a cached value of the handle then the handle could be freed and reused).
-
-#if !CORECLR
- // the handle field is effectively readonly until the object is finalized.
- private IntPtr _handleAndKind;
-
- // the lowermost bit is used to indicate whether the handle is tracking resurrection
- private const nint TracksResurrectionBit = 1;
-#endif
+ private nint _taggedHandle;
// Creates a new WeakReference that keeps track of target.
// Assumes a Short Weak Reference (ie TrackResurrection is false.)
- //
public WeakReference(T target)
: this(target, false)
{
@@ -64,7 +58,6 @@ private WeakReference(SerializationInfo info, StreamingContext context)
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public bool TryGetTarget([MaybeNullWhen(false), NotNullWhen(true)] out T target)
{
- // Call the worker method that has more performant but less user friendly signature.
T? o = this.Target;
target = o!;
return o != null;
@@ -78,32 +71,47 @@ public void GetObjectData(SerializationInfo info, StreamingContext context)
info.AddValue("TrackResurrection", IsTrackResurrection()); // Do not rename (binary serialization)
}
-#if !CORECLR
// Returns a boolean indicating whether or not we're tracking objects until they're collected (true)
// or just until they're finalized (false).
- private bool IsTrackResurrection() => (_handleAndKind & TracksResurrectionBit) != 0;
+ private bool IsTrackResurrection() => (_taggedHandle & TracksResurrectionBit) != 0;
// Creates a new WeakReference that keeps track of target.
private void Create(T target, bool trackResurrection)
{
- IntPtr h = GCHandle.InternalAlloc(target, trackResurrection ? GCHandleType.WeakTrackResurrection : GCHandleType.Weak);
- _handleAndKind = trackResurrection ?
+ nint h = GCHandle.InternalAlloc(target, trackResurrection ? GCHandleType.WeakTrackResurrection : GCHandleType.Weak);
+ _taggedHandle = trackResurrection ?
h | TracksResurrectionBit :
h;
- }
- private IntPtr Handle => _handleAndKind & ~TracksResurrectionBit;
+#if FEATURE_COMINTEROP || FEATURE_COMWRAPPERS
+ ComAwareWeakReference.ComInfo? comInfo = ComAwareWeakReference.ComInfo.FromObject(target);
+ if (comInfo != null)
+ {
+ ComAwareWeakReference.SetComInfoInConstructor(ref _taggedHandle, comInfo);
+ }
+#endif
+ }
public void SetTarget(T target)
{
- IntPtr h = Handle;
+ nint th = _taggedHandle & ~TracksResurrectionBit;
+
// Should only happen for corner cases, like using a WeakReference from a finalizer.
// GC can finalize the instance if it becomes F-Reachable.
// That, however, cannot happen while we use the instance.
- if (default(IntPtr) == h)
+ if (th == 0)
throw new InvalidOperationException(SR.InvalidOperation_HandleIsNotInitialized);
- GCHandle.InternalSet(h, target);
+#if FEATURE_COMINTEROP || FEATURE_COMWRAPPERS
+ var comInfo = ComAwareWeakReference.ComInfo.FromObject(target);
+ if ((th & ComAwareBit) != 0 || comInfo != null)
+ {
+ ComAwareWeakReference.SetTarget(ref _taggedHandle, target, comInfo);
+ return;
+ }
+#endif
+
+ GCHandle.InternalSet(th, target);
// must keep the instance alive as long as we use the handle.
GC.KeepAlive(this);
@@ -111,17 +119,24 @@ public void SetTarget(T target)
private T? Target
{
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
get
{
- IntPtr h = Handle;
+ nint th = _taggedHandle & ~TracksResurrectionBit;
+
// Should only happen for corner cases, like using a WeakReference from a finalizer.
// GC can finalize the instance if it becomes F-Reachable.
// That, however, cannot happen while we use the instance.
- if (default(IntPtr) == h)
+ if (th == 0)
return default;
+#if FEATURE_COMINTEROP || FEATURE_COMWRAPPERS
+ if ((th & ComAwareBit) != 0)
+ return Unsafe.As(ComAwareWeakReference.GetTarget(th));
+#endif
+
// unsafe cast is ok as the handle cannot be destroyed and recycled while we keep the instance alive
- T? target = Unsafe.As(GCHandle.InternalGet(h));
+ T? target = Unsafe.As(GCHandle.InternalGet(th));
// must keep the instance alive as long as we use the handle.
GC.KeepAlive(this);
@@ -140,6 +155,5 @@ private T? Target
}
#pragma warning restore CA1821 // Remove empty Finalizers
-#endif
}
}
diff --git a/src/libraries/System.Private.CoreLib/src/System/WeakReference.cs b/src/libraries/System.Private.CoreLib/src/System/WeakReference.cs
index 2f56806b48c83..81c33fd07445e 100644
--- a/src/libraries/System.Private.CoreLib/src/System/WeakReference.cs
+++ b/src/libraries/System.Private.CoreLib/src/System/WeakReference.cs
@@ -2,11 +2,30 @@
// The .NET Foundation licenses this file to you under the MIT license.
using System.Diagnostics;
+using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.Serialization;
+using static System.WeakReferenceHandleTags;
+
namespace System
{
+ internal static class WeakReferenceHandleTags
+ {
+ // the lowermost bit is used to indicate whether the handle is tracking resurrection
+ // handles are at least 2-byte aligned, so we can use one bit for tagging
+ internal const nint TracksResurrectionBit = 1;
+
+#if FEATURE_COMINTEROP || FEATURE_COMWRAPPERS
+ // one more bit is used to track whether the handle refers to an instance of ComAwareWeakReference
+ // we can use this bit because on COM-supporting platforms a handle is at least 4-byte aligned
+ internal const nint ComAwareBit = 2;
+ internal const nint HandleTagBits = TracksResurrectionBit | ComAwareBit;
+#else
+ internal const nint HandleTagBits = TracksResurrectionBit;
+#endif
+ }
+
[Serializable]
[System.Runtime.CompilerServices.TypeForwardedFrom("mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089")]
public partial class WeakReference : ISerializable
@@ -17,13 +36,7 @@ public partial class WeakReference : ISerializable
// attacks (i.e. if the WeakReference instance is finalized away underneath you when you're still
// handling a cached value of the handle then the handle could be freed and reused).
-#if !CORECLR
- // the handle field is effectively readonly until the object is finalized.
- private IntPtr _handleAndKind;
-
- // the lowermost bit is used to indicate whether the handle is tracking resurrection
- private const nint TracksResurrectionBit = 1;
-#endif
+ private nint _taggedHandle;
// Creates a new WeakReference that keeps track of target.
// Assumes a Short Weak Reference (ie TrackResurrection is false.)
@@ -60,20 +73,40 @@ public virtual void GetObjectData(SerializationInfo info, StreamingContext conte
// or just until they're finalized (false).
public virtual bool TrackResurrection => IsTrackResurrection();
-#if !CORECLR
private void Create(object? target, bool trackResurrection)
{
- IntPtr h = GCHandle.InternalAlloc(target, trackResurrection ? GCHandleType.WeakTrackResurrection : GCHandleType.Weak);
- _handleAndKind = trackResurrection ?
+ nint h = GCHandle.InternalAlloc(target, trackResurrection ? GCHandleType.WeakTrackResurrection : GCHandleType.Weak);
+ _taggedHandle = trackResurrection ?
h | TracksResurrectionBit :
h;
+
+#if FEATURE_COMINTEROP || FEATURE_COMWRAPPERS
+ ComAwareWeakReference.ComInfo? comInfo = ComAwareWeakReference.ComInfo.FromObject(target);
+ if (comInfo != null)
+ {
+ ComAwareWeakReference.SetComInfoInConstructor(ref _taggedHandle, comInfo);
+ }
+#endif
}
// Returns a boolean indicating whether or not we're tracking objects until they're collected (true)
// or just until they're finalized (false).
- private bool IsTrackResurrection() => (_handleAndKind & TracksResurrectionBit) != 0;
+ private bool IsTrackResurrection() => (_taggedHandle & TracksResurrectionBit) != 0;
- internal IntPtr Handle => _handleAndKind & ~TracksResurrectionBit;
+ internal nint WeakHandle
+ {
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ get
+ {
+ nint th = _taggedHandle;
+
+#if FEATURE_COMINTEROP || FEATURE_COMWRAPPERS
+ if ((th & ComAwareBit) != 0)
+ return ComAwareWeakReference.GetWeakHandle(th);
+#endif
+ return th & ~HandleTagBits;
+ }
+ }
// Determines whether or not this instance of WeakReference still refers to an object
// that has not been collected.
@@ -81,14 +114,14 @@ public virtual bool IsAlive
{
get
{
- IntPtr h = Handle;
+ nint wh = WeakHandle;
// In determining whether it is valid to use this object, we need to at least expose this
// without throwing an exception.
- if (default(IntPtr) == h)
+ if (wh == 0)
return false;
- bool result = GCHandle.InternalGet(h) != null;
+ bool result = GCHandle.InternalGet(wh) != null;
// must keep the instance alive as long as we use the handle.
GC.KeepAlive(this);
@@ -101,9 +134,11 @@ public virtual bool IsAlive
// Or sets it.
public virtual object? Target
{
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
get
{
- IntPtr h = Handle;
+ nint th = _taggedHandle & ~TracksResurrectionBit;
+
// Should only happen for corner cases, like using a WeakReference from a finalizer.
// GC can finalize the instance if it becomes F-Reachable.
// That, however, cannot happen while we use the instance.
@@ -114,10 +149,16 @@ public virtual object? Target
// There is a possibility that a derived type overrides the default finalizer and arranges concurrent access.
// There is nothing that we can do about that and a few other exotic ways to break this.
//
- if (default(IntPtr) == h)
+ if (th == 0)
return default;
- object? target = GCHandle.InternalGet(h);
+#if FEATURE_COMINTEROP || FEATURE_COMWRAPPERS
+ if ((th & ComAwareBit) != 0)
+ return ComAwareWeakReference.GetTarget(th);
+#endif
+
+ // unsafe cast is ok as the handle cannot be destroyed and recycled while we keep the instance alive
+ object? target = GCHandle.InternalGet(th);
// must keep the instance alive as long as we use the handle.
GC.KeepAlive(this);
@@ -127,13 +168,24 @@ public virtual object? Target
set
{
- IntPtr h = Handle;
+ nint th = _taggedHandle & ~TracksResurrectionBit;
+
// Should only happen for corner cases, like using a WeakReference from a finalizer.
- // See the comment in the getter.
- if (default(IntPtr) == h)
+ // GC can finalize the instance if it becomes F-Reachable.
+ // That, however, cannot happen while we use the instance.
+ if (th == 0)
throw new InvalidOperationException(SR.InvalidOperation_HandleIsNotInitialized);
- GCHandle.InternalSet(h, value);
+#if FEATURE_COMINTEROP || FEATURE_COMWRAPPERS
+ var comInfo = ComAwareWeakReference.ComInfo.FromObject(value);
+ if ((th & ComAwareBit) != 0 || comInfo != null)
+ {
+ ComAwareWeakReference.SetTarget(ref _taggedHandle, value, comInfo);
+ return;
+ }
+#endif
+
+ GCHandle.InternalSet(th, value);
// must keep the instance alive as long as we use the handle.
GC.KeepAlive(this);
@@ -152,15 +204,14 @@ public virtual object? Target
Debug.Assert(this.GetType() != typeof(WeakReference));
- IntPtr handle = Handle;
- if (handle != default(IntPtr))
+ nint handle = _taggedHandle & ~HandleTagBits;
+ if (handle != 0)
{
GCHandle.InternalFree(handle);
- // keep the bit that indicates whether this reference was tracking resurrection
- _handleAndKind &= TracksResurrectionBit;
+ // keep the bit that indicates whether this reference was tracking resurrection, clear the rest.
+ _taggedHandle &= TracksResurrectionBit;
}
}
-#endif
}
}
diff --git a/src/mono/mono/metadata/object-internals.h b/src/mono/mono/metadata/object-internals.h
index 7725b25946369..ea7cd23836e4a 100644
--- a/src/mono/mono/metadata/object-internals.h
+++ b/src/mono/mono/metadata/object-internals.h
@@ -653,7 +653,7 @@ typedef struct {
typedef struct {
MonoObject object;
- gsize handleAndKind;
+ gsize taggedHandle;
} MonoWeakReference;
/* Safely access System.Delegate from native code */
diff --git a/src/mono/mono/metadata/sgen-mono.c b/src/mono/mono/metadata/sgen-mono.c
index 64f8bda2b2764..263b7da12def0 100644
--- a/src/mono/mono/metadata/sgen-mono.c
+++ b/src/mono/mono/metadata/sgen-mono.c
@@ -460,9 +460,10 @@ sgen_client_object_finalize_eagerly (GCObject *obj)
if (obj->vtable->klass == mono_defaults.weakreference_class ||
obj->vtable->klass == mono_defaults.generic_weakreference_class) {
MonoWeakReference *wr = (MonoWeakReference*)obj;
- MonoGCHandle gc_handle = (MonoGCHandle)(wr->handleAndKind & ~(gsize)1);
+ MonoGCHandle gc_handle = (MonoGCHandle)(wr->taggedHandle & ~(gsize)1);
mono_gchandle_free_internal (gc_handle);
- wr->handleAndKind &= (gsize)1;
+ // keep the bit that indicates whether this reference was tracking resurrection, clear the rest.
+ wr->taggedHandle &= (gsize)1;
return TRUE;
}