Skip to content

Commit e17d2f5

Browse files
github-actions[bot]vitek-karassbomer
authored
[release/8.0] Implement support for InlineArray in the trimmer (#92107)
* Implement support for InlineArray in the trimmer Types annotated with `InlineArray` need to preserve all of their fields, even if otherwise this would not be the case. It's possible to have a struct with `LayoutKind.Auto` and with `InlineArray` - trimmer would normally trim fields on such struct. This leads to corruption since the field is never accessed directly. This changes the marking to preserve all fields on a type with `InlineArray` attribute just like we would for explicit layout struct and similar other types. Adds tests to cover both the explicit usage of `InlineArray` attribute as well as the compiler generate usage via collection literals. * Update src/tools/illink/test/Mono.Linker.Tests.Cases/DataFlow/InlineArrayDataflow.cs Co-authored-by: Sven Boemer <[email protected]> --------- Co-authored-by: vitek-karas <[email protected]> Co-authored-by: Sven Boemer <[email protected]>
1 parent 28e72d2 commit e17d2f5

File tree

11 files changed

+230
-2
lines changed

11 files changed

+230
-2
lines changed

src/coreclr/tools/aot/Mono.Linker.Tests/TestCases/TestDatabase.cs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,11 @@ public static IEnumerable<object[]> Generics ()
2929
return TestNamesBySuiteName ();
3030
}
3131

32+
public static IEnumerable<object[]> InlineArrays ()
33+
{
34+
return TestNamesBySuiteName();
35+
}
36+
3237
public static IEnumerable<object[]> LinkXml()
3338
{
3439
return TestNamesBySuiteName();

src/coreclr/tools/aot/Mono.Linker.Tests/TestCases/TestSuites.cs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,13 @@ public void Generics (string t)
3030
Run (t);
3131
}
3232

33+
[Theory]
34+
[MemberData(nameof(TestDatabase.InlineArrays), MemberType = typeof(TestDatabase))]
35+
public void InlineArrays(string t)
36+
{
37+
Run(t);
38+
}
39+
3340
[Theory]
3441
[MemberData (nameof (TestDatabase.LinkXml), MemberType = typeof (TestDatabase))]
3542
public void LinkXml (string t)

src/coreclr/tools/aot/Mono.Linker.Tests/TestCasesRunner/TestCaseCompilationMetadataProvider.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -129,9 +129,11 @@ public virtual IEnumerable<string> GetCommonReferencedAssemblies (NPath workingD
129129

130130
yield return Path.Combine (referenceDir, "mscorlib.dll");
131131
yield return Path.Combine (referenceDir, "System.Collections.dll");
132+
yield return Path.Combine (referenceDir, "System.Collections.Immutable.dll");
132133
yield return Path.Combine (referenceDir, "System.ComponentModel.TypeConverter.dll");
133134
yield return Path.Combine (referenceDir, "System.Console.dll");
134135
yield return Path.Combine (referenceDir, "System.Linq.Expressions.dll");
136+
yield return Path.Combine (referenceDir, "System.Memory.dll");
135137
yield return Path.Combine (referenceDir, "System.ObjectModel.dll");
136138
yield return Path.Combine (referenceDir, "System.Runtime.dll");
137139
yield return Path.Combine (referenceDir, "System.Runtime.Extensions.dll");

src/tools/illink/src/linker/Linker.Steps/MarkStep.cs

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3317,11 +3317,23 @@ void MarkImplicitlyUsedFields (TypeDefinition type)
33173317
if (type?.HasFields != true)
33183318
return;
33193319

3320-
// keep fields for types with explicit layout and for enums
3321-
if (!type.IsAutoLayout || type.IsEnum)
3320+
// keep fields for types with explicit layout, for enums and for InlineArray types
3321+
if (!type.IsAutoLayout || type.IsEnum || TypeIsInlineArrayType(type))
33223322
MarkFields (type, includeStatic: type.IsEnum, reason: new DependencyInfo (DependencyKind.MemberOfType, type));
33233323
}
33243324

