Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@ private partial bool TryHandleIntrinsic(
}
else
{
_reflectionMarker.RuntimeDeterminedDependencies.Add(new MakeGenericTypeSite(typeInstantiated));
_reflectionMarker.RuntimeDeterminedDependencies.Add((_callingMethod, new MakeGenericTypeSite(typeInstantiated)));
}
}
}
Expand Down Expand Up @@ -160,7 +160,7 @@ private partial bool TryHandleIntrinsic(
}
else
{
_reflectionMarker.RuntimeDeterminedDependencies.Add(new MakeGenericMethodSite(methodInstantiated));
_reflectionMarker.RuntimeDeterminedDependencies.Add((_callingMethod, new MakeGenericMethodSite(methodInstantiated)));
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ public class ReflectionMarker
public NodeFactory Factory { get; }
public FlowAnnotations Annotations { get; }
public DependencyList Dependencies { get => _dependencies; }
public List<INodeWithRuntimeDeterminedDependencies> RuntimeDeterminedDependencies { get; } = new List<INodeWithRuntimeDeterminedDependencies>();
public List<(MethodDesc OwningMethod, INodeWithRuntimeDeterminedDependencies Dependency)> RuntimeDeterminedDependencies { get; } = new List<(MethodDesc, INodeWithRuntimeDeterminedDependencies)>();

internal enum AccessKind
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -124,7 +124,7 @@ protected override void Scan(MethodIL methodIL, ref InterproceduralState interpr
base.Scan(methodIL, ref interproceduralState);
}

public static DependencyList ScanAndProcessReturnValue(NodeFactory factory, FlowAnnotations annotations, Logger logger, MethodIL methodIL, out List<INodeWithRuntimeDeterminedDependencies> runtimeDependencies)
public static DependencyList ScanAndProcessReturnValue(NodeFactory factory, FlowAnnotations annotations, Logger logger, MethodIL methodIL, out List<(MethodDesc OwningMethod, INodeWithRuntimeDeterminedDependencies Dependency)> runtimeDependencies)
{
#if !ILTRIM
methodIL = AsyncMaskingILProvider.WrapIL(methodIL);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ namespace ILCompiler.DependencyAnalysis
public class DataflowAnalyzedMethodNode : DependencyNodeCore<NodeFactory>
{
private readonly MethodIL _methodIL;
private List<INodeWithRuntimeDeterminedDependencies> _runtimeDependencies;
private List<(MethodDesc OwningMethod, INodeWithRuntimeDeterminedDependencies Dependency)> _runtimeDependencies;

public DataflowAnalyzedMethodNode(MethodIL methodIL)
{
Expand All @@ -39,29 +39,30 @@ public override IEnumerable<DependencyListEntry> GetStaticDependencies(NodeFacto
{
// Something wrong with the input - missing references, etc.
// The method body likely won't compile either, so we don't care.
_runtimeDependencies = new List<INodeWithRuntimeDeterminedDependencies>();
_runtimeDependencies = new List<(MethodDesc, INodeWithRuntimeDeterminedDependencies)>();
return Array.Empty<DependencyListEntry>();
}
}

public override IEnumerable<CombinedDependencyListEntry> SearchDynamicDependencies(List<DependencyNodeCore<NodeFactory>> markedNodes, int firstNode, NodeFactory factory)
{
MethodDesc analyzedMethod = _methodIL.OwningMethod;

// Look for any generic specialization of this method. If any are found, specialize any dataflow dependencies.
// Look for any generic specialization of this method or its compiler-generated callees (local methods, lambdas).
// If any are found, specialize the dataflow dependencies that originated from that method.
for (int i = firstNode; i < markedNodes.Count; i++)
{
if (markedNodes[i] is not IMethodBodyNode methodBody)
continue;

MethodDesc method = methodBody.Method;
if (method.GetTypicalMethodDefinition() != analyzedMethod)
continue;
MethodDesc typicalMethod = method.GetTypicalMethodDefinition();

// Instantiate all runtime dependencies for the found generic specialization
// Instantiate runtime dependencies whose owning method matches this method body's typical definition
foreach (var n in _runtimeDependencies)
Comment thread
MichalStrehovsky marked this conversation as resolved.
{
foreach (var d in n.InstantiateDependencies(factory, method.OwningType.Instantiation, method.Instantiation, isConcreteInstantiation: !method.IsSharedByGenericInstantiations))
if (n.OwningMethod != typicalMethod)
continue;

foreach (var d in n.Dependency.InstantiateDependencies(factory, method.OwningType.Instantiation, method.Instantiation, isConcreteInstantiation: !method.IsSharedByGenericInstantiations))
{
yield return new CombinedDependencyListEntry(d.Node, null, d.Reason);
}
Expand Down
23 changes: 23 additions & 0 deletions src/tests/nativeaot/SmokeTests/TrimmingBehaviors/Dataflow.cs
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ public static int Run()
TestMakeGenericConstrainedDataflow.Run();
TestMarshalIntrinsics.Run();
Regression97758.Run();
TestMakeGenericDataflowInLocalMethod.Run();

return 100;
}
Expand Down Expand Up @@ -792,6 +793,28 @@ public static void Run()
Foo<int>.Trigger();
}
}

class TestMakeGenericDataflowInLocalMethod
{
class Gen<T> { }

struct Atom { }

class GenMethods
{
public static void Bridge<T>() { }
}

public static void Run()
{
MakeGenericType<Atom>();
MakeGenericMethod<Atom>();

static object MakeGenericType<T>() => Activator.CreateInstance(typeof(Gen<>).MakeGenericType(typeof(T)));

static void MakeGenericMethod<T>() => typeof(GenMethods).GetMethod(nameof(GenMethods.Bridge)).MakeGenericMethod(typeof(T)).Invoke(null, []);
}
}
}

static class Assert
Expand Down
Loading