Skip to content

Commit a194555

Browse files
authored
Linker to NativeAOT sync (#73380)
Syncs latest linker changes to NativeAOT * Improvements in the compiler generated code space * Fixes a source build problem * Sync the tests which are already enabled in NativeAOT
1 parent d63c65d commit a194555

20 files changed

+718
-231
lines changed

eng/Versions.props

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@
5050
TODO: Remove pinned version once arcade supplies a compiler that enables the repo to compile.
5151
-->
5252
<MicrosoftNetCompilersToolsetVersion>4.4.0-1.22358.14</MicrosoftNetCompilersToolsetVersion>
53-
<StaticCsVersion>0.1.0</StaticCsVersion>
53+
<StaticCsVersion>0.2.0</StaticCsVersion>
5454
<!-- SDK dependencies -->
5555
<MicrosoftDotNetApiCompatTaskVersion>7.0.100-rc.1.22402.1</MicrosoftDotNetApiCompatTaskVersion>
5656
<!-- Arcade dependencies -->

src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/Dataflow/CompilerGeneratedState.cs

Lines changed: 118 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@
77
using System.Diagnostics.CodeAnalysis;
88
using System.Linq;
99
using System.Reflection.Metadata;
10-
using System.Reflection.PortableExecutable;
1110
using ILCompiler.Logging;
1211
using ILLink.Shared;
1312
using Internal.IL;
@@ -111,58 +110,86 @@ void ProcessMethod(MethodDesc method)
111110
while (reader.HasNext)
112111
{
113112
ILOpcode opcode = reader.ReadILOpcode();
114-
MethodDesc? lambdaOrLocalFunction;
115113
switch (opcode)
116114
{
117115
case ILOpcode.ldftn:
118116
case ILOpcode.ldtoken:
119117
case ILOpcode.call:
120118
case ILOpcode.callvirt:
121119
case ILOpcode.newobj:
122-
lambdaOrLocalFunction = methodBody.GetObject(reader.ReadILToken(), NotFoundBehavior.ReturnNull) as MethodDesc;
120+
{
121+
MethodDesc? referencedMethod = methodBody.GetObject(reader.ReadILToken(), NotFoundBehavior.ReturnNull) as MethodDesc;
122+
if (referencedMethod == null)
123+
continue;
124+
125+
referencedMethod = referencedMethod.GetTypicalMethodDefinition();
126+
127+
if (referencedMethod.IsConstructor &&
128+
referencedMethod.OwningType is MetadataType generatedType &&
129+
// Don't consider calls in the same type, like inside a static constructor
130+
method.OwningType != generatedType &&
131+
CompilerGeneratedNames.IsLambdaDisplayClass(generatedType.Name))
132+
{
133+
Debug.Assert(generatedType.IsTypeDefinition);
134+
135+
// fill in null for now, attribute providers will be filled in later
136+
_generatedTypeToTypeArgumentInfo ??= new Dictionary<MetadataType, TypeArgumentInfo>();
137+
138+
if (!_generatedTypeToTypeArgumentInfo.TryAdd(generatedType, new TypeArgumentInfo(method, null)))
139+
{
140+
var alreadyAssociatedMethod = _generatedTypeToTypeArgumentInfo[generatedType].CreatingMethod;
141+
logger?.LogWarning(new MessageOrigin(method), DiagnosticId.MethodsAreAssociatedWithUserMethod, method.GetDisplayName(), alreadyAssociatedMethod.GetDisplayName(), generatedType.GetDisplayName());
142+
}
143+
continue;
144+
}
145+
146+
if (!CompilerGeneratedNames.IsLambdaOrLocalFunction(referencedMethod.Name))
147+
continue;
148+
149+
if (isStateMachineMember)
150+
{
151+
callGraph.TrackCall((MetadataType)method.OwningType, referencedMethod);
152+
}
153+
else
154+
{
155+
callGraph.TrackCall(method, referencedMethod);
156+
}
157+
}
158+
break;
159+
160+
case ILOpcode.stsfld:
161+
{
162+
// Same as above, but stsfld instead of a call to the constructor
163+
FieldDesc? field = methodBody.GetObject(reader.ReadILToken()) as FieldDesc;
164+
if (field == null)
165+
continue;
166+
167+
field = field.GetTypicalFieldDefinition();
168+
169+
if (field.OwningType is MetadataType generatedType &&
170+
// Don't consider field accesses in the same type, like inside a static constructor
171+
method.OwningType != generatedType &&
172+
CompilerGeneratedNames.IsLambdaDisplayClass(generatedType.Name))
173+
{
174+
Debug.Assert(generatedType.IsTypeDefinition);
175+
176+
_generatedTypeToTypeArgumentInfo ??= new Dictionary<MetadataType, TypeArgumentInfo>();
177+
178+
if (!_generatedTypeToTypeArgumentInfo.TryAdd(generatedType, new TypeArgumentInfo(method, null)))
179+
{
180+
// It's expected that there may be multiple methods associated with the same static closure environment.
181+
// All of these methods will substitute the same type arguments into the closure environment
182+
// (if it is generic). Don't warn.
183+
}
184+
continue;
185+
}
186+
}
123187
break;
124188

125189
default:
126-
lambdaOrLocalFunction = null;
127190
reader.Skip(opcode);
128191
break;
129192
}
130-
131-
if (lambdaOrLocalFunction == null)
132-
continue;
133-
134-
lambdaOrLocalFunction = lambdaOrLocalFunction.GetTypicalMethodDefinition();
135-
136-
if (lambdaOrLocalFunction.IsConstructor &&
137-
lambdaOrLocalFunction.OwningType is MetadataType generatedType &&
138-
// Don't consider calls in the same type, like inside a static constructor
139-
method.OwningType != generatedType &&
140-
CompilerGeneratedNames.IsLambdaDisplayClass(generatedType.Name))
141-
{
142-
Debug.Assert(generatedType.IsTypeDefinition);
143-
144-
// fill in null for now, attribute providers will be filled in later
145-
_generatedTypeToTypeArgumentInfo ??= new Dictionary<MetadataType, TypeArgumentInfo>();
146-
147-
if (!_generatedTypeToTypeArgumentInfo.TryAdd(generatedType, new TypeArgumentInfo(method, null)))
148-
{
149-
var alreadyAssociatedMethod = _generatedTypeToTypeArgumentInfo[generatedType].CreatingMethod;
150-
logger?.LogWarning(new MessageOrigin(method), DiagnosticId.MethodsAreAssociatedWithUserMethod, method.GetDisplayName(), alreadyAssociatedMethod.GetDisplayName(), generatedType.GetDisplayName());
151-
}
152-
continue;
153-
}
154-
155-
if (!CompilerGeneratedNames.IsLambdaOrLocalFunction(lambdaOrLocalFunction.Name))
156-
continue;
157-
158-
if (isStateMachineMember)
159-
{
160-
callGraph.TrackCall((MetadataType)method.OwningType, lambdaOrLocalFunction);
161-
}
162-
else
163-
{
164-
callGraph.TrackCall(method, lambdaOrLocalFunction);
165-
}
166193
}
167194
}
168195

