/// <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); } }