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
public static void Test(object x) 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
if (parameter.ReferenceKind != ReferenceKind.None) if (parameter.ReferenceKind != ReferenceKind.None)
{ {
arg = ExpressionBuilder.ChangeDirectionExpressionTo(arg, parameter.ReferenceKind); arg = ExpressionBuilder.ChangeDirectionExpressionTo(arg, parameter.ReferenceKind, callArguments[i] is AddressOf);
} }
arguments.Add(arg); arguments.Add(arg);
@ -1179,14 +1179,20 @@ namespace ICSharpCode.Decompiler.CSharp
} }
else else
{ {
IParameter parameter = expectedParameters[i];
IType parameterType; IType parameterType;
if (expectedParameters[i].Type.Kind == TypeKind.Dynamic) if (parameter.Type.Kind == TypeKind.Dynamic)
{ {
parameterType = expressionBuilder.compilation.FindType(KnownTypeCode.Object); parameterType = expressionBuilder.compilation.FindType(KnownTypeCode.Object);
} }
else 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); arguments[i] = arguments[i].ConvertTo(parameterType, expressionBuilder, allowImplicitConversion: false);
@ -1295,7 +1301,10 @@ namespace ICSharpCode.Decompiler.CSharp
resolver.CurrentTypeDefinition == method.DeclaringTypeDefinition; resolver.CurrentTypeDefinition == method.DeclaringTypeDefinition;
if (lookup.IsAccessible(ctor, allowProtectedAccess)) 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
} }
if (info.HasFlag(CSharpArgumentInfoFlags.IsOut)) 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)) if (info.HasFlag(CSharpArgumentInfoFlags.NamedArgument) && !string.IsNullOrWhiteSpace(info.Name))
{ {
@ -4184,10 +4184,14 @@ namespace ICSharpCode.Decompiler.CSharp
return translatedExpression; 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)) if (!(input.Expression is DirectionExpression dirExpr && input.ResolveResult is ByReferenceResolveResult brrr))
return input; return input;
if (isAddressOf && kind is ReferenceKind.In or ReferenceKind.RefReadOnly)
{
return input.UnwrapChild(dirExpr.Expression);
}
dirExpr.FieldDirection = kind switch { dirExpr.FieldDirection = kind switch {
ReferenceKind.Ref => FieldDirection.Ref, ReferenceKind.Ref => FieldDirection.Ref,
ReferenceKind.Out => FieldDirection.Out, ReferenceKind.Out => FieldDirection.Out,
@ -4454,7 +4458,7 @@ namespace ICSharpCode.Decompiler.CSharp
var arg = Translate(argInst, typeHint: paramType).ConvertTo(paramType, this, allowImplicitConversion: true); var arg = Translate(argInst, typeHint: paramType).ConvertTo(paramType, this, allowImplicitConversion: true);
if (paramRefKind != ReferenceKind.None) if (paramRefKind != ReferenceKind.None)
{ {
arg = ChangeDirectionExpressionTo(arg, paramRefKind); arg = ChangeDirectionExpressionTo(arg, paramRefKind, argInst is AddressOf);
} }
invocation.Arguments.Add(arg); invocation.Arguments.Add(arg);
} }

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

@ -244,7 +244,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms
var loadInst = r.LoadInst; var loadInst = r.LoadInst;
if (loadInst.OpCode == OpCode.LdLoca) if (loadInst.OpCode == OpCode.LdLoca)
{ {
if (!IsGeneratedValueTypeTemporary((LdLoca)loadInst, v, inlinedExpression, options)) if (!IsGeneratedTemporaryForAddressOf((LdLoca)loadInst, v, inlinedExpression, options))
return false; return false;
} }
else else
@ -289,7 +289,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms
/// </summary> /// </summary>
/// <param name="loadInst">The load instruction (a descendant within 'next')</param> /// <param name="loadInst">The load instruction (a descendant within 'next')</param>
/// <param name="v">The variable being inlined.</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); Debug.Assert(loadInst.Variable == v);
if (!options.HasFlag(InliningOptions.AllowInliningOfLdloca)) if (!options.HasFlag(InliningOptions.AllowInliningOfLdloca))
@ -301,7 +301,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms
// Thus, we have to ensure we're operating on an r-value. // 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 // 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). // 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)) if (options.HasFlag(InliningOptions.Aggressive))
{ {
@ -415,6 +415,17 @@ namespace ICSharpCode.Decompiler.IL.Transforms
return inst != ldloca && inst.Parent is LdObj; 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> /// <summary>
/// Gets whether the instruction, when converted into C#, turns into an l-value that can /// Gets whether the instruction, when converted into C#, turns into an l-value that can
/// be used to mutate a value-type. /// be used to mutate a value-type.

Loading…
Cancel
Save