Skip to content

Commit e296ee8

Browse files
tannergoodingjkotas
authored andcommitted
Updating the JIT to support marshaling blittable generics. (#103)
* Adding some tests for marshalling generics. * Updating the VM to allow marshalling blittable generic types. * Adding comments for why certain blittable generics are blocked from being marshaled * Removing the new IDS_EE_BADMARSHAL_BLITTABLE_GENERICS_RESTRICTION string in favor of fixing the text in IDS_EE_BADMARSHAL_GENERICS_RESTRICTION * Updating CrossGen2 to handle marshalling blittable generics
1 parent da1b717 commit e296ee8

155 files changed

Lines changed: 10903 additions & 5 deletions

File tree

Some content is hidden

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

src/coreclr/src/dlls/mscorrc/mscorrc.rc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -627,7 +627,7 @@ BEGIN
627627
IDS_EE_BADMARSHAL_NOTMARSHALABLE "The type definition of this field has layout information but has an invalid managed/unmanaged type combination or is unmarshalable."
628628
IDS_EE_BADMARSHAL_BADMETADATA "Invalid marshaling metadata."
629629
IDS_EE_BADMARSHAL_CUSTOMMARSHALER "Custom marshalers are only allowed on classes, strings, arrays, and boxed value types."
630-
IDS_EE_BADMARSHAL_GENERICS_RESTRICTION "Generic types cannot be marshaled."
630+
IDS_EE_BADMARSHAL_GENERICS_RESTRICTION "Non-blittable generic types cannot be marshaled."
631631
IDS_EE_BADMARSHAL_STRING_OUT "Cannot marshal a string by-value with the [Out] attribute."
632632

633633
IDS_EE_BADMARSHALPARAM_STRINGBUILDER "Invalid managed/unmanaged type combination (StringBuilders must be paired with LPStr, LPWStr, or LPTStr)."

src/coreclr/src/tools/crossgen2/Common/TypeSystem/Interop/IL/MarshalHelpers.cs

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -334,13 +334,29 @@ internal static MarshallerKind GetMarshallerKind(
334334
return MarshallerKind.Invalid;
335335
}
336336

337-
if (type.HasInstantiation)
337+
bool isBlittable = MarshalUtils.IsBlittableType(type);
338+
339+
// Blittable generics are allowed to be marshalled with the following exceptions:
340+
// * ByReference<T>: This represents an interior pointer and is not actually blittable
341+
// * Nullable<T>: We don't want to be locked into the default behavior as we may want special handling later
342+
// * Vector64<T>: Represents the __m64 ABI primitive which requires currently unimplemented handling
343+
// * Vector128<T>: Represents the __m128 ABI primitive which requires currently unimplemented handling
344+
// * Vector256<T>: Represents the __m256 ABI primitive which requires currently unimplemented handling
345+
// * Vector<T>: Has a variable size (either __m128 or __m256) and isn't readily usable for inteorp scenarios
346+
347+
if (type.HasInstantiation && (!isBlittable
348+
|| InteropTypes.IsSystemByReference(context, type)
349+
|| InteropTypes.IsSystemNullable(context, type)
350+
|| InteropTypes.IsSystemRuntimeIntrinsicsVector64T(context, type)
351+
|| InteropTypes.IsSystemRuntimeIntrinsicsVector128T(context, type)
352+
|| InteropTypes.IsSystemRuntimeIntrinsicsVector256T(context, type)
353+
|| InteropTypes.IsSystemNumericsVectorT(context, type)))
338354
{
339355
// Generic types cannot be marshaled.
340356
return MarshallerKind.Invalid;
341357
}
342358

343-
if (MarshalUtils.IsBlittableType(type))
359+
if (isBlittable)
344360
{
345361
if (nativeType != NativeTypeKind.Default && nativeType != NativeTypeKind.Struct)
346362
return MarshallerKind.Invalid;

src/coreclr/src/tools/crossgen2/Common/TypeSystem/Interop/InteropTypes.cs

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,36 @@ public static bool IsSystemArgIterator(TypeSystemContext context, TypeDesc type)
108108
return IsCoreNamedType(context, type, "System", "ArgIterator");
109109
}
110110

111+
public static bool IsSystemByReference(TypeSystemContext context, TypeDesc type)
112+
{
113+
return IsCoreNamedType(context, type, "System", "ByReference`1");
114+
}
115+
116+
public static bool IsSystemNullable(TypeSystemContext context, TypeDesc type)
117+
{
118+
return IsCoreNamedType(context, type, "System", "Nullable`1");
119+
}
120+
121+
public static bool IsSystemRuntimeIntrinsicsVector64T(TypeSystemContext context, TypeDesc type)
122+
{
123+
return IsCoreNamedType(context, type, "System.Runtime.Intrinsics", "Vector64`1");
124+
}
125+
126+
public static bool IsSystemRuntimeIntrinsicsVector128T(TypeSystemContext context, TypeDesc type)
127+
{
128+
return IsCoreNamedType(context, type, "System.Runtime.Intrinsics", "Vector128`1");
129+
}
130+
131+
public static bool IsSystemRuntimeIntrinsicsVector256T(TypeSystemContext context, TypeDesc type)
132+
{
133+
return IsCoreNamedType(context, type, "System.Runtime.Intrinsics", "Vector256`1");
134+
}
135+
136+
public static bool IsSystemNumericsVectorT(TypeSystemContext context, TypeDesc type)
137+
{
138+
return IsCoreNamedType(context, type, "System.Numerics", "Vector`1");
139+
}
140+
111141
private static bool IsOrDerivesFromType(TypeDesc type, MetadataType targetType)
112142
{
113143
while (type != null)

src/coreclr/src/vm/mlinfo.cpp

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2796,7 +2796,25 @@ MarshalInfo::MarshalInfo(Module* pModule,
27962796
}
27972797
#endif // FEATURE_COMINTEROP
27982798

2799-
if (m_pMT->HasInstantiation())
2799+
// Blittable generics are allowed to be marshalled with the following exceptions:
2800+
// * ByReference<T>: This represents an interior pointer and is not actually blittable
2801+
// * Nullable<T>: We don't want to be locked into the default behavior as we may want special handling later
2802+
// * Vector64<T>: Represents the __m64 ABI primitive which requires currently unimplemented handling
2803+
// * Vector128<T>: Represents the __m128 ABI primitive which requires currently unimplemented handling
2804+
// * Vector256<T>: Represents the __m256 ABI primitive which requires currently unimplemented handling
2805+
// * Vector<T>: Has a variable size (either __m128 or __m256) and isn't readily usable for inteorp scenarios
2806+
2807+
if (m_pMT->HasInstantiation() && (!m_pMT->IsBlittable()
2808+
|| m_pMT->HasSameTypeDefAs(g_pByReferenceClass)
2809+
|| m_pMT->HasSameTypeDefAs(g_pNullableClass)
2810+
|| m_pMT->HasSameTypeDefAs(MscorlibBinder::GetClass(CLASS__VECTOR64T))
2811+
|| m_pMT->HasSameTypeDefAs(MscorlibBinder::GetClass(CLASS__VECTOR128T))
2812+
|| m_pMT->HasSameTypeDefAs(MscorlibBinder::GetClass(CLASS__VECTOR256T))
2813+
#ifndef CROSSGEN_COMPILE
2814+
// Crossgen scenarios block Vector<T> from even being loaded
2815+
|| m_pMT->HasSameTypeDefAs(MscorlibBinder::GetClass(CLASS__VECTORT))
2816+
#endif // !CROSSGEN_COMPILE
2817+
))
28002818
{
28012819
m_resID = IDS_EE_BADMARSHAL_GENERICS_RESTRICTION;
28022820
IfFailGoto(E_FAIL, lFail);
@@ -2916,7 +2934,7 @@ MarshalInfo::MarshalInfo(Module* pModule,
29162934
if (m_ms != MARSHAL_SCENARIO_WINRT)
29172935
#endif // FEATURE_COMINTEROP
29182936
{
2919-
if (thElement.HasInstantiation())
2937+
if (thElement.HasInstantiation() && !thElement.IsBlittable())
29202938
{
29212939
m_resID = IDS_EE_BADMARSHAL_GENERICS_RESTRICTION;
29222940
IfFailGoto(E_FAIL, lFail);

src/coreclr/src/vm/mscorlib.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -499,6 +499,14 @@ DEFINE_FIELD(MARSHAL, SYSTEM_MAX_DBCS_CHAR_SIZE, SystemMax
499499
DEFINE_CLASS(NATIVELIBRARY, Interop, NativeLibrary)
500500
DEFINE_METHOD(NATIVELIBRARY, LOADLIBRARYCALLBACKSTUB, LoadLibraryCallbackStub, SM_Str_AssemblyBase_Bool_UInt_RetIntPtr)
501501

502+
DEFINE_CLASS(VECTOR64T, Intrinsics, Vector64`1)
503+
DEFINE_CLASS(VECTOR128T, Intrinsics, Vector128`1)
504+
DEFINE_CLASS(VECTOR256T, Intrinsics, Vector256`1)
505+
506+
#ifndef CROSSGEN_COMPILE
507+
DEFINE_CLASS(VECTORT, Numerics, Vector`1)
508+
#endif // !CROSSGEN_COMPILE
509+
502510
DEFINE_CLASS(MEMBER, Reflection, MemberInfo)
503511

504512

src/coreclr/src/vm/namespace.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@
4040
#endif // FEATURE_COMINTEROP
4141

4242
#define g_IntrinsicsNS g_RuntimeNS ".Intrinsics"
43+
#define g_NumericsNS g_SystemNS ".Numerics"
4344

4445
#define g_InternalCompilerServicesNS "Internal.Runtime.CompilerServices"
4546
#define g_CompilerServicesNS g_RuntimeNS ".CompilerServices"

src/coreclr/tests/src/Interop/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ add_subdirectory(PInvoke/Miscellaneous/HandleRef)
3030
add_subdirectory(PInvoke/Miscellaneous/ThisCall)
3131
add_subdirectory(PInvoke/Miscellaneous/MultipleAssembliesWithSamePInvoke)
3232
add_subdirectory(PInvoke/CriticalHandles)
33+
add_subdirectory(PInvoke/Generics)
3334
add_subdirectory(PInvoke/AsAny)
3435
add_subdirectory(PInvoke/SafeHandles)
3536
add_subdirectory(NativeCallable)
Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
cmake_minimum_required (VERSION 2.6)
2+
project (GenericsNative)
3+
include ("${CLR_INTEROP_TEST_ROOT}/Interop.cmake")
4+
if(CLR_CMAKE_TARGET_ARCH_I386)
5+
add_definitions(-D_TARGET_X86_)
6+
add_definitions(-D_TARGET_XARCH_)
7+
elseif(CLR_CMAKE_TARGET_ARCH_AMD64)
8+
add_definitions(-D_TARGET_AMD64_)
9+
add_definitions(-D_TARGET_XARCH_)
10+
elseif(CLR_CMAKE_TARGET_ARCH_ARM)
11+
add_definitions(-D_TARGET_ARM_)
12+
add_definitions(-D_TARGET_ARMARCH_)
13+
elseif(CLR_CMAKE_TARGET_ARCH_ARM64)
14+
add_definitions(-D_TARGET_ARM64_)
15+
add_definitions(-D_TARGET_ARMARCH_)
16+
endif()
17+
set(SOURCES
18+
GenericsNative.IUnknown.cpp
19+
GenericsNative.NullableB.cpp
20+
GenericsNative.NullableC.cpp
21+
GenericsNative.NullableD.cpp
22+
GenericsNative.NullableF.cpp
23+
GenericsNative.NullableL.cpp
24+
GenericsNative.NullableU.cpp
25+
GenericsNative.Point1B.cpp
26+
GenericsNative.Point1C.cpp
27+
GenericsNative.Point1D.cpp
28+
GenericsNative.Point1F.cpp
29+
GenericsNative.Point1L.cpp
30+
GenericsNative.Point1U.cpp
31+
GenericsNative.Point2B.cpp
32+
GenericsNative.Point2C.cpp
33+
GenericsNative.Point2D.cpp
34+
GenericsNative.Point2F.cpp
35+
GenericsNative.Point2L.cpp
36+
GenericsNative.Point2U.cpp
37+
GenericsNative.Point3B.cpp
38+
GenericsNative.Point3C.cpp
39+
GenericsNative.Point3D.cpp
40+
GenericsNative.Point3F.cpp
41+
GenericsNative.Point3L.cpp
42+
GenericsNative.Point3U.cpp
43+
GenericsNative.Point4B.cpp
44+
GenericsNative.Point4C.cpp
45+
GenericsNative.Point4D.cpp
46+
GenericsNative.Point4F.cpp
47+
GenericsNative.Point4L.cpp
48+
GenericsNative.Point4U.cpp
49+
GenericsNative.SequentialClassB.cpp
50+
GenericsNative.SequentialClassC.cpp
51+
GenericsNative.SequentialClassD.cpp
52+
GenericsNative.SequentialClassF.cpp
53+
GenericsNative.SequentialClassL.cpp
54+
GenericsNative.SequentialClassU.cpp
55+
GenericsNative.SpanB.cpp
56+
GenericsNative.SpanC.cpp
57+
GenericsNative.SpanD.cpp
58+
GenericsNative.SpanF.cpp
59+
GenericsNative.SpanL.cpp
60+
GenericsNative.SpanU.cpp
61+
GenericsNative.Vector64B.cpp
62+
GenericsNative.Vector64C.cpp
63+
GenericsNative.Vector64D.cpp
64+
GenericsNative.Vector64F.cpp
65+
GenericsNative.Vector64L.cpp
66+
GenericsNative.Vector64U.cpp
67+
GenericsNative.Vector128B.cpp
68+
GenericsNative.Vector128C.cpp
69+
GenericsNative.Vector128D.cpp
70+
GenericsNative.Vector128F.cpp
71+
GenericsNative.Vector128L.cpp
72+
GenericsNative.Vector128U.cpp
73+
GenericsNative.Vector256B.cpp
74+
GenericsNative.Vector256C.cpp
75+
GenericsNative.Vector256D.cpp
76+
GenericsNative.Vector256F.cpp
77+
GenericsNative.Vector256L.cpp
78+
GenericsNative.Vector256U.cpp
79+
GenericsNative.VectorB.cpp
80+
GenericsNative.VectorC.cpp
81+
GenericsNative.VectorD.cpp
82+
GenericsNative.VectorF.cpp
83+
GenericsNative.VectorL.cpp
84+
GenericsNative.VectorU.cpp
85+
)
86+
add_library (GenericsNative SHARED ${SOURCES})
87+
install (TARGETS GenericsNative DESTINATION bin)
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
// Licensed to the .NET Foundation under one or more agreements.
2+
// The .NET Foundation licenses this file to you under the MIT license.
3+
// See the LICENSE file in the project root for more information.
4+
5+
#include <stdio.h>
6+
#include <stdint.h>
7+
#include <xplatform.h>
8+
#include <platformdefines.h>
9+
10+
extern "C" DLL_EXPORT IUnknown* STDMETHODCALLTYPE GetIComInterface()
11+
{
12+
throw "P/Invoke for IComInterface<T> should be unsupported.";
13+
}
14+
15+
extern "C" DLL_EXPORT void STDMETHODCALLTYPE GetIComInterfaceOut(IUnknown** pValue)
16+
{
17+
throw "P/Invoke for IComInterface<T> should be unsupported.";
18+
}
19+
20+
extern "C" DLL_EXPORT const IUnknown** STDMETHODCALLTYPE GetIComInterfacePtr()
21+
{
22+
throw "P/Invoke for IComInterface<T> should be unsupported.";
23+
}
24+
25+
extern "C" DLL_EXPORT void STDMETHODCALLTYPE GetIComInterfaces(IUnknown** pValues, int count)
26+
{
27+
throw "P/Invoke for IComInterface<T> should be unsupported.";
28+
}
29+
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
// Licensed to the .NET Foundation under one or more agreements.
2+
// The .NET Foundation licenses this file to you under the MIT license.
3+
// See the LICENSE file in the project root for more information.
4+
5+
#include <stdio.h>
6+
#include <stdint.h>
7+
#include <xplatform.h>
8+
#include <platformdefines.h>
9+
10+
struct NullableB
11+
{
12+
bool hasValue;
13+
bool value;
14+
};
15+
16+
static NullableB NullableBValue = { };
17+
18+
extern "C" DLL_EXPORT NullableB STDMETHODCALLTYPE GetNullableB(bool hasValue, bool value)
19+
{
20+
throw "P/Invoke for Nullable<bool> should be unsupported.";
21+
}
22+
23+
extern "C" DLL_EXPORT void STDMETHODCALLTYPE GetNullableBOut(bool hasValue, bool value, NullableB* pValue)
24+
{
25+
throw "P/Invoke for Nullable<bool> should be unsupported.";
26+
}
27+
28+
extern "C" DLL_EXPORT const NullableB* STDMETHODCALLTYPE GetNullableBPtr(bool hasValue, bool value)
29+
{
30+
throw "P/Invoke for Nullable<bool> should be unsupported.";
31+
}
32+
33+
extern "C" DLL_EXPORT NullableB STDMETHODCALLTYPE AddNullableB(NullableB lhs, NullableB rhs)
34+
{
35+
throw "P/Invoke for Nullable<bool> should be unsupported.";
36+
}
37+
38+
extern "C" DLL_EXPORT NullableB STDMETHODCALLTYPE AddNullableBs(const NullableB* pValues, uint32_t count)
39+
{
40+
throw "P/Invoke for Nullable<bool> should be unsupported.";
41+
}

0 commit comments

Comments
 (0)