From 5dffc010f0746a5d9e0ee95ee9504fbbb1b6cee1 Mon Sep 17 00:00:00 2001
From: Jeremi Kurdek <59935235+jkurdek@users.noreply.github.com>
Date: Fri, 13 Sep 2024 16:12:51 +0200
Subject: [PATCH 1/2] Fix lowering support for inline arrays (#107744)
---
src/mono/mono/metadata/marshal.c | 8 ++++++--
1 file changed, 6 insertions(+), 2 deletions(-)
diff --git a/src/mono/mono/metadata/marshal.c b/src/mono/mono/metadata/marshal.c
index d0e0b2327907c..0ad51eae802a9 100644
--- a/src/mono/mono/metadata/marshal.c
+++ b/src/mono/mono/metadata/marshal.c
@@ -6798,11 +6798,15 @@ static void record_struct_field_physical_lowering (guint8* lowered_bytes, MonoTy
static void record_inlinearray_struct_physical_lowering (guint8* lowered_bytes, MonoClass* klass, guint32 offset)
{
+ int align;
+ int type_offset = MONO_ABI_SIZEOF (MonoObject);
+
// Get the first field and record its physical lowering N times
- MonoClassField* field = mono_class_get_fields_internal (klass, NULL);
+ gpointer iter = NULL;
+ MonoClassField* field = mono_class_get_fields_internal (klass, &iter);
MonoType* fieldType = field->type;
for (int i = 0; i < m_class_inlinearray_value(klass); ++i) {
- record_struct_field_physical_lowering(lowered_bytes, fieldType, offset + m_field_get_offset(field) + i * mono_type_size(fieldType, NULL));
+ record_struct_field_physical_lowering(lowered_bytes, fieldType, offset + m_field_get_offset(field) + i * mono_type_size(fieldType, &align) - type_offset);
}
}
From 5d4c664b63017845757db513486ec670245d3ad3 Mon Sep 17 00:00:00 2001
From: Jeremi Kurdek <59935235+jkurdek@users.noreply.github.com>
Date: Tue, 1 Oct 2024 17:55:59 +0200
Subject: [PATCH 2/2] [Swift interop] Add inline array struct lowering tests
(#107859)
* [swift interop] Add inline array tests
* Rename test suite
---
src/tests/Interop/CMakeLists.txt | 1 +
.../Swift/SwiftInlineArray/CMakeLists.txt | 24 +++
.../SwiftInlineArray/SwiftInlineArray.cs | 153 ++++++++++++++++++
.../SwiftInlineArray/SwiftInlineArray.csproj | 16 ++
.../SwiftInlineArray/SwiftInlineArray.swift | 102 ++++++++++++
5 files changed, 296 insertions(+)
create mode 100644 src/tests/Interop/Swift/SwiftInlineArray/CMakeLists.txt
create mode 100644 src/tests/Interop/Swift/SwiftInlineArray/SwiftInlineArray.cs
create mode 100644 src/tests/Interop/Swift/SwiftInlineArray/SwiftInlineArray.csproj
create mode 100644 src/tests/Interop/Swift/SwiftInlineArray/SwiftInlineArray.swift
diff --git a/src/tests/Interop/CMakeLists.txt b/src/tests/Interop/CMakeLists.txt
index 4a6bca7b8fad8..4137b5ba16df6 100644
--- a/src/tests/Interop/CMakeLists.txt
+++ b/src/tests/Interop/CMakeLists.txt
@@ -110,4 +110,5 @@ if(CLR_CMAKE_TARGET_APPLE)
add_subdirectory(Swift/SwiftInvalidCallConv)
add_subdirectory(Swift/SwiftRetAbiStress)
add_subdirectory(Swift/SwiftSelfContext)
+ add_subdirectory(Swift/SwiftInlineArray)
endif()
diff --git a/src/tests/Interop/Swift/SwiftInlineArray/CMakeLists.txt b/src/tests/Interop/Swift/SwiftInlineArray/CMakeLists.txt
new file mode 100644
index 0000000000000..c8ad8b4654981
--- /dev/null
+++ b/src/tests/Interop/Swift/SwiftInlineArray/CMakeLists.txt
@@ -0,0 +1,24 @@
+project(SwiftInlineArray)
+include ("${CLR_INTEROP_TEST_ROOT}/Interop.cmake")
+
+set(SOURCE SwiftInlineArray)
+
+if (NOT SWIFT_COMPILER_TARGET AND CLR_CMAKE_TARGET_APPLE)
+ set(SWIFT_PLATFORM "macosx")
+ set(SWIFT_PLATFORM_SUFFIX "")
+ if (NOT CMAKE_OSX_DEPLOYMENT_TARGET)
+ set(CMAKE_OSX_DEPLOYMENT_TARGET "12.0")
+ endif()
+ set(SWIFT_DEPLOYMENT_TARGET ${CMAKE_OSX_DEPLOYMENT_TARGET})
+ set(SWIFT_COMPILER_TARGET "${CMAKE_OSX_ARCHITECTURES}-apple-${SWIFT_PLATFORM}${SWIFT_DEPLOYMENT_TARGET}${SWIFT_PLATFORM_SUFFIX}")
+endif()
+
+add_custom_target(${SOURCE} ALL
+ COMMAND xcrun swiftc -target ${SWIFT_COMPILER_TARGET} -emit-library ${CMAKE_CURRENT_SOURCE_DIR}/${SOURCE}.swift -o ${CMAKE_CURRENT_BINARY_DIR}/lib${SOURCE}.dylib
+ DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/${SOURCE}.swift
+ COMMENT "Generating ${SOURCE} library"
+)
+
+install(FILES ${CMAKE_CURRENT_BINARY_DIR}/lib${SOURCE}.dylib
+ DESTINATION bin
+)
diff --git a/src/tests/Interop/Swift/SwiftInlineArray/SwiftInlineArray.cs b/src/tests/Interop/Swift/SwiftInlineArray/SwiftInlineArray.cs
new file mode 100644
index 0000000000000..c3937290d6839
--- /dev/null
+++ b/src/tests/Interop/Swift/SwiftInlineArray/SwiftInlineArray.cs
@@ -0,0 +1,153 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+
+using System;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+using System.Runtime.InteropServices.Swift;
+using Xunit;
+
+public class SwiftInlineArray
+{
+ private const string SwiftLib = "libSwiftInlineArray.dylib";
+
+ [InlineArray(32)]
+ struct F0
+ {
+ private byte _element0;
+ }
+
+ [UnmanagedCallConv(CallConvs = new Type[] { typeof(CallConvSwift) })]
+ [DllImport(SwiftLib, EntryPoint = "$s16SwiftInlineArray10swiftFunc02a0SiAA2F0V_tF")]
+ private static extern nint SwiftFunc0(F0 a0);
+
+ [Fact]
+ public static unsafe void TestFuncWithByteInlineArray()
+ {
+ F0 a0 = default;
+ byte* ptr = (byte*)&a0;
+
+ ptr[0] = (byte)122;
+ ptr[1] = (byte)223;
+ ptr[2] = (byte)66;
+ ptr[3] = (byte)1;
+ ptr[4] = (byte)135;
+ ptr[5] = (byte)209;
+ ptr[6] = (byte)54;
+ ptr[7] = (byte)221;
+ ptr[8] = (byte)24;
+ ptr[9] = (byte)104;
+ ptr[10] = (byte)21;
+ ptr[11] = (byte)222;
+ ptr[12] = (byte)156;
+ ptr[13] = (byte)241;
+ ptr[14] = (byte)97;
+ ptr[15] = (byte)141;
+ ptr[16] = (byte)239;
+ ptr[17] = (byte)184;
+ ptr[18] = (byte)69;
+ ptr[19] = (byte)247;
+ ptr[20] = (byte)134;
+ ptr[21] = (byte)121;
+ ptr[22] = (byte)204;
+ ptr[23] = (byte)45;
+ ptr[24] = (byte)112;
+ ptr[25] = (byte)166;
+ ptr[26] = (byte)220;
+ ptr[27] = (byte)221;
+ ptr[28] = (byte)86;
+ ptr[29] = (byte)197;
+ ptr[30] = (byte)178;
+ ptr[31] = (byte)29;
+
+
+ long result = SwiftFunc0(a0);
+ Assert.Equal(8091295595945034296, result);
+ Console.WriteLine("OK");
+ }
+
+
+ [InlineArray(8)]
+ struct F1
+ {
+ private int _element0;
+ }
+
+ [UnmanagedCallConv(CallConvs = new Type[] { typeof(CallConvSwift) })]
+ [DllImport(SwiftLib, EntryPoint = "$s16SwiftInlineArray10swiftFunc12a0SiAA2F1V_tF")]
+ private static extern nint SwiftFunc1(F1 a0);
+
+ [Fact]
+ public static unsafe void TestFuncWithIntInlineArray()
+ {
+ F1 a0 = default;
+ int* ptr = (int*)&a0;
+
+ ptr[0] = (int)-1172606642;
+ ptr[1] = (int)2004011304;
+ ptr[2] = (int)-1751053775;
+ ptr[3] = (int)-1361536584;
+ ptr[4] = (int)1578364919;
+ ptr[5] = (int)1205365715;
+ ptr[6] = (int)-883274792;
+ ptr[7] = (int)-550660826;
+
+
+ long result = SwiftFunc1(a0);
+ Assert.Equal(8444261314257660732, result);
+ Console.WriteLine("OK");
+ }
+
+ [InlineArray(6)]
+ struct F2
+ {
+ private ulong _element0;
+ }
+
+ [UnmanagedCallConv(CallConvs = new Type[] { typeof(CallConvSwift) })]
+ [DllImport(SwiftLib, EntryPoint = "$s16SwiftInlineArray10swiftFunc22a0SiAA2F2V_tF")]
+ private static extern nint SwiftFunc2(F2 a0);
+
+ [Fact]
+ public static unsafe void TestFuncWithLargeInlineArray()
+ {
+ F2 a0 = default;
+ ulong* ptr = (ulong*)&a0;
+
+ ptr[0] = (ulong)163054281557578879;
+ ptr[1] = (ulong)3715665182263428629;
+ ptr[2] = (ulong)15352099497683712058;
+ ptr[3] = (ulong)9456667702469177637;
+ ptr[4] = (ulong)5768234261922277852;
+ ptr[5] = (ulong)17154681812528174574;
+
+
+ long result = SwiftFunc2(a0);
+ Assert.Equal(-627554439188077294, result);
+ Console.WriteLine("OK");
+ }
+
+ [InlineArray(1)]
+ struct F3
+ {
+ private byte _element0;
+ }
+
+ [UnmanagedCallConv(CallConvs = new Type[] { typeof(CallConvSwift) })]
+ [DllImport(SwiftLib, EntryPoint = "$s16SwiftInlineArray10swiftFunc32a0SiAA2F3V_tF")]
+ private static extern nint SwiftFunc3(F3 a0);
+
+ [Fact]
+ public static unsafe void TestFuncWithSingleElementInlineArray()
+ {
+ F3 a0 = default;
+ byte* ptr = (byte*)&a0;
+
+ ptr[0] = (byte)177;
+
+
+ long result = SwiftFunc3(a0);
+ Assert.Equal(-5808468912223652740, result);
+ Console.WriteLine("OK");
+ }
+}
diff --git a/src/tests/Interop/Swift/SwiftInlineArray/SwiftInlineArray.csproj b/src/tests/Interop/Swift/SwiftInlineArray/SwiftInlineArray.csproj
new file mode 100644
index 0000000000000..89eda99352fd2
--- /dev/null
+++ b/src/tests/Interop/Swift/SwiftInlineArray/SwiftInlineArray.csproj
@@ -0,0 +1,16 @@
+
+
+
+ true
+ true
+
+ true
+
+
+
+
+
+
+
+
+
diff --git a/src/tests/Interop/Swift/SwiftInlineArray/SwiftInlineArray.swift b/src/tests/Interop/Swift/SwiftInlineArray/SwiftInlineArray.swift
new file mode 100644
index 0000000000000..e5ddefd2e1038
--- /dev/null
+++ b/src/tests/Interop/Swift/SwiftInlineArray/SwiftInlineArray.swift
@@ -0,0 +1,102 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+
+struct HasherFNV1a {
+
+ private var hash: UInt = 14_695_981_039_346_656_037
+ private let prime: UInt = 1_099_511_628_211
+
+ mutating func combine(_ val: T) {
+ for byte in withUnsafeBytes(of: val, Array.init) {
+ hash ^= UInt(byte)
+ hash = hash &* prime
+ }
+ }
+
+ func finalize() -> Int {
+ Int(truncatingIfNeeded: hash)
+ }
+}
+
+@frozen public struct F0 {
+ public var elements: (UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8)
+}
+
+public func swiftFunc0(a0: F0) -> Int {
+ var hasher = HasherFNV1a()
+ hasher.combine(a0.elements.0);
+ hasher.combine(a0.elements.1);
+ hasher.combine(a0.elements.2);
+ hasher.combine(a0.elements.3);
+ hasher.combine(a0.elements.4);
+ hasher.combine(a0.elements.5);
+ hasher.combine(a0.elements.6);
+ hasher.combine(a0.elements.7);
+ hasher.combine(a0.elements.8);
+ hasher.combine(a0.elements.9);
+ hasher.combine(a0.elements.10);
+ hasher.combine(a0.elements.11);
+ hasher.combine(a0.elements.12);
+ hasher.combine(a0.elements.13);
+ hasher.combine(a0.elements.14);
+ hasher.combine(a0.elements.15);
+ hasher.combine(a0.elements.16);
+ hasher.combine(a0.elements.17);
+ hasher.combine(a0.elements.18);
+ hasher.combine(a0.elements.19);
+ hasher.combine(a0.elements.20);
+ hasher.combine(a0.elements.21);
+ hasher.combine(a0.elements.22);
+ hasher.combine(a0.elements.23);
+ hasher.combine(a0.elements.24);
+ hasher.combine(a0.elements.25);
+ hasher.combine(a0.elements.26);
+ hasher.combine(a0.elements.27);
+ hasher.combine(a0.elements.28);
+ hasher.combine(a0.elements.29);
+ hasher.combine(a0.elements.30);
+ hasher.combine(a0.elements.31);
+ return hasher.finalize()
+}
+
+@frozen public struct F1 {
+ public var elements: (Int32, Int32, Int32, Int32, Int32, Int32, Int32, Int32)
+}
+
+public func swiftFunc1(a0: F1) -> Int {
+ var hasher = HasherFNV1a()
+ hasher.combine(a0.elements.0);
+ hasher.combine(a0.elements.1);
+ hasher.combine(a0.elements.2);
+ hasher.combine(a0.elements.3);
+ hasher.combine(a0.elements.4);
+ hasher.combine(a0.elements.5);
+ hasher.combine(a0.elements.6);
+ hasher.combine(a0.elements.7);
+ return hasher.finalize()
+}
+
+@frozen public struct F2 {
+ public var elements: (UInt64, UInt64, UInt64, UInt64, UInt64, UInt64)
+}
+
+public func swiftFunc2(a0: F2) -> Int {
+ var hasher = HasherFNV1a()
+ hasher.combine(a0.elements.0);
+ hasher.combine(a0.elements.1);
+ hasher.combine(a0.elements.2);
+ hasher.combine(a0.elements.3);
+ hasher.combine(a0.elements.4);
+ hasher.combine(a0.elements.5);
+ return hasher.finalize()
+}
+
+@frozen public struct F3 {
+ public var element: UInt8
+}
+
+public func swiftFunc3(a0: F3) -> Int {
+ var hasher = HasherFNV1a()
+ hasher.combine(a0.element);
+ return hasher.finalize()
+}