@@ -284,15 +311,7 @@ void MapGeneratedTypeTypeParameters(MetadataType generatedType)
284311
Debug.Assert(CompilerGeneratedNames.IsGeneratedType(generatedType.Name));
285312
Debug.Assert(generatedType == generatedType.GetTypeDefinition());
286313

287-
if (_generatedTypeToTypeArgumentInfo?.TryGetValue(generatedType, out var typeInfo) != true)
288-
{
289-
// This can happen for static (non-capturing) closure environments, where more than
290-
// nested function can map to the same closure environment. Since the current functionality
291-
// is based on a one-to-one relationship between environments (types) and methods, this is
292-
// not supported.
293-
return;
294-
}
295-
314+
var typeInfo = _generatedTypeToTypeArgumentInfo[generatedType];
296315
if (typeInfo.OriginalAttributes is not null)
297316
{
298317
return;
@@ -337,11 +356,14 @@ void MapGeneratedTypeTypeParameters(MetadataType generatedType)
337356
{
338357
owningType = (MetadataType)owningType.GetTypeDefinition();
339358
MapGeneratedTypeTypeParameters(owningType);
340-
if (_generatedTypeToTypeArgumentInfo.TryGetValue(owningType, out var owningInfo) &&
341-
owningInfo.OriginalAttributes is { } owningAttrs)
359+
if (_generatedTypeToTypeArgumentInfo[owningType].OriginalAttributes is { } owningAttrs)
342360
{
343361
userAttrs = owningAttrs[param.Index];
344362
}
363+
else
364+
{
365+
Debug.Assert(false, "This should be impossible in valid code");
366+
}
345367
}
346368
}
347369
}
@@ -352,27 +374,67 @@ void MapGeneratedTypeTypeParameters(MetadataType generatedType)
352374
_generatedTypeToTypeArgumentInfo[generatedType] = typeInfo with { OriginalAttributes = typeArgs };
353375
}
354376

