Browse Source

Merge branch 'LordJZ-case/pointer-arithmetic'

pull/550/head
Siegfried Pammer 10 years ago
parent
commit
715cae08c7
  1. 58
      ICSharpCode.Decompiler/Ast/AstMethodBodyBuilder.cs
  2. 105
      ICSharpCode.Decompiler/ILAst/ILAstOptimizer.cs
  3. 8
      ICSharpCode.Decompiler/ILAst/TypeAnalysis.cs
  4. 17
      ICSharpCode.Decompiler/Tests/UnsafeCode.cs

58
ICSharpCode.Decompiler/Ast/AstMethodBodyBuilder.cs

@ -291,16 +291,10 @@ namespace ICSharpCode.Decompiler.Ast @@ -291,16 +291,10 @@ namespace ICSharpCode.Decompiler.Ast
{
BinaryOperatorExpression boe;
if (byteCode.InferredType is PointerType) {
if (byteCode.Arguments[0].ExpectedType is PointerType) {
arg2 = DivideBySize(arg2, ((PointerType)byteCode.InferredType).ElementType);
boe = new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.Add, arg2);
boe.AddAnnotation(IntroduceUnsafeModifier.PointerArithmeticAnnotation);
} else if (byteCode.Arguments[1].ExpectedType is PointerType) {
arg1 = DivideBySize(arg1, ((PointerType)byteCode.InferredType).ElementType);
boe = new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.Add, arg2);
boe = new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.Add, arg2);
if (byteCode.Arguments[0].ExpectedType is PointerType ||
byteCode.Arguments[1].ExpectedType is PointerType) {
boe.AddAnnotation(IntroduceUnsafeModifier.PointerArithmeticAnnotation);
} else {
boe = new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.Add, arg2);
}
} else {
boe = new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.Add, arg2);
@ -314,12 +308,9 @@ namespace ICSharpCode.Decompiler.Ast @@ -314,12 +308,9 @@ namespace ICSharpCode.Decompiler.Ast
{
BinaryOperatorExpression boe;
if (byteCode.InferredType is PointerType) {
boe = new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.Subtract, arg2);
if (byteCode.Arguments[0].ExpectedType is PointerType) {
arg2 = DivideBySize(arg2, ((PointerType)byteCode.InferredType).ElementType);
boe = new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.Subtract, arg2);
boe.WithAnnotation(IntroduceUnsafeModifier.PointerArithmeticAnnotation);
} else {
boe = new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.Subtract, arg2);
}
} else {
boe = new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.Subtract, arg2);
@ -724,7 +715,7 @@ namespace ICSharpCode.Decompiler.Ast @@ -724,7 +715,7 @@ namespace ICSharpCode.Decompiler.Ast
}
return new StackAllocExpression {
Type = AstBuilder.ConvertType(type),
CountExpression = DivideBySize(arg1, type)
CountExpression = arg1
};
}
case ILCode.Mkrefany:
@ -920,45 +911,6 @@ namespace ICSharpCode.Decompiler.Ast @@ -920,45 +911,6 @@ namespace ICSharpCode.Decompiler.Ast
}
}
/// <summary>
/// Divides expr by the size of 'type'.
/// </summary>
Expression DivideBySize(Expression expr, TypeReference type)
{
CastExpression cast = expr as CastExpression;
if (cast != null && cast.Type is PrimitiveType && ((PrimitiveType)cast.Type).Keyword == "int")
expr = cast.Expression.Detach();
Expression sizeOfExpression;
switch (TypeAnalysis.GetInformationAmount(type)) {
case 1:
case 8:
sizeOfExpression = new PrimitiveExpression(1);
break;
case 16:
sizeOfExpression = new PrimitiveExpression(2);
break;
case 32:
sizeOfExpression = new PrimitiveExpression(4);
break;
case 64:
sizeOfExpression = new PrimitiveExpression(8);
break;
default:
sizeOfExpression = new SizeOfExpression { Type = AstBuilder.ConvertType(type) };
break;
}
BinaryOperatorExpression boe = expr as BinaryOperatorExpression;
if (boe != null && boe.Operator == BinaryOperatorType.Multiply && sizeOfExpression.IsMatch(boe.Right))
return boe.Left.Detach();
if (sizeOfExpression.IsMatch(expr))
return new PrimitiveExpression(1);
return new BinaryOperatorExpression(expr, BinaryOperatorType.Divide, sizeOfExpression);
}
Expression MakeDefaultValue(TypeReference type)
{
TypeDefinition typeDef = type.Resolve();

105
ICSharpCode.Decompiler/ILAst/ILAstOptimizer.cs

@ -39,6 +39,7 @@ namespace ICSharpCode.Decompiler.ILAst @@ -39,6 +39,7 @@ namespace ICSharpCode.Decompiler.ILAst
PropertyAccessInstructions,
SplitToMovableBlocks,
TypeInference,
HandlePointerArithmetic,
SimplifyShortCircuit,
SimplifyTernaryOperator,
SimplifyNullCoalescing,
@ -125,6 +126,9 @@ namespace ICSharpCode.Decompiler.ILAst @@ -125,6 +126,9 @@ namespace ICSharpCode.Decompiler.ILAst
// Types are needed for the ternary operator optimization
TypeAnalysis.Run(context, method);
if (abortBeforeStep == ILAstOptimizationStep.HandlePointerArithmetic) return;
HandlePointerArithmetic(method);
foreach(ILBlock block in method.GetSelfAndChildrenRecursive<ILBlock>()) {
bool modified;
do {
@ -664,6 +668,107 @@ namespace ICSharpCode.Decompiler.ILAst @@ -664,6 +668,107 @@ namespace ICSharpCode.Decompiler.ILAst
return combinedVariable;
});
}
static void HandlePointerArithmetic(ILNode method)
{
foreach (ILExpression expr in method.GetSelfAndChildrenRecursive<ILExpression>()) {
List<ILExpression> args = expr.Arguments;
switch (expr.Code) {
case ILCode.Localloc:
args[0] = DivideBySize(args[0], ((PointerType)expr.InferredType).ElementType);
break;
case ILCode.Add:
case ILCode.Add_Ovf:
case ILCode.Add_Ovf_Un:
if (expr.InferredType is PointerType) {
if (args[0].ExpectedType is PointerType)
args[1] = DivideBySize(args[1], ((PointerType)expr.InferredType).ElementType);
else if (args[1].ExpectedType is PointerType)
args[0] = DivideBySize(args[0], ((PointerType)expr.InferredType).ElementType);
}
break;
case ILCode.Sub:
case ILCode.Sub_Ovf:
case ILCode.Sub_Ovf_Un:
if (expr.InferredType is PointerType) {
if (args[0].ExpectedType is PointerType)
args[1] = DivideBySize(args[1], ((PointerType)expr.InferredType).ElementType);
}
break;
}
}
}
static ILExpression UnwrapIntPtrCast(ILExpression expr)
{
if (expr.Code != ILCode.Conv_I && expr.Code != ILCode.Conv_U)
return expr;
ILExpression arg = expr.Arguments[0];
switch (arg.InferredType.MetadataType) {
case MetadataType.Byte:
case MetadataType.SByte:
case MetadataType.UInt16:
case MetadataType.Int16:
case MetadataType.UInt32:
case MetadataType.Int32:
case MetadataType.UInt64:
case MetadataType.Int64:
return arg;
}
return expr;
}
static ILExpression DivideBySize(ILExpression expr, TypeReference type)
{
expr = UnwrapIntPtrCast(expr);
ILExpression sizeOfExpression;
switch (TypeAnalysis.GetInformationAmount(type)) {
case 1:
case 8:
sizeOfExpression = new ILExpression(ILCode.Ldc_I4, 1);
break;
case 16:
sizeOfExpression = new ILExpression(ILCode.Ldc_I4, 2);
break;
case 32:
sizeOfExpression = new ILExpression(ILCode.Ldc_I4, 4);
break;
case 64:
sizeOfExpression = new ILExpression(ILCode.Ldc_I4, 8);
break;
default:
sizeOfExpression = new ILExpression(ILCode.Sizeof, type);
break;
}
if (expr.Code == ILCode.Mul || expr.Code == ILCode.Mul_Ovf || expr.Code == ILCode.Mul_Ovf_Un) {
ILExpression mulArg = expr.Arguments[1];
if (mulArg.Code == sizeOfExpression.Code && sizeOfExpression.Operand.Equals(mulArg.Operand))
return UnwrapIntPtrCast(expr.Arguments[0]);
}
if (expr.Code == sizeOfExpression.Code) {
if (sizeOfExpression.Operand.Equals(expr.Operand))
return new ILExpression(ILCode.Ldc_I4, 1);
if (expr.Code == ILCode.Ldc_I4) {
int offsetInBytes = (int)expr.Operand;
int elementSize = (int)sizeOfExpression.Operand;
int offsetInElements = offsetInBytes / elementSize;
// ensure integer division
if (offsetInElements * elementSize == offsetInBytes) {
expr.Operand = offsetInElements;
return expr;
}
}
}
return new ILExpression(ILCode.Div_Un, null, expr, sizeOfExpression);
}
public static void ReplaceVariables(ILNode node, Func<ILVariable, ILVariable> variableMapping)
{

8
ICSharpCode.Decompiler/ILAst/TypeAnalysis.cs

@ -450,7 +450,7 @@ namespace ICSharpCode.Decompiler.ILAst @@ -450,7 +450,7 @@ namespace ICSharpCode.Decompiler.ILAst
return (TypeReference)expr.Operand;
case ILCode.Localloc:
if (forceInferChildren) {
InferTypeForExpression(expr.Arguments[0], typeSystem.Int32);
InferTypeForExpression(expr.Arguments[0], null);
}
if (expectedType is PointerType)
return expectedType;
@ -1013,7 +1013,7 @@ namespace ICSharpCode.Decompiler.ILAst @@ -1013,7 +1013,7 @@ namespace ICSharpCode.Decompiler.ILAst
TypeReference leftPreferred = DoInferTypeForExpression(left, expectedType);
if (leftPreferred is PointerType) {
left.InferredType = left.ExpectedType = leftPreferred;
InferTypeForExpression(right, typeSystem.IntPtr);
InferTypeForExpression(right, null);
return leftPreferred;
}
if (IsEnum(leftPreferred)) {
@ -1024,7 +1024,7 @@ namespace ICSharpCode.Decompiler.ILAst @@ -1024,7 +1024,7 @@ namespace ICSharpCode.Decompiler.ILAst
}
TypeReference rightPreferred = DoInferTypeForExpression(right, expectedType);
if (rightPreferred is PointerType) {
InferTypeForExpression(left, typeSystem.IntPtr);
InferTypeForExpression(left, null);
right.InferredType = right.ExpectedType = rightPreferred;
return rightPreferred;
}
@ -1044,7 +1044,7 @@ namespace ICSharpCode.Decompiler.ILAst @@ -1044,7 +1044,7 @@ namespace ICSharpCode.Decompiler.ILAst
TypeReference leftPreferred = DoInferTypeForExpression(left, expectedType);
if (leftPreferred is PointerType) {
left.InferredType = left.ExpectedType = leftPreferred;
InferTypeForExpression(right, typeSystem.IntPtr);
InferTypeForExpression(right, null);
return leftPreferred;
}
if (IsEnum(leftPreferred)) {

17
ICSharpCode.Decompiler/Tests/UnsafeCode.cs

@ -122,7 +122,22 @@ public class UnsafeCode @@ -122,7 +122,22 @@ public class UnsafeCode
}
return this.PointerReferenceExpression((double*)ptr);
}
public unsafe int* PointerArithmetic(int* p)
{
return p + 2;
}
public unsafe byte* PointerArithmetic2(long* p, int y, int x)
{
return (byte*)p + (y * x);
}
public unsafe long* PointerArithmetic3(long* p)
{
return (long*)((byte*)p + 3);
}
unsafe ~UnsafeCode()
{
this.PassPointerAsRefParameter(this.NullPointer);

Loading…
Cancel
Save