internal static bool IsClosure(ILTransformContext context, ILVariable variable, out ITypeDefinition closureType, out ILInstruction initializer) { closureType = null; initializer = null; if (variable.IsSingleDefinition && variable.StoreInstructions.SingleOrDefault() is StLoc inst) { initializer = inst; if (IsClosureInit(context, inst, out closureType)) { return true; } } closureType = variable.Type.GetDefinition(); if (context.Settings.LocalFunctions && closureType?.Kind == TypeKind.Struct && variable.HasInitialValue && IsPotentialClosure(context, closureType)) { initializer = LocalFunctionDecompiler.GetStatement(variable.AddressInstructions.OrderBy(i => i.StartILOffset).First()); return true; } return false; }
/// <summary> /// catch E_189 : 0200007C System.Exception when (BlockContainer { /// Block IL_0079 (incoming: 1) { /// stloc S_30(ldloc E_189) /// br IL_0085 /// } /// /// Block IL_0085 (incoming: 1) { /// stloc I_1(ldloc S_30) /// where S_30 and I_1 are single definition /// => /// copy-propagate E_189 to replace all uses of S_30 and I_1 /// </summary> static void PropagateExceptionVariable(ILTransformContext context, TryCatchHandler handler) { var exceptionVariable = handler.Variable; if (!exceptionVariable.IsSingleDefinition) { return; } context.StepStartGroup(nameof(PropagateExceptionVariable)); int i = 0; while (i < exceptionVariable.LoadInstructions.Count) { var load = exceptionVariable.LoadInstructions[i]; if (!load.IsDescendantOf(handler)) { i++; continue; } // We are only interested in store "statements" copying the exception variable // without modifying it. var statement = LocalFunctionDecompiler.GetStatement(load); if (!(statement is StLoc stloc)) { i++; continue; } // simple copy case: // stloc b(ldloc a) if (stloc.Value == load) { PropagateExceptionInstance(stloc); } // if the type of the cast-class instruction matches the exceptionType, // this cast can be removed without losing any side-effects. // Note: this would also hold true iff exceptionType were an exception derived // from cc.Type, however, we are more restrictive to match the pattern exactly. // stloc b(castclass exceptionType(ldloc a)) else if (stloc.Value is CastClass cc && cc.Type.Equals(exceptionVariable.Type) && cc.Argument == load) { stloc.Value = load; PropagateExceptionInstance(stloc); }