Browse Source

Fix #562: Update ILSpy to version 2.2

pull/567/head
Daniel Grunwald 11 years ago
parent
commit
72c23cdbad
  1. 23
      src/Libraries/ICSharpCode.Decompiler/Ast/AstBuilder.cs
  2. 16
      src/Libraries/ICSharpCode.Decompiler/Ast/AstMethodBodyBuilder.cs
  3. 2
      src/Libraries/ICSharpCode.Decompiler/Ast/Transforms/ExpressionTreeConverter.cs
  4. 15
      src/Libraries/ICSharpCode.Decompiler/DecompilerSettings.cs
  5. 8
      src/Libraries/ICSharpCode.Decompiler/Disassembler/DisassemblerHelpers.cs
  6. 4
      src/Libraries/ICSharpCode.Decompiler/Disassembler/MethodBodyDisassembler.cs
  7. 97
      src/Libraries/ICSharpCode.Decompiler/ILAst/AsyncDecompiler.cs
  8. 8
      src/Libraries/ICSharpCode.Decompiler/ILAst/ILAstBuilder.cs
  9. 20
      src/Libraries/ICSharpCode.Decompiler/ILAst/ILAstOptimizer.cs
  10. 20
      src/Libraries/ICSharpCode.Decompiler/ILAst/ILInlining.cs
  11. 6
      src/Libraries/ICSharpCode.Decompiler/ILAst/PatternMatching.cs
  12. 14
      src/Libraries/ICSharpCode.Decompiler/ILAst/StateRange.cs
  13. 13
      src/Libraries/ICSharpCode.Decompiler/ILAst/SymbolicExecution.cs
  14. 4
      src/Libraries/ICSharpCode.Decompiler/ILAst/TypeAnalysis.cs
  15. 30
      src/Libraries/ICSharpCode.Decompiler/ILAst/YieldReturnDecompiler.cs
  16. 26
      src/Libraries/ICSharpCode.Decompiler/Properties/AssemblyInfo.cs
  17. 11
      src/Libraries/ICSharpCode.Decompiler/Tests/Async.cs
  18. 16
      src/Libraries/ICSharpCode.Decompiler/Tests/DelegateConstruction.cs
  19. 28
      src/Libraries/ICSharpCode.Decompiler/Tests/DoubleConstants.cs
  20. 1
      src/Libraries/ICSharpCode.Decompiler/Tests/ICSharpCode.Decompiler.Tests.csproj
  21. 6
      src/Libraries/ICSharpCode.Decompiler/Tests/TestRunner.cs

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

