summaryrefslogtreecommitdiff
path: root/tests
diff options
context:
space:
mode:
authorJeremy Koritzinsky <jkoritzinsky@gmail.com>2019-04-04 18:37:57 -0700
committerGitHub <noreply@github.com>2019-04-04 18:37:57 -0700
commitdf804273f7bebbe45cb51f22b748c31b5fbe60cf (patch)
treeb83dee7b3cd863d56c0cec86e53c9f8dab542a35 /tests
parent126aaf4619adb085a210178ead14fa9439a5ebb6 (diff)
downloadcoreclr-df804273f7bebbe45cb51f22b748c31b5fbe60cf.tar.gz
coreclr-df804273f7bebbe45cb51f22b748c31b5fbe60cf.tar.bz2
coreclr-df804273f7bebbe45cb51f22b748c31b5fbe60cf.zip
Fix SystemV AMD64 Explicit structure classification (#22041)
* Don't bail out on enregistering explicit structs if there are no overlapping fields. * Don't enregister if any unaligned fields. * Enable passing explicit structs by-value by enregistering on systemv. Some edge cases are likely still broken, but just removing our blanket opt-out makes the current tests pass. * Enable MarshalstructAsLayoutExp off-Windows. * Start adding additional tests for explicit layout to try to catch edge cases in SystemV classification. * Added a test that spans across multiple eightbytes and has an overlap in the second eightbyte. * Change repro to use an array of floats and an int field in managed and use a float array for padding in native to force an SSE classification on the first byte. * New algorithm to calculate eightbyte classification by going throw the structure byte-by-byte instead of field-by-field. * Fix updating eightbyte classifications in the loop to actually used the iterated-upon variable. * Consider each element of a fixed array as a separate field (to match native implementations). * Implement correct SystemV classification for fixed buffers in non-blittable structures. Fixed buffers in blittable structures have the managed layout assign classifications, which still is buggy. * Add tests. * Correctly classify blittable fixed buffers. Move "is this field a fixed buffer" tracking into one of the unused bits in FieldDesc as code that isn't in marshalers needs to know about it. * Handle the case where we have a struct that has no fields in an eightbyte that contains (i.e. no fields in the first eight bytes of the structure). * PR feedback. * Only look up FixedBufferAttribute when the type is a value class and the type of the field is a value type. * Use heuristic to determine if a type is a fixed buffer for SystemV classification. * Revert tracking if a field is a fixed buffer in the FieldDesc. * Update comments. * Classify aligned, nonoverlapping, float/double only structures as HFAs even if explicitly laid out * Enable overlapping fields in HFAs. Update NativeType HFA to check for alignment. I checked Godbolt to verify that HFAs for overlapping fields are allowed. * Add HFA tests. * Fix compile errors from HFA alignment check. * Non-valuetypes will never have their managed layout used to classify SystemV eightbytes. * Don't classify a struct with no zero-offset field as an HFA. * Remove duplicate semicolon. * PR feedback. * Add test with 2-field double HFA. * Clean up and add static asserts for struct size. * Add define for static_assert_no_msg to the native test headers * Fix build breaks. * Remove unneeded "size = X bytes" comments. They were holdovers from the .NET Framework test tree. * Use GetNumInstanceFieldBytes instead of GetLayoutInfo()->GetManagedSize() * Fix build break. * Centralize FieldMarshaler offsettting in ClassifyEightBytesWithNativeLayout. * Fix signed/unsigned mismatch * Fix condition to also detect arm64. * Change ifdef to if defined. * Remove duplicate declaration (broken in rebase) * Add some logging in one of the unreproable OSX test failures. * Mark System.Numerics.Vector as intrinsic and don't use the eightbyte classifier to enregister it. * Also explicitly opt-out of HFAs for System.Numerics.Vector`1 for consistency. * Update R2R required version to 3.0. * Remove debugging prints.
Diffstat (limited to 'tests')
-rw-r--r--tests/src/Common/Platform/platformdefines.h1
-rw-r--r--tests/src/Interop/StructMarshalling/PInvoke/MarshalStructAsLayoutExp.cs105
-rw-r--r--tests/src/Interop/StructMarshalling/PInvoke/MarshalStructAsLayoutExp.csproj6
-rw-r--r--tests/src/Interop/StructMarshalling/PInvoke/MarshalStructAsLayoutSeq.cs110
-rw-r--r--tests/src/Interop/StructMarshalling/PInvoke/MarshalStructAsParamDLL.cpp26
-rw-r--r--tests/src/Interop/StructMarshalling/PInvoke/MarshalStructAsParamDLL.h161
-rw-r--r--tests/src/Interop/StructMarshalling/PInvoke/Struct.cs116
7 files changed, 470 insertions, 55 deletions
diff --git a/tests/src/Common/Platform/platformdefines.h b/tests/src/Common/Platform/platformdefines.h
index 0c2008b9c2..c76983b355 100644
--- a/tests/src/Common/Platform/platformdefines.h
+++ b/tests/src/Common/Platform/platformdefines.h
@@ -27,6 +27,7 @@
#endif
#include <wchar.h>
+#define static_assert_no_msg(x) static_assert((x), #x)
//
// types and constants
diff --git a/tests/src/Interop/StructMarshalling/PInvoke/MarshalStructAsLayoutExp.cs b/tests/src/Interop/StructMarshalling/PInvoke/MarshalStructAsLayoutExp.cs
index 262ec0b1ad..9cffdfaccc 100644
--- a/tests/src/Interop/StructMarshalling/PInvoke/MarshalStructAsLayoutExp.cs
+++ b/tests/src/Interop/StructMarshalling/PInvoke/MarshalStructAsLayoutExp.cs
@@ -15,7 +15,10 @@ public class Managed
ByteStructPack2ExplicitId,
ShortStructPack4ExplicitId,
IntStructPack8ExplicitId,
- LongStructPack16ExplicitId
+ LongStructPack16ExplicitId,
+ OverlappingLongFloatId,
+ OverlappingMultipleEightbyteId,
+ HFAId
}
[SecuritySafeCritical]
@@ -34,7 +37,7 @@ public class Managed
if (failures > 0)
{
Console.WriteLine("\nTEST FAILED!");
- return 101;
+ return 100 + failures;
}
else
{
@@ -209,6 +212,21 @@ public class Managed
[DllImport("MarshalStructAsParam")]
static extern LongStructPack16Explicit GetLongStruct(long l1, long l2);
+ [DllImport("MarshalStructAsParam")]
+ static extern bool MarshalStructAsParam_AsExpByValOverlappingLongFloat(OverlappingLongFloat str, long expected);
+ [DllImport("MarshalStructAsParam")]
+ static extern bool MarshalStructAsParam_AsExpByValOverlappingLongFloat(OverlappingLongFloat2 str, long expected);
+
+ [DllImport("MarshalStructAsParam")]
+ static extern bool MarshalStructAsParam_AsExpByValOverlappingMultipleEightByte(OverlappingMultipleEightbyte str, float i1, float i2, float i3);
+
+ [DllImport("MarshalStructAsParam")]
+ static extern float ProductHFA(ExplicitHFA hfa);
+ [DllImport("MarshalStructAsParam")]
+ static extern float ProductHFA(ExplicitFixedHFA hfa);
+ [DllImport("MarshalStructAsParam")]
+ static extern float ProductHFA(OverlappingHFA hfa);
+
#region Marshal Explicit struct method
[SecuritySafeCritical]
private static void MarshalStructAsParam_AsExpByVal(StructID id)
@@ -351,7 +369,85 @@ public class Managed
{
failures++;
}
- break;
+ break;
+ case StructID.OverlappingLongFloatId:
+ OverlappingLongFloat overlappingLongFloat = new OverlappingLongFloat
+ {
+ l = 12345,
+ f = 12.45f
+ };
+ Console.WriteLine("\tCalling MarshalStructAsParam_AsExpByValOverlappingLongFloat...");
+ if (!MarshalStructAsParam_AsExpByValOverlappingLongFloat(overlappingLongFloat, overlappingLongFloat.l))
+ {
+ Console.WriteLine("\tFAILED! Managed to Native failed in MarshalStructAsParam_AsExpByValOverlappingLongFloat. Expected:True;Actual:False");
+ failures++;
+ }
+ OverlappingLongFloat2 overlappingLongFloat2 = new OverlappingLongFloat2
+ {
+ l = 12345,
+ f = 12.45f
+ };
+ Console.WriteLine("\tCalling MarshalStructAsParam_AsExpByValOverlappingLongFloat (Reversed field order)...");
+ if (!MarshalStructAsParam_AsExpByValOverlappingLongFloat(overlappingLongFloat2, overlappingLongFloat.l))
+ {
+ Console.WriteLine("\tFAILED! Managed to Native failed in MarshalStructAsParam_AsExpByValOverlappingLongFloat. Expected:True;Actual:False");
+ failures++;
+ }
+ break;
+ case StructID.OverlappingMultipleEightbyteId:
+ Console.WriteLine("\tCalling MarshalStructAsParam_AsExpByValOverlappingMultipleEightByte...");
+ OverlappingMultipleEightbyte overlappingMultipleEightbyte = new OverlappingMultipleEightbyte
+ {
+ arr = new float[3] { 1f, 400f, 623289f},
+ i = 1234
+ };
+ if (!MarshalStructAsParam_AsExpByValOverlappingMultipleEightByte(
+ overlappingMultipleEightbyte,
+ overlappingMultipleEightbyte.arr[0],
+ overlappingMultipleEightbyte.arr[1],
+ overlappingMultipleEightbyte.arr[2]))
+ {
+ Console.WriteLine("\tFAILED! Managed to Native failed in MarshalStructAsParam_AsExpByValOverlappingMultipleEightByte. Expected True;Actual:False");
+ failures++;
+ }
+ break;
+ case StructID.HFAId:
+ OverlappingHFA hfa = new OverlappingHFA
+ {
+ hfa = new HFA
+ {
+ f1 = 2.0f,
+ f2 = 10.5f,
+ f3 = 15.2f,
+ f4 = 0.12f
+ }
+ };
+
+ float expected = hfa.hfa.f1 * hfa.hfa.f2 * hfa.hfa.f3 * hfa.hfa.f4;
+ float actual;
+
+ Console.WriteLine("\tCalling ProductHFA with Explicit HFA.");
+ actual = ProductHFA(hfa.explicitHfa);
+ if (expected != actual)
+ {
+ Console.WriteLine($"\tFAILED! Expected {expected}. Actual {actual}");
+ failures++;
+ }
+ Console.WriteLine("\tCalling ProductHFA with Explicit Fixed HFA.");
+ actual = ProductHFA(hfa.explicitFixedHfa);
+ if (expected != actual)
+ {
+ Console.WriteLine($"\tFAILED! Expected {expected}. Actual {actual}");
+ failures++;
+ }
+ Console.WriteLine("\tCalling ProductHFA with Overlapping HFA.");
+ actual = ProductHFA(hfa);
+ if (expected != actual)
+ {
+ Console.WriteLine($"\tFAILED! Expected {expected}. Actual {actual}");
+ failures++;
+ }
+ break;
default:
Console.WriteLine("\tThere is not the struct id");
failures++;
@@ -1464,6 +1560,9 @@ public class Managed
MarshalStructAsParam_AsExpByVal(StructID.ShortStructPack4ExplicitId);
MarshalStructAsParam_AsExpByVal(StructID.IntStructPack8ExplicitId);
MarshalStructAsParam_AsExpByVal(StructID.LongStructPack16ExplicitId);
+ MarshalStructAsParam_AsExpByVal(StructID.OverlappingLongFloatId);
+ MarshalStructAsParam_AsExpByVal(StructID.OverlappingMultipleEightbyteId);
+ MarshalStructAsParam_AsExpByVal(StructID.HFAId);
}
[SecuritySafeCritical]
diff --git a/tests/src/Interop/StructMarshalling/PInvoke/MarshalStructAsLayoutExp.csproj b/tests/src/Interop/StructMarshalling/PInvoke/MarshalStructAsLayoutExp.csproj
index 2a38e61fbe..4f69d9c080 100644
--- a/tests/src/Interop/StructMarshalling/PInvoke/MarshalStructAsLayoutExp.csproj
+++ b/tests/src/Interop/StructMarshalling/PInvoke/MarshalStructAsLayoutExp.csproj
@@ -13,10 +13,6 @@
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<DefineConstants>$(DefineConstants);STATIC</DefineConstants>
<CLRTestPriority>1</CLRTestPriority>
-
- <!-- Test unsupported outside of windows -->
- <TestUnsupportedOutsideWindows>true</TestUnsupportedOutsideWindows>
- <DisableProjectBuild Condition="'$(TargetsUnix)' == 'true'">true</DisableProjectBuild>
</PropertyGroup>
<!-- Default configurations to help VS understand the configurations -->
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|x64'"></PropertyGroup>
@@ -42,4 +38,4 @@
<ProjectReference Include="CMakeLists.txt"></ProjectReference>
</ItemGroup>
<Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.targets))\dir.targets" />
-</Project> \ No newline at end of file
+</Project>
diff --git a/tests/src/Interop/StructMarshalling/PInvoke/MarshalStructAsLayoutSeq.cs b/tests/src/Interop/StructMarshalling/PInvoke/MarshalStructAsLayoutSeq.cs
index 6eb77a44f1..20aa1dfb0f 100644
--- a/tests/src/Interop/StructMarshalling/PInvoke/MarshalStructAsLayoutSeq.cs
+++ b/tests/src/Interop/StructMarshalling/PInvoke/MarshalStructAsLayoutSeq.cs
@@ -27,7 +27,10 @@ public class Managed
IntWithInnerSequentialId,
SequentialWrapperId,
SequentialDoubleWrapperId,
- AggregateSequentialWrapperId
+ AggregateSequentialWrapperId,
+ FixedBufferClassificationTestId,
+ HFAId,
+ DoubleHFAId
}
private static void InitialArray(int[] iarr, int[] icarr)
@@ -318,10 +321,22 @@ public class Managed
static extern bool MarshalStructAsParam_AsSeqByValSequentialAggregateSequentialWrapper(AggregateSequentialWrapper wrapper);
[DllImport("MarshalStructAsParam")]
+ static extern bool MarshalStructAsParam_AsSeqByValFixedBufferClassificationTest(FixedBufferClassificationTest str, float f);
+ [DllImport("MarshalStructAsParam")]
+ static extern bool MarshalStructAsParam_AsSeqByValFixedBufferClassificationTest(FixedBufferClassificationTestBlittable str, float f);
+ [DllImport("MarshalStructAsParam")]
+ static extern bool MarshalStructAsParam_AsSeqByValFixedBufferClassificationTest(FixedArrayClassificationTest str, float f);
+ [DllImport("MarshalStructAsParam")]
static extern int GetStringLength(AutoString str);
[DllImport("MarshalStructAsParam")]
static extern HFA GetHFA(float f1, float f2, float f3, float f4);
+
+ [DllImport("MarshalStructAsParam")]
+ static extern float ProductHFA(HFA hfa);
+
+ [DllImport("MarshalStructAsParam")]
+ static extern double ProductDoubleHFA(DoubleHFA hfa);
[DllImport("MarshalStructAsParam")]
static extern ManyInts GetMultiplesOf(int i);
@@ -617,6 +632,96 @@ public class Managed
failures++;
}
break;
+ case StructID.FixedBufferClassificationTestId:
+ Console.WriteLine("\tCalling MarshalStructAsParam_AsSeqByValFixedBufferClassificationTest with nonblittable struct...");
+ unsafe
+ {
+ FixedBufferClassificationTest str = new FixedBufferClassificationTest();
+ str.arr[0] = 123456;
+ str.arr[1] = 78910;
+ str.arr[2] = 1234;
+ str.f = new NonBlittableFloat(56.789f);
+ if (!MarshalStructAsParam_AsSeqByValFixedBufferClassificationTest(str, str.f.F))
+ {
+ Console.WriteLine("\tFAILED! Managed to Native failed in MarshalStructAsParam_AsSeqByValFixedBufferClassificationTest. Expected:True;Actual:False");
+ failures++;
+ }
+ }
+
+ Console.WriteLine("\tCalling MarshalStructAsParam_AsSeqByValFixedBufferClassificationTest with blittable struct...");
+ unsafe
+ {
+ FixedBufferClassificationTestBlittable str = new FixedBufferClassificationTestBlittable();
+ str.arr[0] = 123456;
+ str.arr[1] = 78910;
+ str.arr[2] = 1234;
+ str.f = 56.789f;
+ if (!MarshalStructAsParam_AsSeqByValFixedBufferClassificationTest(str, str.f))
+ {
+ Console.WriteLine("\tFAILED! Managed to Native failed in MarshalStructAsParam_AsSeqByValFixedBufferClassificationTest. Expected:True;Actual:False");
+ failures++;
+ }
+ }
+
+ Console.WriteLine("\tCalling MarshalStructAsParam_AsSeqByValFixedBufferClassificationTest with fixed array...");
+ FixedArrayClassificationTest fixedArrayTest = new FixedArrayClassificationTest
+ {
+ arr = new Int32Wrapper[3]
+ {
+ new Int32Wrapper { i = 123456 },
+ new Int32Wrapper { i = 78910 },
+ new Int32Wrapper { i = 1234 }
+ },
+ f = 56.789f
+ };
+ if (!MarshalStructAsParam_AsSeqByValFixedBufferClassificationTest(fixedArrayTest, fixedArrayTest.f))
+ {
+ Console.WriteLine("\tFAILED! Managed to Native failed in MarshalStructAsParam_AsSeqByValFixedBufferClassificationTest. Expected:True;Actual:False");
+ failures++;
+ }
+ break;
+ case StructID.HFAId:
+ {
+ HFA hfa = new HFA
+ {
+ f1 = 2.0f,
+ f2 = 10.5f,
+ f3 = 15.2f,
+ f4 = 0.12f
+ };
+
+ float expected = hfa.f1 * hfa.f2 * hfa.f3 * hfa.f4;
+ float actual;
+
+ Console.WriteLine("\tCalling ProductHFA with HFA.");
+ actual = ProductHFA(hfa);
+ if (expected != actual)
+ {
+ Console.WriteLine($"\tFAILED! Expected {expected}. Actual {actual}");
+ failures++;
+ }
+ break;
+ }
+ case StructID.DoubleHFAId:
+ {
+ DoubleHFA doubleHFA = new DoubleHFA
+ {
+ d1 = 123.456,
+ d2 = 456.789
+ };
+
+ double expected = doubleHFA.d1 * doubleHFA.d2;
+ double actual;
+
+ Console.WriteLine("\tCalling ProductDoubleHFA.");
+ actual = ProductDoubleHFA(doubleHFA);
+ if (expected != actual)
+ {
+ Console.WriteLine($"\tFAILED! Expected {expected}. Actual {actual}");
+ failures++;
+ }
+ break;
+ }
default:
Console.WriteLine("\tThere is not the struct id");
failures++;
@@ -2239,6 +2344,9 @@ public class Managed
MarshalStructAsParam_AsSeqByVal(StructID.SequentialWrapperId);
MarshalStructAsParam_AsSeqByVal(StructID.SequentialDoubleWrapperId);
MarshalStructAsParam_AsSeqByVal(StructID.AggregateSequentialWrapperId);
+ MarshalStructAsParam_AsSeqByVal(StructID.FixedBufferClassificationTestId);
+ MarshalStructAsParam_AsSeqByVal(StructID.HFAId);
+ MarshalStructAsParam_AsSeqByVal(StructID.DoubleHFAId);
}
[SecuritySafeCritical]
diff --git a/tests/src/Interop/StructMarshalling/PInvoke/MarshalStructAsParamDLL.cpp b/tests/src/Interop/StructMarshalling/PInvoke/MarshalStructAsParamDLL.cpp
index 9de3f78770..0f2582ab31 100644
--- a/tests/src/Interop/StructMarshalling/PInvoke/MarshalStructAsParamDLL.cpp
+++ b/tests/src/Interop/StructMarshalling/PInvoke/MarshalStructAsParamDLL.cpp
@@ -1178,6 +1178,23 @@ extern "C" DLL_EXPORT BOOL STDMETHODCALLTYPE MarshalStructAsParam_AsExpByRefOutL
return TRUE;
}
+//////////////////////////////////////////////////////////////////////////////////////
+extern "C" DLL_EXPORT BOOL STDMETHODCALLTYPE MarshalStructAsParam_AsExpByValOverlappingLongFloat(OverlappingLongFloat str, LONG64 expected)
+{
+ return str.a == expected;
+}
+
+extern "C" DLL_EXPORT BOOL STDMETHODCALLTYPE MarshalStructAsParam_AsExpByValOverlappingMultipleEightByte(OverlappingMultipleEightbyte str, float i1, float i2, float i3)
+{
+ return str.arr[0] == i1 && str.arr[1] == i2 && str.arr[2] == i3;
+}
+
+extern "C" DLL_EXPORT BOOL STDMETHODCALLTYPE MarshalStructAsParam_AsSeqByValFixedBufferClassificationTest(FixedBufferClassificationTest str, float f)
+{
+ return str.f == f;
+}
+
+////////////////////////////////////////////////////////////////////////////////////
extern "C" DLL_EXPORT int GetStringLength(AutoString str)
{
#ifdef _WIN32
@@ -1187,12 +1204,21 @@ extern "C" DLL_EXPORT int GetStringLength(AutoString str)
#endif
}
+extern "C" DLL_EXPORT float STDMETHODCALLTYPE ProductHFA(HFA hfa)
+{
+ return hfa.f1 * hfa.f2 * hfa.f3 * hfa.f4;
+}
extern "C" DLL_EXPORT HFA STDMETHODCALLTYPE GetHFA(float f1, float f2, float f3, float f4)
{
return {f1, f2, f3, f4};
}
+extern "C" DLL_EXPORT double STDMETHODCALLTYPE ProductDoubleHFA(DoubleHFA hfa)
+{
+ return hfa.d1 * hfa.d2;
+}
+
extern "C" DLL_EXPORT ManyInts STDMETHODCALLTYPE GetMultiplesOf(int value)
{
ManyInts multiples =
diff --git a/tests/src/Interop/StructMarshalling/PInvoke/MarshalStructAsParamDLL.h b/tests/src/Interop/StructMarshalling/PInvoke/MarshalStructAsParamDLL.h
index dcedc46b1e..15d98aecba 100644
--- a/tests/src/Interop/StructMarshalling/PInvoke/MarshalStructAsParamDLL.h
+++ b/tests/src/Interop/StructMarshalling/PInvoke/MarshalStructAsParamDLL.h
@@ -56,12 +56,13 @@ typedef float FLOAT;
typedef double DOUBLE;
#endif
-struct INNER2 // size = 12 bytes
+struct INNER2
{
INT f1;
FLOAT f2;
LPCSTR f3;
};
+
void ChangeINNER2(INNER2* p)
{
p->f1 = 77;
@@ -161,7 +162,7 @@ bool IsCorrectInnerArraySequential(InnerArraySequential* p)
}
-union InnerArrayExplicit // size = 32 bytes
+union InnerArrayExplicit
{
struct InnerSequential arr[2];
struct
@@ -173,34 +174,48 @@ union InnerArrayExplicit // size = 32 bytes
#ifdef WINDOWS
- #ifdef _WIN64
- #pragma warning(push)
- #pragma warning(disable: 4201) // nonstandard extension used: nameless struct/union
- union OUTER3 // size = 32 bytes
- {
- struct InnerSequential arr[2];
- struct
- {
- CHAR _unused0[24];
- LPCSTR f4;
- };
- };
- #pragma warning(pop)
- #else
- struct OUTER3 // size = 28 bytes
- {
- struct InnerSequential arr[2];
- LPCSTR f4;
- };
- #endif
+#ifdef _WIN64
+#pragma warning(push)
+#pragma warning(disable: 4201) // nonstandard extension used: nameless struct/union
+union OUTER3
+{
+ struct InnerSequential arr[2];
+ struct
+ {
+ CHAR _unused0[24];
+ LPCSTR f4;
+ };
+};
+static_assert_no_msg(sizeof(OUTER3) == 32);
+#pragma warning(pop)
+#else
+struct OUTER3
+{
+ struct InnerSequential arr[2];
+ LPCSTR f4;
+};
+static_assert_no_msg(sizeof(OUTER3) == 28);
+#endif
+#else // WINDOWS
+#if defined(__x86_64__) || defined(__aarch64__)
+union OUTER3
+{
+ struct InnerSequential arr[2];
+ struct
+ {
+ CHAR _unused0[24];
+ LPCSTR f4;
+ };
+};
+static_assert_no_msg(sizeof(OUTER3) == 32);
+#else
+struct OUTER3
+{
+ struct InnerSequential arr[2];
+ LPCSTR f4;
+};
+static_assert_no_msg(sizeof(OUTER3) == 28);
#endif
-
-#ifndef WINDOWS
- struct OUTER3 // size = 28 bytes
- {
- struct InnerSequential arr[2];
- LPCSTR f4;
- };
#endif
void PrintOUTER3(OUTER3* p, char const * name)
@@ -326,7 +341,7 @@ bool IsCorrectCharSetUnicodeSequential(CharSetUnicodeSequential* p)
}
-struct NumberSequential // size = 64 bytes
+struct NumberSequential
{
LONG64 i64;
ULONG64 ui64;
@@ -383,7 +398,7 @@ bool IsCorrectNumberSequential(NumberSequential* p)
return true;
}
-struct S3 // size = 1032 bytes
+struct S3
{
BOOL flag;
LPCSTR str;
@@ -434,7 +449,7 @@ bool IsCorrectS3(S3* p)
return true;
}
-struct S4 // size = 8 bytes
+struct S4
{
INT age;
LPCSTR name;
@@ -444,7 +459,7 @@ enum Enum1
e1 = 1,
e2 = 3
};
-struct S5 // size = 8 bytes
+struct S5
{
struct S4 s4;
Enum1 ef;
@@ -471,7 +486,7 @@ bool IsCorrectS5(S5* str)
return true;
}
-struct StringStructSequentialAnsi // size = 8 bytes
+struct StringStructSequentialAnsi
{
LPCSTR first;
LPCSTR last;
@@ -518,7 +533,7 @@ void ChangeStringStructSequentialAnsi(StringStructSequentialAnsi* str)
str->last = newLast;
}
-struct StringStructSequentialUnicode // size = 8 bytes
+struct StringStructSequentialUnicode
{
LPCWSTR first;
LPCWSTR last;
@@ -571,7 +586,7 @@ void ChangeStringStructSequentialUnicode(StringStructSequentialUnicode* str)
}
-struct S8 // size = 32 bytes
+struct S8
{
LPCSTR name;
BOOL gender;
@@ -614,7 +629,7 @@ void ChangeS8(S8* str)
str->mySByte = 64;
}
#pragma pack (8)
-struct S_int // size = 4 bytes
+struct S_int
{
INT i;
};
@@ -622,19 +637,19 @@ struct S_int // size = 4 bytes
struct S9;
typedef void (*TestDelegate1)(struct S9 myStruct);
-struct S9 // size = 8 bytes
+struct S9
{
INT i32;
TestDelegate1 myDelegate1;
};
-struct S101 // size = 8 bytes
+struct S101
{
INT i;
struct S_int s_int;
};
-struct S10 // size = 8 bytes
+struct S10
{
struct S101 s;
};
@@ -661,13 +676,13 @@ void ChangeS10(S10* str)
typedef int* LPINT;
#endif
-struct S11 // size = 8 bytes
+struct S11
{
LPINT i32;
INT i;
};
-union U // size = 8 bytes
+union U
{
INT i32;
UINT ui32;
@@ -724,7 +739,7 @@ bool IsCorrectU(U* p)
return true;
}
-struct ByteStructPack2Explicit // size = 2 bytes
+struct ByteStructPack2Explicit
{
BYTE b1;
BYTE b2;
@@ -749,7 +764,7 @@ bool IsCorrectByteStructPack2Explicit(ByteStructPack2Explicit* p)
-struct ShortStructPack4Explicit // size = 4 bytes
+struct ShortStructPack4Explicit
{
SHORT s1;
SHORT s2;
@@ -773,7 +788,7 @@ bool IsCorrectShortStructPack4Explicit(ShortStructPack4Explicit* p)
}
-struct IntStructPack8Explicit // size = 8 bytes
+struct IntStructPack8Explicit
{
INT i1;
INT i2;
@@ -796,7 +811,7 @@ bool IsCorrectIntStructPack8Explicit(IntStructPack8Explicit* p)
return true;
}
-struct LongStructPack16Explicit // size = 16 bytes
+struct LongStructPack16Explicit
{
LONG64 l1;
LONG64 l2;
@@ -836,6 +851,12 @@ struct HFA
float f4;
};
+struct DoubleHFA
+{
+ double d1;
+ double d2;
+};
+
struct ManyInts
{
int i1;
@@ -888,3 +909,51 @@ struct AggregateSequentialWrapper
InnerSequential sequential;
SequentialWrapper wrapper2;
};
+
+union OverlappingLongFloat
+{
+ LONG64 a;
+ struct
+ {
+ char unused[4];
+ float f;
+ };
+};
+
+struct FixedBufferClassificationTest
+{
+ int arr[3];
+ float f;
+};
+
+// use float padding to ensure that we match the SystemV Classification
+// as if this field was not here (the case in the managed representation).
+union OverlappingMultipleEightbyte
+{
+ float arr[3];
+ struct
+ {
+ float padding[2];
+ int i;
+ };
+};
+
+union OverlappingMultipleEightbyteFirst
+{
+ float arr[3];
+ struct
+ {
+ float padding;
+ int i;
+ };
+};
+
+union OverlappingMultipleEightbyteMultiple
+{
+ float arr[3];
+ struct
+ {
+ float padding;
+ int i[3];
+ };
+};
diff --git a/tests/src/Interop/StructMarshalling/PInvoke/Struct.cs b/tests/src/Interop/StructMarshalling/PInvoke/Struct.cs
index 7ade4c377c..59623ea2c4 100644
--- a/tests/src/Interop/StructMarshalling/PInvoke/Struct.cs
+++ b/tests/src/Interop/StructMarshalling/PInvoke/Struct.cs
@@ -313,6 +313,50 @@ public struct HFA
public float f4;
}
+[StructLayout(LayoutKind.Explicit)]
+public struct ExplicitHFA
+{
+ [FieldOffset(0)]
+ public float f1;
+ [FieldOffset(4)]
+ public float f2;
+ [FieldOffset(8)]
+ public float f3;
+ [FieldOffset(12)]
+ public float f4;
+}
+
+[StructLayout(LayoutKind.Explicit)]
+public unsafe struct ExplicitFixedHFA
+{
+ [FieldOffset(0)]
+ public float f1;
+ [FieldOffset(4)]
+ public float f2;
+ [FieldOffset(8)]
+ public fixed float fs[2];
+}
+
+[StructLayout(LayoutKind.Explicit)]
+public struct OverlappingHFA
+{
+ [FieldOffset(0)]
+ public HFA hfa;
+
+ [FieldOffset(0)]
+ public ExplicitHFA explicitHfa;
+
+ [FieldOffset(0)]
+ public ExplicitFixedHFA explicitFixedHfa;
+}
+
+[StructLayout(LayoutKind.Sequential)]
+public struct DoubleHFA
+{
+ public double d1;
+ public double d2;
+}
+
[StructLayout(LayoutKind.Sequential)]
public struct ManyInts
{
@@ -369,3 +413,75 @@ public struct MultipleBool
public bool b1;
public bool b2;
}
+
+[StructLayout(LayoutKind.Explicit)]
+public struct OverlappingLongFloat
+{
+ [FieldOffset(0)]
+ public long l;
+
+ [FieldOffset(4)]
+ public float f;
+}
+
+[StructLayout(LayoutKind.Explicit)]
+public struct OverlappingLongFloat2
+{
+ [FieldOffset(4)]
+ public float f;
+ [FieldOffset(0)]
+ public long l;
+}
+
+[StructLayout(LayoutKind.Explicit)]
+public struct OverlappingMultipleEightbyte
+{
+ [FieldOffset(8)]
+ public int i;
+ [FieldOffset(0), MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)]
+ public float[] arr;
+}
+
+[StructLayout(LayoutKind.Sequential)]
+public unsafe struct FixedBufferClassificationTestBlittable
+{
+ public fixed int arr[3];
+ public float f;
+}
+
+[StructLayout(LayoutKind.Sequential)]
+public unsafe struct FixedBufferClassificationTest
+{
+ public fixed int arr[3];
+ public NonBlittableFloat f;
+}
+
+// A non-blittable wrapper for a float value.
+// Used to force a type with a float field to be non-blittable
+// and take a different code path.
+[StructLayout(LayoutKind.Sequential)]
+public struct NonBlittableFloat
+{
+ public NonBlittableFloat(float f)
+ {
+ arr = new []{f};
+ }
+
+ [MarshalAs(UnmanagedType.ByValArray, SizeConst = 1)]
+ private float[] arr;
+
+ public float F => arr[0];
+}
+
+public struct Int32Wrapper
+{
+ public int i;
+}
+
+[StructLayout(LayoutKind.Sequential)]
+public unsafe struct FixedArrayClassificationTest
+{
+ [MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)]
+ public Int32Wrapper[] arr;
+ public float f;
+}