diff --git a/src/coreclr/src/System.Private.CoreLib/src/System/RuntimeHandles.cs b/src/coreclr/src/System.Private.CoreLib/src/System/RuntimeHandles.cs
index 501e96f9a1437..fdbba863d0e53 100644
--- a/src/coreclr/src/System.Private.CoreLib/src/System/RuntimeHandles.cs
+++ b/src/coreclr/src/System.Private.CoreLib/src/System/RuntimeHandles.cs
@@ -214,7 +214,14 @@ internal static bool HasElementType(RuntimeType type)
/// MethodTable* corresponding to that type. If the type is closed over
/// some T and is true, then returns the values for the 'T'.
///
- internal static delegate* GetNewobjHelperFnPtr(RuntimeType type, out MethodTable* pMT, bool unwrapNullable, bool allowCom)
+ internal static delegate* GetNewobjHelperFnPtr(
+ // This API doesn't call any constructors, but the type needs to be seen as constructed.
+ // A type is seen as constructed if a constructor is kept.
+ // This obviously won't cover a type with no constructor. Reference types with no
+ // constructor are an academic problem. Valuetypes with no constructors are a problem,
+ // but IL Linker currently treats them as always implicitly boxed.
+ [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicConstructors | DynamicallyAccessedMemberTypes.NonPublicConstructors)] RuntimeType type,
+ out MethodTable* pMT, bool unwrapNullable, bool allowCom)
{
Debug.Assert(type != null);
diff --git a/src/coreclr/src/System.Private.CoreLib/src/System/RuntimeType.CoreCLR.cs b/src/coreclr/src/System.Private.CoreLib/src/System/RuntimeType.CoreCLR.cs
index 3e6c887e78d89..7c890cc2b3f25 100644
--- a/src/coreclr/src/System.Private.CoreLib/src/System/RuntimeType.CoreCLR.cs
+++ b/src/coreclr/src/System.Private.CoreLib/src/System/RuntimeType.CoreCLR.cs
@@ -3971,24 +3971,26 @@ public void EnsureInitialized(RuntimeType type)
Debug.Assert(cache._pfnNewobj != null);
Debug.Assert(cache._pfnCtor != null);
+ Debug.Assert(cache._pMT != null);
if (!cache._ctorIsPublic && publicOnly)
{
throw new MissingMethodException(SR.Format(SR.Arg_NoDefCTor, this));
}
+ object? obj = cache._pfnNewobj(cache._pMT); // allocation outside the try block (allow OOM to bubble up)
+ GC.KeepAlive(this); // can't allow the type to be collected before the object is created
+
try
{
- object? obj = cache._pfnNewobj(cache._pMT);
- GC.KeepAlive(this); // can't allow the type to be collected before the object is created
-
cache._pfnCtor(obj);
- return obj;
}
catch (Exception e) when (wrapExceptions)
{
throw new TargetInvocationException(e);
}
+
+ return obj;
}
if (!skipCheckThis)
diff --git a/src/coreclr/src/vm/reflectioninvocation.cpp b/src/coreclr/src/vm/reflectioninvocation.cpp
index be484f8157eac..ebafe5ec7d4b0 100644
--- a/src/coreclr/src/vm/reflectioninvocation.cpp
+++ b/src/coreclr/src/vm/reflectioninvocation.cpp
@@ -568,7 +568,7 @@ FCIMPLEND
* throws an exception. If TypeHandle is a value type, the NEWOBJ helper will create
* a boxed zero-inited instance of the value type.
*/
- void QCALLTYPE RuntimeTypeHandle::GetNewobjHelperFnPtr(
+void QCALLTYPE RuntimeTypeHandle::GetNewobjHelperFnPtr(
QCall::TypeHandle pTypeHandle,
PCODE* ppNewobjHelper,
MethodTable** ppMT,
@@ -597,6 +597,8 @@ FCIMPLEND
MethodTable* pMT = typeHandle.AsMethodTable();
PREFIX_ASSUME(pMT != NULL);
+ pMT->EnsureInstanceActive();
+
// Don't allow creating instances of void or delegates
if (pMT == MscorlibBinder::GetElementType(ELEMENT_TYPE_VOID) || pMT->IsDelegate())
{
@@ -646,13 +648,10 @@ FCIMPLEND
pMT = pMT->GetInstantiation()[0].GetMethodTable();
}
- // Ensure the type's cctor has run
- Assembly* pAssem = pMT->GetAssembly();
- if (!pMT->IsClassInited())
+ // Run the type's cctor if needed (if not marked beforefieldinit)
+ if (pMT->HasPreciseInitCctors())
{
- pMT->CheckRestore();
- pMT->EnsureInstanceActive();
- pMT->CheckRunClassInitThrowing();
+ pMT->CheckRunClassInitAsIfConstructingThrowing();
}
// And we're done!
diff --git a/src/libraries/Common/tests/TestUtilities/System/PlatformDetection.cs b/src/libraries/Common/tests/TestUtilities/System/PlatformDetection.cs
index f22afa8b6a05c..d9292d7351bc2 100644
--- a/src/libraries/Common/tests/TestUtilities/System/PlatformDetection.cs
+++ b/src/libraries/Common/tests/TestUtilities/System/PlatformDetection.cs
@@ -69,6 +69,7 @@ public static bool IsDrawingSupported
}
public static bool IsInContainer => GetIsInContainer();
+ public static bool SupportsComInterop => IsWindows && IsNetCore; // matches definitions in clr.featuredefines.props
public static bool SupportsSsl3 => GetSsl3Support();
public static bool SupportsSsl2 => IsWindows && !PlatformDetection.IsWindows10Version1607OrGreater;
diff --git a/src/libraries/System.Runtime/tests/System/Runtime/CompilerServices/RuntimeHelpersTests.cs b/src/libraries/System.Runtime/tests/System/Runtime/CompilerServices/RuntimeHelpersTests.cs
index 5b3667da142ee..bdfd23323170e 100644
--- a/src/libraries/System.Runtime/tests/System/Runtime/CompilerServices/RuntimeHelpersTests.cs
+++ b/src/libraries/System.Runtime/tests/System/Runtime/CompilerServices/RuntimeHelpersTests.cs
@@ -196,8 +196,6 @@ public static IEnumerable