@ -167,7 +167,12 @@ namespace ICSharpCode.Decompiler.Ast @@ -167,7 +167,12 @@ namespace ICSharpCode.Decompiler.Ast
public void AddAssembly(AssemblyDefinition assemblyDefinition, bool onlyAssemblyLevel = false)
{
if (assemblyDefinition.Name.Version != null) {
AddAssembly(assemblyDefinition.MainModule, onlyAssemblyLevel);
}
public void AddAssembly(ModuleDefinition moduleDefinition, bool onlyAssemblyLevel = false)
{
if (moduleDefinition.Assembly != null && moduleDefinition.Assembly.Name.Version != null) {
syntaxTree.AddChild(
new AttributeSection {
AttributeTarget = "assembly",
@ -176,22 +181,24 @@ namespace ICSharpCode.Decompiler.Ast @@ -176,22 +181,24 @@ namespace ICSharpCode.Decompiler.Ast
Type = new SimpleType("AssemblyVersion")
.WithAnnotation(new TypeReference(
"System.Reflection", "AssemblyVersionAttribute",
assemblyDefinition.MainModule, assemblyDefinition.MainModule.TypeSystem.Corlib)),
moduleDefinition, moduleDefinition.TypeSystem.Corlib)),
Arguments = {
new PrimitiveExpression(assemblyDefinition.Name.Version.ToString())
new PrimitiveExpression(moduleDefinition.Assembly.Name.Version.ToString())
}
}
}
}, EntityDeclaration.AttributeRole);
}
ConvertCustomAttributes(syntaxTree, assemblyDefinition, "assembly");
ConvertSecurityAttributes(syntaxTree, assemblyDefinition, "assembly");
ConvertCustomAttributes(syntaxTree, assemblyDefinition.MainModule, "module");
AddTypeForwarderAttributes(syntaxTree, assemblyDefinition.MainModule, "assembly");
if (moduleDefinition.Assembly != null) {
ConvertCustomAttributes(syntaxTree, moduleDefinition.Assembly, "assembly");
ConvertSecurityAttributes(syntaxTree, moduleDefinition.Assembly, "assembly");
}
ConvertCustomAttributes(syntaxTree, moduleDefinition, "module");
AddTypeForwarderAttributes(syntaxTree, moduleDefinition, "assembly");
if (!onlyAssemblyLevel) {
foreach (TypeDefinition typeDef in assemblyDefinition.MainModule.Types) {
foreach (TypeDefinition typeDef in moduleDefinition.Types) {
// Skip the <Module> class
if (typeDef.Name == "<Module>") continue;
// Skip any hidden types

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

@ -849,7 +849,7 @@ namespace ICSharpCode.Decompiler.Ast @@ -849,7 +849,7 @@ namespace ICSharpCode.Decompiler.Ast
args[args.Count - 1].AddAnnotation(new ParameterDeclarationAnnotation(byteCode));
return args[args.Count - 1];
case ILCode.Await:
return new UnaryOperatorExpression(UnaryOperatorType.Await, arg1);
return new UnaryOperatorExpression(UnaryOperatorType.Await, UnpackDirectionExpression(arg1));
case ILCode.NullableOf:
case ILCode.ValueOf:
return arg1;
@ -975,10 +975,7 @@ namespace ICSharpCode.Decompiler.Ast @@ -975,10 +975,7 @@ namespace ICSharpCode.Decompiler.Ast
// Unpack any DirectionExpression that is used as target for the call
// (calling methods on value types implicitly passes the first argument by reference)
if (target is DirectionExpression) {
target = ((DirectionExpression)target).Expression;
target.Remove(); // detach from DirectionExpression
}
target = UnpackDirectionExpression(target);
if (cecilMethodDef != null) {
// convert null.ToLower() to ((string)null).ToLower()
@ -1078,6 +1075,15 @@ namespace ICSharpCode.Decompiler.Ast @@ -1078,6 +1075,15 @@ namespace ICSharpCode.Decompiler.Ast
return target.Invoke(cecilMethod.Name, ConvertTypeArguments(cecilMethod), methodArgs).WithAnnotation(cecilMethod);
}
static Expression UnpackDirectionExpression(Expression target)
{
if (target is DirectionExpression) {
return ((DirectionExpression)target).Expression.Detach();
} else {
return target;
}
}
static void AdjustArgumentsForMethodCall(MethodReference cecilMethod, List<Expression> methodArgs)
{
// Convert 'ref' into 'out' where necessary

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

@ -804,7 +804,7 @@ namespace ICSharpCode.Decompiler.Ast.Transforms @@ -804,7 +804,7 @@ namespace ICSharpCode.Decompiler.Ast.Transforms
return new IndexerExpression(targetConverted, indexConverted);
}
IList<Expression> indexesConverted = ConvertExpressionsArray(index);
if (indexConverted != null) {
if (indexesConverted != null) {
return new IndexerExpression(targetConverted, indexesConverted);
}
return null;

15
src/Libraries/ICSharpCode.Decompiler/DecompilerSettings.cs

@ -283,6 +283,21 @@ namespace ICSharpCode.Decompiler @@ -283,6 +283,21 @@ namespace ICSharpCode.Decompiler
}
}
bool makeAssignmentExpressions = true;
/// <summary>
/// Gets/Sets whether to use assignment expressions such as in while ((count = Do()) != 0) ;
/// </summary>
public bool MakeAssignmentExpressions {
get { return makeAssignmentExpressions; }
set {
if (makeAssignmentExpressions != value) {
makeAssignmentExpressions = value;
OnPropertyChanged("MakeAssignmentExpressions");
}
}
}
bool alwaysGenerateExceptionVariableForCatchBlocks = false;
/// <summary>

8
src/Libraries/ICSharpCode.Decompiler/Disassembler/DisassemblerHelpers.cs

@ -359,6 +359,10 @@ namespace ICSharpCode.Decompiler.Disassembler @@ -359,6 +359,10 @@ namespace ICSharpCode.Decompiler.Disassembler
} else if (operand is float) {
float val = (float)operand;
if (val == 0) {
if (1 / val == float.NegativeInfinity) {
// negative zero is a special case
writer.Write('-');
}
writer.Write("0.0");
} else if (float.IsInfinity(val) || float.IsNaN(val)) {
byte[] data = BitConverter.GetBytes(val);
@ -375,6 +379,10 @@ namespace ICSharpCode.Decompiler.Disassembler @@ -375,6 +379,10 @@ namespace ICSharpCode.Decompiler.Disassembler
} else if (operand is double) {
double val = (double)operand;
if (val == 0) {
if (1 / val == double.NegativeInfinity) {
// negative zero is a special case
writer.Write('-');
}
writer.Write("0.0");
} else if (double.IsInfinity(val) || double.IsNaN(val)) {
byte[] data = BitConverter.GetBytes(val);

4
src/Libraries/ICSharpCode.Decompiler/Disassembler/MethodBodyDisassembler.cs

@ -54,8 +54,8 @@ namespace ICSharpCode.Decompiler.Disassembler @@ -54,8 +54,8 @@ namespace ICSharpCode.Decompiler.Disassembler
output.WriteLine("// Method begins at RVA 0x{0:x4}", method.RVA);
output.WriteLine("// Code size {0} (0x{0:x})", body.CodeSize);
output.WriteLine(".maxstack {0}", body.MaxStackSize);
if (method.DeclaringType.Module.Assembly.EntryPoint == method)
output.WriteLine (".entrypoint");
if (method.DeclaringType.Module.Assembly != null && method.DeclaringType.Module.Assembly.EntryPoint == method)
output.WriteLine (".entrypoint");
if (method.Body.HasVariables) {
output.Write(".locals ");

97
src/Libraries/ICSharpCode.Decompiler/ILAst/AsyncDecompiler.cs

@ -58,6 +58,7 @@ namespace ICSharpCode.Decompiler.ILAst @@ -58,6 +58,7 @@ namespace ICSharpCode.Decompiler.ILAst
FieldDefinition builderField;
FieldDefinition stateField;
Dictionary<FieldDefinition, ILVariable> fieldToParameterMap = new Dictionary<FieldDefinition, ILVariable>();
ILVariable cachedStateVar;
// These fields are set by AnalyzeMoveNext()
int finalState = -2;
@ -155,7 +156,7 @@ namespace ICSharpCode.Decompiler.ILAst @@ -155,7 +156,7 @@ namespace ICSharpCode.Decompiler.ILAst
ILExpression loadStateMachineForBuilderExpr;
if (!loadBuilderExpr.Match(ILCode.Ldfld, out builderFieldRef, out loadStateMachineForBuilderExpr))
return false;
if (!loadStateMachineForBuilderExpr.MatchLdloca(stateMachineVar))
if (!(loadStateMachineForBuilderExpr.MatchLdloca(stateMachineVar) || loadStateMachineForBuilderExpr.MatchLdloc(stateMachineVar)))
return false;
builderField = builderFieldRef.ResolveWithinSameModule();
if (builderField == null)
@ -235,36 +236,50 @@ namespace ICSharpCode.Decompiler.ILAst @@ -235,36 +236,50 @@ namespace ICSharpCode.Decompiler.ILAst
{
ILBlock ilMethod = CreateILAst(moveNextMethod);
if (ilMethod.Body.Count != 6)
int startIndex;
if (ilMethod.Body.Count == 6) {
startIndex = 0;
} else if (ilMethod.Body.Count == 7) {
// stloc(cachedState, ldfld(valuetype StateMachineStruct::<>1__state, ldloc(this)))
ILExpression cachedStateInit;
if (!ilMethod.Body[0].Match(ILCode.Stloc, out cachedStateVar, out cachedStateInit))
throw new SymbolicAnalysisFailedException();
ILExpression instanceExpr;
FieldReference loadedField;
if (!cachedStateInit.Match(ILCode.Ldfld, out loadedField, out instanceExpr) || loadedField.ResolveWithinSameModule() != stateField || !instanceExpr.MatchThis())
throw new SymbolicAnalysisFailedException();
startIndex = 1;
} else {
throw new SymbolicAnalysisFailedException();
}
mainTryCatch = ilMethod.Body[0] as ILTryCatchBlock;
mainTryCatch = ilMethod.Body[startIndex + 0] as ILTryCatchBlock;
if (mainTryCatch == null || mainTryCatch.CatchBlocks.Count != 1)
throw new SymbolicAnalysisFailedException();
if (mainTryCatch.FaultBlock != null || mainTryCatch.FinallyBlock != null)
throw new SymbolicAnalysisFailedException();
setResultAndExitLabel = ilMethod.Body[1] as ILLabel;
setResultAndExitLabel = ilMethod.Body[startIndex + 1] as ILLabel;
if (setResultAndExitLabel == null)
throw new SymbolicAnalysisFailedException();
if (!MatchStateAssignment(ilMethod.Body[2], out finalState))
if (!MatchStateAssignment(ilMethod.Body[startIndex + 2], out finalState))
throw new SymbolicAnalysisFailedException();
// call(AsyncTaskMethodBuilder`1::SetResult, ldflda(StateMachine::<>t__builder, ldloc(this)), ldloc(<>t__result))
MethodReference setResultMethod;
ILExpression builderExpr;
if (methodType == AsyncMethodType.TaskOfT) {
if (!ilMethod.Body[3].Match(ILCode.Call, out setResultMethod, out builderExpr, out resultExpr))
if (!ilMethod.Body[startIndex + 3].Match(ILCode.Call, out setResultMethod, out builderExpr, out resultExpr))
throw new SymbolicAnalysisFailedException();
} else {
if (!ilMethod.Body[3].Match(ILCode.Call, out setResultMethod, out builderExpr))
if (!ilMethod.Body[startIndex + 3].Match(ILCode.Call, out setResultMethod, out builderExpr))
throw new SymbolicAnalysisFailedException();
}
if (!(setResultMethod.Name == "SetResult" && IsBuilderFieldOnThis(builderExpr)))
throw new SymbolicAnalysisFailedException();
exitLabel = ilMethod.Body[4] as ILLabel;
exitLabel = ilMethod.Body[startIndex + 4] as ILLabel;
if (exitLabel == null)
throw new SymbolicAnalysisFailedException();
}
@ -318,7 +333,7 @@ namespace ICSharpCode.Decompiler.ILAst @@ -318,7 +333,7 @@ namespace ICSharpCode.Decompiler.ILAst
bool MatchStateAssignment(ILNode stfld, out int stateID)
{
// stfld(StateMachine::<>1__state, ldloc(this), ldc.i4(-2))
// stfld(StateMachine::<>1__state, ldloc(this), ldc.i4(stateId))
stateID = 0;
FieldReference fieldRef;
ILExpression target, val;
@ -329,6 +344,31 @@ namespace ICSharpCode.Decompiler.ILAst @@ -329,6 +344,31 @@ namespace ICSharpCode.Decompiler.ILAst
}
return false;
}
bool MatchRoslynStateAssignment(List<ILNode> block, int index, out int stateID)
{
// v = ldc.i4(stateId)
// stloc(cachedState, v)
// stfld(StateMachine::<>1__state, ldloc(this), v)
stateID = 0;
if (index < 0)
return false;
ILVariable v;
ILExpression val;
if (!block[index].Match(ILCode.Stloc, out v, out val) || !val.Match(ILCode.Ldc_I4, out stateID))
return false;
ILExpression loadV;
if (!block[index + 1].MatchStloc(cachedStateVar, out loadV) || !loadV.MatchLdloc(v))
return false;
ILExpression target;
FieldReference fieldRef;
if (block[index + 2].Match(ILCode.Stfld, out fieldRef, out target, out loadV)) {
return fieldRef.ResolveWithinSameModule() == stateField
&& target.MatchThis()
&& loadV.MatchLdloc(v);
}
return false;
}
#endregion
#region AnalyzeStateMachine
@ -345,7 +385,7 @@ namespace ICSharpCode.Decompiler.ILAst @@ -345,7 +385,7 @@ namespace ICSharpCode.Decompiler.ILAst
if (body.Count == 0)
throw new SymbolicAnalysisFailedException();
}
StateRangeAnalysis rangeAnalysis = new StateRangeAnalysis(body[0], StateRangeAnalysisMode.AsyncMoveNext, stateField);
StateRangeAnalysis rangeAnalysis = new StateRangeAnalysis(body[0], StateRangeAnalysisMode.AsyncMoveNext, stateField, cachedStateVar);
int bodyLength = block.Body.Count;
int pos = rangeAnalysis.AssignStateRanges(body, bodyLength);
rangeAnalysis.EnsureLabelAtPos(body, ref pos, ref bodyLength);
@ -435,18 +475,16 @@ namespace ICSharpCode.Decompiler.ILAst @@ -435,18 +475,16 @@ namespace ICSharpCode.Decompiler.ILAst
List<ILNode> ConvertFinally(List<ILNode> body)
{
List<ILNode> newBody = new List<ILNode>(body);
if (newBody.Count == 0)
return newBody;
ILLabel endFinallyLabel;
ILExpression ceqExpr;
if (newBody.Count > 0 && newBody[0].Match(ILCode.Brtrue, out endFinallyLabel, out ceqExpr)) {
ILExpression loadDoFinallyBodies, loadZero;
object unused;
if (ceqExpr.Match(ILCode.Ceq, out unused, out loadDoFinallyBodies, out loadZero)) {
int num;
if (loadDoFinallyBodies.MatchLdloc(doFinallyBodies) && loadZero.Match(ILCode.Ldc_I4, out num) && num == 0) {
if (newBody[0].Match(ILCode.Brtrue, out endFinallyLabel, out ceqExpr)) {
ILExpression condition;
if (MatchLogicNot(ceqExpr, out condition)) {
if (condition.MatchLdloc(doFinallyBodies)) {
newBody.RemoveAt(0);
}
} else if (ceqExpr.Match(ILCode.LogicNot, out loadDoFinallyBodies)) {
if (loadDoFinallyBodies.MatchLdloc(doFinallyBodies)) {
} else if (condition.Code == ILCode.Clt && condition.Arguments[0].MatchLdloc(cachedStateVar) && condition.Arguments[1].MatchLdcI4(0)) {
newBody.RemoveAt(0);
}
}
@ -454,6 +492,17 @@ namespace ICSharpCode.Decompiler.ILAst @@ -454,6 +492,17 @@ namespace ICSharpCode.Decompiler.ILAst
return newBody;
}
bool MatchLogicNot(ILExpression expr, out ILExpression arg)
{
ILExpression loadZero;
object unused;
if (expr.Match(ILCode.Ceq, out unused, out arg, out loadZero)) {
int num;
return loadZero.Match(ILCode.Ldc_I4, out num) && num == 0;
}
return expr.Match(ILCode.LogicNot, out arg);
}
void HandleAwait(List<ILNode> newBody, out ILVariable awaiterVar, out FieldDefinition awaiterField, out int targetStateID)
{
// Handle the instructions prior to the exit out of the method to detect what is being awaited.
@ -475,7 +524,8 @@ namespace ICSharpCode.Decompiler.ILAst @@ -475,7 +524,8 @@ namespace ICSharpCode.Decompiler.ILAst
newBody.RemoveAt(newBody.Count - 1); // remove AwaitUnsafeOnCompleted call
if (callAwaitUnsafeOnCompleted == null || callAwaitUnsafeOnCompleted.Code != ILCode.Call)
throw new SymbolicAnalysisFailedException();
if (((MethodReference)callAwaitUnsafeOnCompleted.Operand).Name != "AwaitUnsafeOnCompleted")
string methodName = ((MethodReference)callAwaitUnsafeOnCompleted.Operand).Name;
if (methodName != "AwaitUnsafeOnCompleted" && methodName != "AwaitOnCompleted")
throw new SymbolicAnalysisFailedException();
if (callAwaitUnsafeOnCompleted.Arguments.Count != 3)
throw new SymbolicAnalysisFailedException();
@ -493,9 +543,10 @@ namespace ICSharpCode.Decompiler.ILAst @@ -493,9 +543,10 @@ namespace ICSharpCode.Decompiler.ILAst
throw new SymbolicAnalysisFailedException();
// stfld(StateMachine::<>1__state, ldloc(this), ldc.i4(0))
if (!MatchStateAssignment(newBody.LastOrDefault(), out targetStateID))
throw new SymbolicAnalysisFailedException();
newBody.RemoveAt(newBody.Count - 1); // remove awaiter field assignment
if (MatchStateAssignment(newBody.LastOrDefault(), out targetStateID))
newBody.RemoveAt(newBody.Count - 1); // remove awaiter field assignment
else if (MatchRoslynStateAssignment(newBody, newBody.Count - 3, out targetStateID))
newBody.RemoveRange(newBody.Count - 3, 3); // remove awaiter field assignment
}
#endregion

8
src/Libraries/ICSharpCode.Decompiler/ILAst/ILAstBuilder.cs

@ -413,11 +413,11 @@ namespace ICSharpCode.Decompiler.ILAst @@ -413,11 +413,11 @@ namespace ICSharpCode.Decompiler.ILAst
}
}
// Occasionally the compilers or obfuscators generate unreachable code (which might be intentonally invalid)
// I belive it is safe to just remove it
// Occasionally the compilers or obfuscators generate unreachable code (which might be intentionally invalid)
// I believe it is safe to just remove it
body.RemoveAll(b => b.StackBefore == null);
// Genertate temporary variables to replace stack
// Generate temporary variables to replace stack
foreach(ByteCode byteCode in body) {
int argIdx = 0;
int popCount = byteCode.PopCount ?? byteCode.StackBefore.Length;
@ -652,7 +652,7 @@ namespace ICSharpCode.Decompiler.ILAst @@ -652,7 +652,7 @@ namespace ICSharpCode.Decompiler.ILAst
// Find the first and widest scope
int tryStart = ehs.Min(eh => eh.TryStart.Offset);
int tryEnd = ehs.Where(eh => eh.TryStart.Offset == tryStart).Max(eh => eh.TryEnd.Offset);
var handlers = ehs.Where(eh => eh.TryStart.Offset == tryStart && eh.TryEnd.Offset == tryEnd).OrderBy(eh => eh.TryStart.Offset).ToList();
var handlers = ehs.Where(eh => eh.TryStart.Offset == tryStart && eh.TryEnd.Offset == tryEnd).ToList();
// Remember that any part of the body migt have been removed due to unreachability

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

@ -170,11 +170,15 @@ namespace ICSharpCode.Decompiler.ILAst @@ -170,11 +170,15 @@ namespace ICSharpCode.Decompiler.ILAst
modified |= block.RunOptimization(TransformObjectInitializers);
if (abortBeforeStep == ILAstOptimizationStep.MakeAssignmentExpression) return;
modified |= block.RunOptimization(MakeAssignmentExpression);
if (context.Settings.MakeAssignmentExpressions) {
modified |= block.RunOptimization(MakeAssignmentExpression);
}
modified |= block.RunOptimization(MakeCompoundAssignments);
if (abortBeforeStep == ILAstOptimizationStep.IntroducePostIncrement) return;
modified |= block.RunOptimization(IntroducePostIncrement);
if (context.Settings.IntroduceIncrementAndDecrement) {
modified |= block.RunOptimization(IntroducePostIncrement);
}
if (abortBeforeStep == ILAstOptimizationStep.InlineExpressionTreeParameterDeclarations) return;
if (context.Settings.ExpressionTrees) {
@ -225,11 +229,13 @@ namespace ICSharpCode.Decompiler.ILAst @@ -225,11 +229,13 @@ namespace ICSharpCode.Decompiler.ILAst
new ILInlining(method).InlineAllVariables();
if (abortBeforeStep == ILAstOptimizationStep.CachedDelegateInitialization) return;
foreach(ILBlock block in method.GetSelfAndChildrenRecursive<ILBlock>()) {
for (int i = 0; i < block.Body.Count; i++) {
// TODO: Move before loops
CachedDelegateInitializationWithField(block, ref i);
CachedDelegateInitializationWithLocal(block, ref i);
if (context.Settings.AnonymousMethods) {
foreach(ILBlock block in method.GetSelfAndChildrenRecursive<ILBlock>()) {
for (int i = 0; i < block.Body.Count; i++) {
// TODO: Move before loops
CachedDelegateInitializationWithField(block, ref i);
CachedDelegateInitializationWithLocal(block, ref i);
}
}
}

20
src/Libraries/ICSharpCode.Decompiler/ILAst/ILInlining.cs

@ -50,32 +50,36 @@ namespace ICSharpCode.Decompiler.ILAst @@ -50,32 +50,36 @@ namespace ICSharpCode.Decompiler.ILAst
AnalyzeNode(method);
}
void AnalyzeNode(ILNode node)
/// <summary>
/// For each variable reference, adds <paramref name="direction"/> to the num* dicts.
/// Direction will be 1 for analysis, and -1 when removing a node from analysis.
/// </summary>
void AnalyzeNode(ILNode node, int direction = 1)
{
ILExpression expr = node as ILExpression;
if (expr != null) {
ILVariable locVar = expr.Operand as ILVariable;
if (locVar != null) {
if (expr.Code == ILCode.Stloc) {
numStloc[locVar] = numStloc.GetOrDefault(locVar) + 1;
numStloc[locVar] = numStloc.GetOrDefault(locVar) + direction;
} else if (expr.Code == ILCode.Ldloc) {
numLdloc[locVar] = numLdloc.GetOrDefault(locVar) + 1;
numLdloc[locVar] = numLdloc.GetOrDefault(locVar) + direction;
} else if (expr.Code == ILCode.Ldloca) {
numLdloca[locVar] = numLdloca.GetOrDefault(locVar) + 1;
numLdloca[locVar] = numLdloca.GetOrDefault(locVar) + direction;
} else {
throw new NotSupportedException(expr.Code.ToString());
}
}
foreach (ILExpression child in expr.Arguments)
AnalyzeNode(child);
AnalyzeNode(child, direction);
} else {
var catchBlock = node as ILTryCatchBlock.CatchBlock;
if (catchBlock != null && catchBlock.ExceptionVariable != null) {
numStloc[catchBlock.ExceptionVariable] = numStloc.GetOrDefault(catchBlock.ExceptionVariable) + 1;
numStloc[catchBlock.ExceptionVariable] = numStloc.GetOrDefault(catchBlock.ExceptionVariable) + direction;
}
foreach (ILNode child in node.GetChildren())
AnalyzeNode(child);
AnalyzeNode(child, direction);
}
}
@ -194,6 +198,7 @@ namespace ICSharpCode.Decompiler.ILAst @@ -194,6 +198,7 @@ namespace ICSharpCode.Decompiler.ILAst
// The variable is never loaded
if (inlinedExpression.HasNoSideEffects()) {
// Remove completely
AnalyzeNode(body[pos], -1);
body.RemoveAt(pos);
return true;
} else if (inlinedExpression.CanBeExpressionStatement() && v.IsGenerated) {
@ -334,6 +339,7 @@ namespace ICSharpCode.Decompiler.ILAst @@ -334,6 +339,7 @@ namespace ICSharpCode.Decompiler.ILAst
case ILCode.Stfld:
case ILCode.Ldfld:
case ILCode.Ldflda:
case ILCode.Await:
return true;
}
}

6
src/Libraries/ICSharpCode.Decompiler/ILAst/PatternMatching.cs

@ -167,5 +167,11 @@ namespace ICSharpCode.Decompiler.ILAst @@ -167,5 +167,11 @@ namespace ICSharpCode.Decompiler.ILAst
ILVariable v;
return node.Match(ILCode.Stloc, out v, out expr) && v == expectedVar;
}
public static bool MatchLdcI4(this ILNode node, int expectedValue)
{
int v;
return node.Match(ILCode.Ldc_I4, out v) && v == expectedValue;
}
}
}

14
src/Libraries/ICSharpCode.Decompiler/ILAst/StateRange.cs

@ -137,23 +137,25 @@ namespace ICSharpCode.Decompiler.ILAst @@ -137,23 +137,25 @@ namespace ICSharpCode.Decompiler.ILAst
internal DefaultDictionary<ILNode, StateRange> ranges;
SymbolicEvaluationContext evalContext;
internal Dictionary<MethodDefinition, Interval> finallyMethodToStateInterval; // used only for IteratorDispose
internal Dictionary<MethodDefinition, StateRange> finallyMethodToStateRange; // used only for IteratorDispose
/// <summary>
/// Initializes the state range logic:
/// Clears 'ranges' and sets 'ranges[entryPoint]' to the full range (int.MinValue to int.MaxValue)
/// </summary>
public StateRangeAnalysis(ILNode entryPoint, StateRangeAnalysisMode mode, FieldDefinition stateField)
public StateRangeAnalysis(ILNode entryPoint, StateRangeAnalysisMode mode, FieldDefinition stateField, ILVariable cachedStateVar = null)
{
this.mode = mode;
this.stateField = stateField;
if (mode == StateRangeAnalysisMode.IteratorDispose) {
finallyMethodToStateInterval = new Dictionary<MethodDefinition, Interval>();
finallyMethodToStateRange = new Dictionary<MethodDefinition, StateRange>();
}
ranges = new DefaultDictionary<ILNode, StateRange>(n => new StateRange());
ranges[entryPoint] = new StateRange(int.MinValue, int.MaxValue);
evalContext = new SymbolicEvaluationContext(stateField);
if (cachedStateVar != null)
evalContext.AddStateVariable(cachedStateVar);
}
public int AssignStateRanges(List<ILNode> body, int bodyLength)
@ -213,7 +215,7 @@ namespace ICSharpCode.Decompiler.ILAst @@ -213,7 +215,7 @@ namespace ICSharpCode.Decompiler.ILAst
break;
case ILCode.Brtrue:
{
SymbolicValue val = evalContext.Eval(expr.Arguments[0]);
SymbolicValue val = evalContext.Eval(expr.Arguments[0]).AsBool();
if (val.Type == SymbolicValueType.StateEquals) {
ranges[(ILLabel)expr.Operand].UnionWith(nodeRange, val.Constant, val.Constant);
StateRange nextRange = ranges[body[i + 1]];
@ -249,9 +251,9 @@ namespace ICSharpCode.Decompiler.ILAst @@ -249,9 +251,9 @@ namespace ICSharpCode.Decompiler.ILAst
// in some cases (e.g. foreach over array) the C# compiler produces a finally method outside of try-finally blocks
if (mode == StateRangeAnalysisMode.IteratorDispose) {
MethodDefinition mdef = (expr.Operand as MethodReference).ResolveWithinSameModule();
if (mdef == null || finallyMethodToStateInterval.ContainsKey(mdef))
if (mdef == null || finallyMethodToStateRange.ContainsKey(mdef))
throw new SymbolicAnalysisFailedException();
finallyMethodToStateInterval.Add(mdef, nodeRange.ToEnclosingInterval());
finallyMethodToStateRange.Add(mdef, nodeRange);
break;
} else {
goto default;

13
src/Libraries/ICSharpCode.Decompiler/ILAst/SymbolicExecution.cs

@ -68,6 +68,15 @@ namespace ICSharpCode.Decompiler.ILAst @@ -68,6 +68,15 @@ namespace ICSharpCode.Decompiler.ILAst
this.Constant = constant;
}
public SymbolicValue AsBool()
{
if (Type == SymbolicValueType.State) {
// convert state integer to bool:
// if (state + c) = if (state + c != 0) = if (state != -c)
return new SymbolicValue(SymbolicValueType.StateInEquals, unchecked(-Constant));
}
return this;
}
public override string ToString()
{
return string.Format("[SymbolicValue {0}: {1}]", this.Type, this.Constant);
@ -133,7 +142,7 @@ namespace ICSharpCode.Decompiler.ILAst @@ -133,7 +142,7 @@ namespace ICSharpCode.Decompiler.ILAst
// bool: (state == right.Constant - left.Constant)
return new SymbolicValue(expr.Code == ILCode.Ceq ? SymbolicValueType.StateEquals : SymbolicValueType.StateInEquals, unchecked(right.Constant - left.Constant));
case ILCode.LogicNot:
SymbolicValue val = Eval(expr.Arguments[0]);
SymbolicValue val = Eval(expr.Arguments[0]).AsBool();
if (val.Type == SymbolicValueType.StateEquals)
return new SymbolicValue(SymbolicValueType.StateInEquals, val.Constant);
else if (val.Type == SymbolicValueType.StateInEquals)
@ -141,7 +150,7 @@ namespace ICSharpCode.Decompiler.ILAst @@ -141,7 +150,7 @@ namespace ICSharpCode.Decompiler.ILAst
else
return Failed();
default:
return Failed();
return Failed();
}
}
}

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

@ -539,6 +539,8 @@ namespace ICSharpCode.Decompiler.ILAst @@ -539,6 +539,8 @@ namespace ICSharpCode.Decompiler.ILAst
if (forceInferChildren)
InferTypeForExpression(expr.Arguments[1], typeSystem.Int32);
TypeReference type = NumericPromotion(InferTypeForExpression(expr.Arguments[0], null));
if (type == null)
return null;
TypeReference expectedInputType = null;
switch (type.MetadataType) {
case MetadataType.Int32:
@ -827,7 +829,7 @@ namespace ICSharpCode.Decompiler.ILAst @@ -827,7 +829,7 @@ namespace ICSharpCode.Decompiler.ILAst
case ILCode.Await:
{
TypeReference taskType = InferTypeForExpression(expr.Arguments[0], null);
if (taskType.Name == "Task`1" && taskType.IsGenericInstance && taskType.Namespace == "System.Threading.Tasks") {
if (taskType != null && taskType.Name == "Task`1" && taskType.IsGenericInstance && taskType.Namespace == "System.Threading.Tasks") {
return ((GenericInstanceType)taskType).GenericArguments[0];
}
return null;

30
src/Libraries/ICSharpCode.Decompiler/ILAst/YieldReturnDecompiler.cs

@ -312,7 +312,7 @@ namespace ICSharpCode.Decompiler.ILAst @@ -312,7 +312,7 @@ namespace ICSharpCode.Decompiler.ILAst
// This is (int.MinValue, int.MaxValue) for the first instruction.
// These ranges are propagated depending on the conditional jumps performed by the code.
Dictionary<MethodDefinition, Interval> finallyMethodToStateInterval;
Dictionary<MethodDefinition, StateRange> finallyMethodToStateRange;
void ConstructExceptionTable()
{
@ -321,11 +321,11 @@ namespace ICSharpCode.Decompiler.ILAst @@ -321,11 +321,11 @@ namespace ICSharpCode.Decompiler.ILAst
var rangeAnalysis = new StateRangeAnalysis(ilMethod.Body[0], StateRangeAnalysisMode.IteratorDispose, stateField);
rangeAnalysis.AssignStateRanges(ilMethod.Body, ilMethod.Body.Count);
finallyMethodToStateInterval = rangeAnalysis.finallyMethodToStateInterval;
finallyMethodToStateRange = rangeAnalysis.finallyMethodToStateRange;
// Now look at the finally blocks:
foreach (var tryFinally in ilMethod.GetSelfAndChildrenRecursive<ILTryCatchBlock>()) {
Interval interval = rangeAnalysis.ranges[tryFinally.TryBlock.Body[0]].ToEnclosingInterval();
var range = rangeAnalysis.ranges[tryFinally.TryBlock.Body[0]];
var finallyBody = tryFinally.FinallyBlock.Body;
if (finallyBody.Count != 2)
throw new SymbolicAnalysisFailedException();
@ -338,9 +338,9 @@ namespace ICSharpCode.Decompiler.ILAst @@ -338,9 +338,9 @@ namespace ICSharpCode.Decompiler.ILAst
throw new SymbolicAnalysisFailedException();
MethodDefinition mdef = GetMethodDefinition(call.Operand as MethodReference);
if (mdef == null || finallyMethodToStateInterval.ContainsKey(mdef))
if (mdef == null || finallyMethodToStateRange.ContainsKey(mdef))
throw new SymbolicAnalysisFailedException();
finallyMethodToStateInterval.Add(mdef, interval);
finallyMethodToStateRange.Add(mdef, range);
}
rangeAnalysis = null;
}
@ -430,10 +430,9 @@ namespace ICSharpCode.Decompiler.ILAst @@ -430,10 +430,9 @@ namespace ICSharpCode.Decompiler.ILAst
bodyLength--; // don't conside the stloc instruction to be part of the body
}
// verify that the last element in the body is a label pointing to the 'ret(false)'
// The last element in the body usually is a label pointing to the 'ret(false)'
returnFalseLabel = body.ElementAtOrDefault(bodyLength - 1) as ILLabel;
if (returnFalseLabel == null)
throw new SymbolicAnalysisFailedException();
// Note: in Roslyn-compiled code, returnFalseLabel may be null.
var rangeAnalysis = new StateRangeAnalysis(body[0], StateRangeAnalysisMode.IteratorMoveNext, stateField);
int pos = rangeAnalysis.AssignStateRanges(body, bodyLength);
@ -485,7 +484,7 @@ namespace ICSharpCode.Decompiler.ILAst @@ -485,7 +484,7 @@ namespace ICSharpCode.Decompiler.ILAst
throw new SymbolicAnalysisFailedException();
int val = (int)expr.Arguments[0].Operand;
if (val == 0) {
newBody.Add(MakeGoTo(returnFalseLabel));
newBody.Add(new ILExpression(ILCode.YieldBreak, null));
} else if (val == 1) {
newBody.Add(MakeGoTo(labels, currentState));
} else {
@ -497,7 +496,7 @@ namespace ICSharpCode.Decompiler.ILAst @@ -497,7 +496,7 @@ namespace ICSharpCode.Decompiler.ILAst
// handle direct return (e.g. in release builds)
int val = (int)expr.Arguments[0].Operand;
if (val == 0) {
newBody.Add(MakeGoTo(returnFalseLabel));
newBody.Add(new ILExpression(ILCode.YieldBreak, null));
} else if (val == 1) {
newBody.Add(MakeGoTo(labels, currentState));
} else {
@ -507,21 +506,21 @@ namespace ICSharpCode.Decompiler.ILAst @@ -507,21 +506,21 @@ namespace ICSharpCode.Decompiler.ILAst
MethodDefinition method = GetMethodDefinition(expr.Operand as MethodReference);
if (method == null)
throw new SymbolicAnalysisFailedException();
Interval interval;
StateRange stateRange;
if (method == disposeMethod) {
// Explicit call to dispose is used for "yield break;" within the method.
ILExpression br = body.ElementAtOrDefault(++pos) as ILExpression;
if (br == null || !(br.Code == ILCode.Br || br.Code == ILCode.Leave) || br.Operand != returnFalseLabel)
throw new SymbolicAnalysisFailedException();
newBody.Add(MakeGoTo(returnFalseLabel));
} else if (finallyMethodToStateInterval.TryGetValue(method, out interval)) {
newBody.Add(new ILExpression(ILCode.YieldBreak, null));
} else if (finallyMethodToStateRange.TryGetValue(method, out stateRange)) {
// Call to Finally-method
int index = stateChanges.FindIndex(ss => ss.NewState >= interval.Start && ss.NewState <= interval.End);
int index = stateChanges.FindIndex(ss => stateRange.Contains(ss.NewState));
if (index < 0)
throw new SymbolicAnalysisFailedException();
ILLabel label = new ILLabel();
label.Name = "JumpOutOfTryFinally" + interval.Start + "_" + interval.End;
label.Name = "JumpOutOfTryFinally" + stateChanges[index].NewState;
newBody.Add(new ILExpression(ILCode.Leave, label));
SetState stateChange = stateChanges[index];
@ -544,6 +543,7 @@ namespace ICSharpCode.Decompiler.ILAst @@ -544,6 +543,7 @@ namespace ICSharpCode.Decompiler.ILAst
ILExpression MakeGoTo(ILLabel targetLabel)
{
Debug.Assert(targetLabel != null);
if (targetLabel == returnFalseLabel)
return new ILExpression(ILCode.YieldBreak, null);
else

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

@ -1,31 +1,17 @@ @@ -1,31 +1,17 @@
// Copyright (c) 2011 AlphaSierraPapa for the SharpDevelop Team
//
// Permission is hereby granted, free of charge, to any person obtaining a copy of this
// software and associated documentation files (the "Software"), to deal in the Software
// without restriction, including without limitation the rights to use, copy, modify, merge,
// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
// to whom the Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all copies or
// substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
#region Using directives
using System;
using System.Resources;
using System.Reflection;
using System.Runtime.InteropServices;
#endregion
[assembly: AssemblyTitle("ICSharpCode.Decompiler")]
[assembly: AssemblyDescription("IL decompiler engine")]
[assembly: AssemblyCompany("ic#code")]
[assembly: AssemblyProduct("ILSpy")]
[assembly: AssemblyCopyright("Copyright 2011 AlphaSierraPapa for the SharpDevelop Team")]
[assembly: AssemblyCopyright("Copyright 2011-2014 AlphaSierraPapa for the SharpDevelop Team")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
@ -33,8 +19,8 @@ using System.Runtime.InteropServices; @@ -33,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.1.0.1619")]
[assembly: AssemblyInformationalVersion("2.1.0.1619-214c1f73")]
[assembly: AssemblyVersion("2.2.0.1706")]
[assembly: AssemblyInformationalVersion("2.2.0.1706-cc270c8f")]
[assembly: NeutralResourcesLanguage("en-US")]
[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2243:AttributeStringLiteralsShouldParseCorrectly",

11
src/Libraries/ICSharpCode.Decompiler/Tests/Async.cs

@ -20,6 +20,7 @@ @@ -20,6 +20,7 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Runtime.CompilerServices;
using System.Threading.Tasks;
public class Async
@ -36,6 +37,16 @@ public class Async @@ -36,6 +37,16 @@ public class Async
Console.WriteLine("No Await");
}
public async void AwaitYield()
{
await Task.Yield();
}
public async void AwaitDefaultYieldAwaitable()
{
await default(YieldAwaitable);
}
public async Task SimpleVoidTaskMethod()
{
Console.WriteLine("Before");

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

@ -62,6 +62,22 @@ public static class DelegateConstruction @@ -62,6 +62,22 @@ public static class DelegateConstruction
}
return null;
}
public void LambdaInForLoop()
{
for (int i = 0; i < 100000; i++) {
Bar(() => Foo());
}
}
public int Foo()
{
return 0;
}
public void Bar(Func<int> f)
{
}
}
public static void Test(this string a)

28
src/Libraries/ICSharpCode.Decompiler/Tests/DoubleConstants.cs

@ -0,0 +1,28 @@ @@ -0,0 +1,28 @@
// Copyright (c) AlphaSierraPapa for the SharpDevelop Team
//
// Permission is hereby granted, free of charge, to any person obtaining a copy of this
// software and associated documentation files (the "Software"), to deal in the Software
// without restriction, including without limitation the rights to use, copy, modify, merge,
// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
// to whom the Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all copies or
// substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
using System;
public class DoubleConstants
{
public const double Zero = 0.0;
public const double MinusZero = -0.0;
public const double NaN = double.NaN;
public const double PositiveInfinity = double.PositiveInfinity;
public const double NegativeInfinity = double.NegativeInfinity;
}

1
src/Libraries/ICSharpCode.Decompiler/Tests/ICSharpCode.Decompiler.Tests.csproj

@ -67,6 +67,7 @@ @@ -67,6 +67,7 @@
<Compile Include="CallOverloadedMethod.cs" />
<Compile Include="CheckedUnchecked.cs" />
<Compile Include="ControlFlow.cs" />
<Compile Include="DoubleConstants.cs" />
<Compile Include="ExpressionTrees.cs" />
<None Include="IL\SequenceOfNestedIfs.Output.cs" />
<Compile Include="IL\ILTests.cs" />

6
src/Libraries/ICSharpCode.Decompiler/Tests/TestRunner.cs

@ -88,6 +88,12 @@ namespace ICSharpCode.Decompiler.Tests @@ -88,6 +88,12 @@ namespace ICSharpCode.Decompiler.Tests
TestFile(@"..\..\Tests\ControlFlow.cs", optimize: false, useDebug: true);
}
[Test]
public void DoubleConstants()
{
TestFile(@"..\..\Tests\DoubleConstants.cs");
}
[Test]
public void IncrementDecrement()
{

Loading…
Cancel
Save