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
FieldDefinition builderField; FieldDefinition builderField;
FieldDefinition stateField; FieldDefinition stateField;
Dictionary<FieldDefinition, ILVariable> fieldToParameterMap = new Dictionary<FieldDefinition, ILVariable>(); Dictionary<FieldDefinition, ILVariable> fieldToParameterMap = new Dictionary<FieldDefinition, ILVariable>();
ILVariable cachedStateVar;
// These fields are set by AnalyzeMoveNext() // These fields are set by AnalyzeMoveNext()
int finalState = -2; int finalState = -2;
@ -155,7 +156,7 @@ namespace ICSharpCode.Decompiler.ILAst
ILExpression loadStateMachineForBuilderExpr; ILExpression loadStateMachineForBuilderExpr;
if (!loadBuilderExpr.Match(ILCode.Ldfld, out builderFieldRef, out loadStateMachineForBuilderExpr)) if (!loadBuilderExpr.Match(ILCode.Ldfld, out builderFieldRef, out loadStateMachineForBuilderExpr))
return false; return false;
if (!loadStateMachineForBuilderExpr.MatchLdloca(stateMachineVar)) if (!(loadStateMachineForBuilderExpr.MatchLdloca(stateMachineVar) || loadStateMachineForBuilderExpr.MatchLdloc(stateMachineVar)))
return false; return false;
builderField = builderFieldRef.ResolveWithinSameModule(); builderField = builderFieldRef.ResolveWithinSameModule();
if (builderField == null) if (builderField == null)
@ -235,36 +236,50 @@ namespace ICSharpCode.Decompiler.ILAst
{ {
ILBlock ilMethod = CreateILAst(moveNextMethod); 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(); throw new SymbolicAnalysisFailedException();
}
mainTryCatch = ilMethod.Body[0] as ILTryCatchBlock; mainTryCatch = ilMethod.Body[startIndex + 0] as ILTryCatchBlock;
if (mainTryCatch == null || mainTryCatch.CatchBlocks.Count != 1) if (mainTryCatch == null || mainTryCatch.CatchBlocks.Count != 1)
throw new SymbolicAnalysisFailedException(); throw new SymbolicAnalysisFailedException();
if (mainTryCatch.FaultBlock != null || mainTryCatch.FinallyBlock != null) if (mainTryCatch.FaultBlock != null || mainTryCatch.FinallyBlock != null)
throw new SymbolicAnalysisFailedException(); throw new SymbolicAnalysisFailedException();
setResultAndExitLabel = ilMethod.Body[1] as ILLabel; setResultAndExitLabel = ilMethod.Body[startIndex + 1] as ILLabel;
if (setResultAndExitLabel == null) if (setResultAndExitLabel == null)
throw new SymbolicAnalysisFailedException(); throw new SymbolicAnalysisFailedException();
if (!MatchStateAssignment(ilMethod.Body[2], out finalState)) if (!MatchStateAssignment(ilMethod.Body[startIndex + 2], out finalState))
throw new SymbolicAnalysisFailedException(); throw new SymbolicAnalysisFailedException();
// call(AsyncTaskMethodBuilder`1::SetResult, ldflda(StateMachine::<>t__builder, ldloc(this)), ldloc(<>t__result)) // call(AsyncTaskMethodBuilder`1::SetResult, ldflda(StateMachine::<>t__builder, ldloc(this)), ldloc(<>t__result))
MethodReference setResultMethod; MethodReference setResultMethod;
ILExpression builderExpr; ILExpression builderExpr;
if (methodType == AsyncMethodType.TaskOfT) { 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(); throw new SymbolicAnalysisFailedException();
} else { } 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(); throw new SymbolicAnalysisFailedException();
} }
if (!(setResultMethod.Name == "SetResult" && IsBuilderFieldOnThis(builderExpr))) if (!(setResultMethod.Name == "SetResult" && IsBuilderFieldOnThis(builderExpr)))
throw new SymbolicAnalysisFailedException(); throw new SymbolicAnalysisFailedException();
exitLabel = ilMethod.Body[4] as ILLabel; exitLabel = ilMethod.Body[startIndex + 4] as ILLabel;
if (exitLabel == null) if (exitLabel == null)
throw new SymbolicAnalysisFailedException(); throw new SymbolicAnalysisFailedException();
} }
@ -345,7 +360,7 @@ namespace ICSharpCode.Decompiler.ILAst
if (body.Count == 0) if (body.Count == 0)
throw new SymbolicAnalysisFailedException(); 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 bodyLength = block.Body.Count;
int pos = rangeAnalysis.AssignStateRanges(body, bodyLength); int pos = rangeAnalysis.AssignStateRanges(body, bodyLength);
rangeAnalysis.EnsureLabelAtPos(body, ref pos, ref bodyLength); rangeAnalysis.EnsureLabelAtPos(body, ref pos, ref bodyLength);

