static AsyncMethodDecompiler()
        {
            var type = typeof(AsyncVoidMethodBuilder);
            var aoc1 = type.GetMethod("AwaitOnCompleted");
            var aoc2 = type.GetMethod("AwaitUnsafeOnCompleted");
            var rwc = new AwaitOnCompletedRewriter();
            AttributeInjector.Inject(aoc1, rwc);
            AttributeInjector.Inject(aoc2, rwc);
            var sr = type.GetMethod("SetResult");
            var rwsr = new SetResultRewriter();
            AttributeInjector.Inject(sr, rwsr);
            var se = type.GetMethod("SetException");
            var serw = new SetExceptionRewriter();
            AttributeInjector.Inject(se, serw);

            type = typeof(AsyncTaskMethodBuilder);
            aoc1 = type.GetMethod("AwaitOnCompleted");
            aoc2 = type.GetMethod("AwaitUnsafeOnCompleted");
            AttributeInjector.Inject(aoc1, rwc);
            AttributeInjector.Inject(aoc2, rwc);
            sr = type.GetMethod("SetResult");
            AttributeInjector.Inject(sr, rwsr);
            se = type.GetMethod("SetException");
            AttributeInjector.Inject(se, serw);

            var tarwc = new TaskAwaiterAwaitOnCompletedRewriter();
            type = typeof(TaskAwaiter);
            AttributeInjector.Inject(type.GetMethod("get_IsCompleted"), new RewriteIsCompleted(), true);
            AttributeInjector.Inject(type.GetMethod("OnCompleted"), tarwc, true);
            AttributeInjector.Inject(type.GetMethod("UnsafeOnCompleted"), tarwc, true);
            AttributeInjector.Inject(type.GetMethod("GetResult"), new RewriteGetResult(), true);
            type = typeof(TaskAwaiter<>);
            AttributeInjector.Inject(type.GetMethod("get_IsCompleted"), new RewriteIsCompleted(), true);
            AttributeInjector.Inject(type.GetMethod("OnCompleted"), tarwc, true);
            AttributeInjector.Inject(type.GetMethod("UnsafeOnCompleted"), tarwc, true);
            AttributeInjector.Inject(type.GetMethod("GetResult"), new RewriteGetResult(), true);

            AttributeInjector.Inject(typeof(TaskAwaiter),
                new MapToIntrinsicType(Meta.EIntrinsicTypes.IllegalRuntimeType));
            AttributeInjector.Inject(typeof(TaskAwaiter<>),
                new MapToIntrinsicType(Meta.EIntrinsicTypes.IllegalRuntimeType));
            AttributeInjector.Inject(typeof(Task),
                new MapToIntrinsicType(Meta.EIntrinsicTypes.IllegalRuntimeType));
            AttributeInjector.Inject(typeof(Task<>),
                new MapToIntrinsicType(Meta.EIntrinsicTypes.IllegalRuntimeType));
        }
        private void InjectAttributes(string prefix)
        {
            var fsmType = _code.AsyncMethod.GetStateMachineType();
            _fsmInstance = Activator.CreateInstance(fsmType);
            AttributeInjector.Inject(fsmType, new HideDeclaration());

            var thisField = fsmType
                .GetFields(BindingFlags.Public | BindingFlags.Instance)
                .Where(f => f.Name.Contains("this") && f.FieldType.Equals(_code.AsyncMethod.DeclaringType))
                .FirstOrDefault();
            if (thisField != null)
            {
                AttributeInjector.Inject(thisField, new StaticEvaluation());
                thisField.SetValue(_fsmInstance, _instance);
            }

            var stateField = fsmType
                .GetFields(BindingFlags.Public | BindingFlags.Instance)
                .Where(f => f.Name.Contains("state") && f.FieldType.Equals(typeof(int)))
                .FirstOrDefault();
            if (stateField != null)
            {
                AttributeInjector.Inject(stateField, new StateAccessRewriter());
            }

            var awaiterFields = fsmType
                .GetFields(BindingFlags.NonPublic | BindingFlags.Instance)
                .Where(f => f.Name.Contains("$awaiter"));

            foreach (var awaiterField in awaiterFields)
            {
                AttributeInjector.Inject(awaiterField, new AwaiterAccessRewriter());
            }

            _locFields = new Dictionary<string, Variable>();
            _declared = new HashSet<Variable>();
            _tasks = new Dictionary<string, object>();
            var fields = fsmType.GetFields();
            var lfar = new LocalFieldAccessRewriter();
            var afar = new ArgFieldAccessRewriter();
            var tar = new TaskAccessRewriter();
            var argNames = _code.AsyncMethod
                .GetParameters()
                .Select(p => p.Name)
                .ToArray();
            foreach (var field in fields)
            {
                var name = field.Name;

                bool isTask = false;

                if (field.FieldType.IsGenericType &&
                    field.FieldType.GetGenericTypeDefinition().Equals(typeof(Task<>)))
                {
                    // it is a task variable
                    AttributeInjector.Inject(field, tar);
                    AttributeInjector.Inject(field.FieldType,
                        new MapToIntrinsicType(Meta.EIntrinsicTypes.IllegalRuntimeType));
                    AttributeInjector.Inject(field.FieldType, new HideDeclaration());
                    isTask = true;
                }

                if (field.FieldType.IsGenericType &&
                    field.FieldType.GetGenericTypeDefinition().Equals(typeof(AsyncTaskMethodBuilder<>)))
                {
                    var builderType = field.FieldType;
                    var aoc1 = builderType.GetMethod("AwaitOnCompleted");
                    var aoc2 = builderType.GetMethod("AwaitUnsafeOnCompleted");
                    var rwc = new AwaitOnCompletedRewriter();
                    AttributeInjector.Inject(aoc1, rwc);
                    AttributeInjector.Inject(aoc2, rwc);
                    var sr = builderType.GetMethod("SetResult");
                    var rwsr = new SetResultRewriter();
                    AttributeInjector.Inject(sr, rwsr);
                    var se = builderType.GetMethod("SetException");
                    var serw = new SetExceptionRewriter();
                    AttributeInjector.Inject(se, serw);
                }

                int pindex = Array.IndexOf(argNames, name);
                if (pindex >= 0)
                {
                    field.SetValue(_fsmInstance, _arguments[pindex]);
                    if (isTask)
                    {
                        var task = _arguments[pindex];
                        var lr = LiteralReference.CreateConstant(task);
                        _tasks[field.Name] = new StackElement(lr, task, EVariability.Constant);
                    }
                    else
                    {
                        AttributeInjector.Inject(field, afar);
                    }
                    continue;
                }

                if (isTask)
                    continue;

                int beg = name.IndexOf('<');
                int end = name.LastIndexOf('>');
                if (beg == -1 || end == -1 || (end - beg) <= 1)
                    continue;

                var locName = prefix + name.Substring(beg + 1, end - beg - 1);

                var v = new Variable(field.FieldType)
                {
                    Name = locName
                };
                _locFields[field.Name] = v;
                AttributeInjector.Inject(field, lfar);
            }

            foreach (var local in _code.Method.GetMethodBody().LocalVariables)
            {
                var locType = local.LocalType;
                if (locType.IsGenericType &&
                    locType.GetGenericTypeDefinition().Equals(typeof(TaskAwaiter<>)))
                {
                    AttributeInjector.Inject(locType, new HideDeclaration());
                }
            }
        }
        private CoFSM DecompileToCoFSM(string prefix)
        {
            ImplStyle = EAsyncImplStyle.FSM;
            InjectAttributes(prefix);
            InitializeCFGs();

            CoFSM cofsm = new CoFSM();

            var args = _code.AsyncMethod.GetParameters();
            cofsm.Arguments = new Variable[args.Length];
            _argFields = new Dictionary<string, Variable>();
            for (int i = 0; i < args.Length; i++)
            {
                string name = prefix + "_" + args[i].Name;
                var argv = new Variable(TypeDescriptor.GetTypeOf(_arguments[i]))
                {
                    Name = name
                };
                _argFields[args[i].Name] = argv;
                cofsm.Arguments[i] = argv;
            }

            int numILStates = _stateCFGs.Length;
            var mym = _code as MethodDescriptor;
            cofsm.Method = mym;
            cofsm.Dependencies = new HashSet<Task>();

            // Create result variable and done flag
            cofsm.DoneVar = new Variable(typeof(bool)) {
                Name = prefix + "_$done"
            };
            if (_code.AsyncMethod.ReturnType.IsGenericType &&
                _code.AsyncMethod.ReturnType.GetGenericTypeDefinition().Equals(typeof(Task<>)))
            {
                var resultType = _code.AsyncMethod.ReturnType.GetGenericArguments()[0];
                if (!resultType.Equals(typeof(void)))
                {
                    cofsm.ResultVar = new Variable(resultType)
                    {
                        Name = prefix + "_$result"
                    };

                    var builderType = typeof(AsyncTaskMethodBuilder<>).MakeGenericType(resultType);
                    AttributeInjector.Inject(builderType,
                        new MapToIntrinsicType(Meta.EIntrinsicTypes.IllegalRuntimeType));
                    var aoc1 = builderType.GetMethod("AwaitOnCompleted");
                    var aoc2 = builderType.GetMethod("AwaitUnsafeOnCompleted");
                    var rwc = new AwaitOnCompletedRewriter();
                    AttributeInjector.Inject(aoc1, rwc);
                    AttributeInjector.Inject(aoc2, rwc);
                    var sr = builderType.GetMethod("SetResult");
                    var rwsr = new SetResultRewriter();
                    AttributeInjector.Inject(sr, rwsr);
                    var se = builderType.GetMethod("SetException");
                    var serw = new SetExceptionRewriter();
                    AttributeInjector.Inject(se, serw);
                    AttributeInjector.Inject(builderType, new HideDeclaration());

                    var awaiterType = typeof(TaskAwaiter<>).MakeGenericType(resultType);
                    AttributeInjector.Inject(awaiterType,
                        new MapToIntrinsicType(Meta.EIntrinsicTypes.IllegalRuntimeType));
                    AttributeInjector.Inject(awaiterType.GetMethod("get_IsCompleted"), new RewriteIsCompleted());
                    AttributeInjector.Inject(awaiterType.GetMethod("OnCompleted"), new AwaitOnCompletedRewriter());
                    AttributeInjector.Inject(awaiterType.GetMethod("UnsafeOnCompleted"), new AwaitOnCompletedRewriter());
                    AttributeInjector.Inject(awaiterType.GetMethod("GetResult"), new RewriteGetResult());
                    AttributeInjector.Inject(awaiterType, new HideDeclaration());
                }
            }

            // Decompile state handlers
            _stateInfos = new Dictionary<StateInfo, StateInfo>();
            var decomp = new MSILDecompiler(_code, _stateCFGs[0], _fsmInstance);
            _curTempl = decomp.Template;
            _curTempl.AddAttribute(this);
            _curTempl.DisallowReturnStatements = true;
            _curTempl.DisallowConditionals = true;
            _curTempl.DisallowLoops = true;
            var lvState = _curTempl.ExportLocalVariableState();
            var startSI = new StateInfo(-1);
            foreach (var kvp in _locFields)
                startSI.LVState[kvp.Key] = kvp.Value.Type.GetSampleInstance(ETypeCreationOptions.ForceCreation);
            _stateInfos[startSI] = startSI;
            _curSI = startSI;
            var stateList = new List<StateInfo>();
            stateList.Add(startSI);
            _stateQ = new Queue<StateInfo>();
            _curCoFSM = cofsm;
            startSI.Result = decomp.Decompile();
            while (_stateQ.Any())
            {
                var nextSI = _stateQ.Dequeue();
                _curSI = nextSI.Fork(nextSI.ILState);
                decomp = new MSILDecompiler(_code, _stateCFGs[nextSI.ILState + 1], _fsmInstance);
                _curTempl = decomp.Template;
                _curTempl.AddAttribute(this);
                _curTempl.DisallowReturnStatements = true;
                _curTempl.DisallowConditionals = true;
                _curTempl.DisallowLoops = true;
                _curSI.Result = decomp.Decompile();
                stateList.Add(_curSI);
                _stateInfos[_curSI] = _curSI;
            }

            // Create state active variables
            cofsm.StateActiveVars = new List<Variable>();
            int j = 0;
            for (int i = 0; i < stateList.Count; i++)
            {
                if (stateList[i].HasWaitState)
                {
                    cofsm.StateActiveVars.Add(new Variable(typeof(bool))
                    {
                        Name = prefix + "_$waitStateActive" + i
                    });
                    stateList[i].WaitStateValue = j++;
                }
                cofsm.StateActiveVars.Add(new Variable(typeof(bool))
                {
                    Name = prefix + "_$stateActive" + i
                });
                stateList[i].StateValue = j++;
            }

            int numStates = j;

            // Replace ProceedWithState calls with actual states
            var states = new Statement[numStates];

            j = 0;
            for (int i = 0; i < stateList.Count; i++)
            {
                if (stateList[i].HasWaitState)
                {
                    var wsb = new DefaultAlgorithmBuilder();
                    ImplementJoin(stateList[i].JP, wsb, stateList[i]);
                    //wsb.Call(stateList[i].JoinSpec, new Expression[0]);
                    var join = wsb.Complete();
                    states[j++] = join.Body;
                }
                states[j++] = stateList[i].Result.Decompiled.Body;
            }

            for (j = 0; j < states.Length; j++)
            {
                var orgBody = states[j];
                var xform = new CoStateAssigner(this, cofsm.StateActiveVars, orgBody, j);
                var state = xform.GetAlgorithm();
                states[j] = state.Body;
            }

            var calledMethods = stateList
                .SelectMany(b => b.Result.CalledMethods)
                .Distinct()
                .ToList();
            var calledSyncMethods = calledMethods
                .Where(mci => !mci.Method.IsAsync())
                .ToList();
            cofsm.CalledMethods = calledSyncMethods;

            // State handlers
            var alg = new DefaultAlgorithmBuilder();
            alg.Store(cofsm.DoneVar, LiteralReference.CreateConstant(false));
            for (int i = states.Length - 1; i >= 1; i--)
            {
                var lrsa = (LiteralReference)cofsm.StateActiveVars[i];
                alg.If(lrsa);
                alg.InlineCall(states[i]);
                alg.EndIf();
            }
            var handlerAlg = alg.Complete();
            cofsm.HandlerBody = handlerAlg.Body;
            alg = new DefaultAlgorithmBuilder();
            alg.Store(cofsm.DoneVar, LiteralReference.CreateConstant(false));
            alg.InlineCall(states[0]);
            cofsm.InitialHandler = alg.Complete().Body;

            return cofsm;
        }