Skip to content

Commit ace8a98

Browse files
authored
Mark forwarders for all TypeReferences (dotnet/linker#2276) (dotnet/linker#2280)
* Build testcases against reference assemblies * Reproduce issue in testcase * Add TypeReferenceMarker * Update one more testcase * Don't mark forwarders in TypeReferenceMarker Leave the logic as before and mark them from MarkStep. * PR feedback - Use ref assemblies for ReferenceAttribute - Avoid adding to common references unless needed by test dependencies Commit migrated from dotnet/linker@ff06442
1 parent 31b1c50 commit ace8a98

22 files changed

+493
-76
lines changed

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

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1385,6 +1385,11 @@ void MarkEntireAssembly (AssemblyDefinition assembly)
13851385
MarkingHelpers.MarkForwardedScope (new TypeReference (exportedType.Namespace, exportedType.Name, module, exportedType.Scope));
13861386
}
13871387

1388+
// Mark scopes of type references by traversing the assembly.
1389+
new TypeReferenceMarker (assembly, MarkingHelpers).Process ();
1390+
1391+
// Also mark the scopes of metadata typeref rows to cover any not discovered by the traversal.
1392+
// This can happen when the compiler emits typerefs into IL which aren't strictly necessary per ECMA 335.
13881393
foreach (TypeReference typeReference in module.GetTypeReferences ())
13891394
MarkingHelpers.MarkForwardedScope (typeReference);
13901395
}
Lines changed: 343 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,343 @@
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+
// See the LICENSE file in the project root for more information.
4+
5+
using System.Collections.Generic;
6+
using Mono.Cecil;
7+
using Mono.Cecil.Cil;
8+
using Mono.Collections.Generic;
9+
10+
namespace Mono.Linker
11+
{
12+
struct TypeReferenceMarker
13+
{
14+
readonly AssemblyDefinition assembly;
15+
readonly MarkingHelpers markingHelpers;
16+
HashSet<TypeReference> visited;
17+
18+
public TypeReferenceMarker (AssemblyDefinition assembly, MarkingHelpers markingHelpers)
19+
{
20+
this.assembly = assembly;
21+
this.markingHelpers = markingHelpers;
22+
visited = null;
23+
}
24+
25+
// Traverse the assembly and mark the scopes of discovered type references (but not exported types).
26+
// This includes scopes referenced by Cecil TypeReference objects that don't represent rows in the typeref table,
27+
// such as references to built-in types, or attribute arguments which encode type references as strings.
28+
public void Process ()
29+
{
30+
visited = new HashSet<TypeReference> ();
31+
32+
WalkCustomAttributesTypesScopes (assembly);
33+
WalkSecurityAttributesTypesScopes (assembly);
34+
35+
foreach (var module in assembly.Modules)
36+
WalkCustomAttributesTypesScopes (module);
37+
38+
var mmodule = assembly.MainModule;
39+
if (mmodule.HasTypes) {
40+
foreach (var type in mmodule.Types) {
41+
WalkScopes (type);
42+
}
43+
}
44+
45+
visited = null;
46+
}
47+
48+
void WalkScopes (TypeDefinition typeDefinition)
49+
{
50+
WalkCustomAttributesTypesScopes (typeDefinition);
51+
WalkSecurityAttributesTypesScopes (typeDefinition);
52+
53+
if (typeDefinition.BaseType != null)
54+
WalkScopeOfTypeReference (typeDefinition.BaseType);
55+
56+
if (typeDefinition.HasInterfaces) {
57+
foreach (var iface in typeDefinition.Interfaces) {
58+
WalkCustomAttributesTypesScopes (iface);
59+
WalkScopeOfTypeReference (iface.InterfaceType);
60+
}
61+
}
62+
63+
if (typeDefinition.HasGenericParameters)
64+
WalkTypeScope (typeDefinition.GenericParameters);
65+
66+
if (typeDefinition.HasEvents) {
67+
foreach (var e in typeDefinition.Events) {
68+
WalkCustomAttributesTypesScopes (e);
69+
// e.EventType is not saved
70+
}
71+
}
72+
73+
if (typeDefinition.HasFields) {
74+
foreach (var f in typeDefinition.Fields) {
75+
WalkCustomAttributesTypesScopes (f);
76+
WalkScopeOfTypeReference (f.FieldType);
77+
WalkMarshalInfoTypeScope (f);
78+
}
79+
}
80+
81+
if (typeDefinition.HasMethods) {
82+
foreach (var m in typeDefinition.Methods) {
83+
WalkCustomAttributesTypesScopes (m);
84+
WalkSecurityAttributesTypesScopes (m);
85+
if (m.HasGenericParameters)
86+
WalkTypeScope (m.GenericParameters);
87+
88+
WalkCustomAttributesTypesScopes (m.MethodReturnType);
89+
WalkScopeOfTypeReference (m.MethodReturnType.ReturnType);
90+
WalkMarshalInfoTypeScope (m.MethodReturnType);
91+
if (m.HasOverrides) {
92+
foreach (var mo in m.Overrides)
93+
WalkMethodReference (mo);
94+
}
95+
96+
if (m.HasParameters)
97+
WalkTypeScope (m.Parameters);
98+
99+
if (m.HasBody)
100+
WalkTypeScope (m.Body);
101+
}
102+
}
103+
104+
if (typeDefinition.HasProperties) {
105+
foreach (var p in typeDefinition.Properties) {
106+
WalkCustomAttributesTypesScopes (p);
107+
// p.PropertyType is not saved
108+
}
109+
}
110+
111+
if (typeDefinition.HasNestedTypes) {
112+
foreach (var nestedType in typeDefinition.NestedTypes) {
113+
WalkScopes (nestedType);
114+
}
115+
}
116+
}
117+
118+
void WalkTypeScope (Collection<GenericParameter> genericParameters)
119+
{
120+
foreach (var gp in genericParameters) {
121+
WalkCustomAttributesTypesScopes (gp);
122+
if (gp.HasConstraints)
123+
WalkTypeScope (gp.Constraints);
124+
}
125+
}
126+
127+
void WalkTypeScope (Collection<GenericParameterConstraint> constraints)
128+
{
129+
foreach (var gc in constraints) {
130+
WalkCustomAttributesTypesScopes (gc);
131+
WalkScopeOfTypeReference (gc.ConstraintType);
132+
}
133+
}
134+
135+
void WalkTypeScope (Collection<ParameterDefinition> parameters)
136+
{
137+
foreach (var p in parameters) {
138+
WalkCustomAttributesTypesScopes (p);
139+
WalkScopeOfTypeReference (p.ParameterType);
140+
WalkMarshalInfoTypeScope (p);
141+
}
142+
}
143+
144+
void WalkTypeScope (MethodBody body)
145+
{
146+
if (body.HasVariables) {
147+
foreach (var v in body.Variables) {
148+
WalkScopeOfTypeReference (v.VariableType);
149+
}
150+
}
151+
152+
if (body.HasExceptionHandlers) {
153+
foreach (var eh in body.ExceptionHandlers) {
154+
if (eh.CatchType != null)
155+
WalkScopeOfTypeReference (eh.CatchType);
156+
}
157+
}
158+
159+
foreach (var instr in body.Instructions) {
160+
switch (instr.OpCode.OperandType) {
161+
162+
case OperandType.InlineMethod: {
163+
var mr = (MethodReference) instr.Operand;
164+
WalkMethodReference (mr);
165+
break;
166+
}
167+
168+
case OperandType.InlineField: {
169+
var fr = (FieldReference) instr.Operand;
170+
WalkFieldReference (fr);
171+
break;
172+
}
173+
174+
case OperandType.InlineTok: {
175+
switch (instr.Operand) {
176+
case TypeReference tr:
177+
WalkScopeOfTypeReference (tr);
178+
break;
179+
case FieldReference fr:
180+
WalkFieldReference (fr);
181+
break;
182+
case MethodReference mr:
183+
WalkMethodReference (mr);
184+
break;
185+
}
186+
187+
break;
188+
}
189+
190+
case OperandType.InlineType: {
191+
var tr = (TypeReference) instr.Operand;
192+
WalkScopeOfTypeReference (tr);
193+
break;
194+
}
195+
}
196+
}
197+
}
198+
199+
void WalkMethodReference (MethodReference mr)
200+
{
201+
WalkScopeOfTypeReference (mr.ReturnType);
202+
WalkScopeOfTypeReference (mr.DeclaringType);
203+
204+
if (mr is GenericInstanceMethod gim) {
205+
foreach (var tr in gim.GenericArguments)
206+
WalkScopeOfTypeReference (tr);
207+
}
208+
209+
if (mr.HasParameters) {
210+
WalkTypeScope (mr.Parameters);
211+
}
212+
}
213+
214+
void WalkFieldReference (FieldReference fr)
215+
{
216+
WalkScopeOfTypeReference (fr.FieldType);
217+
WalkScopeOfTypeReference (fr.DeclaringType);
218+
}
219+
220+
void WalkMarshalInfoTypeScope (IMarshalInfoProvider provider)
221+
{
222+
if (!provider.HasMarshalInfo)
223+
return;
224+
225+
if (provider.MarshalInfo is CustomMarshalInfo cmi)
226+
WalkScopeOfTypeReference (cmi.ManagedType);
227+
}
228+
229+
void WalkCustomAttributesTypesScopes (ICustomAttributeProvider customAttributeProvider)
230+
{
231+
if (!customAttributeProvider.HasCustomAttributes)
232+
return;
233+
234+
foreach (var ca in customAttributeProvider.CustomAttributes)
235+
WalkForwardedTypesScope (ca);
236+
}
237+
238+
void WalkSecurityAttributesTypesScopes (ISecurityDeclarationProvider securityAttributeProvider)
239+
{
240+
if (!securityAttributeProvider.HasSecurityDeclarations)
241+
return;
242+
243+
foreach (var ca in securityAttributeProvider.SecurityDeclarations) {
244+
if (!ca.HasSecurityAttributes)
245+
continue;
246+
247+
foreach (var securityAttribute in ca.SecurityAttributes)
248+
WalkForwardedTypesScope (securityAttribute);
249+
}
250+
}
251+
252+
void WalkForwardedTypesScope (CustomAttribute attribute)
253+
{
254+
WalkMethodReference (attribute.Constructor);
255+
256+
if (attribute.HasConstructorArguments) {
257+
foreach (var ca in attribute.ConstructorArguments)
258+
WalkForwardedTypesScope (ca);
259+
}
260+
261+
if (attribute.HasFields) {
262+
foreach (var field in attribute.Fields)
263+
WalkForwardedTypesScope (field.Argument);
264+
}
265+
266+
if (attribute.HasProperties) {
267+
foreach (var property in attribute.Properties)
268+
WalkForwardedTypesScope (property.Argument);
269+
}
270+
}
271+
272+
void WalkForwardedTypesScope (SecurityAttribute attribute)
273+
{
274+
if (attribute.HasFields) {
275+
foreach (var field in attribute.Fields)
276+
WalkForwardedTypesScope (field.Argument);
277+
}
278+
279+
if (attribute.HasProperties) {
280+
foreach (var property in attribute.Properties)
281+
WalkForwardedTypesScope (property.Argument);
282+
}
283+
}
284+
285+
void WalkForwardedTypesScope (CustomAttributeArgument attributeArgument)
286+
{
287+
WalkScopeOfTypeReference (attributeArgument.Type);
288+
289+
switch (attributeArgument.Value) {
290+
case TypeReference tr:
291+
WalkScopeOfTypeReference (tr);
292+
break;
293+
case CustomAttributeArgument caa:
294+
WalkForwardedTypesScope (caa);
295+
break;
296+
case CustomAttributeArgument[] array:
297+
foreach (var item in array)
298+
WalkForwardedTypesScope (item);
299+
break;
300+
}
301+
}
302+
303+
void WalkScopeOfTypeReference (TypeReference type)
304+
{
305+
if (type == null)
306+
return;
307+
308+
if (!visited.Add (type))
309+
return;
310+
311+
// Don't walk the scope of windows runtime projections
312+
if (type.IsWindowsRuntimeProjection)
313+
return;
314+
315+
switch (type) {
316+
case GenericInstanceType git:
317+
WalkScopeOfTypeReference (git.ElementType);
318+
foreach (var ga in git.GenericArguments)
319+
WalkScopeOfTypeReference (ga);
320+
return;
321+
case FunctionPointerType fpt:
322+
WalkScopeOfTypeReference (fpt.ReturnType);
323+
if (fpt.HasParameters)
324+
WalkTypeScope (fpt.Parameters);
325+
return;
326+
case IModifierType imt:
327+
WalkScopeOfTypeReference (imt.ModifierType);
328+
WalkScopeOfTypeReference (imt.ElementType);
329+
return;
330+
case TypeSpecification ts:
331+
WalkScopeOfTypeReference (ts.ElementType);
332+
return;
333+
case TypeDefinition:
334+
case GenericParameter:
335+
// Nothing to walk
336+
return;
337+
}
338+
339+
markingHelpers.MarkForwardedScope (type);
340+
}
341+
}
342+
343+
}

