Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/mono/linker.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJackson Schuster <36744439+jtschuster@users.noreply.github.com>2022-08-29 23:13:24 +0300
committerGitHub <noreply@github.com>2022-08-29 23:13:24 +0300
commit45e2e5944abc04763263cc1c4b3f9ed86659ae43 (patch)
tree7b39256652ef565cd71f3704b40e8b831e18c0f8
parentd0462c464774db99f0fb5d8239c81dd39fb97d37 (diff)
Use enum for method parameter indexing (#2993)
This change adds ILParameterIndex to represent the IL-based indexing where 0 may refer to this, and SourceParameterIndex where 0 is the first "real" parameter in C# source code. Converting from ILParameterIndex to SourceParameterIndex returns a SourceParameterKind to differentiate between thisand other parameters and ensure that anySourceParameterIndexwill be able to indexMethodReference.Parameters`. It uses these in ParameterReferenceValue as well as GetMethodParameterValue() and adds a GetMethodThisParameterValue(), ThisParameterReferenceValue, and bubbles the changes where necessary. Most places should use SourceParameterIndex, and convert to ILParameterIndex when necessary or at the boundary of updated and old code.
-rw-r--r--src/ILLink.RoslynAnalyzer/TrimAnalysis/FlowAnnotations.cs8
-rw-r--r--src/ILLink.Shared/ILLink.Shared.projitems2
-rw-r--r--src/ILLink.Shared/SourceParameterIndex.cs19
-rw-r--r--src/ILLink.Shared/TrimAnalysis/FlowAnnotations.cs4
-rw-r--r--src/ILLink.Shared/TrimAnalysis/HandleCallAction.cs6
-rw-r--r--src/linker/BannedSymbols.txt2
-rw-r--r--src/linker/Linker.Dataflow/AttributeDataFlow.cs3
-rw-r--r--src/linker/Linker.Dataflow/FlowAnnotations.cs26
-rw-r--r--src/linker/Linker.Dataflow/MethodBodyScanner.cs103
-rw-r--r--src/linker/Linker.Dataflow/ParameterReferenceValue.cs6
-rw-r--r--src/linker/Linker.Dataflow/ReflectionMethodBodyScanner.cs16
-rw-r--r--src/linker/Linker.Dataflow/ThisParameterReferenceValue.cs16
-rw-r--r--src/linker/Linker/ILParameterIndex.cs22
-rw-r--r--src/linker/Linker/MethodReferenceExtensions.cs15
-rw-r--r--src/linker/Linker/ParameterHelpers.cs88
-rw-r--r--src/linker/Linker/TypeMapInfo.cs4
16 files changed, 247 insertions, 93 deletions
diff --git a/src/ILLink.RoslynAnalyzer/TrimAnalysis/FlowAnnotations.cs b/src/ILLink.RoslynAnalyzer/TrimAnalysis/FlowAnnotations.cs
index 533ef6a83..d3146c157 100644
--- a/src/ILLink.RoslynAnalyzer/TrimAnalysis/FlowAnnotations.cs
+++ b/src/ILLink.RoslynAnalyzer/TrimAnalysis/FlowAnnotations.cs
@@ -94,12 +94,12 @@ namespace ILLink.Shared.TrimAnalysis
internal partial MethodThisParameterValue GetMethodThisParameterValue (MethodProxy method)
=> GetMethodThisParameterValue (method, method.Method.GetDynamicallyAccessedMemberTypes ());
- internal partial MethodParameterValue GetMethodParameterValue (MethodProxy method, int parameterIndex, DynamicallyAccessedMemberTypes dynamicallyAccessedMemberTypes)
- => new MethodParameterValue (method.Method.Parameters[parameterIndex], dynamicallyAccessedMemberTypes);
+ internal partial MethodParameterValue GetMethodParameterValue (MethodProxy method, SourceParameterIndex parameterIndex, DynamicallyAccessedMemberTypes dynamicallyAccessedMemberTypes)
+ => new MethodParameterValue (method.Method.Parameters[(int) parameterIndex], dynamicallyAccessedMemberTypes);
- internal partial MethodParameterValue GetMethodParameterValue (MethodProxy method, int parameterIndex)
+ internal partial MethodParameterValue GetMethodParameterValue (MethodProxy method, SourceParameterIndex parameterIndex)
{
- var annotation = GetMethodParameterAnnotation (method.Method.Parameters[parameterIndex]);
+ var annotation = GetMethodParameterAnnotation (method.Method.Parameters[(int) parameterIndex]);
return GetMethodParameterValue (method, parameterIndex, annotation);
}
#pragma warning restore CA1822
diff --git a/src/ILLink.Shared/ILLink.Shared.projitems b/src/ILLink.Shared/ILLink.Shared.projitems
index 8b16e3778..66dd85465 100644
--- a/src/ILLink.Shared/ILLink.Shared.projitems
+++ b/src/ILLink.Shared/ILLink.Shared.projitems
@@ -23,4 +23,4 @@
<SubType>Designer</SubType>
</None>
</ItemGroup>
-</Project>
+</Project> \ No newline at end of file
diff --git a/src/ILLink.Shared/SourceParameterIndex.cs b/src/ILLink.Shared/SourceParameterIndex.cs
new file mode 100644
index 000000000..ecca20ac6
--- /dev/null
+++ b/src/ILLink.Shared/SourceParameterIndex.cs
@@ -0,0 +1,19 @@
+// Copyright (c) .NET Foundation and contributors. All rights reserved.
+// Licensed under the MIT license. See LICENSE file in the project root for full license information.
+
+namespace ILLink.Shared
+{
+ /// <summary>
+ /// Used to indicate the index of the parameter in source code (i.e. the index is not offset by 1 if there is a `this` parameter)
+ /// This enum and <see cref="T:Mono.Linker.ILParameterIndex"/> is used to enforce a differentiation between scenarios where the 0 index should be `this` and when the 0 index should be the first non-this parameter in the type system.
+ /// There is no way to represent a `this` parameter with a SourceParameterIndex
+ /// </summary>
+ /// <example>
+ /// In a call to a non-static function Foo(int a, int b, int c)
+ /// 0 refers to a,
+ /// 1 refers to b,
+ /// 2 refers to c.
+ /// </example>
+ public enum SourceParameterIndex
+ { }
+}
diff --git a/src/ILLink.Shared/TrimAnalysis/FlowAnnotations.cs b/src/ILLink.Shared/TrimAnalysis/FlowAnnotations.cs
index 7d3912e97..40688f448 100644
--- a/src/ILLink.Shared/TrimAnalysis/FlowAnnotations.cs
+++ b/src/ILLink.Shared/TrimAnalysis/FlowAnnotations.cs
@@ -24,8 +24,8 @@ namespace ILLink.Shared.TrimAnalysis
internal partial MethodThisParameterValue GetMethodThisParameterValue (MethodProxy method);
- internal partial MethodParameterValue GetMethodParameterValue (MethodProxy method, int parameterIndex, DynamicallyAccessedMemberTypes dynamicallyAccessedMemberTypes);
+ internal partial MethodParameterValue GetMethodParameterValue (MethodProxy method, SourceParameterIndex parameterIndex, DynamicallyAccessedMemberTypes dynamicallyAccessedMemberTypes);
- internal partial MethodParameterValue GetMethodParameterValue (MethodProxy method, int parameterIndex);
+ internal partial MethodParameterValue GetMethodParameterValue (MethodProxy method, SourceParameterIndex parameterIndex);
}
} \ No newline at end of file
diff --git a/src/ILLink.Shared/TrimAnalysis/HandleCallAction.cs b/src/ILLink.Shared/TrimAnalysis/HandleCallAction.cs
index dd4334808..934cbd002 100644
--- a/src/ILLink.Shared/TrimAnalysis/HandleCallAction.cs
+++ b/src/ILLink.Shared/TrimAnalysis/HandleCallAction.cs
@@ -631,7 +631,7 @@ namespace ILLink.Shared.TrimAnalysis
// In all other cases we may not even know which type this is about, so there's nothing we can do
// report it as a warning.
_diagnosticContext.AddDiagnostic (DiagnosticId.PropertyAccessorParameterInLinqExpressionsCannotBeStaticallyDetermined,
- _annotations.GetMethodParameterValue (calledMethod, 1, DynamicallyAccessedMemberTypes.None).GetDiagnosticArgumentsForAnnotationMismatch ().ToArray ());
+ _annotations.GetMethodParameterValue (calledMethod, (SourceParameterIndex) 1, DynamicallyAccessedMemberTypes.None).GetDiagnosticArgumentsForAnnotationMismatch ().ToArray ());
}
}
break;
@@ -652,7 +652,7 @@ namespace ILLink.Shared.TrimAnalysis
break;
}
- var targetValue = _annotations.GetMethodParameterValue (calledMethod, 1, memberTypes);
+ var targetValue = _annotations.GetMethodParameterValue (calledMethod, (SourceParameterIndex) 1, memberTypes);
foreach (var value in argumentValues[1]) {
if (value is SystemTypeValue systemTypeValue) {
foreach (var stringParam in argumentValues[2]) {
@@ -1147,7 +1147,7 @@ namespace ILLink.Shared.TrimAnalysis
for (int argumentIndex = 0; argumentIndex < argumentValues.Count; argumentIndex++) {
if (argumentIndex >= calledMethod.GetParametersCount () || calledMethod.ParameterReferenceKind (argumentIndex) == ReferenceKind.Out)
continue;
- _requireDynamicallyAccessedMembersAction.Invoke (argumentValues[argumentIndex], _annotations.GetMethodParameterValue (calledMethod, argumentIndex));
+ _requireDynamicallyAccessedMembersAction.Invoke (argumentValues[argumentIndex], _annotations.GetMethodParameterValue (calledMethod, (SourceParameterIndex) argumentIndex));
}
}
break;
diff --git a/src/linker/BannedSymbols.txt b/src/linker/BannedSymbols.txt
index c39f451ee..6ef58b3b0 100644
--- a/src/linker/BannedSymbols.txt
+++ b/src/linker/BannedSymbols.txt
@@ -1,2 +1,4 @@
T:Mono.Cecil.Cil.ILProcessor;Use LinkerILProcessor instead
M:Mono.Cecil.TypeReference.Resolve();Use LinkContext.Resolve and LinkContext.TryResolve helpers instead
+P:Mono.Collections.Generic.Collection`1{Mono.Cecil.ParameterDefinition}.Item(System.Int32); use x
+P:Mono.Cecil.ParameterDefinitionCollection.Item(System.Int32); use x
diff --git a/src/linker/Linker.Dataflow/AttributeDataFlow.cs b/src/linker/Linker.Dataflow/AttributeDataFlow.cs
index 3ed11d392..5dccfe2b1 100644
--- a/src/linker/Linker.Dataflow/AttributeDataFlow.cs
+++ b/src/linker/Linker.Dataflow/AttributeDataFlow.cs
@@ -4,6 +4,7 @@
using System;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
+using ILLink.Shared;
using ILLink.Shared.TrimAnalysis;
using Mono.Cecil;
using Mono.Linker.Steps;
@@ -27,7 +28,7 @@ namespace Mono.Linker.Dataflow
public void ProcessAttributeDataflow (MethodDefinition method, IList<CustomAttributeArgument> arguments)
{
for (int i = 0; i < method.Parameters.Count; i++) {
- var parameterValue = _context.Annotations.FlowAnnotations.GetMethodParameterValue (method, i);
+ var parameterValue = _context.Annotations.FlowAnnotations.GetMethodParameterValue (method, (SourceParameterIndex)i);
if (parameterValue.DynamicallyAccessedMemberTypes != DynamicallyAccessedMemberTypes.None) {
MultiValue value = GetValueForCustomAttributeArgument (arguments[i]);
var diagnosticContext = new DiagnosticContext (_origin, diagnosticsEnabled: true, _context);
diff --git a/src/linker/Linker.Dataflow/FlowAnnotations.cs b/src/linker/Linker.Dataflow/FlowAnnotations.cs
index 472f8567f..e7ed760df 100644
--- a/src/linker/Linker.Dataflow/FlowAnnotations.cs
+++ b/src/linker/Linker.Dataflow/FlowAnnotations.cs
@@ -45,11 +45,23 @@ namespace ILLink.Shared.TrimAnalysis
/// </summary>
/// <param name="parameterIndex">Parameter index in the IL sense. Parameter 0 on instance methods is `this`.</param>
/// <returns></returns>
- public DynamicallyAccessedMemberTypes GetParameterAnnotation (MethodDefinition method, int parameterIndex)
+ public DynamicallyAccessedMemberTypes GetParameterAnnotation (MethodDefinition method, SourceParameterIndex parameterIndex)
{
if (GetAnnotations (method.DeclaringType).TryGetAnnotation (method, out var annotation) &&
annotation.ParameterAnnotations != null)
- return annotation.ParameterAnnotations[parameterIndex];
+ return annotation.ParameterAnnotations[(int) ParameterHelpers.GetILParameterIndex (method, parameterIndex)];
+
+ return DynamicallyAccessedMemberTypes.None;
+ }
+
+ public DynamicallyAccessedMemberTypes GetThisParameterAnnotation (MethodDefinition method)
+ {
+ if (!method.HasThis)
+ throw new InvalidOperationException ($"Cannot get annotation of `this` of method {method.FullName} without `this`");
+
+ if (GetAnnotations (method.DeclaringType).TryGetAnnotation (method, out var annotation) &&
+ annotation.ParameterAnnotations != null)
+ return annotation.ParameterAnnotations[0];
return DynamicallyAccessedMemberTypes.None;
}
@@ -704,13 +716,13 @@ namespace ILLink.Shared.TrimAnalysis
#pragma warning restore CA1822
internal partial MethodThisParameterValue GetMethodThisParameterValue (MethodProxy method)
- => GetMethodThisParameterValue (method, GetParameterAnnotation (method.Method, 0));
+ => GetMethodThisParameterValue (method, GetThisParameterAnnotation (method.Method));
- internal partial MethodParameterValue GetMethodParameterValue (MethodProxy method, int parameterIndex, DynamicallyAccessedMemberTypes dynamicallyAccessedMemberTypes)
- => new (method.Method.Parameters[parameterIndex].ParameterType.ResolveToTypeDefinition (_context), method.Method, parameterIndex, dynamicallyAccessedMemberTypes);
+ internal partial MethodParameterValue GetMethodParameterValue (MethodProxy method, SourceParameterIndex parameterIndex, DynamicallyAccessedMemberTypes dynamicallyAccessedMemberTypes)
+ => new (method.Method.Parameters[(int) parameterIndex].ParameterType.ResolveToTypeDefinition (_context), method.Method, (int) parameterIndex, dynamicallyAccessedMemberTypes);
- internal partial MethodParameterValue GetMethodParameterValue (MethodProxy method, int parameterIndex)
- => GetMethodParameterValue (method, parameterIndex, GetParameterAnnotation (method.Method, parameterIndex + (method.IsStatic () ? 0 : 1)));
+ internal partial MethodParameterValue GetMethodParameterValue (MethodProxy method, SourceParameterIndex parameterIndex)
+ => GetMethodParameterValue (method, parameterIndex, GetParameterAnnotation (method.Method, parameterIndex));
// Linker-specific dataflow value creation. Eventually more of these should be shared.
internal SingleValue GetFieldValue (FieldDefinition field)
diff --git a/src/linker/Linker.Dataflow/MethodBodyScanner.cs b/src/linker/Linker.Dataflow/MethodBodyScanner.cs
index 2e3f09d6c..179ac10bb 100644
--- a/src/linker/Linker.Dataflow/MethodBodyScanner.cs
+++ b/src/linker/Linker.Dataflow/MethodBodyScanner.cs
@@ -16,6 +16,7 @@ using LocalVariableStore = System.Collections.Generic.Dictionary<
Mono.Cecil.Cil.VariableDefinition,
Mono.Linker.Dataflow.ValueBasicBlockPair>;
using MultiValue = ILLink.Shared.DataFlow.ValueSet<ILLink.Shared.DataFlow.SingleValue>;
+using static Mono.Linker.ParameterHelpers;
namespace Mono.Linker.Dataflow
{
@@ -402,7 +403,7 @@ namespace Mono.Linker.Dataflow
case Code.Ldarg_S:
case Code.Ldarga:
case Code.Ldarga_S:
- ScanLdarg (operation, currentStack, thisMethod, methodBody);
+ ScanLdarg (operation, currentStack, thisMethod);
break;
case Code.Ldloc:
@@ -717,53 +718,35 @@ namespace Mono.Linker.Dataflow
}
}
- protected abstract SingleValue GetMethodParameterValue (MethodDefinition method, int parameterIndex);
+ protected abstract SingleValue GetMethodParameterValue (MethodDefinition method, SourceParameterIndex parameterIndex);
- private void ScanLdarg (Instruction operation, Stack<StackSlot> currentStack, MethodDefinition thisMethod, MethodBody methodBody)
+ protected abstract SingleValue GetMethodThisParameterValue (MethodDefinition method);
+
+ private void ScanLdarg (Instruction operation, Stack<StackSlot> currentStack, MethodDefinition thisMethod)
{
Code code = operation.OpCode.Code;
+ bool isByRef = code == Code.Ldarga || code == Code.Ldarga_S;
- bool isByRef;
-
- // Thank you Cecil, Operand being a ParameterDefinition instead of an integer,
- // (except for Ldarg_0 - Ldarg_3, where it's null) makes all of this really convenient...
- // NOT.
- int paramNum;
- if (code >= Code.Ldarg_0 &&
- code <= Code.Ldarg_3) {
- paramNum = code - Code.Ldarg_0;
-
- if (thisMethod.HasImplicitThis ()) {
- if (paramNum == 0) {
- isByRef = thisMethod.DeclaringType.IsValueType;
- } else {
- isByRef = thisMethod.Parameters[paramNum - 1].ParameterType.IsByRefOrPointer ();
- }
- } else {
- isByRef = thisMethod.Parameters[paramNum].ParameterType.IsByRefOrPointer ();
- }
- } else {
- var paramDefinition = (ParameterDefinition) operation.Operand;
- if (thisMethod.HasImplicitThis ()) {
- if (paramDefinition == methodBody.ThisParameter) {
- paramNum = 0;
- } else {
- paramNum = paramDefinition.Index + 1;
- }
- } else {
- paramNum = paramDefinition.Index;
- }
-
+ SingleValue valueToPush;
+ switch (GetSourceParameterIndex (thisMethod, operation, out var sourceIndex)) {
+ case SourceParameterKind.Numbered:
// This is semantically wrong if it returns true - we would representing a reference parameter as a reference to a parameter - but it should be fine for now
- isByRef = paramDefinition.ParameterType.IsByRefOrPointer ();
+ isByRef |= thisMethod.GetParameterType (sourceIndex).IsByRefOrPointer ();
+ valueToPush = isByRef
+ ? new ParameterReferenceValue (thisMethod, sourceIndex)
+ : GetMethodParameterValue (thisMethod, sourceIndex);
+ break;
+ case SourceParameterKind.This:
+ isByRef |= thisMethod.DeclaringType.IsValueType;
+ valueToPush = isByRef
+ ? new ThisParameterReferenceValue (thisMethod)
+ : GetMethodThisParameterValue (thisMethod);
+ break;
+ default:
+ throw new InvalidOperationException ("Unexpected IParameterIndex type");
}
- isByRef |= code == Code.Ldarga || code == Code.Ldarga_S;
-
- StackSlot slot = new StackSlot (
- isByRef
- ? new ParameterReferenceValue (thisMethod, paramNum)
- : GetMethodParameterValue (thisMethod, paramNum));
+ StackSlot slot = new StackSlot (valueToPush);
currentStack.Push (slot);
}
@@ -773,13 +756,19 @@ namespace Mono.Linker.Dataflow
MethodDefinition thisMethod,
MethodBody methodBody)
{
- ParameterDefinition param = (ParameterDefinition) operation.Operand;
var valueToStore = PopUnknown (currentStack, 1, methodBody, operation.Offset);
- var targetValue = GetMethodParameterValue (thisMethod, param.Sequence);
- if (targetValue is MethodParameterValue targetParameterValue)
- HandleStoreParameter (thisMethod, targetParameterValue, operation, valueToStore.Value);
-
+ switch (GetSourceParameterIndex (thisMethod, operation, out var sourceParameterIndex)) {
+ case SourceParameterKind.Numbered:
+ var targetValue = GetMethodParameterValue (thisMethod, sourceParameterIndex);
+ if (targetValue is MethodParameterValue targetParameterValue)
+ HandleStoreParameter (thisMethod, targetParameterValue, operation, valueToStore.Value);
+ break;
// If the targetValue is MethodThisValue do nothing - it should never happen really, and if it does, there's nothing we can track there
+ case SourceParameterKind.This:
+ break;
+ default:
+ break;
+ }
}
private void ScanLdloc (
@@ -899,8 +888,8 @@ namespace Mono.Linker.Dataflow
when GetMethodParameterValue (parameterReference.MethodDefinition, parameterReference.ParameterIndex) is MethodParameterValue parameterValue:
HandleStoreParameter (method, parameterValue, operation, source);
break;
- case ParameterReferenceValue parameterReference
- when GetMethodParameterValue (parameterReference.MethodDefinition, parameterReference.ParameterIndex) is MethodThisParameterValue thisParameterValue:
+ case ThisParameterReferenceValue parameterReference
+ when GetMethodThisParameterValue (parameterReference.MethodDefinition) is MethodThisParameterValue thisParameterValue:
HandleStoreMethodThisParameter (method, thisParameterValue, operation, source);
break;
case MethodReturnValue methodReturnValue:
@@ -1069,6 +1058,11 @@ namespace Mono.Linker.Dataflow
else
dereferencedValue = MultiValue.Meet (dereferencedValue, UnknownValue.Instance);
break;
+ case ThisParameterReferenceValue thisParameterReferenceValue:
+ dereferencedValue = MultiValue.Meet (
+ dereferencedValue,
+ GetMethodThisParameterValue (thisParameterReferenceValue.MethodDefinition));
+ break;
case ReferenceValue referenceValue:
throw new NotImplementedException ($"Unhandled dereference of ReferenceValue of type {referenceValue.GetType ().FullName}");
// Incomplete handling for ref values
@@ -1097,15 +1091,16 @@ namespace Mono.Linker.Dataflow
{
MethodDefinition? calledMethodDefinition = _context.Resolve (calledMethod);
bool methodIsResolved = calledMethodDefinition is not null;
- int offset = calledMethod.HasImplicitThis () ? 1 : 0;
- int parameterIndex = 0;
- for (int ilArgumentIndex = offset; ilArgumentIndex < methodArguments.Count; ilArgumentIndex++, parameterIndex++) {
- if (calledMethod.ParameterReferenceKind (ilArgumentIndex) is not (ReferenceKind.Ref or ReferenceKind.Out))
+ ILParameterIndex ilArgumentIndex;
+ for (SourceParameterIndex parameterIndex = 0; (int) parameterIndex < calledMethod.Parameters.Count; parameterIndex++) {
+ ilArgumentIndex = GetILParameterIndex (calledMethod, parameterIndex);
+
+ if (calledMethod.ParameterReferenceKind ((int) ilArgumentIndex) is not (ReferenceKind.Ref or ReferenceKind.Out))
continue;
- SingleValue newByRefValue = methodIsResolved && parameterIndex < calledMethodDefinition!.Parameters.Count
+ SingleValue newByRefValue = methodIsResolved && (int)parameterIndex < calledMethodDefinition!.Parameters.Count
? _context.Annotations.FlowAnnotations.GetMethodParameterValue (calledMethodDefinition!, parameterIndex)
: UnknownValue.Instance;
- StoreInReference (methodArguments[ilArgumentIndex], newByRefValue, callingMethodBody.Method, operation, locals, curBasicBlock, ref ipState);
+ StoreInReference (methodArguments[(int) ilArgumentIndex], newByRefValue, callingMethodBody.Method, operation, locals, curBasicBlock, ref ipState);
}
}
diff --git a/src/linker/Linker.Dataflow/ParameterReferenceValue.cs b/src/linker/Linker.Dataflow/ParameterReferenceValue.cs
index 79bdfdeab..853b31664 100644
--- a/src/linker/Linker.Dataflow/ParameterReferenceValue.cs
+++ b/src/linker/Linker.Dataflow/ParameterReferenceValue.cs
@@ -2,13 +2,11 @@
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
using ILLink.Shared.DataFlow;
using Mono.Cecil;
-using Mono.Linker;
namespace ILLink.Shared.TrimAnalysis
{
- public partial record ParameterReferenceValue (MethodDefinition MethodDefinition, int ParameterIndex)
- : ReferenceValue (MethodDefinition.HasImplicitThis () && ParameterIndex == 0 ? MethodDefinition.DeclaringType
- : MethodDefinition.Parameters[MethodDefinition.HasImplicitThis () ? --ParameterIndex : ParameterIndex].ParameterType)
+ public partial record ParameterReferenceValue (MethodDefinition MethodDefinition, SourceParameterIndex ParameterIndex)
+ : ReferenceValue (MethodDefinition.Parameters[(int) ParameterIndex].ParameterType)
{
public override SingleValue DeepCopy ()
{
diff --git a/src/linker/Linker.Dataflow/ReflectionMethodBodyScanner.cs b/src/linker/Linker.Dataflow/ReflectionMethodBodyScanner.cs
index 56d554989..adac45faf 100644
--- a/src/linker/Linker.Dataflow/ReflectionMethodBodyScanner.cs
+++ b/src/linker/Linker.Dataflow/ReflectionMethodBodyScanner.cs
@@ -93,18 +93,14 @@ namespace Mono.Linker.Dataflow
Debug.Fail ("Invalid IL or a bug in the scanner");
}
- protected override ValueWithDynamicallyAccessedMembers GetMethodParameterValue (MethodDefinition method, int parameterIndex)
- => GetMethodParameterValue (method, parameterIndex, _context.Annotations.FlowAnnotations.GetParameterAnnotation (method, parameterIndex));
+ protected override ValueWithDynamicallyAccessedMembers GetMethodThisParameterValue (MethodDefinition method)
+ => _annotations.GetMethodThisParameterValue (method);
- ValueWithDynamicallyAccessedMembers GetMethodParameterValue (MethodDefinition method, int parameterIndex, DynamicallyAccessedMemberTypes dynamicallyAccessedMemberTypes)
- {
- if (method.HasImplicitThis ()) {
- if (parameterIndex == 0)
- return _annotations.GetMethodThisParameterValue (method, dynamicallyAccessedMemberTypes);
-
- parameterIndex--;
- }
+ protected override ValueWithDynamicallyAccessedMembers GetMethodParameterValue (MethodDefinition method, SourceParameterIndex parameterIndex)
+ => GetMethodParameterValue (method, parameterIndex, _annotations.GetParameterAnnotation (method, parameterIndex));
+ ValueWithDynamicallyAccessedMembers GetMethodParameterValue (MethodDefinition method, SourceParameterIndex parameterIndex, DynamicallyAccessedMemberTypes dynamicallyAccessedMemberTypes)
+ {
return _annotations.GetMethodParameterValue (method, parameterIndex, dynamicallyAccessedMemberTypes);
}
diff --git a/src/linker/Linker.Dataflow/ThisParameterReferenceValue.cs b/src/linker/Linker.Dataflow/ThisParameterReferenceValue.cs
new file mode 100644
index 000000000..727181fbd
--- /dev/null
+++ b/src/linker/Linker.Dataflow/ThisParameterReferenceValue.cs
@@ -0,0 +1,16 @@
+// Copyright (c) .NET Foundation and contributors. All rights reserved.
+// Licensed under the MIT license. See LICENSE file in the project root for full license information.
+using ILLink.Shared.DataFlow;
+using Mono.Cecil;
+
+namespace ILLink.Shared.TrimAnalysis
+{
+ public partial record ThisParameterReferenceValue (MethodDefinition MethodDefinition)
+ : ReferenceValue (MethodDefinition.DeclaringType)
+ {
+ public override SingleValue DeepCopy ()
+ {
+ return this;
+ }
+ }
+}
diff --git a/src/linker/Linker/ILParameterIndex.cs b/src/linker/Linker/ILParameterIndex.cs
new file mode 100644
index 000000000..3d9da48f4
--- /dev/null
+++ b/src/linker/Linker/ILParameterIndex.cs
@@ -0,0 +1,22 @@
+// Copyright (c) .NET Foundation and contributors. All rights reserved.
+// Licensed under the MIT license. See LICENSE file in the project root for full license information.
+
+namespace Mono.Linker
+{
+ /// <summary>
+ /// Represents the index of arguments passed to a function in IL (i.e. (ILParameterIndex)0 represents `this` for non-static methods.
+ /// This is used to enforce a differentiation between scenarios where the 0 index should be `this` and when the 0 index should be the first non-this parameter in the type system.
+ /// There are no named enum values, the underlying integer value represents the index value.
+ /// Generally prefer to use <see cref="ILLink.Shared.SourceParameterIndex"/> when possible.
+ /// See also <seealso cref="Mono.Linker.ParameterHelpers"/>.
+ /// </summary>
+ /// <example>
+ /// In a call to a non-static function Foo(int a, int b, int c)
+ /// 0 refers to `this`,
+ /// 1 refers to a,
+ /// 2 refers to b.
+ /// 3 referes to c.
+ /// </example>
+ public enum ILParameterIndex
+ { }
+}
diff --git a/src/linker/Linker/MethodReferenceExtensions.cs b/src/linker/Linker/MethodReferenceExtensions.cs
index e38371399..3bbe6816a 100644
--- a/src/linker/Linker/MethodReferenceExtensions.cs
+++ b/src/linker/Linker/MethodReferenceExtensions.cs
@@ -2,6 +2,7 @@
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
using System;
+using ILLink.Shared;
using ILLink.Shared.TypeSystemProxy;
using Mono.Cecil;
@@ -80,14 +81,18 @@ namespace Mono.Linker
return method.ReturnType.WithoutModifiers ().MetadataType == MetadataType.Void;
}
- public static TypeReference? GetParameterType (this MethodReference method, int parameterIndex, LinkContext context)
+ public static TypeReference? GetInflatedParameterType (this MethodReference method, int index, LinkContext context)
{
- if (method.DeclaringType is GenericInstanceType genericInstance)
- return TypeReferenceExtensions.InflateGenericType (genericInstance, method.Parameters[parameterIndex].ParameterType, context);
-
- return method.Parameters[parameterIndex].ParameterType;
+ var uninflatedParameterType = method.GetParameterType ((SourceParameterIndex) index);
+ if (method.DeclaringType is GenericInstanceType genericInstance) {
+ return TypeReferenceExtensions.InflateGenericType (genericInstance, uninflatedParameterType, context);
+ }
+ return uninflatedParameterType;
}
+ public static TypeReference GetParameterType (this MethodReference method, SourceParameterIndex index)
+ => method.Parameters[(int) index].ParameterType;
+
public static bool IsDeclaredOnType (this MethodReference method, string fullTypeName)
{
return method.DeclaringType.IsTypeOf (fullTypeName);
diff --git a/src/linker/Linker/ParameterHelpers.cs b/src/linker/Linker/ParameterHelpers.cs
new file mode 100644
index 000000000..2ea4786b1
--- /dev/null
+++ b/src/linker/Linker/ParameterHelpers.cs
@@ -0,0 +1,88 @@
+// Copyright (c) .NET Foundation and contributors. All rights reserved.
+// Licensed under the MIT license. See LICENSE file in the project root for full license information.
+
+using System;
+using Mono.Cecil;
+using Mono.Cecil.Cil;
+using ILLink.Shared;
+
+namespace Mono.Linker
+{
+ public static class ParameterHelpers
+ {
+ public static ILParameterIndex GetILParameterIndex (MethodDefinition thisMethod, Instruction operation)
+ {
+ // Thank you Cecil, Operand being a ParameterDefinition instead of an integer,
+ // (except for Ldarg_0 - Ldarg_3, where it's null) makes all of this really convenient...
+ // NOT.
+ Code code = operation.OpCode.Code;
+ return code switch {
+ Code.Ldarg_0
+ or Code.Ldarg_1
+ or Code.Ldarg_2
+ or Code.Ldarg_3
+ => GetLdargParamIndex (),
+
+ Code.Starg
+ or Code.Ldarg
+ or Code.Starg_S
+ or Code.Ldarg_S
+ or Code.Ldarga
+ or Code.Ldarga_S
+ => GetParamSequence (),
+
+ _ => throw new ArgumentException ($"{nameof (ILParameterIndex)} expected an ldarg or starg instruction, got {operation.OpCode.Name}")
+ };
+
+ ILParameterIndex GetLdargParamIndex ()
+ {
+ return (ILParameterIndex) (code - Code.Ldarg_0);
+ }
+ ILParameterIndex GetParamSequence ()
+ {
+ ParameterDefinition param = (ParameterDefinition) operation.Operand;
+ return (ILParameterIndex) param.Sequence;
+ }
+ }
+
+ /// <Summary>
+ /// This enum is used when converting from an ILParameterIndex to a SourceParamterIndex to
+ /// differentiate `This` parameters from other parameters.
+ /// </Summary>
+ public enum SourceParameterKind
+ {
+ This,
+ Numbered
+ }
+
+ /// <summary>
+ /// Used to get the SourceParameterIndex that an instruction refers to.
+ /// If the return value is <see cref="SourceParameterKind.Numbered" />, the instruction refers to a numbered non-this parameter and <paramref name="sourceParameterIndex"/> will have a valid value.
+ /// If the return value is <see cref="SourceParameterKind.This" />, the instruction refers to the `this` parameter, and <paramref name="sourceParameterIndex"/> will not have a valid value.
+ /// </summary>
+ public static SourceParameterKind GetSourceParameterIndex (MethodDefinition method, Instruction operation, out SourceParameterIndex sourceParameterIndex)
+ => GetSourceParameterIndex (method, GetILParameterIndex (method, operation), out sourceParameterIndex);
+
+ /// <summary>
+ /// Used to get the SourceParameterIndex that an ILParameterIndex refers to.
+ /// If the return value is <see cref="SourceParameterKind.Numbered" />, the instruction refers to a numbered non-this parameter and <paramref name="sourceParameterIndex"/> will have a valid value.
+ /// If the return value is <see cref="SourceParameterKind.This" />, the instruction refers to the `this` parameter, and <paramref name="sourceParameterIndex"/> will not have a valid value.
+ /// </summary>
+ public static SourceParameterKind GetSourceParameterIndex (MethodReference method, ILParameterIndex ilIndex, out SourceParameterIndex sourceParameterIndex)
+ {
+ sourceParameterIndex = (SourceParameterIndex) (int) ilIndex;
+ if (method.HasImplicitThis ()) {
+ if (ilIndex == 0) {
+ return SourceParameterKind.This;
+ }
+ sourceParameterIndex--;
+ }
+ return SourceParameterKind.Numbered;
+ }
+
+ public static ILParameterIndex GetILParameterIndex (MethodReference method, SourceParameterIndex sourceIndex)
+ => method.HasImplicitThis ()
+ ? (ILParameterIndex) (sourceIndex + 1)
+ : (ILParameterIndex) sourceIndex;
+ }
+}
diff --git a/src/linker/Linker/TypeMapInfo.cs b/src/linker/Linker/TypeMapInfo.cs
index 117df8fad..75613e2c0 100644
--- a/src/linker/Linker/TypeMapInfo.cs
+++ b/src/linker/Linker/TypeMapInfo.cs
@@ -347,8 +347,8 @@ namespace Mono.Linker
return false;
for (int i = 0; i < cp.Count; i++) {
- if (candidate.GetParameterType (i, context) is not TypeReference candidateParameterType ||
- method.GetParameterType (i, context) is not TypeReference methodParameterType ||
+ if (candidate.GetInflatedParameterType (i, context) is not TypeReference candidateParameterType ||
+ method.GetInflatedParameterType (i, context) is not TypeReference methodParameterType ||
!TypeMatch (candidateParameterType, methodParameterType))
return false;
}