Ejemplo n.º 1
0
        /// <summary>
        /// mcs likes to optimize closures in yield state machines away by moving the captured variables' fields into the state machine type,
        /// We construct a <see cref="DisplayClass"/> that spans the whole method body.
        /// </summary>
        bool HandleMonoStateMachine(ILFunction currentFunction, ILVariable thisVariable, SimpleTypeResolveContext decompilationContext, ILFunction nestedFunction)
        {
            if (!(nestedFunction.StateMachineCompiledWithMono && thisVariable.IsThis()))
            {
                return(false);
            }
            // Special case for Mono-compiled yield state machines
            ITypeDefinition closureType = thisVariable.Type.GetDefinition();

            if (!(closureType != decompilationContext.CurrentTypeDefinition &&
                  IsPotentialClosure(decompilationContext.CurrentTypeDefinition, closureType, allowTypeImplementingInterfaces: true)))
            {
                return(false);
            }

            var displayClass = new DisplayClass {
                IsMono       = true,
                Initializer  = nestedFunction.Body,
                Variable     = thisVariable,
                Definition   = thisVariable.Type.GetDefinition(),
                Variables    = new Dictionary <IField, ILVariable>(),
                CaptureScope = (BlockContainer)nestedFunction.Body
            };

            displayClasses.Add(thisVariable, displayClass);
            foreach (var stateMachineVariable in nestedFunction.Variables)
            {
                if (stateMachineVariable.StateMachineField == null || displayClass.Variables.ContainsKey(stateMachineVariable.StateMachineField))
                {
                    continue;
                }
                displayClass.Variables.Add(stateMachineVariable.StateMachineField, stateMachineVariable);
            }
            if (!currentFunction.Method.IsStatic && FindThisField(out var thisField))
            {
                var thisVar = currentFunction.Variables
                              .FirstOrDefault(t => t.IsThis() && t.Type.GetDefinition() == decompilationContext.CurrentTypeDefinition);
                if (thisVar == null)
                {
                    thisVar = new ILVariable(VariableKind.Parameter, decompilationContext.CurrentTypeDefinition, -1)
                    {
                        Name = "this"
                    };
                    currentFunction.Variables.Add(thisVar);
                }
                displayClass.Variables.Add(thisField, thisVar);
            }
            return(true);

            bool FindThisField(out IField foundField)
            {
                foundField = null;
                foreach (var field in closureType.GetFields(f2 => !f2.IsStatic && !displayClass.Variables.ContainsKey(f2) && f2.Type.GetDefinition() == decompilationContext.CurrentTypeDefinition))
                {
                    thisField = field;
                    return(true);
                }
                return(false);
            }
        }
        private DisplayClass AnalyzeVariable(ILVariable v)
        {
            switch (v.Kind)
            {
            case VariableKind.Parameter:
                if (context.Settings.YieldReturn && v.Function.StateMachineCompiledWithMono && v.IsThis())
                {
                    return(HandleMonoStateMachine(v.Function, v));
                }
                return(null);

            case VariableKind.StackSlot:
            case VariableKind.Local:
            case VariableKind.DisplayClassLocal:
                return(DetectDisplayClass(v));

            case VariableKind.InitializerTarget:
                return(DetectDisplayClassInitializer(v));

            default:
                return(null);
            }
        }