src/tools/illink/test/Mono.Linker.Tests.Cases/BCLFeatures/ETW/CustomEventSource.cs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,10 @@
1-
using System;
2-
using System.Diagnostics.Tracing;
1+
using System.Diagnostics.Tracing;
32
using Mono.Linker.Tests.Cases.Expectations.Assertions;
3+
using Mono.Linker.Tests.Cases.Expectations.Metadata;
44

55
namespace Mono.Linker.Tests.Cases.BCLFeatures.ETW
66
{
7+
[Reference ("System.Diagnostics.Tracing.dll")]
78
public class CustomEventSource
89
{
910
public static void Main ()

src/tools/illink/test/Mono.Linker.Tests.Cases/BCLFeatures/ETW/CustomLibraryEventSource.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
1-
using System;
2-
using System.Diagnostics.Tracing;
1+
using System.Diagnostics.Tracing;
32
using Mono.Linker.Tests.Cases.Expectations.Assertions;
43
using Mono.Linker.Tests.Cases.Expectations.Metadata;
54

65
namespace Mono.Linker.Tests.Cases.BCLFeatures.ETW
76
{
7+
[Reference ("System.Diagnostics.Tracing.dll")]
88
[SetupLinkerArgument ("-a", "test.exe", "library")]
99
[KeptMember (".ctor()")]
1010
public class CustomLibraryEventSource

0 commit comments

Comments
 (0)