Exemplo n.º 1
0
        void AnalyzeFunction(ILFunction function)
        {
            void VisitFunction(ILFunction f)
            {
                foreach (var v in f.Variables.ToArray())
                {
                    var result = AnalyzeVariable(v);
                    if (result == null || displayClasses.ContainsKey(result.Variable))
                    {
                        continue;
                    }
                    context.Step($"Detected display-class {result.Variable}", result.Initializer ?? f.Body);
                    displayClasses.Add(result.Variable, result);
                }
            }

            void VisitChildren(ILInstruction inst)
            {
                foreach (var child in inst.Children)
                {
                    Visit(child);
                }
            }

            void Visit(ILInstruction inst)
            {
                switch (inst)
                {
                case ILFunction f:
                    VisitFunction(f);
                    VisitChildren(inst);
                    break;

                default:
                    VisitChildren(inst);
                    break;
                }
            }

            Visit(function);

            foreach (var(v, displayClass) in displayClasses.ToArray())
            {
                if (!ValidateDisplayClassUses(v, displayClass))
                {
                    displayClasses.Remove(v);
                }
            }

            foreach (var displayClass in displayClasses.Values)
            {
                // handle uninitialized fields
                foreach (var f in displayClass.Type.Fields)
                {
                    if (displayClass.VariablesToDeclare.ContainsKey(f))
                    {
                        continue;
                    }
                    var variable = AddVariable(displayClass, null, f);
                    variable.UsesInitialValue = true;
                    displayClass.VariablesToDeclare[(IField)f.MemberDefinition] = variable;
                }

                foreach (var v in displayClass.VariablesToDeclare.Values)
                {
                    if (v.CanPropagate)
                    {
                        var variableToPropagate = v.GetOrDeclare();
                        if (variableToPropagate.Kind != VariableKind.Parameter && !displayClasses.ContainsKey(variableToPropagate))
                        {
                            v.Propagate(null);
                        }
                    }
                }
            }
        }
Exemplo n.º 2
0
 ExtractionContext(ILFunction function)
 {
     Debug.Assert(function != null);
     this.Function = function;
 }
