Browse Source

Fix #1903: un-inline argument of unsupported `isinst` instructions.

pull/2069/head
Daniel Grunwald 5 years ago
parent
commit
016d9f8f4d
  1. 1
      ICSharpCode.Decompiler/CSharp/CSharpDecompiler.cs
  2. 10
      ICSharpCode.Decompiler/CSharp/ExpressionBuilder.cs
  3. 1
      ICSharpCode.Decompiler/ICSharpCode.Decompiler.csproj
  4. 59
      ICSharpCode.Decompiler/IL/Transforms/FixLoneIsInst.cs
  5. 21
      ICSharpCode.Decompiler/IL/Transforms/FixRemainingIncrements.cs

1
ICSharpCode.Decompiler/CSharp/CSharpDecompiler.cs

@ -157,6 +157,7 @@ namespace ICSharpCode.Decompiler.CSharp
},
new ProxyCallReplacer(),
new FixRemainingIncrements(),
new FixLoneIsInst(),
new CopyPropagation(),
new DelegateConstruction(),
new LocalFunctionDecompiler(),

10
ICSharpCode.Decompiler/CSharp/ExpressionBuilder.cs

@ -310,7 +310,7 @@ namespace ICSharpCode.Decompiler.CSharp
// isinst with a value type results in an expression of "boxed value type",
// which is not supported in C#.
// Note that several other instructions special-case isinst arguments:
// unbox.any T(isinst T(expr)) ==> "expr as T" for nullable value types
// unbox.any T(isinst T(expr)) ==> "expr as T" for nullable value types and class-constrained generic types
// comp(isinst T(expr) != null) ==> "expr is T"
// on block level (StatementBuilder.VisitIsInst) => "expr is T"
if (SemanticHelper.IsPure(inst.Argument.Flags)) {
@ -2287,10 +2287,16 @@ namespace ICSharpCode.Decompiler.CSharp
return input.ConvertTo(compilation.FindType(targetType), this);
}
internal static bool IsUnboxAnyWithIsInst(UnboxAny unboxAny, IsInst isInst)
{
return unboxAny.Type.Equals(isInst.Type)
&& (unboxAny.Type.IsKnownType(KnownTypeCode.NullableOfT) || isInst.Type.IsReferenceType == true);
}
protected internal override TranslatedExpression VisitUnboxAny(UnboxAny inst, TranslationContext context)
{
TranslatedExpression arg;
if (inst.Argument is IsInst isInst && inst.Type.Equals(isInst.Type)) {
if (inst.Argument is IsInst isInst && IsUnboxAnyWithIsInst(inst, isInst)) {
// unbox.any T(isinst T(expr)) ==> expr as T
// This is used for generic types and nullable value types
arg = UnwrapBoxingConversion(Translate(isInst.Argument));

1
ICSharpCode.Decompiler/ICSharpCode.Decompiler.csproj

@ -71,6 +71,7 @@
<Compile Include="CSharp\ProjectDecompiler\TargetFramework.cs" />
<Compile Include="CSharp\ProjectDecompiler\TargetServices.cs" />
<Compile Include="CSharp\Syntax\FunctionPointerType.cs" />
<Compile Include="IL\Transforms\FixLoneIsInst.cs" />
<Compile Include="IL\Transforms\IndexRangeTransform.cs" />
<Compile Include="CSharp\TranslatedStatement.cs" />
<Compile Include="DebugInfo\KnownGuids.cs" />

59
ICSharpCode.Decompiler/IL/Transforms/FixLoneIsInst.cs

@ -0,0 +1,59 @@
// Copyright (c) 2020 Daniel Grunwald
//
// Permission is hereby granted, free of charge, to any person obtaining a copy of this
// software and associated documentation files (the "Software"), to deal in the Software
// without restriction, including without limitation the rights to use, copy, modify, merge,
// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
// to whom the Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all copies or
// substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
using System;
using System.Collections.Generic;
using System.Linq;
using ICSharpCode.Decompiler.CSharp;
namespace ICSharpCode.Decompiler.IL.Transforms
{
/// <summary>
/// C# cannot represent `isinst T` directly for value-types.
/// This transform un-inlines the argument of `isinst` instructions that can't be directly translated to C#,
/// thus allowing the emulation via "expr is T ? (T)expr : null".
/// </summary>
class FixLoneIsInst : IILTransform
{
void IILTransform.Run(ILFunction function, ILTransformContext context)
{
var instructionsToFix = new List<IsInst>();
foreach (var isInst in function.Descendants.OfType<IsInst>()) {
if (isInst.Type.IsReferenceType == true) {
continue; // reference-type isinst is always supported
}
if (SemanticHelper.IsPure(isInst.Argument.Flags)) {
continue; // emulated via "expr is T ? (T)expr : null"
}
if (isInst.Parent is UnboxAny unboxAny && ExpressionBuilder.IsUnboxAnyWithIsInst(unboxAny, isInst)) {
continue; // supported pattern "expr as T?"
}
if (isInst.Parent.MatchCompEqualsNull(out _) || isInst.Parent.MatchCompNotEqualsNull(out _)) {
continue; // supported pattern "expr is T"
}
instructionsToFix.Add(isInst);
}
// Need to delay fixing until we're done with iteration, because Extract() modifies parents
foreach (var isInst in instructionsToFix) {
// Use extraction to turn isInst.Argument into a pure instruction, thus making the emulation possible
context.Step("FixLoneIsInst", isInst);
isInst.Argument.Extract();
}
}
}
}

21
ICSharpCode.Decompiler/IL/Transforms/FixRemainingIncrements.cs

@ -1,7 +1,24 @@
using System;
// Copyright (c) 2019 Daniel Grunwald
//
// Permission is hereby granted, free of charge, to any person obtaining a copy of this
// software and associated documentation files (the "Software"), to deal in the Software
// without restriction, including without limitation the rights to use, copy, modify, merge,
// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
// to whom the Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all copies or
// substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
using System;
using System.Linq;
using System.Collections.Generic;
using System.Text;
using System.Diagnostics;
using ICSharpCode.Decompiler.TypeSystem;

Loading…
Cancel
Save