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;
 }
예제 #2
0
        /// <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);
                }