Browse Source

AsyncDecompiler: fix some issues with Roslyn-compiled code

pull/469/merge
Daniel Grunwald 11 years ago
parent
commit
58404e8f9e
  1. 33
      ICSharpCode.Decompiler/ILAst/AsyncDecompiler.cs
  2. 19
      ICSharpCode.Decompiler/ILAst/ILInlining.cs
  3. 4
      ICSharpCode.Decompiler/ILAst/StateRange.cs
  4. 2
      ICSharpCode.Decompiler/ILAst/TypeAnalysis.cs

33
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();
}
@ -345,7 +360,7 @@ namespace ICSharpCode.Decompiler.ILAst @@ -345,7 +360,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);

19
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) {

4
ICSharpCode.Decompiler/ILAst/StateRange.cs

@ -143,7 +143,7 @@ namespace ICSharpCode.Decompiler.ILAst @@ -143,7 +143,7 @@ namespace ICSharpCode.Decompiler.ILAst
/// 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;
@ -154,6 +154,8 @@ namespace ICSharpCode.Decompiler.ILAst @@ -154,6 +154,8 @@ namespace ICSharpCode.Decompiler.ILAst
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)

2
ICSharpCode.Decompiler/ILAst/TypeAnalysis.cs

@ -829,7 +829,7 @@ namespace ICSharpCode.Decompiler.ILAst @@ -829,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;

Loading…
Cancel
Save