Browse Source

Update ICSharpCode.Decompiler to ILSpy commit 11520fd4 (ILSpy 2.0.0.1566).

pull/18/head
Siegfried Pammer 14 years ago
parent
commit
27eda0399b
  1. 70
      src/Libraries/ICSharpCode.Decompiler/Ast/AstBuilder.cs
  2. 20
      src/Libraries/ICSharpCode.Decompiler/Ast/AstMethodBodyBuilder.cs
  3. 3
      src/Libraries/ICSharpCode.Decompiler/Ast/TextOutputFormatter.cs
  4. 22
      src/Libraries/ICSharpCode.Decompiler/Ast/Transforms/AddCheckedBlocks.cs
  5. 2
      src/Libraries/ICSharpCode.Decompiler/Ast/Transforms/DelegateConstruction.cs
  6. 61
      src/Libraries/ICSharpCode.Decompiler/Ast/Transforms/PatternStatementTransform.cs
  7. 24
      src/Libraries/ICSharpCode.Decompiler/CecilExtensions.cs
  8. 18
      src/Libraries/ICSharpCode.Decompiler/ILAst/ILAstOptimizer.cs
  9. 142
      src/Libraries/ICSharpCode.Decompiler/ILAst/InitializerPeepholeTransforms.cs
  10. 68
      src/Libraries/ICSharpCode.Decompiler/ILAst/PeepholeTransform.cs
  11. 53
      src/Libraries/ICSharpCode.Decompiler/ILAst/TypeAnalysis.cs
  12. 4
      src/Libraries/ICSharpCode.Decompiler/Properties/AssemblyInfo.cs
  13. 16
      src/Libraries/ICSharpCode.Decompiler/Tests/InitializerTests.cs
  14. 12
      src/Libraries/ICSharpCode.Decompiler/Tests/Switch.cs
  15. 20
      src/Libraries/ICSharpCode.Decompiler/Tests/TypeAnalysisTests.cs

70
src/Libraries/ICSharpCode.Decompiler/Ast/AstBuilder.cs

