Browse Source

Fix stackalloc[] decompilation.

pull/728/merge
Daniel Grunwald 9 years ago
parent
commit
385048f32c
  1. 63
      ICSharpCode.Decompiler/CSharp/ExpressionBuilder.cs
  2. 3
      ICSharpCode.Decompiler/CSharp/Transforms/IntroduceUnsafeModifier.cs
  3. 7
      ICSharpCode.Decompiler/CSharp/TranslationContext.cs
  4. 2
      ICSharpCode.Decompiler/Tests/CorrectnessTestRunner.cs
  5. 14
      ICSharpCode.Decompiler/Tests/TestCases/Correctness/UnsafeCode.cs
  6. 2
      NRefactory

63
ICSharpCode.Decompiler/CSharp/ExpressionBuilder.cs

@ -108,10 +108,13 @@ namespace ICSharpCode.Decompiler.CSharp @@ -108,10 +108,13 @@ namespace ICSharpCode.Decompiler.CSharp
return new ExpressionWithResolveResult(expr, exprRR);
}
public TranslatedExpression Translate(ILInstruction inst)
public TranslatedExpression Translate(ILInstruction inst, IType typeHint = null)
{
Debug.Assert(inst != null);
var cexpr = inst.AcceptVisitor(this, new TranslationContext());
TranslationContext context = new TranslationContext {
TypeHint = typeHint ?? SpecialType.UnknownType
};
var cexpr = inst.AcceptVisitor(this, context);
#if DEBUG
if (inst.ResultType != StackType.Void && cexpr.Type.Kind != TypeKind.Unknown) {
if (inst.ResultType.IsIntegerType()) {
@ -127,7 +130,7 @@ namespace ICSharpCode.Decompiler.CSharp @@ -127,7 +130,7 @@ namespace ICSharpCode.Decompiler.CSharp
public TranslatedExpression TranslateCondition(ILInstruction condition)
{
var expr = Translate(condition);
var expr = Translate(condition, compilation.FindType(KnownTypeCode.Boolean));
return expr.ConvertToBoolean(this);
}
@ -206,11 +209,51 @@ namespace ICSharpCode.Decompiler.CSharp @@ -206,11 +209,51 @@ namespace ICSharpCode.Decompiler.CSharp
protected internal override TranslatedExpression VisitLocAlloc(LocAlloc inst, TranslationContext context)
{
var byteType = compilation.FindType(KnownTypeCode.Byte);
IType elementType;
TranslatedExpression countExpression = TranslatePointerArgument(inst.Argument, context, out elementType);
countExpression = countExpression.ConvertTo(compilation.FindType(KnownTypeCode.Int32), this);
return new StackAllocExpression {
Type = ConvertType(byteType),
CountExpression = Translate(inst.Argument)
}.WithILInstruction(inst).WithRR(new ResolveResult(new PointerType(byteType)));
Type = ConvertType(elementType ?? compilation.FindType(KnownTypeCode.Byte)),
CountExpression = countExpression
}.WithILInstruction(inst).WithRR(new ResolveResult(new PointerType(elementType)));
}
/// <summary>
/// Translate the argument of an operation that deals with pointers:
/// * undoes the implicit multiplication with `sizeof(elementType)` and returns `elementType`
/// * on failure, translates the whole expression and returns `elementType = null`.
/// </summary>
TranslatedExpression TranslatePointerArgument(ILInstruction countExpr, TranslationContext context, out IType elementType)
{
ILInstruction left;
ILInstruction right;
if (countExpr.MatchBinaryNumericInstruction(BinaryNumericOperator.Mul, out left, out right)
&& right.UnwrapConv(ConversionKind.SignExtend).UnwrapConv(ConversionKind.ZeroExtend).MatchSizeOf(out elementType))
{
return Translate(left);
}
var pointerTypeHint = context.TypeHint as PointerType;
if (pointerTypeHint == null) {
elementType = null;
return Translate(countExpr);
}
ResolveResult sizeofRR = resolver.ResolveSizeOf(pointerTypeHint.ElementType);
if (!(sizeofRR.IsCompileTimeConstant && sizeofRR.ConstantValue is int)) {
elementType = null;
return Translate(countExpr);
}
int typeSize = (int)sizeofRR.ConstantValue;
if (countExpr.MatchBinaryNumericInstruction(BinaryNumericOperator.Mul, out left, out right)
&& right.UnwrapConv(ConversionKind.SignExtend).UnwrapConv(ConversionKind.ZeroExtend).MatchLdcI4(typeSize))
{
elementType = pointerTypeHint.ElementType;
return Translate(left);
}
elementType = null;
return Translate(countExpr);
}
protected internal override TranslatedExpression VisitLdcI4(LdcI4 inst, TranslationContext context)
@ -346,7 +389,7 @@ namespace ICSharpCode.Decompiler.CSharp @@ -346,7 +389,7 @@ namespace ICSharpCode.Decompiler.CSharp
protected internal override TranslatedExpression VisitStLoc(StLoc inst, TranslationContext context)
{
var translatedValue = Translate(inst.Value);
var translatedValue = Translate(inst.Value, typeHint: inst.Variable.Type);
if (inst.Variable.Kind == VariableKind.StackSlot && inst.Variable.IsSingleDefinition
&& inst.Variable.StackType == translatedValue.Type.GetStackType()
&& translatedValue.Type.Kind != TypeKind.Null && !loadedVariablesSet.Contains(inst.Variable)) {
@ -1167,7 +1210,6 @@ namespace ICSharpCode.Decompiler.CSharp @@ -1167,7 +1210,6 @@ namespace ICSharpCode.Decompiler.CSharp
protected internal override TranslatedExpression VisitStObj(StObj inst, TranslationContext context)
{
var target = Translate(inst.Target);
var value = Translate(inst.Value);
TranslatedExpression result;
if (target.Expression is DirectionExpression && TypeUtils.IsCompatibleTypeForMemoryAccess(target.Type, inst.Type)) {
// we can deference the managed reference by stripping away the 'ref'
@ -1181,6 +1223,7 @@ namespace ICSharpCode.Decompiler.CSharp @@ -1181,6 +1223,7 @@ namespace ICSharpCode.Decompiler.CSharp
.WithoutILInstruction()
.WithRR(new ResolveResult(((TypeWithElementType)target.Type).ElementType));
}
var value = Translate(inst.Value, typeHint: result.Type);
return Assignment(result, value).WithILInstruction(inst);
}
@ -1261,7 +1304,7 @@ namespace ICSharpCode.Decompiler.CSharp @@ -1261,7 +1304,7 @@ namespace ICSharpCode.Decompiler.CSharp
protected internal override TranslatedExpression VisitBox(Box inst, TranslationContext context)
{
var obj = compilation.FindType(KnownTypeCode.Object);
var arg = Translate(inst.Argument).ConvertTo(inst.Type, this);
var arg = Translate(inst.Argument, typeHint: inst.Type).ConvertTo(inst.Type, this);
return new CastExpression(ConvertType(obj), arg.Expression)
.WithILInstruction(inst)
.WithRR(new ConversionResolveResult(obj, arg.ResolveResult, Conversion.BoxingConversion));

3
ICSharpCode.Decompiler/CSharp/Transforms/IntroduceUnsafeModifier.cs

@ -99,6 +99,9 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms @@ -99,6 +99,9 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms
pre.CopyAnnotationsFrom(memberReferenceExpression);
memberReferenceExpression.ReplaceWith(pre);
}
var rr = memberReferenceExpression.GetResolveResult();
if (rr != null && rr.Type is PointerType)
return true;
return result;
}

7
ICSharpCode.Decompiler/CSharp/TranslationContext.cs

@ -17,6 +17,7 @@ @@ -17,6 +17,7 @@
// DEALINGS IN THE SOFTWARE.
using System;
using ICSharpCode.NRefactory.TypeSystem;
namespace ICSharpCode.Decompiler.CSharp
{
@ -25,6 +26,10 @@ namespace ICSharpCode.Decompiler.CSharp @@ -25,6 +26,10 @@ namespace ICSharpCode.Decompiler.CSharp
/// </summary>
public struct TranslationContext
{
/// <summary>
/// The expected type during ILAst->C# translation; or <c>SpecialType.Unknown</c>
/// if no specific type is expected.
/// </summary>
public IType TypeHint;
}
}

2
ICSharpCode.Decompiler/Tests/CorrectnessTestRunner.cs

@ -130,7 +130,7 @@ namespace ICSharpCode.Decompiler.Tests @@ -130,7 +130,7 @@ namespace ICSharpCode.Decompiler.Tests
TestAssembleDecompileCompileOutput("BitNot.il", CompilerOptions.UseDebug | CompilerOptions.Force32Bit, AssemblerOptions.Force32Bit);
}
[Test, Ignore("Fixed statements are broken")]
[Test, Ignore("Pointer reference expression is not supported")]
public void UnsafeCode()
{
TestCompileDecompileCompileOutputAll("UnsafeCode.cs");

14
ICSharpCode.Decompiler/Tests/TestCases/Correctness/UnsafeCode.cs

@ -20,6 +20,12 @@ using System; @@ -20,6 +20,12 @@ using System;
public class UnsafeCode
{
struct SimpleStruct
{
public int X;
public double Y;
}
static void Main()
{
// TODO: test behavior, or convert this into a pretty-test
@ -145,6 +151,7 @@ public class UnsafeCode @@ -145,6 +151,7 @@ public class UnsafeCode
public unsafe string StackAlloc(int count)
{
char* ptr = stackalloc char[count];
char* ptr2 = stackalloc char[100];
for (int i = 0; i < count; i++)
{
ptr[i] = (char)i;
@ -152,6 +159,13 @@ public class UnsafeCode @@ -152,6 +159,13 @@ public class UnsafeCode
return this.PointerReferenceExpression((double*)ptr);
}
public unsafe string StackAllocStruct(int count)
{
SimpleStruct* s = stackalloc SimpleStruct[checked(count * 2)];
SimpleStruct* p = stackalloc SimpleStruct[10];
return this.PointerReferenceExpression(&s->Y);
}
public unsafe int* PointerArithmetic(int* p)
{
return p + 2;

2
NRefactory

@ -1 +1 @@ @@ -1 +1 @@
Subproject commit 19497cfae13c3dcebed7dfeb1cba549e4c2deded
Subproject commit 5ca6d4172c8540d01b65d120f46db416d29740e3
Loading…
Cancel
Save