Skip to content

Commit 5f87907

Browse files
[release/9.0] Fix InlineArray swift lowering in mono (#108483)
* Fix lowering support for inline arrays (#107744) * [Swift interop] Add inline array struct lowering tests (#107859) * [swift interop] Add inline array tests * Rename test suite --------- Co-authored-by: Jeff Schwartz <[email protected]>
1 parent 728b131 commit 5f87907

File tree

6 files changed

+302
-2
lines changed

6 files changed

+302
-2
lines changed

src/mono/mono/metadata/marshal.c

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6798,11 +6798,15 @@ static void record_struct_field_physical_lowering (guint8* lowered_bytes, MonoTy
67986798

67996799
static void record_inlinearray_struct_physical_lowering (guint8* lowered_bytes, MonoClass* klass, guint32 offset)
68006800
{
6801+
int align;
6802+
int type_offset = MONO_ABI_SIZEOF (MonoObject);
6803+
68016804
// Get the first field and record its physical lowering N times
6802-
MonoClassField* field = mono_class_get_fields_internal (klass, NULL);
6805+
gpointer iter = NULL;
6806+
MonoClassField* field = mono_class_get_fields_internal (klass, &iter);
68036807
MonoType* fieldType = field->type;
68046808
for (int i = 0; i < m_class_inlinearray_value(klass); ++i) {
6805-
record_struct_field_physical_lowering(lowered_bytes, fieldType, offset + m_field_get_offset(field) + i * mono_type_size(fieldType, NULL));
6809+
record_struct_field_physical_lowering(lowered_bytes, fieldType, offset + m_field_get_offset(field) + i * mono_type_size(fieldType, &align) - type_offset);
68066810
}
68076811
}
68086812

src/tests/Interop/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -110,4 +110,5 @@ if(CLR_CMAKE_TARGET_APPLE)
110110
add_subdirectory(Swift/SwiftInvalidCallConv)
111111
add_subdirectory(Swift/SwiftRetAbiStress)
112112
add_subdirectory(Swift/SwiftSelfContext)
113+
add_subdirectory(Swift/SwiftInlineArray)
113114
endif()
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
project(SwiftInlineArray)
2+
include ("${CLR_INTEROP_TEST_ROOT}/Interop.cmake")
3+
4+
set(SOURCE SwiftInlineArray)
5+
6+
if (NOT SWIFT_COMPILER_TARGET AND CLR_CMAKE_TARGET_APPLE)
7+
set(SWIFT_PLATFORM "macosx")
8+
set(SWIFT_PLATFORM_SUFFIX "")
9+
if (NOT CMAKE_OSX_DEPLOYMENT_TARGET)
10+
set(CMAKE_OSX_DEPLOYMENT_TARGET "12.0")
11+
endif()
12+
set(SWIFT_DEPLOYMENT_TARGET ${CMAKE_OSX_DEPLOYMENT_TARGET})
13+
set(SWIFT_COMPILER_TARGET "${CMAKE_OSX_ARCHITECTURES}-apple-${SWIFT_PLATFORM}${SWIFT_DEPLOYMENT_TARGET}${SWIFT_PLATFORM_SUFFIX}")
14+
endif()
15+
16+
add_custom_target(${SOURCE} ALL
17+
COMMAND xcrun swiftc -target ${SWIFT_COMPILER_TARGET} -emit-library ${CMAKE_CURRENT_SOURCE_DIR}/${SOURCE}.swift -o ${CMAKE_CURRENT_BINARY_DIR}/lib${SOURCE}.dylib
18+
DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/${SOURCE}.swift
19+
COMMENT "Generating ${SOURCE} library"
20+
)
21+
22+
install(FILES ${CMAKE_CURRENT_BINARY_DIR}/lib${SOURCE}.dylib
23+
DESTINATION bin
24+
)
Lines changed: 153 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,153 @@
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+
4+
using System;
5+
using System.Runtime.CompilerServices;
6+
using System.Runtime.InteropServices;
7+
using System.Runtime.InteropServices.Swift;
8+
using Xunit;
9+
10+
public class SwiftInlineArray
11+
{
12+
private const string SwiftLib = "libSwiftInlineArray.dylib";
13+
14+
[InlineArray(32)]
15+
struct F0
16+
{
17+
private byte _element0;
18+
}
19+
20+
[UnmanagedCallConv(CallConvs = new Type[] { typeof(CallConvSwift) })]
21+
[DllImport(SwiftLib, EntryPoint = "$s16SwiftInlineArray10swiftFunc02a0SiAA2F0V_tF")]
22+
private static extern nint SwiftFunc0(F0 a0);
23+
24+
[Fact]
25+
public static unsafe void TestFuncWithByteInlineArray()
26+
{
27+
F0 a0 = default;
28+
byte* ptr = (byte*)&a0;
29+
30+
ptr[0] = (byte)122;
31+
ptr[1] = (byte)223;
32+
ptr[2] = (byte)66;
33+
ptr[3] = (byte)1;
34+
ptr[4] = (byte)135;
35+
ptr[5] = (byte)209;
36+
ptr[6] = (byte)54;
37+
ptr[7] = (byte)221;
38+
ptr[8] = (byte)24;
39+
ptr[9] = (byte)104;
40+
ptr[10] = (byte)21;
41+
ptr[11] = (byte)222;
42+
ptr[12] = (byte)156;
43+
ptr[13] = (byte)241;
44+
ptr[14] = (byte)97;
45+
ptr[15] = (byte)141;
46+
ptr[16] = (byte)239;
47+
ptr[17] = (byte)184;
48+
ptr[18] = (byte)69;
49+
ptr[19] = (byte)247;
50+
ptr[20] = (byte)134;
51+
ptr[21] = (byte)121;
52+
ptr[22] = (byte)204;
53+
ptr[23] = (byte)45;
54+
ptr[24] = (byte)112;
55+
ptr[25] = (byte)166;
56+
ptr[26] = (byte)220;
57+
ptr[27] = (byte)221;
58+
ptr[28] = (byte)86;
59+
ptr[29] = (byte)197;
60+
ptr[30] = (byte)178;
61+
ptr[31] = (byte)29;
62+
63+
64+
long result = SwiftFunc0(a0);
65+
Assert.Equal(8091295595945034296, result);
66+
Console.WriteLine("OK");
67+
}
68+
69+
70+
[InlineArray(8)]
71+
struct F1
72+
{
73+
private int _element0;
74+
}
75+
76+
[UnmanagedCallConv(CallConvs = new Type[] { typeof(CallConvSwift) })]
77+
[DllImport(SwiftLib, EntryPoint = "$s16SwiftInlineArray10swiftFunc12a0SiAA2F1V_tF")]
78+
private static extern nint SwiftFunc1(F1 a0);
79+
80+
[Fact]
81+
public static unsafe void TestFuncWithIntInlineArray()
82+
{
83+
F1 a0 = default;
84+
int* ptr = (int*)&a0;
85+
86+
ptr[0] = (int)-1172606642;
87+
ptr[1] = (int)2004011304;
88+
ptr[2] = (int)-1751053775;
89+
ptr[3] = (int)-1361536584;
90+
ptr[4] = (int)1578364919;
91+
ptr[5] = (int)1205365715;
92+
ptr[6] = (int)-883274792;
93+
ptr[7] = (int)-550660826;
94+
95+
96+
long result = SwiftFunc1(a0);
97+
Assert.Equal(8444261314257660732, result);
98+
Console.WriteLine("OK");
99+
}
100+
101+
[InlineArray(6)]
102+
struct F2
103+
{
104+
private ulong _element0;
105+
}
106+
107+
[UnmanagedCallConv(CallConvs = new Type[] { typeof(CallConvSwift) })]
108+
[DllImport(SwiftLib, EntryPoint = "$s16SwiftInlineArray10swiftFunc22a0SiAA2F2V_tF")]
109+
private static extern nint SwiftFunc2(F2 a0);
110+
111+
[Fact]
112+
public static unsafe void TestFuncWithLargeInlineArray()
113+
{
114+
F2 a0 = default;
115+
ulong* ptr = (ulong*)&a0;
116+
117+
ptr[0] = (ulong)163054281557578879;
118+
ptr[1] = (ulong)3715665182263428629;
119+
ptr[2] = (ulong)15352099497683712058;
120+
ptr[3] = (ulong)9456667702469177637;
121+
ptr[4] = (ulong)5768234261922277852;
122+
ptr[5] = (ulong)17154681812528174574;
123+
124+
125+
long result = SwiftFunc2(a0);
126+
Assert.Equal(-627554439188077294, result);
127+
Console.WriteLine("OK");
128+
}
129+
130+
[InlineArray(1)]
131+
struct F3
132+
{
133+
private byte _element0;
134+
}
135+
136+
[UnmanagedCallConv(CallConvs = new Type[] { typeof(CallConvSwift) })]
137+
[DllImport(SwiftLib, EntryPoint = "$s16SwiftInlineArray10swiftFunc32a0SiAA2F3V_tF")]
138+
private static extern nint SwiftFunc3(F3 a0);
139+
140+
[Fact]
141+
public static unsafe void TestFuncWithSingleElementInlineArray()
142+
{
143+
F3 a0 = default;
144+
byte* ptr = (byte*)&a0;
145+
146+
ptr[0] = (byte)177;
147+
148+
149+
long result = SwiftFunc3(a0);
150+
Assert.Equal(-5808468912223652740, result);
151+
Console.WriteLine("OK");
152+
}
153+
}
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
<Project Sdk="Microsoft.NET.Sdk">
2+
<PropertyGroup>
3+
<!-- Needed for CLRTestTargetUnsupported, CMakeProjectReference -->
4+
<RequiresProcessIsolation>true</RequiresProcessIsolation>
5+
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
6+
<!-- Swift interop is supported on Apple platforms only -->
7+
<CLRTestTargetUnsupported Condition="'$(TargetsOSX)' != 'true' and '$(TargetsAppleMobile)' != 'true'">true</CLRTestTargetUnsupported>
8+
</PropertyGroup>
9+
<ItemGroup>
10+
<Compile Include="$(MSBuildProjectName).cs" />
11+
</ItemGroup>
12+
<ItemGroup>
13+
<ProjectReference Include="$(TestLibraryProjectPath)" />
14+
<CMakeProjectReference Include="CMakeLists.txt" />
15+
</ItemGroup>
16+
</Project>
Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,102 @@
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+
4+
struct HasherFNV1a {
5+
6+
private var hash: UInt = 14_695_981_039_346_656_037
7+
private let prime: UInt = 1_099_511_628_211
8+
9+
mutating func combine<T>(_ val: T) {
10+
for byte in withUnsafeBytes(of: val, Array.init) {
11+
hash ^= UInt(byte)
12+
hash = hash &* prime
13+
}
14+
}
15+
16+
func finalize() -> Int {
17+
Int(truncatingIfNeeded: hash)
18+
}
19+
}
20+
21+
@frozen public struct F0 {
22+
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)
23+
}
24+
25+
public func swiftFunc0(a0: F0) -> Int {
26+
var hasher = HasherFNV1a()
27+
hasher.combine(a0.elements.0);
28+
hasher.combine(a0.elements.1);
29+
hasher.combine(a0.elements.2);
30+
hasher.combine(a0.elements.3);
31+
hasher.combine(a0.elements.4);
32+
hasher.combine(a0.elements.5);
33+
hasher.combine(a0.elements.6);
34+
hasher.combine(a0.elements.7);
35+
hasher.combine(a0.elements.8);
36+
hasher.combine(a0.elements.9);
37+
hasher.combine(a0.elements.10);
38+
hasher.combine(a0.elements.11);
39+
hasher.combine(a0.elements.12);
40+
hasher.combine(a0.elements.13);
41+
hasher.combine(a0.elements.14);
42+
hasher.combine(a0.elements.15);
43+
hasher.combine(a0.elements.16);
44+
hasher.combine(a0.elements.17);
45+
hasher.combine(a0.elements.18);
46+
hasher.combine(a0.elements.19);
47+
hasher.combine(a0.elements.20);
48+
hasher.combine(a0.elements.21);
49+
hasher.combine(a0.elements.22);
50+
hasher.combine(a0.elements.23);
51+
hasher.combine(a0.elements.24);
52+
hasher.combine(a0.elements.25);
53+
hasher.combine(a0.elements.26);
54+
hasher.combine(a0.elements.27);
55+
hasher.combine(a0.elements.28);
56+
hasher.combine(a0.elements.29);
57+
hasher.combine(a0.elements.30);
58+
hasher.combine(a0.elements.31);
59+
return hasher.finalize()
60+
}
61+
62+
@frozen public struct F1 {
63+
public var elements: (Int32, Int32, Int32, Int32, Int32, Int32, Int32, Int32)
64+
}
65+
66+
public func swiftFunc1(a0: F1) -> Int {
67+
var hasher = HasherFNV1a()
68+
hasher.combine(a0.elements.0);
69+
hasher.combine(a0.elements.1);
70+
hasher.combine(a0.elements.2);
71+
hasher.combine(a0.elements.3);
72+
hasher.combine(a0.elements.4);
73+
hasher.combine(a0.elements.5);
74+
hasher.combine(a0.elements.6);
75+
hasher.combine(a0.elements.7);
76+
return hasher.finalize()
77+
}
78+
79+
@frozen public struct F2 {
80+
public var elements: (UInt64, UInt64, UInt64, UInt64, UInt64, UInt64)
81+
}
82+
83+
public func swiftFunc2(a0: F2) -> Int {
84+
var hasher = HasherFNV1a()
85+
hasher.combine(a0.elements.0);
86+
hasher.combine(a0.elements.1);
87+
hasher.combine(a0.elements.2);
88+
hasher.combine(a0.elements.3);
89+
hasher.combine(a0.elements.4);
90+
hasher.combine(a0.elements.5);
91+
return hasher.finalize()
92+
}
93+
94+
@frozen public struct F3 {
95+
public var element: UInt8
96+
}
97+
98+
public func swiftFunc3(a0: F3) -> Int {
99+
var hasher = HasherFNV1a()
100+
hasher.combine(a0.element);
101+
return hasher.finalize()
102+
}

0 commit comments

Comments
 (0)