bool MatchTaskCreationPattern(ILBlock method) { if (method.Body.Count < 5) { return(false); } // Check the second-to-last instruction (the start call) first, as we can get the most information from that MethodReference startMethod; ILExpression loadStartTarget, loadStartArgument; // call(AsyncTaskMethodBuilder::Start, ldloca(builder), ldloca(stateMachine)) if (!method.Body[method.Body.Count - 2].Match(ILCode.Call, out startMethod, out loadStartTarget, out loadStartArgument)) { return(false); } if (startMethod.Name != "Start" || startMethod.DeclaringType == null || startMethod.DeclaringType.Namespace != "System.Runtime.CompilerServices") { return(false); } switch (startMethod.DeclaringType.Name) { case "AsyncTaskMethodBuilder`1": methodType = AsyncMethodType.TaskOfT; break; case "AsyncTaskMethodBuilder": methodType = AsyncMethodType.Task; break; case "AsyncVoidMethodBuilder": methodType = AsyncMethodType.Void; break; default: return(false); } ILVariable stateMachineVar, builderVar; if (!loadStartTarget.Match(ILCode.Ldloca, out builderVar)) { return(false); } if (!loadStartArgument.Match(ILCode.Ldloca, out stateMachineVar)) { return(false); } stateMachineStruct = stateMachineVar.Type.ResolveWithinSameModule(); if (stateMachineStruct == null || !stateMachineStruct.IsValueType) { return(false); } moveNextMethod = stateMachineStruct.Methods.FirstOrDefault(f => f.Name == "MoveNext"); if (moveNextMethod == null) { return(false); } // Check third-to-last instruction (copy of builder): // stloc(builder, ldfld(StateMachine::<>t__builder, ldloca(stateMachine))) ILExpression loadBuilderExpr; if (!method.Body[method.Body.Count - 3].MatchStloc(builderVar, out loadBuilderExpr)) { return(false); } FieldReference builderFieldRef; ILExpression loadStateMachineForBuilderExpr; if (!loadBuilderExpr.Match(ILCode.Ldfld, out builderFieldRef, out loadStateMachineForBuilderExpr)) { return(false); } if (!loadStateMachineForBuilderExpr.MatchLdloca(stateMachineVar)) { return(false); } builderField = builderFieldRef.ResolveWithinSameModule(); if (builderField == null) { return(false); } // Check the last instruction (ret) if (methodType == AsyncMethodType.Void) { if (!method.Body[method.Body.Count - 1].Match(ILCode.Ret)) { return(false); } } else { // ret(call(AsyncTaskMethodBuilder::get_Task, ldflda(StateMachine::<>t__builder, ldloca(stateMachine)))) ILExpression returnValue; if (!method.Body[method.Body.Count - 1].Match(ILCode.Ret, out returnValue)) { return(false); } MethodReference getTaskMethod; ILExpression builderExpr; if (!returnValue.Match(ILCode.Call, out getTaskMethod, out builderExpr)) { return(false); } ILExpression loadStateMachineForBuilderExpr2; FieldReference builderField2; if (!builderExpr.Match(ILCode.Ldflda, out builderField2, out loadStateMachineForBuilderExpr2)) { return(false); } if (builderField2.ResolveWithinSameModule() != builderField || !loadStateMachineForBuilderExpr2.MatchLdloca(stateMachineVar)) { return(false); } } // Check the last field assignment - this should be the state field ILExpression initialStateExpr; if (!MatchStFld(method.Body[method.Body.Count - 4], stateMachineVar, out stateField, out initialStateExpr)) { return(false); } if (!initialStateExpr.Match(ILCode.Ldc_I4, out initialState)) { return(false); } if (initialState != -1) { return(false); } // Check the second-to-last field assignment - this should be the builder field FieldDefinition builderField3; ILExpression builderInitialization; if (!MatchStFld(method.Body[method.Body.Count - 5], stateMachineVar, out builderField3, out builderInitialization)) { return(false); } MethodReference createMethodRef; if (builderField3 != builderField || !builderInitialization.Match(ILCode.Call, out createMethodRef)) { return(false); } if (createMethodRef.Name != "Create") { return(false); } for (int i = 0; i < method.Body.Count - 5; i++) { FieldDefinition field; ILExpression fieldInit; if (!MatchStFld(method.Body[i], stateMachineVar, out field, out fieldInit)) { return(false); } ILVariable v; if (!fieldInit.Match(ILCode.Ldloc, out v)) { return(false); } if (!v.IsParameter) { return(false); } fieldToParameterMap[field] = v; } return(true); }
bool MatchTaskCreationPattern(ILBlock method) { if (method.Body.Count < 5) return false; // Check the second-to-last instruction (the start call) first, as we can get the most information from that IMethod startMethod; ILExpression loadStartTarget, loadStartArgument; // call(AsyncTaskMethodBuilder::Start, ldloca(builder), ldloca(stateMachine)) if (!method.Body[method.Body.Count - 2].Match(ILCode.Call, out startMethod, out loadStartTarget, out loadStartArgument)) return false; if (startMethod.Name != "Start" || startMethod.DeclaringType == null || startMethod.DeclaringType.Namespace != "System.Runtime.CompilerServices") return false; switch (startMethod.DeclaringType.Name) { case "AsyncTaskMethodBuilder`1": methodType = AsyncMethodType.TaskOfT; break; case "AsyncTaskMethodBuilder": methodType = AsyncMethodType.Task; break; case "AsyncVoidMethodBuilder": methodType = AsyncMethodType.Void; break; default: return false; } ILVariable stateMachineVar, builderVar; if (!loadStartTarget.Match(ILCode.Ldloca, out builderVar)) return false; if (!loadStartArgument.Match(ILCode.Ldloca, out stateMachineVar)) return false; stateMachineStruct = stateMachineVar.Type.GetTypeDefOrRef().ResolveWithinSameModule(); if (stateMachineStruct == null || !DnlibExtensions.IsValueType(stateMachineStruct)) return false; moveNextMethod = stateMachineStruct.Methods.FirstOrDefault(f => f.Name == "MoveNext"); if (moveNextMethod == null) return false; // Check third-to-last instruction (copy of builder): // stloc(builder, ldfld(StateMachine::<>t__builder, ldloca(stateMachine))) ILExpression loadBuilderExpr; if (!method.Body[method.Body.Count - 3].MatchStloc(builderVar, out loadBuilderExpr)) return false; IField builderFieldRef; ILExpression loadStateMachineForBuilderExpr; if (!loadBuilderExpr.Match(ILCode.Ldfld, out builderFieldRef, out loadStateMachineForBuilderExpr)) return false; if (!(loadStateMachineForBuilderExpr.MatchLdloca(stateMachineVar) || loadStateMachineForBuilderExpr.MatchLdloc(stateMachineVar))) return false; builderField = builderFieldRef.ResolveFieldWithinSameModule(); if (builderField == null) return false; // Check the last instruction (ret) if (methodType == AsyncMethodType.Void) { if (!method.Body[method.Body.Count - 1].Match(ILCode.Ret)) return false; } else { // ret(call(AsyncTaskMethodBuilder::get_Task, ldflda(StateMachine::<>t__builder, ldloca(stateMachine)))) ILExpression returnValue; if (!method.Body[method.Body.Count - 1].Match(ILCode.Ret, out returnValue)) return false; IMethod getTaskMethod; ILExpression builderExpr; if (!returnValue.Match(ILCode.Call, out getTaskMethod, out builderExpr)) return false; ILExpression loadStateMachineForBuilderExpr2; IField builderField2; if (!builderExpr.Match(ILCode.Ldflda, out builderField2, out loadStateMachineForBuilderExpr2)) return false; if (builderField2.ResolveFieldWithinSameModule() != builderField || !loadStateMachineForBuilderExpr2.MatchLdloca(stateMachineVar)) return false; } // Check the last field assignment - this should be the state field ILExpression initialStateExpr; if (!MatchStFld(method.Body[method.Body.Count - 4], stateMachineVar, out stateField, out initialStateExpr)) return false; if (!initialStateExpr.Match(ILCode.Ldc_I4, out initialState)) return false; if (initialState != -1) return false; // Check the second-to-last field assignment - this should be the builder field FieldDef builderField3; ILExpression builderInitialization; if (!MatchStFld(method.Body[method.Body.Count - 5], stateMachineVar, out builderField3, out builderInitialization)) return false; IMethod createMethodRef; if (builderField3 != builderField || !builderInitialization.Match(ILCode.Call, out createMethodRef)) return false; if (createMethodRef.Name != "Create") return false; for (int i = 0; i < method.Body.Count - 5; i++) { FieldDef field; ILExpression fieldInit; if (!MatchStFld(method.Body[i], stateMachineVar, out field, out fieldInit)) return false; ILVariable v; if (!fieldInit.Match(ILCode.Ldloc, out v)) return false; if (!v.IsParameter) return false; fieldToParameterMap[field] = v; } return true; }