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);
        }
Exemple #2
0
        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;
        }