Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

Add support for pre- and post-increment of dereferenced pointers "(*p…

…tr)++".
  • Loading branch information...
commit d91b56b03367c869287a69cfe7088c391a2bc663 1 parent 4c7a896
@dgrunwald dgrunwald authored
View
16 ICSharpCode.Decompiler/Ast/AstMethodBodyBuilder.cs
@@ -16,8 +16,6 @@ namespace ICSharpCode.Decompiler.Ast
using Ast = ICSharpCode.NRefactory.CSharp;
using Cecil = Mono.Cecil;
- public class ArrayAccessAnnotation {}
-
public class AstMethodBodyBuilder
{
MethodDefinition methodDef;
@@ -25,8 +23,6 @@ public class AstMethodBodyBuilder
DecompilerContext context;
HashSet<ILVariable> localVariablesToDefine = new HashSet<ILVariable>(); // local variables that are missing a definition
- static readonly ArrayAccessAnnotation arrayAccessAnnotation = new ArrayAccessAnnotation();
-
/// <summary>
/// Creates the body for the method definition.
/// </summary>
@@ -327,9 +323,9 @@ AstNode TransformByteCode(ILExpression byteCode)
case ILCode.Ldelem_R8:
case ILCode.Ldelem_Ref:
case ILCode.Ldelem_Any:
- return arg1.Indexer(arg2).WithAnnotation(arrayAccessAnnotation);
+ return arg1.Indexer(arg2);
case ILCode.Ldelema:
- return MakeRef(arg1.Indexer(arg2).WithAnnotation(arrayAccessAnnotation));
+ return MakeRef(arg1.Indexer(arg2));
case ILCode.Stelem_I:
case ILCode.Stelem_I1:
case ILCode.Stelem_I2:
@@ -339,7 +335,7 @@ AstNode TransformByteCode(ILExpression byteCode)
case ILCode.Stelem_R8:
case ILCode.Stelem_Ref:
case ILCode.Stelem_Any:
- return new Ast.AssignmentExpression(arg1.Indexer(arg2).WithAnnotation(arrayAccessAnnotation), arg3);
+ return new Ast.AssignmentExpression(arg1.Indexer(arg2), arg3);
case ILCode.CompoundAssignment:
{
BinaryOperatorExpression boe = (BinaryOperatorExpression)arg1;
@@ -938,8 +934,10 @@ Ast.Expression Convert(Ast.Expression expr, Cecil.TypeReference actualType, Ceci
return expr.CastTo(AstBuilder.ConvertType(actualType));
}
- bool actualIsPrimitiveType = actualIsIntegerOrEnum || actualType.MetadataType == MetadataType.Single || actualType.MetadataType == MetadataType.Double;
- bool requiredIsPrimitiveType = requiredIsIntegerOrEnum || reqType.MetadataType == MetadataType.Single || reqType.MetadataType == MetadataType.Double;
+ bool actualIsPrimitiveType = actualIsIntegerOrEnum
+ || (actualType != null && (actualType.MetadataType == MetadataType.Single || actualType.MetadataType == MetadataType.Double));
+ bool requiredIsPrimitiveType = requiredIsIntegerOrEnum
+ || (reqType != null && (reqType.MetadataType == MetadataType.Single || reqType.MetadataType == MetadataType.Double));
if (actualIsPrimitiveType && requiredIsPrimitiveType) {
if (actualType.FullName == reqType.FullName)
return expr;
View
8 ICSharpCode.Decompiler/Ast/Transforms/IntroduceUsingDeclarations.cs
@@ -24,14 +24,12 @@ public IntroduceUsingDeclarations(DecompilerContext context)
public void Run(AstNode compilationUnit)
{
+ if (!context.Settings.UsingDeclarations)
+ return;
+
// First determine all the namespaces that need to be imported:
compilationUnit.AcceptVisitor(this, null);
- if (importedNamespaces.Count == 0) {
- // abort when no namespaces have to be imported
- return;
- }
-
importedNamespaces.Add("System"); // always import System, even when not necessary
// Now add using declarations for those namespaces:
View
20 ICSharpCode.Decompiler/Ast/Transforms/ReplaceMethodCallsWithOperators.cs
@@ -176,7 +176,7 @@ public override object VisitAssignmentExpression(AssignmentExpression assignment
// Combine "x = x op y" into "x op= y"
BinaryOperatorExpression binary = assignment.Right as BinaryOperatorExpression;
if (binary != null && assignment.Operator == AssignmentOperatorType.Assign) {
- if (IsWithoutSideEffects(assignment.Left) && assignment.Left.Match(binary.Left) != null) {
+ if (CanConvertToCompoundAssignment(assignment.Left) && assignment.Left.Match(binary.Left) != null) {
assignment.Operator = GetAssignmentOperatorForBinaryOperator(binary.Operator);
if (assignment.Operator != AssignmentOperatorType.Assign) {
// If we found a shorter operator, get rid of the BinaryOperatorExpression:
@@ -233,17 +233,23 @@ public static AssignmentOperatorType GetAssignmentOperatorForBinaryOperator(Bina
}
}
- static bool IsWithoutSideEffects(Expression left)
+ static bool CanConvertToCompoundAssignment(Expression left)
{
- if (left is ThisReferenceExpression || left is IdentifierExpression || left is TypeReferenceExpression)
- return true;
MemberReferenceExpression mre = left as MemberReferenceExpression;
if (mre != null)
- return mre.Annotation<FieldReference>() != null && IsWithoutSideEffects(mre.Target);
+ return IsWithoutSideEffects(mre.Target);
IndexerExpression ie = left as IndexerExpression;
- if (ie != null && ie.Annotation<ArrayAccessAnnotation>() != null)
+ if (ie != null)
return IsWithoutSideEffects(ie.Target) && ie.Arguments.All(IsWithoutSideEffects);
- return false;
+ UnaryOperatorExpression uoe = left as UnaryOperatorExpression;
+ if (uoe != null && uoe.Operator == UnaryOperatorType.Dereference)
+ return IsWithoutSideEffects(uoe.Expression);
+ return IsWithoutSideEffects(left);
+ }
+
+ static bool IsWithoutSideEffects(Expression left)
+ {
+ return left is ThisReferenceExpression || left is IdentifierExpression || left is TypeReferenceExpression;
}
void IAstTransform.Run(AstNode node)
View
12 ICSharpCode.Decompiler/DecompilerSettings.cs
@@ -128,6 +128,18 @@ public class DecompilerSettings : INotifyPropertyChanged
}
}
+ bool usingDeclarations = true;
+
+ public bool UsingDeclarations {
+ get { return usingDeclarations; }
+ set {
+ if (usingDeclarations != value) {
+ usingDeclarations = value;
+ OnPropertyChanged("UsingDeclarations");
+ }
+ }
+ }
+
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged(string propertyName)
View
62 ICSharpCode.Decompiler/ILAst/PeepholeTransform.cs
@@ -240,7 +240,9 @@ bool MakeAssignmentExpression(List<ILNode> body, ILExpression expr, int pos)
bool StoreCanBeConvertedToAssignment(ILExpression store, ILVariable exprVar)
{
- if (store != null && (store.Code == ILCode.Stloc || store.Code == ILCode.Stfld || store.Code == ILCode.Stsfld || store.Code.IsStoreToArray())) {
+ if (store != null && (store.Code == ILCode.Stloc || store.Code == ILCode.Stfld || store.Code == ILCode.Stsfld
+ || store.Code.IsStoreToArray() || store.Code == ILCode.Stobj))
+ {
return store.Arguments.Last().Code == ILCode.Ldloc && store.Arguments.Last().Operand == exprVar;
}
return false;
@@ -251,7 +253,7 @@ bool StoreCanBeConvertedToAssignment(ILExpression store, ILVariable exprVar)
bool MakeCompoundAssignments(List<ILNode> body, ILExpression expr, int pos)
{
bool modified = false;
- modified |= MakeCompoundAssignmentForArray(expr);
+ modified |= MakeCompoundAssignmentForArrayOrPointerAccess(expr);
modified |= MakeCompoundAssignmentForInstanceField(expr);
// Static fields and local variables are not handled here - those are expressions without side effects
// and get handled by ReplaceMethodCallsWithOperators
@@ -264,26 +266,43 @@ bool MakeCompoundAssignments(List<ILNode> body, ILExpression expr, int pos)
return modified;
}
- bool MakeCompoundAssignmentForArray(ILExpression expr)
+ bool MakeCompoundAssignmentForArrayOrPointerAccess(ILExpression expr)
{
- // stelem.any(..., ldloc(array), ldloc(pos), <OP>(ldelem.any(int32, ldloc(array), ldloc(pos)), <RIGHT>))
- if (!expr.Code.IsStoreToArray())
- return false;
- ILVariable arrayVar, posVar;
- if (!(expr.Arguments[0].Match(ILCode.Ldloc, out arrayVar) && expr.Arguments[1].Match(ILCode.Ldloc, out posVar)))
+ // stelem.any(T, ldloc(array), ldloc(pos), <OP>(ldelem.any(T, ldloc(array), ldloc(pos)), <RIGHT>))
+ // or
+ // stobj(T, ldloc(ptr), <OP>(ldobj(T, ldloc(ptr)), <RIGHT>))
+ if (!(expr.Code.IsStoreToArray() || expr.Code == ILCode.Stobj))
return false;
+
+ // all arguments except the last (so either array+pos, or ptr):
+ bool hasGeneratedVar = false;
+ for (int i = 0; i < expr.Arguments.Count - 1; i++) {
+ ILVariable inputVar;
+ if (!expr.Arguments[i].Match(ILCode.Ldloc, out inputVar))
+ return false;
+ hasGeneratedVar |= inputVar.IsGenerated;
+ }
// At least one of the variables must be generated; otherwise we just keep the expanded form.
- if (!(arrayVar.IsGenerated || posVar.IsGenerated))
+ // We do this because we want compound assignments to be represented in ILAst only when strictly necessary;
+ // other compound assignments will be introduced by ReplaceMethodCallsWithOperator
+ // (which uses a reversible transformation, see ReplaceMethodCallsWithOperator.RestoreOriginalAssignOperatorAnnotation)
+ if (!hasGeneratedVar)
return false;
- ILExpression op = expr.Arguments[2];
+
+ ILExpression op = expr.Arguments.Last();
if (!CanBeRepresentedAsCompoundAssignment(op.Code))
return false;
ILExpression ldelem = op.Arguments[0];
- if (!(ldelem.Code == ILCode.Ldelem_Any && ldelem.Arguments[0].MatchLdloc(arrayVar) && ldelem.Arguments[1].MatchLdloc(posVar)))
+ if (ldelem.Code != (expr.Code == ILCode.Stobj ? ILCode.Ldobj : ILCode.Ldelem_Any))
return false;
+ Debug.Assert(ldelem.Arguments.Count == expr.Arguments.Count - 1);
+ for (int i = 0; i < ldelem.Arguments.Count; i++) {
+ if (!ldelem.Arguments[i].MatchLdloc((ILVariable)expr.Arguments[i].Operand))
+ return false;
+ }
expr.Code = ILCode.CompoundAssignment;
expr.Operand = null;
- expr.Arguments.RemoveRange(0, 2);
+ expr.Arguments.RemoveRange(0, ldelem.Arguments.Count);
// result is "CompoundAssignment(<OP>(ldelem.any(...), <RIGHT>))"
return true;
}
@@ -391,16 +410,18 @@ ILExpression IntroducePostIncrementForInstanceFields(ILExpression expr)
// ->
// stloc(helperVar, postincrement(1, ldflda(field, ldloc(instance))))
- // Also works for array elements:
+ // Also works for array elements and pointers:
// stelem.any(T, ldloc(instance), ldloc(pos), add(stloc(helperVar, ldelem.any(T, ldloc(instance), ldloc(pos))), ldc.i4:int32(1)))
// ->
// stloc(helperVar, postincrement(1, ldelema(ldloc(instance), ldloc(pos))))
- if (!(expr.Code == ILCode.Stfld || expr.Code.IsStoreToArray()))
+ // stobj(T, ldloc(ptr), add(stloc(helperVar, ldobj(T, ldloc(ptr)), ldc.i4:int32(1))))
+
+ if (!(expr.Code == ILCode.Stfld || expr.Code.IsStoreToArray() || expr.Code == ILCode.Stobj))
return null;
- // Test that all arguments except the last are ldloc (1 arg for fields, 2 args for arrays)
+ // Test that all arguments except the last are ldloc (1 arg for fields and pointers, 2 args for arrays)
for (int i = 0; i < expr.Arguments.Count - 1; i++) {
if (expr.Arguments[i].Code != ILCode.Ldloc)
return null;
@@ -417,6 +438,9 @@ ILExpression IntroducePostIncrementForInstanceFields(ILExpression expr)
if (expr.Code == ILCode.Stfld) {
if (!(initialValue.Code == ILCode.Ldfld && initialValue.Operand == expr.Operand))
return null;
+ } else if (expr.Code == ILCode.Stobj) {
+ if (!(initialValue.Code == ILCode.Ldobj && initialValue.Operand == expr.Operand))
+ return null;
} else {
if (!initialValue.Code.IsLoadFromArray())
return null;
@@ -428,8 +452,12 @@ ILExpression IntroducePostIncrementForInstanceFields(ILExpression expr)
}
ILExpression stloc = addExpr.Arguments[0];
- stloc.Arguments[0] = new ILExpression(ILCode.PostIncrement, incrementAmount, initialValue);
- initialValue.Code = (expr.Code == ILCode.Stfld ? ILCode.Ldflda : ILCode.Ldelema);
+ if (expr.Code == ILCode.Stobj) {
+ stloc.Arguments[0] = new ILExpression(ILCode.PostIncrement, incrementAmount, initialValue.Arguments[0]);
+ } else {
+ stloc.Arguments[0] = new ILExpression(ILCode.PostIncrement, incrementAmount, initialValue);
+ initialValue.Code = (expr.Code == ILCode.Stfld ? ILCode.Ldflda : ILCode.Ldelema);
+ }
// TODO: ILRanges?
return stloc;
View
8 ICSharpCode.Decompiler/ILAst/TypeAnalysis.cs
@@ -435,8 +435,12 @@ TypeReference DoInferTypeForExpression(ILExpression expr, TypeReference expected
case ILCode.PostIncrement_Ovf:
case ILCode.PostIncrement_Ovf_Un:
{
- ByReferenceType byReferenceType = InferTypeForExpression(expr.Arguments[0], null) as ByReferenceType;
- return byReferenceType != null ? byReferenceType.ElementType : null;
+ TypeReference type = UnpackPointer(InferTypeForExpression(expr.Arguments[0], null));
+ if (forceInferChildren) {
+ // Assign expected type to the child expression
+ InferTypeForExpression(expr.Arguments[0], new ByReferenceType(type));
+ }
+ return type;
}
#endregion
#region Arithmetic instructions
View
35 ICSharpCode.Decompiler/Tests/IncrementDecrement.cs
@@ -17,6 +17,11 @@ private IncrementDecrement.MutableClass M()
return new IncrementDecrement.MutableClass();
}
+ private unsafe int* GetPointer()
+ {
+ return null;
+ }
+
public int PreIncrementInAddition(int i, int j)
{
return i + ++j;
@@ -42,6 +47,16 @@ public int PreIncrementStaticField()
return ++IncrementDecrement.StaticField;
}
+ public int PreIncrementByRef(ref int i)
+ {
+ return ++i;
+ }
+
+ public unsafe int PreIncrementByPointer()
+ {
+ return ++(*this.GetPointer());
+ }
+
public int CompoundMultiplyInstanceField()
{
return this.M().Field *= 10;
@@ -62,6 +77,16 @@ public int CompoundMultiplyArrayElement2(int[] array)
return array[Environment.TickCount] *= 10;
}
+ public int CompoundShiftByRef(ref int i)
+ {
+ return i <<= 2;
+ }
+
+ public unsafe double CompoundDivideByPointer(double* ptr)
+ {
+ return *ptr /= 1.5;
+ }
+
public int PostIncrementInAddition(int i, int j)
{
return i++ + j;
@@ -86,4 +111,14 @@ public int PostDecrementInstanceField()
{
return this.M().Field--;
}
+
+ public int PostIncrementByRef(ref int i)
+ {
+ return i++;
+ }
+
+ public unsafe int PostIncrementByPointer()
+ {
+ return (*this.GetPointer())++;
+ }
}
View
2  ICSharpCode.Decompiler/Tests/MultidimensionalArray.cs
@@ -1,6 +1,8 @@
// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt)
// This code is distributed under MIT X11 license (for details please see \doc\license.txt)
+using System;
+
public static class MultidimensionalArray
{
internal class Generic<T, S> where T : new()
Please sign in to comment.
Something went wrong with that request. Please try again.