19
ICSharpCode.Decompiler/ILAst/ILInlining.cs

@ -50,32 +50,36 @@ namespace ICSharpCode.Decompiler.ILAst
AnalyzeNode(method); 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; ILExpression expr = node as ILExpression;
if (expr != null) { if (expr != null) {
ILVariable locVar = expr.Operand as ILVariable; ILVariable locVar = expr.Operand as ILVariable;
if (locVar != null) { if (locVar != null) {
if (expr.Code == ILCode.Stloc) { if (expr.Code == ILCode.Stloc) {
numStloc[locVar] = numStloc.GetOrDefault(locVar) + 1; numStloc[locVar] = numStloc.GetOrDefault(locVar) + direction;
} else if (expr.Code == ILCode.Ldloc) { } else if (expr.Code == ILCode.Ldloc) {
numLdloc[locVar] = numLdloc.GetOrDefault(locVar) + 1; numLdloc[locVar] = numLdloc.GetOrDefault(locVar) + direction;
} else if (expr.Code == ILCode.Ldloca) { } else if (expr.Code == ILCode.Ldloca) {
numLdloca[locVar] = numLdloca.GetOrDefault(locVar) + 1; numLdloca[locVar] = numLdloca.GetOrDefault(locVar) + direction;
} else { } else {
throw new NotSupportedException(expr.Code.ToString()); throw new NotSupportedException(expr.Code.ToString());
} }
} }
foreach (ILExpression child in expr.Arguments) foreach (ILExpression child in expr.Arguments)
AnalyzeNode(child); AnalyzeNode(child, direction);
} else { } else {
var catchBlock = node as ILTryCatchBlock.CatchBlock; var catchBlock = node as ILTryCatchBlock.CatchBlock;
if (catchBlock != null && catchBlock.ExceptionVariable != null) { 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()) foreach (ILNode child in node.GetChildren())
AnalyzeNode(child); AnalyzeNode(child, direction);
} }
} }
@ -194,6 +198,7 @@ namespace ICSharpCode.Decompiler.ILAst
// The variable is never loaded // The variable is never loaded
if (inlinedExpression.HasNoSideEffects()) { if (inlinedExpression.HasNoSideEffects()) {
// Remove completely // Remove completely
AnalyzeNode(body[pos], -1);
body.RemoveAt(pos); body.RemoveAt(pos);
return true; return true;
} else if (inlinedExpression.CanBeExpressionStatement() && v.IsGenerated) { } else if (inlinedExpression.CanBeExpressionStatement() && v.IsGenerated) {

4
ICSharpCode.Decompiler/ILAst/StateRange.cs

@ -143,7 +143,7 @@ namespace ICSharpCode.Decompiler.ILAst
/// Initializes the state range logic: /// Initializes the state range logic:
/// Clears 'ranges' and sets 'ranges[entryPoint]' to the full range (int.MinValue to int.MaxValue) /// Clears 'ranges' and sets 'ranges[entryPoint]' to the full range (int.MinValue to int.MaxValue)
/// </summary> /// </summary>
public StateRangeAnalysis(ILNode entryPoint, StateRangeAnalysisMode mode, FieldDefinition stateField) public StateRangeAnalysis(ILNode entryPoint, StateRangeAnalysisMode mode, FieldDefinition stateField, ILVariable cachedStateVar = null)
{ {
this.mode = mode; this.mode = mode;
this.stateField = stateField; this.stateField = stateField;
@ -154,6 +154,8 @@ namespace ICSharpCode.Decompiler.ILAst
ranges = new DefaultDictionary<ILNode, StateRange>(n => new StateRange()); ranges = new DefaultDictionary<ILNode, StateRange>(n => new StateRange());
ranges[entryPoint] = new StateRange(int.MinValue, int.MaxValue); ranges[entryPoint] = new StateRange(int.MinValue, int.MaxValue);
evalContext = new SymbolicEvaluationContext(stateField); evalContext = new SymbolicEvaluationContext(stateField);
if (cachedStateVar != null)
evalContext.AddStateVariable(cachedStateVar);
} }
public int AssignStateRanges(List<ILNode> body, int bodyLength) public int AssignStateRanges(List<ILNode> body, int bodyLength)

2
ICSharpCode.Decompiler/ILAst/TypeAnalysis.cs

@ -829,7 +829,7 @@ namespace ICSharpCode.Decompiler.ILAst
case ILCode.Await: case ILCode.Await:
{ {
TypeReference taskType = InferTypeForExpression(expr.Arguments[0], null); 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 ((GenericInstanceType)taskType).GenericArguments[0];
} }
return null; return null;

Loading…
Cancel
Save