3325+
static bool TypeIsInlineArrayType(TypeDefinition type)
3326+
{
3327+
if (!type.IsValueType)
3328+
return false;
3329+
3330+
foreach (var customAttribute in type.CustomAttributes)
3331+
if (customAttribute.AttributeType.IsTypeOf ("System.Runtime.CompilerServices", "InlineArrayAttribute"))
3332+
return true;
3333+
3334+
return false;
3335+
}
3336+
33253337
protected virtual void MarkRequirementsForInstantiatedTypes (TypeDefinition type)
33263338
{
33273339
if (Annotations.IsInstantiated (type))

src/tools/illink/test/ILLink.RoslynAnalyzer.Tests/DataFlowTests.cs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -149,6 +149,12 @@ public Task GenericParameterDataFlow ()
149149
return RunTest (nameof (GenericParameterDataFlow));
150150
}
151151

152+
[Fact]
153+
public Task InlineArrayDataflow ()
154+
{
155+
return RunTest ();
156+
}
157+
152158
[Fact]
153159
public Task MakeGenericDataFlow ()
154160
{
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
// Copyright (c) .NET Foundation and contributors. All rights reserved.
2+
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
3+
4+
using System.Threading.Tasks;
5+
using Xunit;
6+
7+
namespace ILLink.RoslynAnalyzer.Tests
8+
{
9+
public sealed partial class InlineArraysTests : LinkerTestBase
10+
{
11+
protected override string TestSuiteName => "InlineArrays";
12+
13+
[Fact]
14+
public Task InlineArray ()
15+
{
16+
return RunTest (nameof (InlineArray));
17+
}
18+
19+
}
20+
}
Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
// Copyright (c) .NET Foundation and contributors. All rights reserved.
2+
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
3+
4+
using System;
5+
using System.Collections.Generic;
6+
using System.Diagnostics.CodeAnalysis;
7+
using System.Reflection;
8+
using System.Runtime.CompilerServices;
9+
using Mono.Linker.Tests.Cases.Expectations.Assertions;
10+
11+
namespace Mono.Linker.Tests.Cases.DataFlow
12+
{
13+
[SkipKeptItemsValidation]
14+
[ExpectedNoWarnings]
15+
public class InlineArrayDataflow
16+
{
17+
public static void Main()
18+
{
19+
AccessPrimitiveTypeArray ();
20+
AccessUnannotatedTypeArray ();
21+
AccessAnnotatedTypeArray ();
22+
}
23+
24+
public int TestProperty { get; set; }
25+
26+
[InlineArray (5)]
27+
struct PrimitiveTypeArray
28+
{
29+
public BindingFlags value;
30+
}
31+
32+
// This case will fallback to not understanding the binding flags and will end up marking all properties
33+
static void AccessPrimitiveTypeArray ()
34+
{
35+
PrimitiveTypeArray a = new PrimitiveTypeArray ();
36+
ref var item = ref a[1];
37+
item = BindingFlags.Public;
38+
39+
typeof (InlineArrayDataflow).GetProperty (nameof (TestProperty), a[1]);
40+
}
41+
42+
[InlineArray (5)]
43+
struct UnannotatedTypeArray
44+
{
45+
public Type value;
46+
}
47+
48+
// Analyzer doesn't understand inline arrays currently - so it doesn't produce a warning here
49+
[ExpectedWarning ("IL2065", "GetProperty", ProducedBy = Tool.Trimmer | Tool.NativeAot)]
50+
static void AccessUnannotatedTypeArray ()
51+
{
52+
UnannotatedTypeArray a = new UnannotatedTypeArray ();
53+
ref var item = ref a[2];
54+
item = typeof (InlineArrayDataflow);
55+
56+
a[2].GetProperty (nameof (TestProperty));
57+
}
58+
59+
[InlineArray (5)]
60+
struct AnnotatedTypeArray
61+
{
62+
[DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicProperties)]
63+
public Type value;
64+
}
65+
66+
// Currently tracking of annotations on inline array values is not implemented
67+
[ExpectedWarning("IL2065", "GetProperty", ProducedBy = Tool.Trimmer | Tool.NativeAot)]
68+
static void AccessAnnotatedTypeArray ()
69+
{
70+
AnnotatedTypeArray a = new AnnotatedTypeArray ();
71+
ref var item = ref a[3];
72+
item = typeof (InlineArrayDataflow);
73+
74+
a[3].GetProperty (nameof (TestProperty));
75+
}
76+
}
77+
}
Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
// Copyright (c) .NET Foundation and contributors. All rights reserved.
2+
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
3+
4+
using System.Collections.Immutable;
5+
using System.Runtime.CompilerServices;
6+
using System.Runtime.InteropServices;
7+
using Mono.Linker.Tests.Cases.Expectations.Assertions;
8+
9+
namespace Mono.Linker.Tests.Cases.InlineArrays
10+
{
11+
[ExpectedNoWarnings]
12+
public class InlineArray
13+
{
14+
public static void Main()
15+
{
16+
InlineArrayUsage.Test ();
17+
CollectionLiteralsOfArrays.Test ();
18+
}
19+
20+
[Kept]
21+
class InlineArrayUsage
22+
{
23+
// NativeAOT will remove most of the struct type information as it's not needed
24+
// in the generated native code. Eventually we might come up with a better test infra to validate this.
25+
[Kept (By = Tool.Trimmer)]
26+
public struct StructWithFixedBuffer
27+
{
28+
[Kept (By = Tool.Trimmer)]
29+
public FixedBuffer Buffer;
30+
31+
[Kept (By = Tool.Trimmer)]
32+
[KeptAttributeAttribute (typeof(InlineArrayAttribute), By = Tool.Trimmer)]
33+
[InlineArray (8)]
34+
public partial struct FixedBuffer
35+
{
36+
[Kept (By = Tool.Trimmer)]
37+
public int e0;
38+
}
39+
}
40+
41+
[Kept (By = Tool.Trimmer)]
42+
public struct StructWithAutoLayoutBuffer
43+
{
44+
[Kept (By = Tool.Trimmer)]
45+
public AutoLayoutBuffer Buffer;
46+
47+
[Kept (By = Tool.Trimmer)]
48+
[KeptAttributeAttribute (typeof (InlineArrayAttribute), By = Tool.Trimmer)]
49+
[InlineArray (8)]
50+
[StructLayout (LayoutKind.Auto)]
51+
public struct AutoLayoutBuffer
52+
{
53+
[Kept (By = Tool.Trimmer)]
54+
public int e0;
55+
}
56+
}
57+
58+
[Kept]
59+
public static void Test ()
60+
{
61+
var s = new StructWithFixedBuffer ();
62+
s.Buffer[0] = 5;
63+
64+
var sa = new StructWithAutoLayoutBuffer ();
65+
_ = sa.Buffer[1];
66+
}
67+
}
68+
69+
[Kept]
70+
[KeptMember (".cctor()")]
71+
class CollectionLiteralsOfArrays
72+
{
73+
[Kept]
74+
public static readonly ImmutableArray<string> ImmutableValues = ["one", "two"];
75+
[Kept]
76+
public static readonly string[] ArrayValues = ["one", "two"];
77+
78+
[Kept]
79+
public static void Test()
80+
{
81+
_ = CollectionLiteralsOfArrays.ImmutableValues[0];
82+
_ = CollectionLiteralsOfArrays.ArrayValues[1];
83+
}
84+
}
85+
}
86+
}

