Skip to content

Commit 4031c97

Browse files
Implement trimming support for the Interop Type Map (#116555)
Co-authored-by: Jackson Schuster <36744439+jtschuster@users.noreply.github.com>
1 parent dcc54b5 commit 4031c97

File tree

19 files changed

+673
-58
lines changed

19 files changed

+673
-58
lines changed

docs/design/features/typemap.md

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -134,7 +134,7 @@ Given the above types the following would take place.
134134
`TypeMapAttribute` assembly attribute that declared the external type system name, a target
135135
type, and optionally a "trim-target" to determine if the target
136136
type should be included in the map. If the `TypeMapAttribute` constructor that doesn't
137-
take a trim-target is used, the "target type" will be treated as the "trim-target".
137+
take a trim-target is used the entry will always be emitted into the type map.
138138

139139
2. Types used in a managed-to-unmanaged interop operation would use `TypeMapAssociationAttribute`
140140
to define a conditional link between the source and proxy type. In other words, if the
@@ -188,14 +188,12 @@ An entry in an External Type Map is included when the "trim target" type is refe
188188
- The argument to the `isinst` IL instruction.
189189
- The argument to the `castclass` IL instruction.
190190
- The argument to the `box` instruction.
191+
- If the trimming tool can determine that this box does not escape and could be stack allocated, it can ignore this `box` instruction and any corresponding `unbox` or `unbox.any` instructions.
191192
- The argument to the `mkrefany` instruction.
192193
- The argument to the `refanyval` instruction.
193194
- The argument to the `newarr` instruction.
194-
- The argument to the `ldobj` instruction.
195-
- The argument to the `stobj` instruction.
196-
- The argument to the `.constrained` instruction prefix.
197-
- The type of a method argument to the `newobj` instruction.
198-
- The owning type of the method argument to `call`, `callvirt`, `ldftn`, or `ldvirtftn`.
195+
- The type of a method argument to the `newobj` instruction if it is a class type.
196+
- The owning type of an instance method argument to `call` or `ldftn`, or the owning type of any method argument to `callvirt` or `ldvirtftn`.
199197
- If the owning type is an interface and the trimming tool can determine that there is only one implementation of the interface, it is free to interpret the method token argument as though it is the method on the only implementing type.
200198
- The generic argument to the `Activator.CreateInstance<T>` method.
201199
- Calls to `Type.GetType` with a constant string representing the type name.
@@ -212,7 +210,6 @@ An entry in the Proxy Type Map is included when the "source type" is referenced
212210
- The generic argument to the `Activator.CreateInstance<T>` method.
213211
- The argument to the `box` instruction.
214212
- The argument to the `newarr` instruction.
215-
- The argument to the `.constrained` instruction prefix.
216213
- The argument to the `mkrefany` instruction.
217214
- The argument to the `refanyval` instruction.
218215

@@ -221,3 +218,5 @@ If the type is an interface type and the user could possibly see a `RuntimeTypeH
221218
- The argument to the `isinst` IL instruction.
222219
- The argument to the `castclass` IL instruction.
223220
- The owning type of the method argument to `callvirt`, or `ldvirtftn`.
221+
222+
Finally, if the trimming tool determines that it is impossible to retrieve a `System.Type` instance the represents the "source type" at runtime, then the entry may be omitted from the Proxy Type Map as its existence is unobservable.

src/coreclr/tools/Common/Compiler/Dataflow/MethodProxy.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ internal partial ParameterProxy GetParameter(ParameterIndex index)
4848

4949
internal partial bool HasGenericParameters() => Method.HasInstantiation;
5050

51-
internal partial bool HasGenericParametersCount(int genericParameterCount) => Method.Instantiation.Length == genericParameterCount;
51+
internal partial bool HasGenericArgumentsCount(int genericArgumentCount) => Method.Instantiation.Length == genericArgumentCount;
5252

5353
internal partial ImmutableArray<GenericParameterProxy> GetGenericParameters()
5454
{

src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/DependencyAnalysis/CustomAttributeBasedDependencyAlgorithm.cs

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -118,9 +118,6 @@ private static void AddDependenciesDueToCustomAttributes(ref DependencyList depe
118118
{
119119
MethodDesc constructor = module.GetMethod(attribute.Constructor);
120120

121-
if (TypeMapManager.LookupTypeMapType(constructor.OwningType) != TypeMapManager.TypeMapAttributeKind.None)
122-
continue;
123-
124121
if (!mdManager.GeneratesAttributeMetadata(constructor.OwningType))
125122
continue;
126123

src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/DependencyAnalysis/ExternalTypeMapNode.cs

Lines changed: 22 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -36,14 +36,29 @@ public override IEnumerable<CombinedDependencyListEntry> GetConditionalStaticDep
3636
foreach (var entry in _mapEntries)
3737
{
3838
var (targetType, trimmingTargetType) = entry.Value;
39-
yield return new CombinedDependencyListEntry(
40-
context.MaximallyConstructableType(targetType),
41-
context.NecessaryTypeSymbol(trimmingTargetType),
42-
"Type in external type map is cast target");
39+
if (trimmingTargetType is not null)
40+
{
41+
yield return new CombinedDependencyListEntry(
42+
context.MaximallyConstructableType(targetType),
43+
context.NecessaryTypeSymbol(trimmingTargetType),
44+
"Type in external type map is cast target");
45+
}
4346
}
4447
}
4548

46-
public override IEnumerable<DependencyListEntry> GetStaticDependencies(NodeFactory context) => [];
49+
public override IEnumerable<DependencyListEntry> GetStaticDependencies(NodeFactory context)
50+
{
51+
foreach (var entry in _mapEntries)
52+
{
53+
var (targetType, trimmingTargetType) = entry.Value;
54+
if (trimmingTargetType is null)
55+
{
56+
yield return new DependencyListEntry(
57+
context.MaximallyConstructableType(targetType),
58+
"External type map entry target type");
59+
}
60+
}
61+
}
4762

4863
public override IEnumerable<CombinedDependencyListEntry> SearchDynamicDependencies(List<DependencyNodeCore<NodeFactory>> markedNodes, int firstNode, NodeFactory context) => Array.Empty<CombinedDependencyListEntry>();
4964
protected override string GetName(NodeFactory context) => $"External type map: {TypeMapGroup}";
@@ -62,7 +77,8 @@ public int CompareToImpl(ISortableNode other, CompilerComparer comparer)
6277
{
6378
var (targetType, trimmingTargetType) = entry.Value;
6479

65-
if (factory.NecessaryTypeSymbol(trimmingTargetType).Marked)
80+
if (trimmingTargetType is null
81+
|| factory.NecessaryTypeSymbol(trimmingTargetType).Marked)
6682
{
6783
IEETypeNode targetNode = factory.MaximallyConstructableType(targetType);
6884
Debug.Assert(targetNode.Marked);

src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/TypeMapMetadata.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -248,7 +248,7 @@ void ProcessTypeMapAttribute(CustomAttributeValue<TypeDesc> attrValue, TypeDesc
248248
{
249249
typeMapStates[typeMapGroup] = typeMapState = new Map(typeMapGroup);
250250
}
251-
typeMapState.AddExternalTypeMapEntry(typeName, targetType, targetType);
251+
typeMapState.AddExternalTypeMapEntry(typeName, targetType, null);
252252
break;
253253
}
254254

src/libraries/System.Private.CoreLib/src/ILLink/ILLink.LinkAttributes.Shared.xml

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,16 @@
11
<linker>
2+
<!-- Type Map attributes will be preserved by NativeAOT or the trimmer when necessary. -->
3+
<assembly fullname="*">
4+
<type fullname="System.Runtime.InteropServices.TypeMapAttribute`1">
5+
<attribute internal="RemoveAttributeInstances" />
6+
</type>
7+
<type fullname="System.Runtime.InteropServices.TypeMapAssociationAttribute`1">
8+
<attribute internal="RemoveAttributeInstances" />
9+
</type>
10+
<type fullname="System.Runtime.InteropServices.TypeMapAssemblyTargetAttribute`1">
11+
<attribute internal="RemoveAttributeInstances" />
12+
</type>
13+
</assembly>
214
<!-- The following attributes are only necessary when debugging is supported -->
315
<assembly fullname="System.Private.CoreLib" feature="System.Diagnostics.Debugger.IsSupported" featurevalue="false">
416
<type fullname="System.Diagnostics.DebuggableAttribute">

src/tools/illink/src/ILLink.RoslynAnalyzer/TrimAnalysis/MethodProxy.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ internal readonly partial struct MethodProxy
3131

3232
internal partial bool HasGenericParameters() => Method.IsGenericMethod;
3333

34-
internal partial bool HasGenericParametersCount(int genericParameterCount) => Method.TypeParameters.Length == genericParameterCount;
34+
internal partial bool HasGenericArgumentsCount(int genericArgumentCount) => Method.TypeArguments.Length == genericArgumentCount;
3535

3636
internal partial ImmutableArray<GenericParameterProxy> GetGenericParameters()
3737
{

src/tools/illink/src/ILLink.Shared/TrimAnalysis/Intrinsics.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -422,13 +422,13 @@ public static IntrinsicId GetIntrinsicIdForMethod(MethodProxy calledMethod)
422422
// static System.Runtime.InteropServices.TypeMapping.GetOrCreateExternalTypeMapping<T> ()
423423
"GetOrCreateExternalTypeMapping" when calledMethod.IsDeclaredOnType("System.Runtime.InteropServices.TypeMapping")
424424
&& calledMethod.IsStatic()
425-
&& calledMethod.HasGenericParametersCount(1)
425+
&& calledMethod.HasGenericArgumentsCount(1)
426426
=> IntrinsicId.TypeMapping_GetOrCreateExternalTypeMapping,
427427

428428
// static System.Runtime.InteropServices.TypeMapping.GetOrCreateProxyTypeMapping<T> ()
429429
"GetOrCreateProxyTypeMapping" when calledMethod.IsDeclaredOnType("System.Runtime.InteropServices.TypeMapping")
430430
&& calledMethod.IsStatic()
431-
&& calledMethod.HasGenericParametersCount(1)
431+
&& calledMethod.HasGenericArgumentsCount(1)
432432
=> IntrinsicId.TypeMapping_GetOrCreateProxyTypeMapping,
433433

434434
_ => IntrinsicId.None,

src/tools/illink/src/ILLink.Shared/TypeSystemProxy/MethodProxy.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,8 +54,8 @@ namespace ILLink.Shared.TypeSystemProxy
5454
internal bool HasParameterOfType(ParameterIndex parameterIndex, string fullTypeName)
5555
=> (int)parameterIndex < GetParametersCount() && GetParameter(parameterIndex).IsTypeOf(fullTypeName);
5656
internal partial bool HasGenericParameters();
57-
internal partial bool HasGenericParametersCount(int genericParameterCount);
5857
internal partial ImmutableArray<GenericParameterProxy> GetGenericParameters();
58+
internal partial bool HasGenericArgumentsCount(int genericArgumentCount);
5959
internal partial bool IsConstructor();
6060
internal partial bool IsStatic();
6161
internal partial bool HasImplicitThis();

src/tools/illink/src/linker/CompatibilitySuppressions.xml

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -869,6 +869,14 @@
869869
<DiagnosticId>CP0002</DiagnosticId>
870870
<Target>M:Mono.Linker.AnnotationStore.TryGetPreservedMembers(Mono.Cecil.TypeDefinition,Mono.Linker.TypePreserveMembers@)</Target>
871871
</Suppression>
872+
<Suppression>
873+
<DiagnosticId>CP0002</DiagnosticId>
874+
<Target>M:Mono.Linker.AnnotationStore.SetEntryPointAssembly(Mono.Cecil.AssemblyDefinition)</Target>
875+
</Suppression>
876+
<Suppression>
877+
<DiagnosticId>CP0002</DiagnosticId>
878+
<Target>M:Mono.Linker.AnnotationStore.GetEntryPointAssembly</Target>
879+
</Suppression>
872880
<Suppression>
873881
<DiagnosticId>CP0002</DiagnosticId>
874882
<Target>M:Mono.Linker.LinkContext.#ctor(Mono.Linker.Pipeline,Mono.Linker.ILogger,System.String,Mono.Linker.UnintializedContextFactory)</Target>
@@ -1561,4 +1569,4 @@
15611569
<DiagnosticId>CP0017</DiagnosticId>
15621570
<Target>M:Mono.Linker.LinkContext.Resolve(Mono.Cecil.AssemblyNameReference)$0</Target>
15631571
</Suppression>
1564-
</Suppressions>
1572+
</Suppressions>

0 commit comments

Comments
 (0)