Browse Source

Support ILInlining for in parameters

pull/3243/head
Siegfried Pammer 10 months ago
parent
commit
03a20f3494
  1. 19
      ICSharpCode.Decompiler.Tests/TestCases/Pretty/ValueTypes.cs
  2. 17
      ICSharpCode.Decompiler/CSharp/CallBuilder.cs
  3. 10
      ICSharpCode.Decompiler/CSharp/ExpressionBuilder.cs
  4. 17
      ICSharpCode.Decompiler/IL/Transforms/ILInlining.cs

19
ICSharpCode.Decompiler.Tests/TestCases/Pretty/ValueTypes.cs

@ -291,5 +291,24 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty @@ -291,5 +291,24 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty
public static void Test(object x)
{
}
#if CS120
public static void AcceptIn(in S o)
{
}
public static void AcceptRefReadOnly(ref readonly S o)
{
}
private static void Use(in S param)
{
AcceptIn(new S(5));
S o = new S(10);
AcceptRefReadOnly(in o);
AcceptIn(in param);
AcceptRefReadOnly(in param);
}
#endif
}
}

17
ICSharpCode.Decompiler/CSharp/CallBuilder.cs

@ -867,7 +867,7 @@ namespace ICSharpCode.Decompiler.CSharp @@ -867,7 +867,7 @@ namespace ICSharpCode.Decompiler.CSharp
if (parameter.ReferenceKind != ReferenceKind.None)
{
arg = ExpressionBuilder.ChangeDirectionExpressionTo(arg, parameter.ReferenceKind);
arg = ExpressionBuilder.ChangeDirectionExpressionTo(arg, parameter.ReferenceKind, callArguments[i] is AddressOf);
}
arguments.Add(arg);
@ -1179,14 +1179,20 @@ namespace ICSharpCode.Decompiler.CSharp @@ -1179,14 +1179,20 @@ namespace ICSharpCode.Decompiler.CSharp
}
else
{
IParameter parameter = expectedParameters[i];
IType parameterType;
if (expectedParameters[i].Type.Kind == TypeKind.Dynamic)
if (parameter.Type.Kind == TypeKind.Dynamic)
{
parameterType = expressionBuilder.compilation.FindType(KnownTypeCode.Object);
}
else
{
parameterType = expectedParameters[i].Type;
parameterType = parameter.Type;
}
if (parameter.ReferenceKind == ReferenceKind.In && parameterType is ByReferenceType brt && arguments[i].Type is not ByReferenceType)
{
parameterType = brt.ElementType;
}
arguments[i] = arguments[i].ConvertTo(parameterType, expressionBuilder, allowImplicitConversion: false);
@ -1295,7 +1301,10 @@ namespace ICSharpCode.Decompiler.CSharp @@ -1295,7 +1301,10 @@ namespace ICSharpCode.Decompiler.CSharp
resolver.CurrentTypeDefinition == method.DeclaringTypeDefinition;
if (lookup.IsAccessible(ctor, allowProtectedAccess))
{
or.AddCandidate(ctor);
Log.Indent();
OverloadResolutionErrors errors = or.AddCandidate(ctor);
Log.Unindent();
or.LogCandidateAddingResult(" Candidate", ctor, errors);
}
}
}

10
ICSharpCode.Decompiler/CSharp/ExpressionBuilder.cs