Exemplo n.º 3
0
 public GroupStores(ILFunction scope, CancellationToken cancellationToken) : base(scope, IsCandidateVariable, cancellationToken)
 {
 }
        /// <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)))
            {
                return(false);
            }

            var displayClass = new DisplayClass {
                IsMono       = true,
                Initializer  = nestedFunction.Body,
                Variable     = thisVariable,
                Definition   = thisVariable.Type.GetDefinition(),
                Variables    = new Dictionary <IField, DisplayClassVariable>(),
                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, new DisplayClassVariable {
                    Variable = stateMachineVariable,
                    Value    = new LdLoc(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, new DisplayClassVariable {
                    Variable = thisVar, Value = new LdLoc(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);
            }
        }
        public static void Run(ILFunction function, ILTransformContext context)
        {
            if (!context.Settings.AwaitInCatchFinally)
            {
                return;
            }
            HashSet <BlockContainer> changedContainers = new HashSet <BlockContainer>();

            // analyze all try-catch statements in the function
            foreach (var tryCatch in function.Descendants.OfType <TryCatch>().ToArray())
            {
                if (!(tryCatch.Parent?.Parent is BlockContainer container))
                {
                    continue;
                }
                // Detect all handlers that contain an await expression
                AnalyzeHandlers(tryCatch.Handlers, out var catchHandlerIdentifier, out var transformableCatchBlocks);
                var cfg = new ControlFlowGraph(container, context.CancellationToken);
                if (transformableCatchBlocks.Count > 0)
                {
                    changedContainers.Add(container);
                }
                foreach (var result in transformableCatchBlocks)
                {
                    var node = cfg.GetNode(result.RealCatchBlockEntryPoint);

                    context.Step("Inline catch block with await", result.Handler);

                    // Remove the IfInstruction from the jump table and eliminate all branches to the block.
                    var jumpTableBlock = (Block)result.JumpTableEntry.Parent;
                    jumpTableBlock.Instructions.RemoveAt(result.JumpTableEntry.ChildIndex);

                    foreach (var branch in tryCatch.Descendants.OfType <Branch>())
                    {
                        if (branch.TargetBlock == jumpTableBlock)
                        {
                            if (result.NextBlockOrExitContainer is BlockContainer exitContainer)
                            {
                                branch.ReplaceWith(new Leave(exitContainer));
                            }
                            else
                            {
                                branch.ReplaceWith(new Branch((Block)result.NextBlockOrExitContainer));
                            }
                        }
                    }

                    // Add the real catch block entry-point to the block container
                    var catchBlockHead = ((BlockContainer)result.Handler.Body).Blocks.Last();

                    result.RealCatchBlockEntryPoint.Remove();
                    ((BlockContainer)result.Handler.Body).Blocks.Insert(0, result.RealCatchBlockEntryPoint);

                    // Remove the generated catch block
                    catchBlockHead.Remove();

                    // Inline all blocks that are dominated by the entrypoint of the real catch block
                    foreach (var n in cfg.cfg)
                    {
                        if (((Block)n.UserData).Parent == result.Handler.Body)
                        {
                            continue;
                        }
                        if (node.Dominates(n))
                        {
                            MoveBlock((Block)n.UserData, (BlockContainer)result.Handler.Body);
                        }
                    }

                    // Remove all assignments to the common object variable that stores the exception object.
                    if (result.ObjectVariableStore != null)
                    {
                        foreach (var load in result.ObjectVariableStore.Variable.LoadInstructions.ToArray())
                        {
                            if (load.Parent is CastClass cc && cc.Type == result.Handler.Variable.Type)
                            {
                                cc.ReplaceWith(new LdLoc(result.Handler.Variable));
                            }
                            else
                            {
                                load.ReplaceWith(new LdLoc(result.Handler.Variable));
                            }
                        }
                    }
                }
Exemplo n.º 6
0
        public static void Run(ILFunction function, ILTransformContext context)
        {
            if (!context.Settings.AwaitInCatchFinally)
            {
                return;
            }
            HashSet <BlockContainer> changedContainers = new HashSet <BlockContainer>();

            // analyze all try-catch statements in the function
            foreach (var tryCatch in function.Descendants.OfType <TryCatch>().ToArray())
            {
                if (!(tryCatch.Parent?.Parent is BlockContainer container))
                {
                    continue;
                }
                //  } catch exceptionVariable : 02000078 System.Object when (ldc.i4 1) BlockContainer {
                //      Block IL_004a (incoming: 1) {
                //          stloc objectVariable(ldloc exceptionVariable)
                //          br finallyBlock
                //      }
                //
                //  }
                // }
                //
                // Block finallyBlock (incoming: 2) {
                //  if (comp.o(ldloc b == ldnull)) br afterFinallyBlock
                //  br finallyBlockContinuation
                // }
                //
                // Block finallyBlockContinuation (incoming: 1) {
                //  await(addressof System.Threading.Tasks.ValueTask(callvirt DisposeAsync(ldloc b)))
                //  br afterFinallyBlock
                // }
                //
                // Block afterFinallyBlock (incoming: 2) {
                //  stloc V_1(ldloc objectVariable)
                //  if (comp.o(ldloc V_1 == ldnull)) br IL_00ea
                //  br IL_00cf
                // }

                // await in finally uses a single catch block with catch-type object
                if (tryCatch.Handlers.Count != 1)
                {
                    continue;
                }
                var handler           = tryCatch.Handlers[0];
                var exceptionVariable = handler.Variable;
                if (handler.Body is not BlockContainer catchBlockContainer)
                {
                    continue;
                }
                if (!exceptionVariable.Type.IsKnownType(KnownTypeCode.Object))
                {
                    continue;
                }
                // Matches the await finally pattern:
                // [stloc V_3(ldloc E_100)	- copy exception variable to a temporary]
                // stloc V_6(ldloc V_3)	- store exception in 'global' object variable
                // br IL_0075				- jump out of catch block to the head of the finallyBlock
                var        catchBlockEntry = catchBlockContainer.EntryPoint;
                ILVariable objectVariable;
                switch (catchBlockEntry.Instructions.Count)
                {
                case 2:
                    if (!catchBlockEntry.Instructions[0].MatchStLoc(out objectVariable, out var value))
Exemplo n.º 7
0
        internal static string GenerateForeachVariableName(ILFunction function, ILInstruction valueContext,
                                                           ILVariable existingVariable = null, bool mustResolveConflicts = false)
        {
            if (function == null)
            {
                throw new ArgumentNullException(nameof(function));
            }
            if (existingVariable != null && !existingVariable.HasGeneratedName)
            {
                return(existingVariable.Name);
            }
            var reservedVariableNames = CollectReservedVariableNames(function, existingVariable, mustResolveConflicts);

            string baseName = GetNameFromInstruction(valueContext);

            if (string.IsNullOrEmpty(baseName))
            {
                if (valueContext is LdLoc ldloc && ldloc.Variable.Kind == VariableKind.Parameter)
                {
                    baseName = ldloc.Variable.Name;
                }
            }
            string proposedName = "item";

            if (!string.IsNullOrEmpty(baseName))
            {
                if (!IsPlural(baseName, ref proposedName))
                {
                    if (baseName.Length > 4 && baseName.EndsWith("List", StringComparison.Ordinal))
                    {
                        proposedName = baseName.Substring(0, baseName.Length - 4);
                    }
                    else if (baseName.Equals("list", StringComparison.OrdinalIgnoreCase))
                    {
                        proposedName = "item";
                    }
                    else if (baseName.EndsWith("children", StringComparison.OrdinalIgnoreCase))
                    {
                        proposedName = baseName.Remove(baseName.Length - 3);
                    }
                }
            }

            // remove any numbers from the proposed name
            proposedName = SplitName(proposedName, out int number);

            if (!reservedVariableNames.ContainsKey(proposedName))
            {
                reservedVariableNames.Add(proposedName, 0);
            }
            int count = ++reservedVariableNames[proposedName];

            Debug.Assert(!string.IsNullOrWhiteSpace(proposedName));
            if (count > 1)
            {
                return(proposedName + count.ToString());
            }
            else
            {
                return(proposedName);
            }
        }
        public void Run(ILFunction function, ILTransformContext context)
        {
            if (!context.Settings.Dynamic)
            {
                return;
            }

            this.context = context;

            Dictionary <IField, CallSiteInfo> callsites          = new Dictionary <IField, CallSiteInfo>();
            HashSet <BlockContainer>          modifiedContainers = new HashSet <BlockContainer>();

            foreach (var block in function.Descendants.OfType <Block>())
            {
                if (block.Instructions.Count < 2)
                {
                    continue;
                }
                // Check if, we deal with a callsite cache field null check:
                // if (comp(ldsfld <>p__3 == ldnull)) br IL_000c
                // br IL_002b
                if (!(block.Instructions.SecondToLastOrDefault() is IfInstruction ifInst))
                {
                    continue;
                }
                if (!(block.Instructions.LastOrDefault() is Branch branchAfterInit))
                {
                    continue;
                }
                if (!MatchCallSiteCacheNullCheck(ifInst.Condition, out var callSiteCacheField, out var callSiteDelegate, out bool invertBranches))
                {
                    continue;
                }
                if (!ifInst.TrueInst.MatchBranch(out var trueBlock))
                {
                    continue;
                }
                Block callSiteInitBlock, targetBlockAfterInit;
                if (invertBranches)
                {
                    callSiteInitBlock    = branchAfterInit.TargetBlock;
                    targetBlockAfterInit = trueBlock;
                }
                else
                {
                    callSiteInitBlock    = trueBlock;
                    targetBlockAfterInit = branchAfterInit.TargetBlock;
                }
                if (!ScanCallSiteInitBlock(callSiteInitBlock, callSiteCacheField, callSiteDelegate, out var callSiteInfo, out var blockAfterInit))
                {
                    continue;
                }
                if (targetBlockAfterInit != blockAfterInit)
                {
                    continue;
                }
                callSiteInfo.DelegateType          = callSiteDelegate;
                callSiteInfo.ConditionalJumpToInit = ifInst;
                callSiteInfo.Inverted        = invertBranches;
                callSiteInfo.BranchAfterInit = branchAfterInit;
                callsites.Add(callSiteCacheField, callSiteInfo);
            }

            var storesToRemove = new List <StLoc>();

            foreach (var invokeCall in function.Descendants.OfType <CallVirt>())
            {
                if (invokeCall.Method.DeclaringType.Kind != TypeKind.Delegate || invokeCall.Method.Name != "Invoke" || invokeCall.Arguments.Count == 0)
                {
                    continue;
                }
                var firstArgument = invokeCall.Arguments[0];
                if (firstArgument.MatchLdLoc(out var stackSlot) && stackSlot.Kind == VariableKind.StackSlot && stackSlot.IsSingleDefinition)
                {
                    firstArgument = ((StLoc)stackSlot.StoreInstructions[0]).Value;
                }
                if (!firstArgument.MatchLdFld(out var cacheFieldLoad, out var targetField))
                {
                    continue;
                }
                if (!cacheFieldLoad.MatchLdsFld(out var cacheField))
                {
                    continue;
                }
                if (!callsites.TryGetValue(cacheField, out var callsite))
                {
                    continue;
                }
                context.Stepper.Step("Transform callsite for " + callsite.MemberName);
                var           deadArguments = new List <ILInstruction>();
                ILInstruction replacement   = MakeDynamicInstruction(callsite, invokeCall, deadArguments);
                if (replacement == null)
                {
                    continue;
                }
                invokeCall.ReplaceWith(replacement);
                Debug.Assert(callsite.ConditionalJumpToInit?.Parent is Block);
                var block = ((Block)callsite.ConditionalJumpToInit.Parent);
                if (callsite.Inverted)
                {
                    block.Instructions.Remove(callsite.ConditionalJumpToInit);
                    callsite.BranchAfterInit.ReplaceWith(callsite.ConditionalJumpToInit.TrueInst);
                }
                else
                {
                    block.Instructions.Remove(callsite.ConditionalJumpToInit);
                }
                foreach (var arg in deadArguments)
                {
                    if (arg.MatchLdLoc(out var temporary) && temporary.Kind == VariableKind.StackSlot && temporary.IsSingleDefinition && temporary.LoadCount == 0)
                    {
                        StLoc stLoc = (StLoc)temporary.StoreInstructions[0];
                        if (stLoc.Parent is Block storeParentBlock)
                        {
                            var value = stLoc.Value;
                            if (value.MatchLdsFld(out var cacheFieldCopy) && cacheFieldCopy.Equals(cacheField))
                            {
                                storesToRemove.Add(stLoc);
                            }
                            if (value.MatchLdFld(out cacheFieldLoad, out var targetFieldCopy) && cacheFieldLoad.MatchLdsFld(out cacheFieldCopy) && cacheField.Equals(cacheFieldCopy) && targetField.Equals(targetFieldCopy))
                            {
                                storesToRemove.Add(stLoc);
                            }
                        }
                    }
                }
                modifiedContainers.Add((BlockContainer)block.Parent);
            }

            foreach (var inst in storesToRemove)
            {
                Block parentBlock = (Block)inst.Parent;
                parentBlock.Instructions.RemoveAt(inst.ChildIndex);
            }

            foreach (var container in modifiedContainers)
            {
                container.SortBlocks(deleteUnreachableBlocks: true);
            }
        }
Exemplo n.º 9
0
        void PerformAssignment(ILFunction function)
        {
            // remove unused variables before assigning names
            function.Variables.RemoveDead();
            int numDisplayClassLocals = 0;
            Dictionary <int, string> assignedLocalSignatureIndices = new Dictionary <int, string>();

            foreach (var v in function.Variables.OrderBy(v => v.Name))
            {
                switch (v.Kind)
                {
                case VariableKind.Parameter:                         // ignore
                    break;

                case VariableKind.InitializerTarget:                         // keep generated names
                    AddExistingName(reservedVariableNames, v.Name);
                    break;

                case VariableKind.DisplayClassLocal:
                    v.Name = "CS$<>8__locals" + (numDisplayClassLocals++);
                    break;

                case VariableKind.Local when v.Index != null:
                    if (assignedLocalSignatureIndices.TryGetValue(v.Index.Value, out string name))
                    {
                        // make sure all local ILVariables that refer to the same slot in the locals signature
                        // are assigned the same name.
                        v.Name = name;
                    }
                    else
                    {
                        AssignName();
                        // Remember the newly assigned name:
                        assignedLocalSignatureIndices.Add(v.Index.Value, v.Name);
                    }
                    break;

                default:
                    AssignName();
                    break;
                }

                void AssignName()
                {
                    if (v.HasGeneratedName || !IsValidName(v.Name) || ConflictWithLocal(v))
                    {
                        // don't use the name from the debug symbols if it looks like a generated name
                        v.Name = null;
                    }
                    else
                    {
                        // use the name from the debug symbols
                        // (but ensure we don't use the same name for two variables)
                        v.Name = GetAlternativeName(v.Name);
                    }
                }
            }
            foreach (var localFunction in function.LocalFunctions)
            {
                if (!LocalFunctionDecompiler.ParseLocalFunctionName(localFunction.Name, out _, out var newName) || !IsValidName(newName))
                {
                    newName = null;
                }
                localFunction.Name = newName;
                localFunction.ReducedMethod.Name = newName;
            }
            // Now generate names:
            var mapping = new Dictionary <ILVariable, string>(ILVariableEqualityComparer.Instance);

            foreach (var inst in function.Descendants.OfType <IInstructionWithVariableOperand>())
            {
                var v = inst.Variable;
                if (!mapping.TryGetValue(v, out string name))
                {
                    if (string.IsNullOrEmpty(v.Name))
                    {
                        v.Name = GenerateNameForVariable(v);
                    }
                    mapping.Add(v, v.Name);
                }
                else
                {
                    v.Name = name;
                }
            }
            foreach (var localFunction in function.LocalFunctions)
            {
                var newName = localFunction.Name;
                if (newName == null)
                {
                    newName = GetAlternativeName("f");
                }
                localFunction.Name = newName;
                localFunction.ReducedMethod.Name = newName;
                localFunctionMapping[(MethodDefinitionHandle)localFunction.ReducedMethod.MetadataToken] = newName;
            }
            foreach (var inst in function.Descendants)
            {
                LocalFunctionMethod localFunction;
                switch (inst)
                {
                case Call call:
                    localFunction = call.Method as LocalFunctionMethod;
                    break;

                case LdFtn ldftn:
                    localFunction = ldftn.Method as LocalFunctionMethod;
                    break;

                default:
                    localFunction = null;
                    break;
                }
                if (localFunction == null || !localFunctionMapping.TryGetValue((MethodDefinitionHandle)localFunction.MetadataToken, out var name))
                {
                    continue;
                }
                localFunction.Name = name;
            }
        }
Exemplo n.º 10
0
        public void Run(ILFunction function, ILTransformContext context)
        {
            this.context = context;

            reservedVariableNames             = new Dictionary <string, int>();
            currentLowerCaseTypeOrMemberNames = new List <string>();
            var currentLowerCaseMemberNames = CollectAllLowerCaseMemberNames(function.Method.DeclaringTypeDefinition);

            foreach (var name in currentLowerCaseMemberNames)
            {
                currentLowerCaseTypeOrMemberNames.Add(name);
            }
            var currentLowerCaseTypeNames = CollectAllLowerCaseTypeNames(function.Method.DeclaringTypeDefinition);

            foreach (var name in currentLowerCaseTypeNames)
            {
                currentLowerCaseTypeOrMemberNames.Add(name);
                AddExistingName(reservedVariableNames, name);
            }
            localFunctionMapping = new Dictionary <MethodDefinitionHandle, string>();
            loopCounters         = CollectLoopCounters(function);
            foreach (var f in function.Descendants.OfType <ILFunction>())
            {
                if (f.Method != null)
                {
                    if (IsSetOrEventAccessor(f.Method) && f.Method.Parameters.Count > 0)
                    {
                        for (int i = 0; i < f.Method.Parameters.Count - 1; i++)
                        {
                            AddExistingName(reservedVariableNames, f.Method.Parameters[i].Name);
                        }
                        var lastParameter = f.Method.Parameters.Last();
                        switch (f.Method.AccessorOwner)
                        {
                        case IProperty prop:
                            if (f.Method.AccessorKind == MethodSemanticsAttributes.Setter)
                            {
                                if (prop.Parameters.Any(p => p.Name == "value"))
                                {
                                    f.Warnings.Add("Parameter named \"value\" already present in property signature!");
                                    break;
                                }
                                var variableForLastParameter = f.Variables.FirstOrDefault(v => v.Function == f &&
                                                                                          v.Kind == VariableKind.Parameter &&
                                                                                          v.Index == f.Method.Parameters.Count - 1);
                                if (variableForLastParameter == null)
                                {
                                    AddExistingName(reservedVariableNames, lastParameter.Name);
                                }
                                else
                                {
                                    if (variableForLastParameter.Name != "value")
                                    {
                                        variableForLastParameter.Name = "value";
                                    }
                                    AddExistingName(reservedVariableNames, variableForLastParameter.Name);
                                }
                            }
                            break;

                        case IEvent ev:
                            if (f.Method.AccessorKind != MethodSemanticsAttributes.Raiser)
                            {
                                var variableForLastParameter = f.Variables.FirstOrDefault(v => v.Function == f &&
                                                                                          v.Kind == VariableKind.Parameter &&
                                                                                          v.Index == f.Method.Parameters.Count - 1);
                                if (variableForLastParameter == null)
                                {
                                    AddExistingName(reservedVariableNames, lastParameter.Name);
                                }
                                else
                                {
                                    if (variableForLastParameter.Name != "value")
                                    {
                                        variableForLastParameter.Name = "value";
                                    }
                                    AddExistingName(reservedVariableNames, variableForLastParameter.Name);
                                }
                            }
                            break;

                        default:
                            AddExistingName(reservedVariableNames, lastParameter.Name);
                            break;
                        }
                    }
                    else
                    {
                        foreach (var p in f.Method.Parameters)
                        {
                            AddExistingName(reservedVariableNames, p.Name);
                        }
                    }
                }
                else
                {
                    foreach (var p in f.Variables.Where(v => v.Kind == VariableKind.Parameter))
                    {
                        AddExistingName(reservedVariableNames, p.Name);
                    }
                }
            }
            foreach (ILFunction f in function.Descendants.OfType <ILFunction>().Reverse())
            {
                PerformAssignment(f);
            }
        }
Exemplo n.º 11
0
        internal static string GenerateVariableName(ILFunction function, IType type, ILVariable existingVariable = null)
        {
            if (function == null)
            {
                throw new ArgumentNullException(nameof(function));
            }
            var reservedVariableNames = new Dictionary <string, int>();

            foreach (var v in function.Descendants.OfType <ILFunction>().SelectMany(m => m.Variables))
            {
                if (v != existingVariable)
                {
                    AddExistingName(reservedVariableNames, v.Name);
                }
            }
            foreach (var f in function.CecilMethod.DeclaringType.Fields.Select(f => f.Name))
            {
                AddExistingName(reservedVariableNames, f);
            }

            string baseName     = GetNameByType(type);
            string proposedName = "obj";

            if (!string.IsNullOrEmpty(baseName))
            {
                if (!IsPlural(baseName, ref proposedName))
                {
                    if (baseName.Length > 4 && baseName.EndsWith("List", StringComparison.Ordinal))
                    {
                        proposedName = baseName.Substring(0, baseName.Length - 4);
                    }
                    else if (baseName.Equals("list", StringComparison.OrdinalIgnoreCase))
                    {
                        proposedName = "item";
                    }
                    else if (baseName.EndsWith("children", StringComparison.OrdinalIgnoreCase))
                    {
                        proposedName = baseName.Remove(baseName.Length - 3);
                    }
                    else
                    {
                        proposedName = baseName;
                    }
                }
            }

            // remove any numbers from the proposed name
            proposedName = SplitName(proposedName, out int number);

            if (!reservedVariableNames.ContainsKey(proposedName))
            {
                reservedVariableNames.Add(proposedName, 0);
            }
            int count = ++reservedVariableNames[proposedName];

            if (count > 1)
            {
                return(proposedName + count.ToString());
            }
            else
            {
                return(proposedName);
            }
        }
Exemplo n.º 12
0
        public void Run(ILFunction function, ILTransformContext context)
        {
            this.context          = context;
            currentFieldNames     = function.Method.DeclaringTypeDefinition.Fields.Select(f => f.Name).ToArray();
            reservedVariableNames = new Dictionary <string, int>();
            loopCounters          = CollectLoopCounters(function);
            foreach (var f in function.Descendants.OfType <ILFunction>())
            {
                if (f.Method != null)
                {
                    if (IsSetOrEventAccessor(f.Method) && f.Method.Parameters.Count > 0)
                    {
                        for (int i = 0; i < f.Method.Parameters.Count - 1; i++)
                        {
                            AddExistingName(reservedVariableNames, f.Method.Parameters[i].Name);
                        }
                        var lastParameter = f.Method.Parameters.Last();
                        switch (f.Method.AccessorOwner)
                        {
                        case IProperty prop:
                            if (prop.Setter == f.Method)
                            {
                                if (prop.Parameters.Any(p => p.Name == "value"))
                                {
                                    f.Warnings.Add("Parameter named \"value\" already present in property signature!");
                                    break;
                                }
                                var variableForLastParameter = f.Variables.FirstOrDefault(v => v.Function == f &&
                                                                                          v.Kind == VariableKind.Parameter &&
                                                                                          v.Index == f.Method.Parameters.Count - 1);
                                if (variableForLastParameter == null)
                                {
                                    AddExistingName(reservedVariableNames, lastParameter.Name);
                                }
                                else
                                {
                                    if (variableForLastParameter.Name != "value")
                                    {
                                        variableForLastParameter.Name = "value";
                                    }
                                    AddExistingName(reservedVariableNames, variableForLastParameter.Name);
                                }
                            }
                            break;

                        case IEvent ev:
                            if (f.Method != ev.InvokeAccessor)
                            {
                                var variableForLastParameter = f.Variables.FirstOrDefault(v => v.Function == f &&
                                                                                          v.Kind == VariableKind.Parameter &&
                                                                                          v.Index == f.Method.Parameters.Count - 1);
                                if (variableForLastParameter == null)
                                {
                                    AddExistingName(reservedVariableNames, lastParameter.Name);
                                }
                                else
                                {
                                    if (variableForLastParameter.Name != "value")
                                    {
                                        variableForLastParameter.Name = "value";
                                    }
                                    AddExistingName(reservedVariableNames, variableForLastParameter.Name);
                                }
                            }
                            break;

                        default:
                            AddExistingName(reservedVariableNames, lastParameter.Name);
                            break;
                        }
                    }
                    else
                    {
                        foreach (var p in f.Method.Parameters)
                        {
                            AddExistingName(reservedVariableNames, p.Name);
                        }
                    }
                }
                else
                {
                    foreach (var p in f.Variables.Where(v => v.Kind == VariableKind.Parameter))
                    {
                        AddExistingName(reservedVariableNames, p.Name);
                    }
                }
            }
            foreach (ILFunction f in function.Descendants.OfType <ILFunction>().Reverse())
            {
                PerformAssignment(f);
            }
        }
Exemplo n.º 13
0
 ExtractionContext(ILFunction function, ILTransformContext context)
 {
     Debug.Assert(function != null);
     this.Function = function;
     this.context  = context;
 }
Exemplo n.º 14
0
 public StatePerSequencePoint(AstNode primaryNode)
 {
     this.PrimaryNode = primaryNode;
     this.Intervals   = new List <Interval>();
     this.Function    = null;
 }
Exemplo n.º 15
0
 public void Run(ILFunction function, ILTransformContext context)
 {
     this.context = context;
     Default(function);
 }
Exemplo n.º 16
0
        void SimplifyBranchChains(ILFunction function, ILTransformContext context)
        {
            List <(BlockContainer, Block)> blocksToAdd = new List <(BlockContainer, Block)>();
            HashSet <Block> visitedBlocks = new HashSet <Block>();

            foreach (var branch in function.Descendants.OfType <Branch>())
            {
                // Resolve chained branches to the final target:
                var targetBlock = branch.TargetBlock;
                visitedBlocks.Clear();
                while (targetBlock.Instructions.Count == 1 && targetBlock.Instructions[0].OpCode == OpCode.Branch)
                {
                    if (!visitedBlocks.Add(targetBlock))
                    {
                        // prevent infinite loop when branch chain is cyclic
                        break;
                    }
                    context.Step("Simplify branch to branch", branch);
                    var nextBranch = (Branch)targetBlock.Instructions[0];
                    branch.TargetBlock = nextBranch.TargetBlock;
                    branch.AddILRange(nextBranch);
                    if (targetBlock.IncomingEdgeCount == 0)
                    {
                        targetBlock.Instructions.Clear();                         // mark the block for deletion
                    }
                    targetBlock = branch.TargetBlock;
                }
                if (IsBranchToReturnBlock(branch))
                {
                    if (aggressivelyDuplicateReturnBlocks)
                    {
                        // Replace branches to 'return blocks' with the return instruction
                        context.Step("Replace branch to return with return", branch);
                        branch.ReplaceWith(targetBlock.Instructions[0].Clone());
                    }
                    else if (branch.TargetContainer != branch.Ancestors.OfType <BlockContainer>().First())
                    {
                        // We don't want to always inline the return directly, because this
                        // might force us to place the return within a loop, when it's better
                        // placed outside.
                        // But we do want to move the return block into the correct try-finally scope,
                        // so that loop detection at least has the option to put it inside
                        // the loop body.
                        context.Step("Copy return block into try block", branch);
                        Block          blockCopy      = (Block)branch.TargetBlock.Clone();
                        BlockContainer localContainer = branch.Ancestors.OfType <BlockContainer>().First();
                        blocksToAdd.Add((localContainer, blockCopy));
                        branch.TargetBlock = blockCopy;
                    }
                }
                else if (targetBlock.Instructions.Count == 1 && targetBlock.Instructions[0] is Leave leave && leave.Value.MatchNop())
                {
                    context.Step("Replace branch to leave with leave", branch);
                    // Replace branches to 'leave' instruction with the leave instruction
                    var leave2 = leave.Clone();
                    if (!branch.HasILRange)                     // use the ILRange of the branch if possible
                    {
                        leave2.AddILRange(branch);
                    }
                    branch.ReplaceWith(leave2);
                }
                if (targetBlock.IncomingEdgeCount == 0)
                {
                    targetBlock.Instructions.Clear();                     // mark the block for deletion
                }
            }
            foreach (var(container, block) in blocksToAdd)
            {
                container.Blocks.Add(block);
            }
        }
Exemplo n.º 17
0
        bool DoTransform(ILFunction function, Block body, int pos)
        {
            if (pos >= body.Instructions.Count - 2)
            {
                return(false);
            }
            ILInstruction inst = body.Instructions[pos];

            if (inst.MatchStLoc(out var v, out var newarrExpr) && MatchNewArr(newarrExpr, out var elementType, out var arrayLength))
            {
                if (HandleRuntimeHelpersInitializeArray(body, pos + 1, v, elementType, arrayLength, out var values, out var initArrayPos))
                {
                    context.Step("HandleRuntimeHelperInitializeArray: single-dim", inst);
                    var tempStore = context.Function.RegisterVariable(VariableKind.InitializerTarget, v.Type);
                    var block     = BlockFromInitializer(tempStore, elementType, arrayLength, values);
                    body.Instructions[pos] = new StLoc(v, block);
                    body.Instructions.RemoveAt(initArrayPos);
                    ILInlining.InlineIfPossible(body, pos, context);
                    return(true);
                }
                if (arrayLength.Length == 1)
                {
                    if (HandleSimpleArrayInitializer(function, body, pos + 1, v, elementType, arrayLength, out var arrayValues, out var instructionsToRemove))
                    {
                        context.Step("HandleSimpleArrayInitializer: single-dim", inst);
                        var block     = new Block(BlockKind.ArrayInitializer);
                        var tempStore = context.Function.RegisterVariable(VariableKind.InitializerTarget, v.Type);
                        block.Instructions.Add(new StLoc(tempStore, new NewArr(elementType, arrayLength.Select(l => new LdcI4(l)).ToArray())));
                        block.Instructions.AddRange(arrayValues.Select(
                                                        t => {
                            var(indices, value) = t;
                            if (value == null)
                            {
                                value = GetNullExpression(elementType);
                            }
                            return(StElem(new LdLoc(tempStore), indices, value, elementType));
                        }
                                                        ));
                        block.FinalInstruction = new LdLoc(tempStore);
                        body.Instructions[pos] = new StLoc(v, block);
                        body.Instructions.RemoveRange(pos + 1, instructionsToRemove);
                        ILInlining.InlineIfPossible(body, pos, context);
                        return(true);
                    }
                    if (HandleJaggedArrayInitializer(body, pos + 1, v, elementType, arrayLength[0], out ILVariable finalStore, out values, out instructionsToRemove))
                    {
                        context.Step("HandleJaggedArrayInitializer: single-dim", inst);
                        var block     = new Block(BlockKind.ArrayInitializer);
                        var tempStore = context.Function.RegisterVariable(VariableKind.InitializerTarget, v.Type);
                        block.Instructions.Add(new StLoc(tempStore, new NewArr(elementType, arrayLength.Select(l => new LdcI4(l)).ToArray())));
                        block.Instructions.AddRange(values.SelectWithIndex((i, value) => StElem(new LdLoc(tempStore), new[] { new LdcI4(i) }, value, elementType)));
                        block.FinalInstruction = new LdLoc(tempStore);
                        body.Instructions[pos] = new StLoc(finalStore, block);
                        body.Instructions.RemoveRange(pos + 1, instructionsToRemove);
                        ILInlining.InlineIfPossible(body, pos, context);
                        return(true);
                    }
                }
            }
            return(false);
        }