src/tools/illink/test/Mono.Linker.Tests/TestCases/TestDatabase.cs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -119,6 +119,11 @@ public static IEnumerable<TestCaseData> InheritanceVirtualMethodsTests ()
119119
return NUnitCasesBySuiteName ("Inheritance.VirtualMethods");
120120
}
121121

122+
public static IEnumerable<TestCaseData> InlineArrayTests ()
123+
{
124+
return NUnitCasesBySuiteName ("InlineArrays");
125+
}
126+
122127
public static IEnumerable<TestCaseData> InteropTests ()
123128
{
124129
return NUnitCasesBySuiteName ("Interop");

src/tools/illink/test/Mono.Linker.Tests/TestCases/TestSuites.cs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -142,6 +142,12 @@ public void InheritanceVirtualMethodsTests (TestCase testCase)
142142
Run (testCase);
143143
}
144144

145+
[TestCaseSource (typeof (TestDatabase), nameof (TestDatabase.InlineArrayTests))]
146+
public void InlineArrayTests (TestCase testCase)
147+
{
148+
Run (testCase);
149+
}
150+
145151
[TestCaseSource (typeof (TestDatabase), nameof (TestDatabase.InteropTests))]
146152
public void InteropTests (TestCase testCase)
147153
{

0 commit comments

Comments
 (0)