@ -70,33 +70,62 @@ namespace ICSharpCode.Decompiler.Ast @@ -70,33 +70,62 @@ namespace ICSharpCode.Decompiler.Ast
if (method != null) {
if (method.IsGetter || method.IsSetter || method.IsAddOn || method.IsRemoveOn)
return true;
if (settings.AnonymousMethods && method.Name.StartsWith("<", StringComparison.Ordinal) && method.IsCompilerGenerated())
if (settings.AnonymousMethods && method.HasGeneratedName() && method.IsCompilerGenerated())
return true;
}
TypeDefinition type = member as TypeDefinition;
if (type != null && type.DeclaringType != null) {
if (settings.AnonymousMethods && type.Name.StartsWith("<>c__DisplayClass", StringComparison.Ordinal) && type.IsCompilerGenerated())
return true;
if (settings.YieldReturn && YieldReturnDecompiler.IsCompilerGeneratorEnumerator(type))
return true;
} else if (type != null && type.IsCompilerGenerated()) {
if (type.Name.StartsWith("<PrivateImplementationDetails>", StringComparison.Ordinal))
return true;
if (type.IsAnonymousType())
return true;
if (type != null) {
if (type.DeclaringType != null) {
if (settings.AnonymousMethods && IsClosureType(type))
return true;
if (settings.YieldReturn && YieldReturnDecompiler.IsCompilerGeneratorEnumerator(type))
return true;
} else if (type.IsCompilerGenerated()) {
if (type.Name.StartsWith("<PrivateImplementationDetails>", StringComparison.Ordinal))
return true;
if (type.IsAnonymousType())
return true;
}
}
FieldDefinition field = member as FieldDefinition;
if (field != null && field.IsCompilerGenerated()) {
if (settings.AnonymousMethods && field.Name.StartsWith("CS$<>", StringComparison.Ordinal))
return true;
if (settings.AutomaticProperties && field.Name.StartsWith("<", StringComparison.Ordinal) && field.Name.EndsWith("BackingField", StringComparison.Ordinal))
if (field != null) {
if (field.IsCompilerGenerated()) {
if (settings.AnonymousMethods && IsAnonymousMethodCacheField(field))
return true;
if (settings.AutomaticProperties && IsAutomaticPropertyBackingField(field))
return true;
if (settings.SwitchStatementOnString && IsSwitchOnStringCache(field))
return true;
}
// event-fields are not [CompilerGenerated]
if (settings.AutomaticEvents && field.DeclaringType.Events.Any(ev => ev.Name == field.Name))
return true;
}
// event-fields are not [CompilerGenerated]
if (field != null && settings.AutomaticEvents && field.DeclaringType.Events.Any(ev => ev.Name == field.Name))
return true;
return false;
}
static bool IsSwitchOnStringCache(FieldDefinition field)
{
return field.Name.StartsWith("<>f__switch", StringComparison.Ordinal);
}
static bool IsAutomaticPropertyBackingField(FieldDefinition field)
{
return field.HasGeneratedName() && field.Name.EndsWith("BackingField", StringComparison.Ordinal);
}
static bool IsAnonymousMethodCacheField(FieldDefinition field)
{
return field.Name.StartsWith("CS$<>", StringComparison.Ordinal) || field.Name.StartsWith("<>f__am", StringComparison.Ordinal);
}
static bool IsClosureType(TypeDefinition type)
{
return type.HasGeneratedName() && type.IsCompilerGenerated() && (type.Name.Contains("DisplayClass") || type.Name.Contains("AnonStorey"));
}
/// <summary>
/// Runs the C# transformations on the compilation unit.
@ -289,7 +318,7 @@ namespace ICSharpCode.Decompiler.Ast @@ -289,7 +318,7 @@ namespace ICSharpCode.Decompiler.Ast
long expectedEnumMemberValue = 0;
bool forcePrintingInitializers = IsFlagsEnum(typeDef);
foreach (FieldDefinition field in typeDef.Fields) {
if (field.IsRuntimeSpecialName) {
if (!field.IsStatic) {
// the value__ field
if (field.FieldType != typeDef.Module.TypeSystem.Int32) {
astType.AddChild(ConvertType(field.FieldType), TypeDeclaration.BaseTypeRole);
@ -920,7 +949,6 @@ namespace ICSharpCode.Decompiler.Ast @@ -920,7 +949,6 @@ namespace ICSharpCode.Decompiler.Ast
IndexerDeclaration ConvertPropertyToIndexer(PropertyDeclaration astProp, PropertyDefinition propDef)
{
var astIndexer = new IndexerDeclaration();
astIndexer.Name = astProp.Name;
astIndexer.CopyAnnotationsFrom(astProp);
astProp.Attributes.MoveTo(astIndexer.Attributes);
astIndexer.Modifiers = astProp.Modifiers;
@ -1489,7 +1517,7 @@ namespace ICSharpCode.Decompiler.Ast @@ -1489,7 +1517,7 @@ namespace ICSharpCode.Decompiler.Ast
foreach (FieldDefinition field in enumDefinition.Fields) {
if (field.IsStatic && object.Equals(CSharpPrimitiveCast.Cast(TypeCode.Int64, field.Constant, false), val))
return ConvertType(type).Member(field.Name).WithAnnotation(field);
else if (!field.IsStatic && field.IsRuntimeSpecialName)
else if (!field.IsStatic)
enumBaseTypeCode = TypeAnalysis.GetTypeCode(field.FieldType); // use primitive type of the enum
}
if (IsFlagsEnum(enumDefinition)) {

20
src/Libraries/ICSharpCode.Decompiler/Ast/AstMethodBodyBuilder.cs

@ -175,7 +175,13 @@ namespace ICSharpCode.Decompiler.Ast @@ -175,7 +175,13 @@ namespace ICSharpCode.Decompiler.Ast
};
} else if (node is ILSwitch) {
ILSwitch ilSwitch = (ILSwitch)node;
if (TypeAnalysis.IsBoolean(ilSwitch.Condition.InferredType) && ilSwitch.CaseBlocks.SelectMany(cb => cb.Values).Any(val => val != 0 && val != 1)) {
if (TypeAnalysis.IsBoolean(ilSwitch.Condition.InferredType) && (
from cb in ilSwitch.CaseBlocks
where cb.Values != null
from val in cb.Values
select val
).Any(val => val != 0 && val != 1))
{
// If switch cases contain values other then 0 and 1, force the condition to be non-boolean
ilSwitch.Condition.ExpectedType = typeSystem.Int32;
}
@ -525,6 +531,10 @@ namespace ICSharpCode.Decompiler.Ast @@ -525,6 +531,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 +543,8 @@ namespace ICSharpCode.Decompiler.Ast @@ -533,11 +543,8 @@ namespace ICSharpCode.Decompiler.Ast
}
return arg1;
}
case ILCode.Conv_Ovf_I: return arg1.CastTo(typeof(IntPtr)); // TODO
case ILCode.Conv_Ovf_U: return arg1.CastTo(typeof(UIntPtr));
case ILCode.Conv_Ovf_I_Un: return arg1.CastTo(typeof(IntPtr));
case ILCode.Conv_Ovf_U_Un: return arg1.CastTo(typeof(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))
@ -999,6 +1006,7 @@ namespace ICSharpCode.Decompiler.Ast @@ -999,6 +1006,7 @@ namespace ICSharpCode.Decompiler.Ast
// This is equivalent to 'target = new ValueType(args);'.
ObjectCreateExpression oce = new ObjectCreateExpression();
oce.Type = AstBuilder.ConvertType(cecilMethod.DeclaringType);
oce.AddAnnotation(cecilMethod);
AdjustArgumentsForMethodCall(cecilMethod, methodArgs);
oce.Arguments.AddRange(methodArgs);
return new AssignmentExpression(target, oce);

3
src/Libraries/ICSharpCode.Decompiler/Ast/TextOutputFormatter.cs

@ -282,6 +282,9 @@ namespace ICSharpCode.Decompiler.Ast @@ -282,6 +282,9 @@ namespace ICSharpCode.Decompiler.Ast
nodeStack.Push(node);
startLocations.Push(output.Location);
if (node is AttributedNode && node.GetChildByRole(AstNode.Roles.Identifier).IsNull)
output.WriteDefinition("", node.Annotation<MemberReference>(), false);
MemberMapping mapping = node.Annotation<MemberMapping>();
if (mapping != null) {
parentMemberMappings.Push(currentMemberMapping);

22
src/Libraries/ICSharpCode.Decompiler/Ast/Transforms/AddCheckedBlocks.cs

@ -45,8 +45,20 @@ namespace ICSharpCode.Decompiler.Ast.Transforms @@ -45,8 +45,20 @@ namespace ICSharpCode.Decompiler.Ast.Transforms
1. Use minimum number of checked blocks+expressions
2. Prefer checked expressions over checked blocks
3. Make the scope of checked expressions as small as possible
4. Make the scope of checked blocks as large as possible
4. Open checked blocks as late as possible, and close checked blocks as late as possible
(where goal 1 has the highest priority)
Goal 4a (open checked blocks as late as possible) is necessary so that we don't move variable declarations
into checked blocks, as the variable might still be used after the checked block.
(this could cause DeclareVariables to omit the variable declaration, producing incorrect code)
Goal 4b (close checked blocks as late as possible) makes the code look nicer in this case:
checked {
int c = a + b;
int r = a + c;
return r;
}
If the checked block was closed as early as possible, the variable r would have to be declared outside
(this would work, but look badly)
*/
#region struct Cost
@ -257,7 +269,7 @@ namespace ICSharpCode.Decompiler.Ast.Transforms @@ -257,7 +269,7 @@ namespace ICSharpCode.Decompiler.Ast.Transforms
Statement statement = block.Statements.FirstOrDefault();
while (true) {
// Blocks can be closed 'for free'. We use '<=' so that blocks are closed as late as possible (goal 4)
// Blocks can be closed 'for free'. We use '<=' so that blocks are closed as late as possible (goal 4b)
if (costCheckedContextUncheckedBlockOpen <= costCheckedContext) {
costCheckedContext = costCheckedContextUncheckedBlockOpen;
nodesCheckedContext = nodesCheckedContextUncheckedBlockOpen + new InsertedBlock(uncheckedBlockStart, statement, false);
@ -268,13 +280,13 @@ namespace ICSharpCode.Decompiler.Ast.Transforms @@ -268,13 +280,13 @@ namespace ICSharpCode.Decompiler.Ast.Transforms
}
if (statement == null)
break;
// Now try opening blocks. We use '<' so that blocks are opened as early as possible. (goal 4)
if (costCheckedContext + new Cost(1, 0) < costCheckedContextUncheckedBlockOpen) {
// Now try opening blocks. We use '<=' so that blocks are opened as late as possible. (goal 4a)
if (costCheckedContext + new Cost(1, 0) <= costCheckedContextUncheckedBlockOpen) {
costCheckedContextUncheckedBlockOpen = costCheckedContext + new Cost(1, 0);
nodesCheckedContextUncheckedBlockOpen = nodesCheckedContext;
uncheckedBlockStart = statement;
}
if (costUncheckedContext + new Cost(1, 0) < costUncheckedContextCheckedBlockOpen) {
if (costUncheckedContext + new Cost(1, 0) <= costUncheckedContextCheckedBlockOpen) {
costUncheckedContextCheckedBlockOpen = costUncheckedContext + new Cost(1, 0);
nodesUncheckedContextCheckedBlockOpen = nodesUncheckedContext;
checkedBlockStart = statement;

2
src/Libraries/ICSharpCode.Decompiler/Ast/Transforms/DelegateConstruction.cs

@ -115,7 +115,7 @@ namespace ICSharpCode.Decompiler.Ast.Transforms @@ -115,7 +115,7 @@ namespace ICSharpCode.Decompiler.Ast.Transforms
internal static bool IsAnonymousMethod(DecompilerContext context, MethodDefinition method)
{
if (method == null || !(method.Name.StartsWith("<", StringComparison.Ordinal) || method.Name.Contains("$")))
if (method == null || !(method.HasGeneratedName() || method.Name.Contains("$")))
return false;
if (!(method.IsCompilerGenerated() || IsPotentialClosure(context, method.DeclaringType)))
return false;

61
src/Libraries/ICSharpCode.Decompiler/Ast/Transforms/PatternStatementTransform.cs

@ -716,7 +716,7 @@ namespace ICSharpCode.Decompiler.Ast.Transforms @@ -716,7 +716,7 @@ namespace ICSharpCode.Decompiler.Ast.Transforms
return null;
}
FieldReference cachedDictField = m.Get<AstNode>("cachedDict").Single().Annotation<FieldReference>();
if (cachedDictField == null || !cachedDictField.DeclaringType.Name.StartsWith("<PrivateImplementationDetails>", StringComparison.Ordinal))
if (cachedDictField == null)
return null;
List<Statement> dictCreation = m.Get<BlockStatement>("dictCreation").Single().Statements.ToList();
List<KeyValuePair<string, int>> dict = BuildDictionary(dictCreation);
@ -764,6 +764,43 @@ namespace ICSharpCode.Decompiler.Ast.Transforms @@ -764,6 +764,43 @@ namespace ICSharpCode.Decompiler.Ast.Transforms
}
List<KeyValuePair<string, int>> BuildDictionary(List<Statement> dictCreation)
{
if (context.Settings.ObjectOrCollectionInitializers && dictCreation.Count == 1)
return BuildDictionaryFromInitializer(dictCreation[0]);
return BuildDictionaryFromAddMethodCalls(dictCreation);
}
static readonly Statement assignInitializedDictionary = new ExpressionStatement {
Expression = new AssignmentExpression {
Left = new AnyNode().ToExpression(),
Right = new ObjectCreateExpression {
Type = new AnyNode(),
Arguments = { new Repeat(new AnyNode()) },
Initializer = new ArrayInitializerExpression {
Elements = { new Repeat(new AnyNode("dictJumpTable")) }
}
},
},
};
private List<KeyValuePair<string, int>> BuildDictionaryFromInitializer(Statement statement)
{
List<KeyValuePair<string, int>> dict = new List<KeyValuePair<string, int>>();
Match m = assignInitializedDictionary.Match(statement);
if (!m.Success)
return dict;
foreach (ArrayInitializerExpression initializer in m.Get<ArrayInitializerExpression>("dictJumpTable")) {
KeyValuePair<string, int> pair;
if (TryGetPairFrom(initializer.Elements, out pair))
dict.Add(pair);
}
return dict;
}
private static List<KeyValuePair<string, int>> BuildDictionaryFromAddMethodCalls(List<Statement> dictCreation)
{
List<KeyValuePair<string, int>> dict = new List<KeyValuePair<string, int>>();
for (int i = 0; i < dictCreation.Count; i++) {
@ -773,13 +810,27 @@ namespace ICSharpCode.Decompiler.Ast.Transforms @@ -773,13 +810,27 @@ namespace ICSharpCode.Decompiler.Ast.Transforms
InvocationExpression ie = es.Expression as InvocationExpression;
if (ie == null)
continue;
PrimitiveExpression arg1 = ie.Arguments.ElementAtOrDefault(0) as PrimitiveExpression;
PrimitiveExpression arg2 = ie.Arguments.ElementAtOrDefault(1) as PrimitiveExpression;
if (arg1 != null && arg2 != null && arg1.Value is string && arg2.Value is int)
dict.Add(new KeyValuePair<string, int>((string)arg1.Value, (int)arg2.Value));
KeyValuePair<string, int> pair;
if (TryGetPairFrom(ie.Arguments, out pair))
dict.Add(pair);
}
return dict;
}
private static bool TryGetPairFrom(AstNodeCollection<Expression> expressions, out KeyValuePair<string, int> pair)
{
PrimitiveExpression arg1 = expressions.ElementAtOrDefault(0) as PrimitiveExpression;
PrimitiveExpression arg2 = expressions.ElementAtOrDefault(1) as PrimitiveExpression;
if (arg1 != null && arg2 != null && arg1.Value is string && arg2.Value is int) {
pair = new KeyValuePair<string, int>((string)arg1.Value, (int)arg2.Value);
return true;
}
pair = default(KeyValuePair<string, int>);
return false;
}
#endregion
#region Automatic Properties

24
src/Libraries/ICSharpCode.Decompiler/CecilExtensions.cs

@ -215,17 +215,39 @@ namespace ICSharpCode.Decompiler @@ -215,17 +215,39 @@ namespace ICSharpCode.Decompiler
return true;
return IsCompilerGeneratedOrIsInCompilerGeneratedClass(member.DeclaringType);
}
public static TypeReference GetEnumUnderlyingType(this TypeDefinition type)
{
if (!type.IsEnum)
throw new ArgumentException("Type must be an enum", "type");
var fields = type.Fields;
for (int i = 0; i < fields.Count; i++)
{
var field = fields[i];
if (!field.IsStatic)
return field.FieldType;
}
throw new NotSupportedException();
}
public static bool IsAnonymousType(this TypeReference type)
{
if (type == null)
return false;
if (string.IsNullOrEmpty(type.Namespace) && type.Name.StartsWith("<>", StringComparison.Ordinal) && type.Name.Contains("AnonymousType")) {
if (string.IsNullOrEmpty(type.Namespace) && type.HasGeneratedName() && (type.Name.Contains("AnonType") || type.Name.Contains("AnonymousType"))) {
TypeDefinition td = type.Resolve();
return td != null && td.IsCompilerGenerated();
}
return false;
}
public static bool HasGeneratedName(this MemberReference member)
{
return member.Name.StartsWith("<", StringComparison.Ordinal);
}
public static bool ContainsAnonymousType(this TypeReference type)
{

18
src/Libraries/ICSharpCode.Decompiler/ILAst/ILAstOptimizer.cs

@ -44,7 +44,7 @@ namespace ICSharpCode.Decompiler.ILAst @@ -44,7 +44,7 @@ namespace ICSharpCode.Decompiler.ILAst
JoinBasicBlocks,
SimplifyLogicNot,
SimplifyShiftOperators,
TransformDecimalCtorToConstant,
TypeConversionSimplifications,
SimplifyLdObjAndStObj,
SimplifyCustomShortCircuit,
SimplifyLiftedOperators,
@ -143,9 +143,8 @@ namespace ICSharpCode.Decompiler.ILAst @@ -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);
@ -852,5 +851,16 @@ namespace ICSharpCode.Decompiler.ILAst @@ -852,5 +851,16 @@ namespace ICSharpCode.Decompiler.ILAst
if (!collection.Remove(key))
throw new Exception("The key was not found in the dictionary");
}
public static bool ContainsReferenceTo(this ILExpression expr, ILVariable v)
{
if (expr.Operand == v)
return true;
foreach (var arg in expr.Arguments) {
if (ContainsReferenceTo(arg, v))
return true;
}
return false;
}
}
}

142
src/Libraries/ICSharpCode.Decompiler/ILAst/InitializerPeepholeTransforms.cs

@ -63,7 +63,9 @@ namespace ICSharpCode.Decompiler.ILAst @@ -63,7 +63,9 @@ namespace ICSharpCode.Decompiler.ILAst
v == v3 &&
nextExpr.Arguments[1].Match(ILCode.Ldc_I4, out arrayPos) &&
arrayPos >= operands.Count &&
arrayPos <= operands.Count + maxConsecutiveDefaultValueExpressions) {
arrayPos <= operands.Count + maxConsecutiveDefaultValueExpressions &&
!nextExpr.Arguments[2].ContainsReferenceTo(v3))
{
while (operands.Count < arrayPos)
operands.Add(new ILExpression(ILCode.DefaultValue, elementType));
operands.Add(nextExpr.Arguments[2]);
@ -109,7 +111,6 @@ namespace ICSharpCode.Decompiler.ILAst @@ -109,7 +111,6 @@ namespace ICSharpCode.Decompiler.ILAst
ILExpression[] newArr;
int initArrayPos;
if (ForwardScanInitializeArrayRuntimeHelper(body, pos + 1, v, arrayType, totalElements, out newArr, out initArrayPos)) {
var mdArr = Array.CreateInstance(typeof(ILExpression), arrayLengths);
body[pos] = new ILExpression(ILCode.Stloc, v, new ILExpression(ILCode.InitArray, arrayType, newArr));
body.RemoveAt(initArrayPos);
return true;
@ -135,8 +136,7 @@ namespace ICSharpCode.Decompiler.ILAst @@ -135,8 +136,7 @@ namespace ICSharpCode.Decompiler.ILAst
FieldDefinition fieldDef = fieldRef.ResolveWithinSameModule();
if (fieldDef != null && fieldDef.InitialValue != null) {
ILExpression[] newArr = new ILExpression[arrayLength];
if (DecodeArrayInitializer(TypeAnalysis.GetTypeCode(arrayType.GetElementType()),
fieldDef.InitialValue, newArr))
if (DecodeArrayInitializer(arrayType.GetElementType(), fieldDef.InitialValue, newArr))
{
values = newArr;
foundPos = pos;
@ -149,81 +149,101 @@ namespace ICSharpCode.Decompiler.ILAst @@ -149,81 +149,101 @@ namespace ICSharpCode.Decompiler.ILAst
return false;
}
static bool DecodeArrayInitializer(TypeCode elementType, 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:
if (initialValue.Length == output.Length) {
for (int j = 0; j < output.Length; j++) {
output[j] = new ILExpression(ILCode.Ldc_I4, (int)initialValue[j]);
}
return true;
}
return false;
return DecodeArrayInitializer(initialValue, output, elementType, (d, i) => (int)d[i]);
case TypeCode.SByte:
if (initialValue.Length == output.Length) {
for (int j = 0; j < output.Length; j++) {
output[j] = new ILExpression(ILCode.Ldc_I4, (int)unchecked((sbyte)initialValue[j]));
}
return true;
}
return false;
return DecodeArrayInitializer(initialValue, output, elementType, (d, i) => (int)unchecked((sbyte)d[i]));
case TypeCode.Int16:
if (initialValue.Length == output.Length * 2) {
for (int j = 0; j < output.Length; j++) {
output[j] = new ILExpression(ILCode.Ldc_I4, (int)BitConverter.ToInt16(initialValue, j * 2));
}
return true;
}
return false;
return DecodeArrayInitializer(initialValue, output, elementType, (d, i) => (int)BitConverter.ToInt16(d, i));
case TypeCode.Char:
case TypeCode.UInt16:
if (initialValue.Length == output.Length * 2) {
for (int j = 0; j < output.Length; j++) {
output[j] = new ILExpression(ILCode.Ldc_I4, (int)BitConverter.ToUInt16(initialValue, j * 2));
}
return true;
}
return false;
return DecodeArrayInitializer(initialValue, output, elementType, (d, i) => (int)BitConverter.ToUInt16(d, i));
case TypeCode.Int32:
case TypeCode.UInt32:
if (initialValue.Length == output.Length * 4) {
for (int j = 0; j < output.Length; j++) {
output[j] = new ILExpression(ILCode.Ldc_I4, BitConverter.ToInt32(initialValue, j * 4));
}
return true;
}
return false;
return DecodeArrayInitializer(initialValue, output, elementType, BitConverter.ToInt32);
case TypeCode.Int64:
case TypeCode.UInt64:
if (initialValue.Length == output.Length * 8) {
for (int j = 0; j < output.Length; j++) {
output[j] = new ILExpression(ILCode.Ldc_I8, BitConverter.ToInt64(initialValue, j * 8));
}
return true;
}
return false;
return DecodeArrayInitializer(initialValue, output, elementType, BitConverter.ToInt64);
case TypeCode.Single:
if (initialValue.Length == output.Length * 4) {
for (int j = 0; j < output.Length; j++) {
output[j] = new ILExpression(ILCode.Ldc_R4, BitConverter.ToSingle(initialValue, j * 4));
}
return true;
}
return false;
return DecodeArrayInitializer(initialValue, output, elementType, BitConverter.ToSingle);
case TypeCode.Double:
if (initialValue.Length == output.Length * 8) {
for (int j = 0; j < output.Length; j++) {
output[j] = new ILExpression(ILCode.Ldc_R8, BitConverter.ToDouble(initialValue, j * 8));
}
return true;
}
return DecodeArrayInitializer(initialValue, output, elementType, BitConverter.ToDouble);
case TypeCode.Object:
var typeDef = elementTypeRef.ResolveWithinSameModule();
if (typeDef != null && typeDef.IsEnum)
return DecodeArrayInitializer(typeDef.GetEnumUnderlyingType(), initialValue, output);
return false;
default:
return false;
}
}
static bool DecodeArrayInitializer<T>(byte[] initialValue, ILExpression[] output, TypeCode elementType, Func<byte[], int, T> 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
/// <summary>
@ -367,7 +387,7 @@ namespace ICSharpCode.Decompiler.ILAst @@ -367,7 +387,7 @@ namespace ICSharpCode.Decompiler.ILAst
{
MethodReference addMethod;
List<ILExpression> args;
if (expr.Match(ILCode.Callvirt, out addMethod, out args)) {
if (expr.Match(ILCode.Callvirt, out addMethod, out args) || expr.Match(ILCode.Call, out addMethod, out args)) {
if (addMethod.Name == "Add" && addMethod.HasThis) {
return args.Count >= 2;
}

68
src/Libraries/ICSharpCode.Decompiler/ILAst/PeepholeTransform.cs

@ -28,8 +28,20 @@ namespace ICSharpCode.Decompiler.ILAst @@ -28,8 +28,20 @@ namespace ICSharpCode.Decompiler.ILAst
{
public partial class ILAstOptimizer
{
#region TransformDecimalCtorToConstant
static bool TransformDecimalCtorToConstant(List<ILNode> body, ILExpression expr, int pos)
#region TypeConversionSimplifications
static bool TypeConversionSimplifications(List<ILNode> 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<ILExpression> args;
@ -62,11 +74,36 @@ namespace ICSharpCode.Decompiler.ILAst @@ -62,11 +74,36 @@ 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)
|| length.Match(ILCode.Conv_Ovf_I_Un, out input) || length.Match(ILCode.Conv_U, out input))
{
expr.Arguments[0] = input;
return true;
}
}
return false;
}
#endregion
@ -129,25 +166,6 @@ namespace ICSharpCode.Decompiler.ILAst @@ -129,25 +166,6 @@ namespace ICSharpCode.Decompiler.ILAst
}
#endregion
#region SimplifyLdcI4ConvI8
static bool SimplifyLdcI4ConvI8(List<ILNode> 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)
{

53
src/Libraries/ICSharpCode.Decompiler/ILAst/TypeAnalysis.cs

@ -606,8 +606,19 @@ namespace ICSharpCode.Decompiler.ILAst @@ -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;
@ -1035,18 +1046,28 @@ namespace ICSharpCode.Decompiler.ILAst @@ -1035,18 +1046,28 @@ namespace ICSharpCode.Decompiler.ILAst
/// </summary>
public const int NativeInt = 33; // treat native int as between int32 and int64
public static int GetInformationAmount(TypeReference type)
/// <summary>
/// Gets the underlying type, if the specified type is an enum.
/// Otherwise, returns null.
/// </summary>
public static TypeReference GetEnumUnderlyingType(TypeReference enumType)
{
if (type == null)
return 0;
if (type.IsValueType && !IsArrayPointerOrReference(type)) {
// unfortunately we cannot rely on enumType.IsValueType here - it's not set when the instruction operand is a typeref (as opposed to a typespec)
if (enumType != null && !IsArrayPointerOrReference(enumType)) {
// value type might be an enum
TypeDefinition typeDef = type.Resolve() as TypeDefinition;
TypeDefinition typeDef = enumType.Resolve() as TypeDefinition;
if (typeDef != null && typeDef.IsEnum) {
TypeReference underlyingType = typeDef.Fields.Single(f => f.IsRuntimeSpecialName && !f.IsStatic).FieldType;
return GetInformationAmount(underlyingType);
return typeDef.Fields.Single(f => !f.IsStatic).FieldType;
}
}
return null;
}
public static int GetInformationAmount(TypeReference type)
{
type = GetEnumUnderlyingType(type) ?? type;
if (type == null)
return 0;
switch (type.MetadataType) {
case MetadataType.Void:
return 0;
@ -1098,14 +1119,9 @@ namespace ICSharpCode.Decompiler.ILAst @@ -1098,14 +1119,9 @@ namespace ICSharpCode.Decompiler.ILAst
static bool? IsSigned(TypeReference type)
{
if (type == null || IsArrayPointerOrReference(type))
type = GetEnumUnderlyingType(type) ?? type;
if (type == null)
return null;
// unfortunately we cannot rely on type.IsValueType here - it's not set when the instruction operand is a typeref (as opposed to a typespec)
TypeDefinition typeDef = type.Resolve() as TypeDefinition;
if (typeDef != null && typeDef.IsEnum) {
TypeReference underlyingType = typeDef.Fields.Single(f => f.IsRuntimeSpecialName && !f.IsStatic).FieldType;
return IsSigned(underlyingType);
}
switch (type.MetadataType) {
case MetadataType.SByte:
case MetadataType.Int16:
@ -1127,10 +1143,7 @@ namespace ICSharpCode.Decompiler.ILAst @@ -1127,10 +1143,7 @@ namespace ICSharpCode.Decompiler.ILAst
static bool OperandFitsInType(TypeReference type, int num)
{
TypeDefinition typeDef = type.Resolve() as TypeDefinition;
if (typeDef != null && typeDef.IsEnum) {
type = typeDef.Fields.Single(f => f.IsRuntimeSpecialName && !f.IsStatic).FieldType;
}
type = GetEnumUnderlyingType(type) ?? type;
switch (type.MetadataType) {
case MetadataType.SByte:
return sbyte.MinValue <= num && num <= sbyte.MaxValue;

4
src/Libraries/ICSharpCode.Decompiler/Properties/AssemblyInfo.cs

@ -19,8 +19,8 @@ using System.Runtime.InteropServices; @@ -19,8 +19,8 @@ using System.Runtime.InteropServices;
// If you need to expose a type to COM, use [ComVisible(true)] on that type.
[assembly: ComVisible(false)]
[assembly: AssemblyVersion("2.0.0.1509")]
[assembly: AssemblyInformationalVersion("2.0.0.1509-09c2b45f")]
[assembly: AssemblyVersion("2.0.0.1489")]
[assembly: AssemblyInformationalVersion("2.0.0.1489-774e3cd8")]
[assembly: NeutralResourcesLanguage("en-US")]
[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2243:AttributeStringLiteralsShouldParseCorrectly",

16
src/Libraries/ICSharpCode.Decompiler/Tests/InitializerTests.cs

@ -353,6 +353,15 @@ public class InitializerTests @@ -353,6 +353,15 @@ public class InitializerTests
InitializerTests.MyEnum.b
});
}
public static void RecursiveArrayInitializer()
{
int[] array = new int[3];
array[0] = 1;
array[1] = 2;
array[2] = array[1] + 1;
array[0] = 0;
}
#endregion
public static void CollectionInitializerList()
@ -365,6 +374,13 @@ public class InitializerTests @@ -365,6 +374,13 @@ public class InitializerTests
});
}
public static object RecursiveCollectionInitializer()
{
List<object> list = new List<object>();
list.Add(list);
return list;
}
public static void CollectionInitializerDictionary()
{
InitializerTests.X(InitializerTests.Y(), new Dictionary<string, int>

12
src/Libraries/ICSharpCode.Decompiler/Tests/Switch.cs

@ -74,4 +74,16 @@ public static class Switch @@ -74,4 +74,16 @@ public static class Switch
return "Default";
}
}
public static string SwitchOverBool(bool b)
{
switch (b) {
case true:
return bool.TrueString;
case false:
return bool.FalseString;
default:
return null;
}
}
}

20
src/Libraries/ICSharpCode.Decompiler/Tests/TypeAnalysisTests.cs

@ -120,4 +120,24 @@ public class TypeAnalysisTests @@ -120,4 +120,24 @@ 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];
}
public byte[] CreateArrayWithUInt(uint length)
{
return new byte[length];
}
public byte[] CreateArrayWithULong(ulong length)
{
return new byte[length];
}
}

Loading…
Cancel
Save