355-
MetadataType? ScanForInit(MetadataType stateMachineType, MethodIL body)
377+
MetadataType? ScanForInit(MetadataType compilerGeneratedType, MethodIL body)
356378
{
357379
ILReader reader = new ILReader(body.GetILBytes());
358380
while (reader.HasNext)
359381
{
360382
ILOpcode opcode = reader.ReadILOpcode();
383+
bool handled = false;
384+
MethodDesc? methodOperand = null;
361385
switch (opcode)
362386
{
363-
case ILOpcode.initobj:
364387
case ILOpcode.newobj:
365-
if (body.GetObject(reader.ReadILToken()) is MethodDesc { OwningType: MetadataType owningType }
366-
&& stateMachineType == owningType.GetTypeDefinition())
367388
{
368-
return owningType;
389+
methodOperand = body.GetObject(reader.ReadILToken()) as MethodDesc;
390+
if (methodOperand is MethodDesc { OwningType: MetadataType owningType }
391+
&& compilerGeneratedType == owningType.GetTypeDefinition())
392+
{
393+
return owningType;
394+
}
395+
handled = true;
396+
}
397+
break;
398+
399+
case ILOpcode.ldftn:
400+
case ILOpcode.ldtoken:
401+
case ILOpcode.call:
402+
case ILOpcode.callvirt:
403+
methodOperand = body.GetObject(reader.ReadILToken()) as MethodDesc;
404+
break;
405+
406+
case ILOpcode.stsfld:
407+
{
408+
if (body.GetObject(reader.ReadILToken()) is FieldDesc { OwningType: MetadataType owningType }
409+
&& compilerGeneratedType == owningType.GetTypeDefinition())
410+
{
411+
return owningType;
412+
}
413+
handled = true;
369414
}
370415
break;
371416

372417
default:
373418
reader.Skip(opcode);
374419
break;
375420
}
421+
422+
// Also look for type substitutions into generic methods
423+
// (such as AsyncTaskMethodBuilder::Start<TStateMachine>).
424+
if (!handled && methodOperand is not null)
425+
{
426+
if (methodOperand != methodOperand.GetMethodDefinition())
427+
{
428+
foreach (var tr in methodOperand.Instantiation)
429+
{
430+
if (tr is MetadataType && tr != tr.GetTypeDefinition()
431+
&& compilerGeneratedType == tr.GetTypeDefinition())
432+
{
433+
return tr as MetadataType;
434+
}
435+
}
436+
}
437+
}
376438
}
377439
return null;
378440
}

src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/Dataflow/FlowAnnotations.cs

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,20 @@ public FlowAnnotations(Logger logger, ILProvider ilProvider, CompilerGeneratedSt
4242
}
4343

4444
public bool RequiresDataflowAnalysis(MethodDesc method)
45+
{
46+
try
47+
{
48+
method = method.GetTypicalMethodDefinition();
49+
return GetAnnotations(method.OwningType).TryGetAnnotation(method, out var methodAnnotations)
50+
&& (methodAnnotations.ReturnParameterAnnotation != DynamicallyAccessedMemberTypes.None || methodAnnotations.ParameterAnnotations != null);
51+
}
52+
catch (TypeSystemException)
53+
{
54+
return false;
55+
}
56+
}
57+
58+
public bool RequiresVirtualMethodDataflowAnalysis(MethodDesc method)
4559
{
4660
try
4761
{
@@ -67,6 +81,18 @@ public bool RequiresDataflowAnalysis(FieldDesc field)
6781
}
6882
}
6983

84+
public bool RequiresGenericArgumentDataFlowAnalysis(GenericParameterDesc genericParameter)
85+
{
86+
try
87+
{
88+
return GetGenericParameterAnnotation(genericParameter) != DynamicallyAccessedMemberTypes.None;
89+
}
90+
catch (TypeSystemException)
91+
{
92+
return false;
93+
}
94+
}
95+
7096
public bool HasAnyAnnotations(TypeDesc type)
7197
{
7298
try

0 commit comments

Comments
 (0)