@ -4174,7 +4174,7 @@ namespace ICSharpCode.Decompiler.CSharp @@ -4174,7 +4174,7 @@ namespace ICSharpCode.Decompiler.CSharp
}
if (info.HasFlag(CSharpArgumentInfoFlags.IsOut))
{
translatedExpression = ChangeDirectionExpressionTo(translatedExpression, ReferenceKind.Out);
translatedExpression = ChangeDirectionExpressionTo(translatedExpression, ReferenceKind.Out, argument is AddressOf);
}
if (info.HasFlag(CSharpArgumentInfoFlags.NamedArgument) && !string.IsNullOrWhiteSpace(info.Name))
{
@ -4184,10 +4184,14 @@ namespace ICSharpCode.Decompiler.CSharp @@ -4184,10 +4184,14 @@ namespace ICSharpCode.Decompiler.CSharp
return translatedExpression;
}
internal static TranslatedExpression ChangeDirectionExpressionTo(TranslatedExpression input, ReferenceKind kind)
internal static TranslatedExpression ChangeDirectionExpressionTo(TranslatedExpression input, ReferenceKind kind, bool isAddressOf)
{
if (!(input.Expression is DirectionExpression dirExpr && input.ResolveResult is ByReferenceResolveResult brrr))
return input;
if (isAddressOf && kind is ReferenceKind.In or ReferenceKind.RefReadOnly)
{
return input.UnwrapChild(dirExpr.Expression);
}
dirExpr.FieldDirection = kind switch {
ReferenceKind.Ref => FieldDirection.Ref,
ReferenceKind.Out => FieldDirection.Out,
@ -4454,7 +4458,7 @@ namespace ICSharpCode.Decompiler.CSharp @@ -4454,7 +4458,7 @@ namespace ICSharpCode.Decompiler.CSharp
var arg = Translate(argInst, typeHint: paramType).ConvertTo(paramType, this, allowImplicitConversion: true);
if (paramRefKind != ReferenceKind.None)
{
arg = ChangeDirectionExpressionTo(arg, paramRefKind);
arg = ChangeDirectionExpressionTo(arg, paramRefKind, argInst is AddressOf);
}
invocation.Arguments.Add(arg);
}

17
ICSharpCode.Decompiler/IL/Transforms/ILInlining.cs

@ -244,7 +244,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms @@ -244,7 +244,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms
var loadInst = r.LoadInst;
if (loadInst.OpCode == OpCode.LdLoca)
{
if (!IsGeneratedValueTypeTemporary((LdLoca)loadInst, v, inlinedExpression, options))
if (!IsGeneratedTemporaryForAddressOf((LdLoca)loadInst, v, inlinedExpression, options))
return false;
}
else
@ -289,7 +289,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms @@ -289,7 +289,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms
/// </summary>
/// <param name="loadInst">The load instruction (a descendant within 'next')</param>
/// <param name="v">The variable being inlined.</param>
static bool IsGeneratedValueTypeTemporary(LdLoca loadInst, ILVariable v, ILInstruction inlinedExpression, InliningOptions options)
static bool IsGeneratedTemporaryForAddressOf(LdLoca loadInst, ILVariable v, ILInstruction inlinedExpression, InliningOptions options)
{
Debug.Assert(loadInst.Variable == v);
if (!options.HasFlag(InliningOptions.AllowInliningOfLdloca))
@ -301,7 +301,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms @@ -301,7 +301,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms
// Thus, we have to ensure we're operating on an r-value.
// Additionally, we cannot inline in cases where the C# compiler prohibits the direct use
// of the rvalue (e.g. M(ref (MyStruct)obj); is invalid).
if (IsUsedAsThisPointerInCall(loadInst, out var method, out var constrainedTo))
if (IsUsedAsThisPointerInCall(loadInst, out var method, out var constrainedTo) || IsPassedToInParameter(loadInst, out method))
{
if (options.HasFlag(InliningOptions.Aggressive))
{
@ -415,6 +415,17 @@ namespace ICSharpCode.Decompiler.IL.Transforms @@ -415,6 +415,17 @@ namespace ICSharpCode.Decompiler.IL.Transforms
return inst != ldloca && inst.Parent is LdObj;
}
static bool IsPassedToInParameter(LdLoca ldloca, out IMethod method)
{
method = null;
if (ldloca.Parent is not CallInstruction call)
{
return false;
}
method = call.Method;
return call.GetParameter(ldloca.ChildIndex)?.ReferenceKind is ReferenceKind.In;
}
/// <summary>
/// Gets whether the instruction, when converted into C#, turns into an l-value that can
/// be used to mutate a value-type.

Loading…
Cancel
Save