|
|
@ -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(); |
|
|
|
} |
|
|
|
} |
|
|
@ -318,7 +333,7 @@ namespace ICSharpCode.Decompiler.ILAst |
|
|
|
|
|
|
|
|
|
|
|
bool MatchStateAssignment(ILNode stfld, out int stateID) |
|
|
|
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; |
|
|
|
stateID = 0; |
|
|
|
FieldReference fieldRef; |
|
|
|
FieldReference fieldRef; |
|
|
|
ILExpression target, val; |
|
|
|
ILExpression target, val; |
|
|
@ -329,6 +344,31 @@ namespace ICSharpCode.Decompiler.ILAst |
|
|
|
} |
|
|
|
} |
|
|
|
return false; |
|
|
|
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
|
|
|
|
#endregion
|
|
|
|
|
|
|
|
|
|
|
|
#region AnalyzeStateMachine
|
|
|
|
#region AnalyzeStateMachine
|
|
|
@ -345,7 +385,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); |
|
|
@ -435,18 +475,16 @@ namespace ICSharpCode.Decompiler.ILAst |
|
|
|
List<ILNode> ConvertFinally(List<ILNode> body) |
|
|
|
List<ILNode> ConvertFinally(List<ILNode> body) |
|
|
|
{ |
|
|
|
{ |
|
|
|
List<ILNode> newBody = new List<ILNode>(body); |
|
|
|
List<ILNode> newBody = new List<ILNode>(body); |
|
|
|
|
|
|
|
if (newBody.Count == 0) |
|
|
|
|
|
|
|
return newBody; |
|
|
|
ILLabel endFinallyLabel; |
|
|
|
ILLabel endFinallyLabel; |
|
|
|
ILExpression ceqExpr; |
|
|
|
ILExpression ceqExpr; |
|
|
|
if (newBody.Count > 0 && newBody[0].Match(ILCode.Brtrue, out endFinallyLabel, out ceqExpr)) { |
|
|
|
if (newBody[0].Match(ILCode.Brtrue, out endFinallyLabel, out ceqExpr)) { |
|
|
|
ILExpression loadDoFinallyBodies, loadZero; |
|
|
|
ILExpression condition; |
|
|
|
object unused; |
|
|
|
if (MatchLogicNot(ceqExpr, out condition)) { |
|
|
|
if (ceqExpr.Match(ILCode.Ceq, out unused, out loadDoFinallyBodies, out loadZero)) { |
|
|
|
if (condition.MatchLdloc(doFinallyBodies)) { |
|
|
|
int num; |
|
|
|
|
|
|
|
if (loadDoFinallyBodies.MatchLdloc(doFinallyBodies) && loadZero.Match(ILCode.Ldc_I4, out num) && num == 0) { |
|
|
|
|
|
|
|
newBody.RemoveAt(0); |
|
|
|
newBody.RemoveAt(0); |
|
|
|
} |
|
|
|
} else if (condition.Code == ILCode.Clt && condition.Arguments[0].MatchLdloc(cachedStateVar) && condition.Arguments[1].MatchLdcI4(0)) { |
|
|
|
} else if (ceqExpr.Match(ILCode.LogicNot, out loadDoFinallyBodies)) { |
|
|
|
|
|
|
|
if (loadDoFinallyBodies.MatchLdloc(doFinallyBodies)) { |
|
|
|
|
|
|
|
newBody.RemoveAt(0); |
|
|
|
newBody.RemoveAt(0); |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
@ -454,6 +492,17 @@ namespace ICSharpCode.Decompiler.ILAst |
|
|
|
return newBody; |
|
|
|
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) |
|
|
|
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.
|
|
|
|
// 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 |
|
|
|
newBody.RemoveAt(newBody.Count - 1); // remove AwaitUnsafeOnCompleted call
|
|
|
|
newBody.RemoveAt(newBody.Count - 1); // remove AwaitUnsafeOnCompleted call
|
|
|
|
if (callAwaitUnsafeOnCompleted == null || callAwaitUnsafeOnCompleted.Code != ILCode.Call) |
|
|
|
if (callAwaitUnsafeOnCompleted == null || callAwaitUnsafeOnCompleted.Code != ILCode.Call) |
|
|
|
throw new SymbolicAnalysisFailedException(); |
|
|
|
throw new SymbolicAnalysisFailedException(); |
|
|
|
if (((MethodReference)callAwaitUnsafeOnCompleted.Operand).Name != "AwaitUnsafeOnCompleted") |
|
|
|
string methodName = ((MethodReference)callAwaitUnsafeOnCompleted.Operand).Name; |
|
|
|
|
|
|
|
if (methodName != "AwaitUnsafeOnCompleted" && methodName != "AwaitOnCompleted") |
|
|
|
throw new SymbolicAnalysisFailedException(); |
|
|
|
throw new SymbolicAnalysisFailedException(); |
|
|
|
if (callAwaitUnsafeOnCompleted.Arguments.Count != 3) |
|
|
|
if (callAwaitUnsafeOnCompleted.Arguments.Count != 3) |
|
|
|
throw new SymbolicAnalysisFailedException(); |
|
|
|
throw new SymbolicAnalysisFailedException(); |
|
|
@ -493,9 +543,10 @@ namespace ICSharpCode.Decompiler.ILAst |
|
|
|
throw new SymbolicAnalysisFailedException(); |
|
|
|
throw new SymbolicAnalysisFailedException(); |
|
|
|
|
|
|
|
|
|
|
|
// stfld(StateMachine::<>1__state, ldloc(this), ldc.i4(0))
|
|
|
|
// stfld(StateMachine::<>1__state, ldloc(this), ldc.i4(0))
|
|
|
|
if (!MatchStateAssignment(newBody.LastOrDefault(), out targetStateID)) |
|
|
|
if (MatchStateAssignment(newBody.LastOrDefault(), out targetStateID)) |
|
|
|
throw new SymbolicAnalysisFailedException(); |
|
|
|
newBody.RemoveAt(newBody.Count - 1); // remove awaiter field assignment
|
|
|
|
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
|
|
|
|
#endregion
|
|
|
|
|
|
|
|
|
|
|
|