From 0010be6adda833cf7c0b53d2c5bc918f7c096f44 Mon Sep 17 00:00:00 2001 From: Daniel Grunwald Date: Thu, 16 Feb 2012 13:51:22 +0100 Subject: [PATCH] Fixed decompiling "new byte[length]" where length is a long. --- .../Ast/AstMethodBodyBuilder.cs | 11 +- .../ILAst/ILAstOptimizer.cs | 7 +- .../ILAst/InitializerPeepholeTransforms.cs | 148 +++++++++--------- .../ILAst/PeepholeTransform.cs | 66 +++++--- ICSharpCode.Decompiler/ILAst/TypeAnalysis.cs | 15 +- .../Tests/TypeAnalysisTests.cs | 10 ++ 6 files changed, 147 insertions(+), 110 deletions(-) diff --git a/ICSharpCode.Decompiler/Ast/AstMethodBodyBuilder.cs b/ICSharpCode.Decompiler/Ast/AstMethodBodyBuilder.cs index 8b3adddb8..5f78c6081 100644 --- a/ICSharpCode.Decompiler/Ast/AstMethodBodyBuilder.cs +++ b/ICSharpCode.Decompiler/Ast/AstMethodBodyBuilder.cs @@ -525,6 +525,10 @@ namespace ICSharpCode.Decompiler.Ast case ILCode.Conv_Ovf_U2_Un: case ILCode.Conv_Ovf_U4_Un: case ILCode.Conv_Ovf_U8_Un: + case ILCode.Conv_Ovf_I: + case ILCode.Conv_Ovf_U: + case ILCode.Conv_Ovf_I_Un: + case ILCode.Conv_Ovf_U_Un: { // conversion was handled by Convert() function using the info from type analysis CastExpression cast = arg1 as CastExpression; @@ -533,11 +537,8 @@ namespace ICSharpCode.Decompiler.Ast } return arg1; } - case ILCode.Conv_Ovf_I: return arg1.CastTo(new SimpleType("IntPtr")); // TODO - case ILCode.Conv_Ovf_U: return arg1.CastTo(new SimpleType("UIntPtr")); - case ILCode.Conv_Ovf_I_Un: return arg1.CastTo(new SimpleType("IntPtr")); - case ILCode.Conv_Ovf_U_Un: return arg1.CastTo(new SimpleType("UIntPtr")); - case ILCode.Castclass: return arg1.CastTo(operandAsTypeRef); + case ILCode.Castclass: + return arg1.CastTo(operandAsTypeRef); case ILCode.Unbox_Any: // unboxing does not require a cast if the argument was an isinst instruction if (arg1 is AsExpression && byteCode.Arguments[0].Code == ILCode.Isinst && TypeAnalysis.IsSameType(operand as TypeReference, byteCode.Arguments[0].Operand as TypeReference)) diff --git a/ICSharpCode.Decompiler/ILAst/ILAstOptimizer.cs b/ICSharpCode.Decompiler/ILAst/ILAstOptimizer.cs index 710ad85ce..ca9041e1b 100644 --- a/ICSharpCode.Decompiler/ILAst/ILAstOptimizer.cs +++ b/ICSharpCode.Decompiler/ILAst/ILAstOptimizer.cs @@ -44,7 +44,7 @@ namespace ICSharpCode.Decompiler.ILAst JoinBasicBlocks, SimplifyLogicNot, SimplifyShiftOperators, - TransformDecimalCtorToConstant, + TypeConversionSimplifications, SimplifyLdObjAndStObj, SimplifyCustomShortCircuit, SimplifyLiftedOperators, @@ -143,9 +143,8 @@ namespace ICSharpCode.Decompiler.ILAst if (abortBeforeStep == ILAstOptimizationStep.SimplifyShiftOperators) return; modified |= block.RunOptimization(SimplifyShiftOperators); - if (abortBeforeStep == ILAstOptimizationStep.TransformDecimalCtorToConstant) return; - modified |= block.RunOptimization(TransformDecimalCtorToConstant); - modified |= block.RunOptimization(SimplifyLdcI4ConvI8); + if (abortBeforeStep == ILAstOptimizationStep.TypeConversionSimplifications) return; + modified |= block.RunOptimization(TypeConversionSimplifications); if (abortBeforeStep == ILAstOptimizationStep.SimplifyLdObjAndStObj) return; modified |= block.RunOptimization(SimplifyLdObjAndStObj); diff --git a/ICSharpCode.Decompiler/ILAst/InitializerPeepholeTransforms.cs b/ICSharpCode.Decompiler/ILAst/InitializerPeepholeTransforms.cs index a9a828ae9..00a64c96e 100644 --- a/ICSharpCode.Decompiler/ILAst/InitializerPeepholeTransforms.cs +++ b/ICSharpCode.Decompiler/ILAst/InitializerPeepholeTransforms.cs @@ -147,101 +147,101 @@ namespace ICSharpCode.Decompiler.ILAst return false; } - static bool DecodeArrayInitializer(TypeReference elementTypeRef, byte[] initialValue, ILExpression[] output) - { + static bool DecodeArrayInitializer(TypeReference elementTypeRef, byte[] initialValue, ILExpression[] output) + { TypeCode elementType = TypeAnalysis.GetTypeCode(elementTypeRef); switch (elementType) { case TypeCode.Boolean: - case TypeCode.Byte: + case TypeCode.Byte: return DecodeArrayInitializer(initialValue, output, elementType, (d, i) => (int)d[i]); - case TypeCode.SByte: + case TypeCode.SByte: return DecodeArrayInitializer(initialValue, output, elementType, (d, i) => (int)unchecked((sbyte)d[i])); - case TypeCode.Int16: + case TypeCode.Int16: return DecodeArrayInitializer(initialValue, output, elementType, (d, i) => (int)BitConverter.ToInt16(d, i)); case TypeCode.Char: - case TypeCode.UInt16: + case TypeCode.UInt16: return DecodeArrayInitializer(initialValue, output, elementType, (d, i) => (int)BitConverter.ToUInt16(d, i)); case TypeCode.Int32: - case TypeCode.UInt32: + case TypeCode.UInt32: return DecodeArrayInitializer(initialValue, output, elementType, BitConverter.ToInt32); case TypeCode.Int64: - case TypeCode.UInt64: + case TypeCode.UInt64: return DecodeArrayInitializer(initialValue, output, elementType, BitConverter.ToInt64); - case TypeCode.Single: + case TypeCode.Single: return DecodeArrayInitializer(initialValue, output, elementType, BitConverter.ToSingle); - case TypeCode.Double: + case TypeCode.Double: return DecodeArrayInitializer(initialValue, output, elementType, BitConverter.ToDouble); - case TypeCode.Object: + case TypeCode.Object: var typeDef = elementTypeRef.ResolveWithinSameModule(); - if (typeDef != null && typeDef.IsEnum) - return DecodeArrayInitializer(typeDef.GetEnumUnderlyingType(), initialValue, output); - + if (typeDef != null && typeDef.IsEnum) + return DecodeArrayInitializer(typeDef.GetEnumUnderlyingType(), initialValue, output); + return false; default: return false; } } - static bool DecodeArrayInitializer(byte[] initialValue, ILExpression[] output, TypeCode elementType, Func decoder) - { - int elementSize = ElementSizeOf(elementType); - if (initialValue.Length < (output.Length * elementSize)) - return false; - - ILCode code = LoadCodeFor(elementType); - for (int i = 0; i < output.Length; i++) - output[i] = new ILExpression(code, decoder(initialValue, i * elementSize)); - - return true; - } - - private static ILCode LoadCodeFor(TypeCode elementType) - { - switch (elementType) { - case TypeCode.Boolean: - case TypeCode.Byte: - case TypeCode.SByte: - case TypeCode.Char: - case TypeCode.Int16: - case TypeCode.UInt16: - case TypeCode.Int32: - case TypeCode.UInt32: - return ILCode.Ldc_I4; - case TypeCode.Int64: - case TypeCode.UInt64: - return ILCode.Ldc_I8; - case TypeCode.Single: - return ILCode.Ldc_R4; - case TypeCode.Double: - return ILCode.Ldc_R8; - default: - throw new ArgumentOutOfRangeException("elementType"); - } - } - - private static int ElementSizeOf(TypeCode elementType) - { - switch (elementType) { - case TypeCode.Boolean: - case TypeCode.Byte: - case TypeCode.SByte: - return 1; - case TypeCode.Char: - case TypeCode.Int16: - case TypeCode.UInt16: - return 2; - case TypeCode.Int32: - case TypeCode.UInt32: - case TypeCode.Single: - return 4; - case TypeCode.Int64: - case TypeCode.UInt64: - case TypeCode.Double: - return 8; - default: - throw new ArgumentOutOfRangeException("elementType"); - } - } + static bool DecodeArrayInitializer(byte[] initialValue, ILExpression[] output, TypeCode elementType, Func decoder) + { + int elementSize = ElementSizeOf(elementType); + if (initialValue.Length < (output.Length * elementSize)) + return false; + + ILCode code = LoadCodeFor(elementType); + for (int i = 0; i < output.Length; i++) + output[i] = new ILExpression(code, decoder(initialValue, i * elementSize)); + + return true; + } + + private static ILCode LoadCodeFor(TypeCode elementType) + { + switch (elementType) { + case TypeCode.Boolean: + case TypeCode.Byte: + case TypeCode.SByte: + case TypeCode.Char: + case TypeCode.Int16: + case TypeCode.UInt16: + case TypeCode.Int32: + case TypeCode.UInt32: + return ILCode.Ldc_I4; + case TypeCode.Int64: + case TypeCode.UInt64: + return ILCode.Ldc_I8; + case TypeCode.Single: + return ILCode.Ldc_R4; + case TypeCode.Double: + return ILCode.Ldc_R8; + default: + throw new ArgumentOutOfRangeException("elementType"); + } + } + + private static int ElementSizeOf(TypeCode elementType) + { + switch (elementType) { + case TypeCode.Boolean: + case TypeCode.Byte: + case TypeCode.SByte: + return 1; + case TypeCode.Char: + case TypeCode.Int16: + case TypeCode.UInt16: + return 2; + case TypeCode.Int32: + case TypeCode.UInt32: + case TypeCode.Single: + return 4; + case TypeCode.Int64: + case TypeCode.UInt64: + case TypeCode.Double: + return 8; + default: + throw new ArgumentOutOfRangeException("elementType"); + } + } #endregion /// diff --git a/ICSharpCode.Decompiler/ILAst/PeepholeTransform.cs b/ICSharpCode.Decompiler/ILAst/PeepholeTransform.cs index 858ba9a52..0094f5378 100644 --- a/ICSharpCode.Decompiler/ILAst/PeepholeTransform.cs +++ b/ICSharpCode.Decompiler/ILAst/PeepholeTransform.cs @@ -28,8 +28,20 @@ namespace ICSharpCode.Decompiler.ILAst { public partial class ILAstOptimizer { - #region TransformDecimalCtorToConstant - static bool TransformDecimalCtorToConstant(List body, ILExpression expr, int pos) + #region TypeConversionSimplifications + static bool TypeConversionSimplifications(List body, ILExpression expr, int pos) + { + bool modified = false; + modified |= TransformDecimalCtorToConstant(expr); + modified |= SimplifyLdcI4ConvI8(expr); + modified |= RemoveConvIFromArrayCreation(expr); + foreach(ILExpression arg in expr.Arguments) { + modified |= TypeConversionSimplifications(null, arg, -1); + } + return modified; + } + + static bool TransformDecimalCtorToConstant(ILExpression expr) { MethodReference r; List args; @@ -62,11 +74,34 @@ namespace ICSharpCode.Decompiler.ILAst } } } - bool modified = false; - foreach(ILExpression arg in expr.Arguments) { - modified |= TransformDecimalCtorToConstant(null, arg, -1); + return false; + } + + static bool SimplifyLdcI4ConvI8(ILExpression expr) + { + ILExpression ldc; + int val; + if (expr.Match(ILCode.Conv_I8, out ldc) && ldc.Match(ILCode.Ldc_I4, out val)) { + expr.Code = ILCode.Ldc_I8; + expr.Operand = (long)val; + expr.Arguments.Clear(); + return true; } - return modified; + return false; + } + + static bool RemoveConvIFromArrayCreation(ILExpression expr) + { + TypeReference typeRef; + ILExpression length; + ILExpression input; + if (expr.Match(ILCode.Newarr, out typeRef, out length)) { + if (length.Match(ILCode.Conv_Ovf_I, out input) || length.Match(ILCode.Conv_I, out input)) { + expr.Arguments[0] = input; + return true; + } + } + return false; } #endregion @@ -129,25 +164,6 @@ namespace ICSharpCode.Decompiler.ILAst } #endregion - #region SimplifyLdcI4ConvI8 - static bool SimplifyLdcI4ConvI8(List body, ILExpression expr, int pos) - { - ILExpression ldc; - int val; - if (expr.Match(ILCode.Conv_I8, out ldc) && ldc.Match(ILCode.Ldc_I4, out val)) { - expr.Code = ILCode.Ldc_I8; - expr.Operand = (long)val; - expr.Arguments.Clear(); - return true; - } - bool modified = false; - foreach(ILExpression arg in expr.Arguments) { - modified |= SimplifyLdcI4ConvI8(null, arg, -1); - } - return modified; - } - #endregion - #region CachedDelegateInitialization void CachedDelegateInitializationWithField(ILBlock block, ref int i) { diff --git a/ICSharpCode.Decompiler/ILAst/TypeAnalysis.cs b/ICSharpCode.Decompiler/ILAst/TypeAnalysis.cs index 4aa9e1514..b9a3f60ca 100644 --- a/ICSharpCode.Decompiler/ILAst/TypeAnalysis.cs +++ b/ICSharpCode.Decompiler/ILAst/TypeAnalysis.cs @@ -606,8 +606,19 @@ namespace ICSharpCode.Decompiler.ILAst #endregion #region Array instructions case ILCode.Newarr: - if (forceInferChildren) - InferTypeForExpression(expr.Arguments.Single(), typeSystem.Int32); + if (forceInferChildren) { + var lengthType = InferTypeForExpression(expr.Arguments.Single(), null); + if (lengthType == typeSystem.IntPtr) { + lengthType = typeSystem.Int64; + } else if (lengthType == typeSystem.UIntPtr) { + lengthType = typeSystem.UInt64; + } else if (lengthType != typeSystem.UInt32 && lengthType != typeSystem.Int64 && lengthType != typeSystem.UInt64) { + lengthType = typeSystem.Int32; + } + if (forceInferChildren) { + InferTypeForExpression(expr.Arguments.Single(), lengthType); + } + } return new ArrayType((TypeReference)expr.Operand); case ILCode.InitArray: var operandAsArrayType = (ArrayType)expr.Operand; diff --git a/ICSharpCode.Decompiler/Tests/TypeAnalysisTests.cs b/ICSharpCode.Decompiler/Tests/TypeAnalysisTests.cs index 9c550279c..71048f736 100644 --- a/ICSharpCode.Decompiler/Tests/TypeAnalysisTests.cs +++ b/ICSharpCode.Decompiler/Tests/TypeAnalysisTests.cs @@ -120,4 +120,14 @@ public class TypeAnalysisTests Console.WriteLine(o is Random); Console.WriteLine(!(o is Random)); } + + public byte[] CreateArrayWithInt(int length) + { + return new byte[length]; + } + + public byte[] CreateArrayWithLong(long length) + { + return new byte[length]; + } }