Ejemplo n.º 1
0
			public void GetMethodInfo(MethodKey key, out Parameter[] parameters, out Local[] locals, out ILVariable[] decLocals) {
				parameters = null;
				locals = null;
				decLocals = null;

				foreach (var textView in MainWindow.Instance.AllTextViews) {
					if (parameters != null && decLocals != null)
						break;

					var cm = textView.CodeMappings;
					if (cm == null)
						continue;
					MemberMapping mapping;
					if (!cm.TryGetValue(key, out mapping))
						continue;
					var method = mapping.MethodDefinition;
					if (mapping.LocalVariables != null && method.Body != null) {
						locals = method.Body.Variables.ToArray();
						decLocals = new ILVariable[method.Body.Variables.Count];
						foreach (var v in mapping.LocalVariables) {
							if (v.IsGenerated)
								continue;
							if (v.OriginalVariable == null)
								continue;
							if ((uint)v.OriginalVariable.Index >= decLocals.Length)
								continue;
							decLocals[v.OriginalVariable.Index] = v;
						}
					}

					parameters = method.Parameters.ToArray();
				}
			}
Ejemplo n.º 2
0
		void AssignNameToVariable(ILVariable varDef, IEnumerable<ILExpression> allExpressions)
		{
			string proposedName = null;
			foreach (ILExpression expr in allExpressions) {
				if (expr.Operand != varDef)
					continue;
				if (expr.Code == ILCode.Stloc) {
					proposedName = GetNameFromExpression(expr.Arguments.Single());
				}
				if (proposedName != null)
					break;
			}
			if (proposedName == null)
				proposedName = GetNameByType(varDef.Type);
			
			if (!typeNames.ContainsKey(proposedName)) {
				typeNames.Add(proposedName, 0);
			}
			int count = ++typeNames[proposedName];
			if (count > 1) {
				varDef.Name = proposedName + count.ToString();
			} else {
				varDef.Name = proposedName;
			}
		}
Ejemplo n.º 3
0
        public bool Get (ILVariable localVariable, out DynamicCallSiteInfo info) {
            FieldReference storageField;

            if (Aliases.TryGetValue(localVariable.Name, out storageField))
                return Get(storageField, out info);

            info = null;
            return false;
        }
Ejemplo n.º 4
0
		bool HasSingleLoad(ILVariable v)
		{
			int loads = 0;
			foreach (ILExpression expr in method.GetSelfAndChildrenRecursive<ILExpression>()) {
				if (expr.Operand == v) {
					if (expr.Code == ILCode.Ldloc)
						loads++;
					else if (expr.Code != ILCode.Stloc)
						return false;
				}
			}
			return loads == 1;
		}
Ejemplo n.º 5
0
		/// <summary>
		/// Finds the position to inline to.
		/// </summary>
		/// <returns>true = found; false = cannot continue search; null = not found</returns>
		static bool? FindLoadInNext(ILExpression expr, ILVariable v, out ILExpression parent, out int pos)
		{
			parent = null;
			pos = 0;
			if (expr == null)
				return false;
			for (int i = 0; i < expr.Arguments.Count; i++) {
				ILExpression arg = expr.Arguments[i];
				if (arg.Code == ILCode.Ldloc && arg.Operand == v) {
					parent = expr;
					pos = i;
					return true;
				}
				bool? r = FindLoadInNext(arg, v, out parent, out pos);
				if (r != null)
					return r;
			}
			return IsWithoutSideEffects(expr.Code) ? (bool?)null : false;
		}
Ejemplo n.º 6
0
		/// <summary>
		/// Gets whether 'expressionBeingMoved' can be inlined into 'expr'.
		/// </summary>
		public bool CanInlineInto(ILExpression expr, ILVariable v, ILExpression expressionBeingMoved)
		{
			ILExpression parent;
			int pos;
			return FindLoadInNext(expr, v, expressionBeingMoved, out parent, out pos) == true;
		}
Ejemplo n.º 7
0
 bool IsPartOfInitializer(InstructionCollection <ILInstruction> instructions, int pos, ILVariable target, IType rootType, ref BlockType blockType, Dictionary <ILVariable, (int Index, ILInstruction Value)> possibleIndexVariables)
Ejemplo n.º 8
0
 ///	finally BlockContainer {
 ///		Block IL_0012(incoming: 1) {
 ///			if (comp(ldloc obj != ldnull)) Block IL_001a  {
 ///				callvirt Dispose(obj)
 ///			}
 ///			leave IL_0012(nop)
 ///		}
 /// }
 bool MatchDisposeBlock(BlockContainer container, ILVariable objVar, bool usingNull,
                        in string disposeMethodFullName = "System.IDisposable.Dispose",
Ejemplo n.º 9
0
 public ReplaceDelegateTargetVisitor(ILInstruction target, ILVariable thisVariable)
 {
     this.target       = target;
     this.thisVariable = thisVariable;
 }
Ejemplo n.º 10
0
        string GenerateNameForVariable(ILVariable variable, ILBlock methodBody)
        {
            string proposedName = null;

            if (variable.Type == context.CurrentType.Module.TypeSystem.Int32)
            {
                // test whether the variable might be a loop counter
                bool isLoopCounter = false;
                foreach (ILWhileLoop loop in methodBody.GetSelfAndChildrenRecursive <ILWhileLoop>())
                {
                    ILExpression expr = loop.Condition;
                    while (expr != null && expr.Code == ILCode.LogicNot)
                    {
                        expr = expr.Arguments[0];
                    }
                    if (expr != null)
                    {
                        switch (expr.Code)
                        {
                        case ILCode.Clt:
                        case ILCode.Clt_Un:
                        case ILCode.Cgt:
                        case ILCode.Cgt_Un:
                        case ILCode.Cle:
                        case ILCode.Cle_Un:
                        case ILCode.Cge:
                        case ILCode.Cge_Un:
                            ILVariable loadVar;
                            if (expr.Arguments[0].Match(ILCode.Ldloc, out loadVar) && loadVar == variable)
                            {
                                isLoopCounter = true;
                            }
                            break;
                        }
                    }
                }
                if (isLoopCounter)
                {
                    // For loop variables, use i,j,k,l,m,n
                    for (char c = 'i'; c <= maxLoopVariableName; c++)
                    {
                        if (!typeNames.ContainsKey(c.ToString()))
                        {
                            proposedName = c.ToString();
                            break;
                        }
                    }
                }
            }
            if (string.IsNullOrEmpty(proposedName))
            {
                var proposedNameForStores =
                    (from expr in methodBody.GetSelfAndChildrenRecursive <ILExpression>()
                     where expr.Code == ILCode.Stloc && expr.Operand == variable
                     select GetNameFromExpression(expr.Arguments.Single())
                    ).Except(fieldNamesInCurrentType).ToList();
                if (proposedNameForStores.Count == 1)
                {
                    proposedName = proposedNameForStores[0];
                }
            }
            if (string.IsNullOrEmpty(proposedName))
            {
                var proposedNameForLoads =
                    (from expr in methodBody.GetSelfAndChildrenRecursive <ILExpression>()
                     from i in Enumerable.Range(0, expr.Arguments.Count)
                     let arg = expr.Arguments[i]
                               where arg.Code == ILCode.Ldloc && arg.Operand == variable
                               select GetNameForArgument(expr, i)
                    ).Except(fieldNamesInCurrentType).ToList();
                if (proposedNameForLoads.Count == 1)
                {
                    proposedName = proposedNameForLoads[0];
                }
            }
            if (string.IsNullOrEmpty(proposedName))
            {
                proposedName = GetNameByType(variable.Type);
            }

            // remove any numbers from the proposed name
            int number;

            proposedName = SplitName(proposedName, out number);

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

            if (count > 1)
            {
                return(proposedName + count.ToString());
            }
            else
            {
                return(proposedName);
            }
        }
		static bool AdjustInitializerStack(List<ILExpression> initializerStack, ILExpression argument, ILVariable v, bool isCollection)
		{
			// Argument is of the form 'getter(getter(...(v)))'
			// Unpack it into a list of getters:
			List<ILExpression> getters = new List<ILExpression>();
			while (argument.Code == ILCode.CallvirtGetter || argument.Code == ILCode.Ldfld) {
				getters.Add(argument);
				if (argument.Arguments.Count != 1)
					return false;
				argument = argument.Arguments[0];
			}
			// Ensure that the final argument is 'v'
			if (!argument.MatchLdloc(v))
				return false;
			// Now compare the getters with those that are currently active on the initializer stack:
			int i;
			for (i = 1; i <= Math.Min(getters.Count, initializerStack.Count - 1); i++) {
				ILExpression g1 = initializerStack[i].Arguments[0]; // getter stored in initializer
				ILExpression g2 = getters[getters.Count - i]; // matching getter from argument
				if (g1.Operand != g2.Operand) {
					// operands differ, so we abort the comparison
					break;
				}
			}
			// Remove all initializers from the stack that were not matched with one from the argument:
			initializerStack.RemoveRange(i, initializerStack.Count - i);
			// Now create new initializers for the remaining arguments:
			for (; i <= getters.Count; i++) {
				ILExpression g = getters[getters.Count - i];
				MemberReference mr = (MemberReference)g.Operand;
				TypeReference returnType;
				if (mr is FieldReference)
					returnType = TypeAnalysis.GetFieldType((FieldReference)mr);
				else
					returnType = TypeAnalysis.SubstituteTypeArgs(((MethodReference)mr).ReturnType, mr);
				
				ILExpression nestedInitializer = new ILExpression(
					IsCollectionType(returnType) ? ILCode.InitCollection : ILCode.InitObject,
					null, g);
				// add new initializer to its parent:
				ILExpression parentInitializer = initializerStack[initializerStack.Count - 1];
				if (parentInitializer.Code == ILCode.InitCollection) {
					// can't add children to collection initializer
					if (parentInitializer.Arguments.Count == 1) {
						// convert empty collection initializer to object initializer
						parentInitializer.Code = ILCode.InitObject;
					} else {
						return false;
					}
				}
				parentInitializer.Arguments.Add(nestedInitializer);
				initializerStack.Add(nestedInitializer);
			}
			ILExpression lastInitializer = initializerStack[initializerStack.Count - 1];
			if (isCollection) {
				return lastInitializer.Code == ILCode.InitCollection;
			} else {
				if (lastInitializer.Code == ILCode.InitCollection) {
					if (lastInitializer.Arguments.Count == 1) {
						// convert empty collection initializer to object initializer
						lastInitializer.Code = ILCode.InitObject;
						return true;
					} else {
						return false;
					}
				} else {
					return true;
				}
			}
		}
Ejemplo n.º 12
0
 protected JSExpression Translate_Ldloca(ILExpression node, ILVariable variable)
 {
     return JSReferenceExpression.New(
         Translate_Ldloc(node, variable)
     );
 }
Ejemplo n.º 13
0
 /// <summary>
 /// Is this a temporary variable generated by the C# compiler for instance method calls on value type values
 /// </summary>
 /// <param name="next">The next top-level expression</param>
 /// <param name="loadInst">The load instruction (a descendant within 'next')</param>
 /// <param name="v">The variable being inlined.</param>
 static bool IsGeneratedValueTypeTemporary(ILInstruction next, LdLoca loadInst, ILVariable v, ILInstruction inlinedExpression)
 {
     Debug.Assert(loadInst.Variable == v);
     // Inlining a value type variable is allowed only if the resulting code will maintain the semantics
     // that the method is operating on a copy.
     // Thus, we have to ensure we're operating on an r-value.
     // Additionally, we cannot inline in cases where the C# compiler prohibits the direct use
     // of the rvalue (e.g. M(ref (MyStruct)obj); is invalid).
     return(IsUsedAsThisPointerInCall(loadInst) && !IsLValue(inlinedExpression));
 }
Ejemplo n.º 14
0
 public bool IsPotentiallyUsedUninitialized(ILVariable v)
 {
     Debug.Assert(v.Function == scope);
     return(variablesWithUninitializedUsage[v.IndexInFunction]);
 }
Ejemplo n.º 15
0
 private bool MatchThreeValuedLogicConditionPattern(ILInstruction condition, out ILVariable nullable1, out ILVariable nullable2)
 {
     // Try to match: nullable1.GetValueOrDefault() || (!nullable2.GetValueOrDefault() && !nullable1.HasValue)
     nullable1 = null;
     nullable2 = null;
     if (!condition.MatchLogicOr(out var lhs, out var rhs))
     {
         return(false);
     }
     if (!MatchGetValueOrDefault(lhs, out nullable1))
     {
         return(false);
     }
     if (!NullableType.GetUnderlyingType(nullable1.Type).IsKnownType(KnownTypeCode.Boolean))
     {
         return(false);
     }
     if (!rhs.MatchLogicAnd(out lhs, out rhs))
     {
         return(false);
     }
     if (!lhs.MatchLogicNot(out var arg))
     {
         return(false);
     }
     if (!MatchGetValueOrDefault(arg, out nullable2))
     {
         return(false);
     }
     if (!NullableType.GetUnderlyingType(nullable2.Type).IsKnownType(KnownTypeCode.Boolean))
     {
         return(false);
     }
     if (!rhs.MatchLogicNot(out arg))
     {
         return(false);
     }
     return(MatchHasValueCall(arg, nullable1));
 }
Ejemplo n.º 16
0
        void EnsureVariableNameIsAvailable(AstNode currentNode, string name)
        {
            int pos = currentlyUsedVariableNames.IndexOf(name);

            if (pos < 0)
            {
                // name is still available
                return;
            }
            // Naming conflict. Let's rename the existing variable so that the field keeps the name from metadata.
            NameVariables nv = new NameVariables();

            // Add currently used variable and parameter names
            foreach (string nameInUse in currentlyUsedVariableNames)
            {
                nv.AddExistingName(nameInUse);
            }
            // variables declared in child nodes of this block
            foreach (VariableInitializer vi in currentNode.Descendants.OfType <VariableInitializer>())
            {
                nv.AddExistingName(vi.Name);
            }
            // parameters in child lambdas
            foreach (ParameterDeclaration pd in currentNode.Descendants.OfType <ParameterDeclaration>())
            {
                nv.AddExistingName(pd.Name);
            }

            string newName = nv.GetAlternativeName(name);

            currentlyUsedVariableNames[pos] = newName;

            // find top-most block
            AstNode topMostBlock = currentNode.Ancestors.OfType <BlockStatement>().LastOrDefault() ?? currentNode;

            // rename identifiers
            foreach (IdentifierExpression ident in topMostBlock.Descendants.OfType <IdentifierExpression>())
            {
                if (ident.Identifier == name)
                {
                    ident.Identifier = newName;
                    ILVariable v = ident.Annotation <ILVariable>();
                    if (v != null)
                    {
                        v.Name = newName;
                    }
                }
            }
            // rename variable declarations
            foreach (VariableInitializer vi in topMostBlock.Descendants.OfType <VariableInitializer>())
            {
                if (vi.Name == name)
                {
                    vi.Name = newName;
                    ILVariable v = vi.Annotation <ILVariable>();
                    if (v != null)
                    {
                        v.Name = newName;
                    }
                }
            }
        }
Ejemplo n.º 17
0
        public override object VisitBlockStatement(BlockStatement blockStatement, object data)
        {
            int numberOfVariablesOutsideBlock = currentlyUsedVariableNames.Count;

            base.VisitBlockStatement(blockStatement, data);
            foreach (ExpressionStatement stmt in blockStatement.Statements.OfType <ExpressionStatement>().ToArray())
            {
                Match displayClassAssignmentMatch = displayClassAssignmentPattern.Match(stmt);
                if (!displayClassAssignmentMatch.Success)
                {
                    continue;
                }

                ILVariable variable = displayClassAssignmentMatch.Get <AstNode>("variable").Single().Annotation <ILVariable>();
                if (variable == null)
                {
                    continue;
                }
                TypeDefinition type = variable.Type.ResolveWithinSameModule();
                if (!IsPotentialClosure(context, type))
                {
                    continue;
                }
                if (displayClassAssignmentMatch.Get <AstType>("type").Single().Annotation <TypeReference>().ResolveWithinSameModule() != type)
                {
                    continue;
                }

                // Looks like we found a display class creation. Now let's verify that the variable is used only for field accesses:
                bool ok = true;
                foreach (var identExpr in blockStatement.Descendants.OfType <IdentifierExpression>())
                {
                    if (identExpr.Identifier == variable.Name && identExpr != displayClassAssignmentMatch.Get("variable").Single())
                    {
                        if (!(identExpr.Parent is MemberReferenceExpression && identExpr.Parent.Annotation <FieldReference>() != null))
                        {
                            ok = false;
                        }
                    }
                }
                if (!ok)
                {
                    continue;
                }
                Dictionary <FieldReference, AstNode> dict = new Dictionary <FieldReference, AstNode>();

                // Delete the variable declaration statement:
                VariableDeclarationStatement displayClassVarDecl = PatternStatementTransform.FindVariableDeclaration(stmt, variable.Name);
                if (displayClassVarDecl != null)
                {
                    displayClassVarDecl.Remove();
                }

                // Delete the assignment statement:
                AstNode cur = stmt.NextSibling;
                stmt.Remove();

                // Delete any following statements as long as they assign parameters to the display class
                BlockStatement    rootBlock            = blockStatement.Ancestors.OfType <BlockStatement>().LastOrDefault() ?? blockStatement;
                List <ILVariable> parameterOccurrances = rootBlock.Descendants.OfType <IdentifierExpression>()
                                                         .Select(n => n.Annotation <ILVariable>()).Where(p => p != null && p.IsParameter).ToList();
                AstNode next;
                for (; cur != null; cur = next)
                {
                    next = cur.NextSibling;

                    // Test for the pattern:
                    // "variableName.MemberName = right;"
                    ExpressionStatement closureFieldAssignmentPattern = new ExpressionStatement(
                        new AssignmentExpression(
                            new NamedNode("left", new MemberReferenceExpression {
                        Target     = new IdentifierExpression(variable.Name),
                        MemberName = Pattern.AnyString
                    }),
                            new AnyNode("right")
                            )
                        );
                    Match m = closureFieldAssignmentPattern.Match(cur);
                    if (m.Success)
                    {
                        FieldDefinition fieldDef    = m.Get <MemberReferenceExpression>("left").Single().Annotation <FieldReference>().ResolveWithinSameModule();
                        AstNode         right       = m.Get <AstNode>("right").Single();
                        bool            isParameter = false;
                        bool            isDisplayClassParentPointerAssignment = false;
                        if (right is ThisReferenceExpression)
                        {
                            isParameter = true;
                        }
                        else if (right is IdentifierExpression)
                        {
                            // handle parameters only if the whole method contains no other occurrence except for 'right'
                            ILVariable v = right.Annotation <ILVariable>();
                            isParameter = v.IsParameter && parameterOccurrances.Count(c => c == v) == 1;
                            if (!isParameter && IsPotentialClosure(context, v.Type.ResolveWithinSameModule()))
                            {
                                // parent display class within the same method
                                // (closure2.localsX = closure1;)
                                isDisplayClassParentPointerAssignment = true;
                            }
                        }
                        else if (right is MemberReferenceExpression)
                        {
                            // copy of parent display class reference from an outer lambda
                            // closure2.localsX = this.localsY
                            MemberReferenceExpression mre = m.Get <MemberReferenceExpression>("right").Single();
                            do
                            {
                                // descend into the targets of the mre as long as the field types are closures
                                FieldDefinition fieldDef2 = mre.Annotation <FieldReference>().ResolveWithinSameModule();
                                if (fieldDef2 == null || !IsPotentialClosure(context, fieldDef2.FieldType.ResolveWithinSameModule()))
                                {
                                    break;
                                }
                                // if we finally get to a this reference, it's copying a display class parent pointer
                                if (mre.Target is ThisReferenceExpression)
                                {
                                    isDisplayClassParentPointerAssignment = true;
                                }
                                mre = mre.Target as MemberReferenceExpression;
                            } while (mre != null);
                        }
                        if (isParameter || isDisplayClassParentPointerAssignment)
                        {
                            dict[fieldDef] = right;
                            cur.Remove();
                        }
                        else
                        {
                            break;
                        }
                    }
                    else
                    {
                        break;
                    }
                }

                // Now create variables for all fields of the display class (except for those that we already handled as parameters)
                List <Tuple <AstType, ILVariable> > variablesToDeclare = new List <Tuple <AstType, ILVariable> >();
                foreach (FieldDefinition field in type.Fields)
                {
                    if (field.IsStatic)
                    {
                        continue;                         // skip static fields
                    }
                    if (dict.ContainsKey(field))          // skip field if it already was handled as parameter
                    {
                        continue;
                    }
                    string capturedVariableName = field.Name;
                    if (capturedVariableName.StartsWith("$VB$Local_", StringComparison.Ordinal) && capturedVariableName.Length > 10)
                    {
                        capturedVariableName = capturedVariableName.Substring(10);
                    }
                    EnsureVariableNameIsAvailable(blockStatement, capturedVariableName);
                    currentlyUsedVariableNames.Add(capturedVariableName);
                    ILVariable ilVar = new ILVariable
                    {
                        IsGenerated = true,
                        Name        = capturedVariableName,
                        Type        = field.FieldType,
                    };
                    variablesToDeclare.Add(Tuple.Create(AstBuilder.ConvertType(field.FieldType, field), ilVar));
                    dict[field] = new IdentifierExpression(capturedVariableName).WithAnnotation(ilVar);
                }

                // Now figure out where the closure was accessed and use the simpler replacement expression there:
                foreach (var identExpr in blockStatement.Descendants.OfType <IdentifierExpression>())
                {
                    if (identExpr.Identifier == variable.Name)
                    {
                        MemberReferenceExpression mre = (MemberReferenceExpression)identExpr.Parent;
                        AstNode replacement;
                        if (dict.TryGetValue(mre.Annotation <FieldReference>().ResolveWithinSameModule(), out replacement))
                        {
                            mre.ReplaceWith(replacement.Clone());
                        }
                    }
                }
                // Now insert the variable declarations (we can do this after the replacements only so that the scope detection works):
                Statement insertionPoint = blockStatement.Statements.FirstOrDefault();
                foreach (var tuple in variablesToDeclare)
                {
                    var newVarDecl = new VariableDeclarationStatement(tuple.Item1, tuple.Item2.Name);
                    newVarDecl.Variables.Single().AddAnnotation(new CapturedVariableAnnotation());
                    newVarDecl.Variables.Single().AddAnnotation(tuple.Item2);
                    blockStatement.Statements.InsertBefore(insertionPoint, newVarDecl);
                }
            }
            currentlyUsedVariableNames.RemoveRange(numberOfVariablesOutsideBlock, currentlyUsedVariableNames.Count - numberOfVariablesOutsideBlock);
            return(null);
        }
Ejemplo n.º 18
0
 public static JSClosureVariable New(ILVariable variable, MethodReference function)
 {
     return(new JSClosureVariable(variable.Name, variable.Type, function));
 }
Ejemplo n.º 19
0
        /// <summary>
        /// Determines whether a variable was merged with other variables.
        /// </summary>
        public bool WasMerged(ILVariable variable)
        {
            VariableToDeclare v = variableDict[variable];

            return(v.InvolvedInCollision || v.RemovedDueToCollision);
        }
Ejemplo n.º 20
0
		/// <summary>
		/// Runs a very simple form of copy propagation.
		/// Copy propagation is used in two cases:
		/// 1) assignments from arguments to local variables
		///    If the target variable is assigned to only once (so always is that argument) and the argument is never changed (no ldarga/starg),
		///    then we can replace the variable with the argument.
		/// 2) assignments of address-loading instructions to local variables
		/// </summary>
		public void CopyPropagation(List<ILNode> newList)
		{
			var newListTemp = newList;
			method.GetSelfAndChildrenRecursive<ILNode>(newList);
			bool recalc = false;
			foreach (var node1 in newList) {
				var block = node1 as ILBlock;
				if (block == null)
					continue;
				for (int i = 0; i < block.Body.Count; i++) {
					ILVariable v;
					ILExpression copiedExpr;
					if (block.Body[i].Match(ILCode.Stloc, out v, out copiedExpr)
					    && !v.IsParameter && numStloc.GetOrDefault(v) == 1 && numLdloca.GetOrDefault(v) == 0
					    && CanPerformCopyPropagation(copiedExpr, v))
					{
						// un-inline the arguments of the ldArg instruction
						ILVariable[] uninlinedArgs = new ILVariable[copiedExpr.Arguments.Count];
						for (int j = 0; j < uninlinedArgs.Length; j++) {
							uninlinedArgs[j] = new ILVariable { GeneratedByDecompiler = true, Name = v.Name + "_cp_" + j };
							block.Body.Insert(i++, new ILExpression(ILCode.Stloc, uninlinedArgs[j], copiedExpr.Arguments[j]));
							recalc = true;
						}
						
						// perform copy propagation:
						foreach (var node2 in newListTemp) {
							var expr = node2 as ILExpression;
							if (expr == null)
								continue;
							if (expr.Code == ILCode.Ldloc && expr.Operand == v) {
								expr.Code = copiedExpr.Code;
								expr.Operand = copiedExpr.Operand;
								for (int j = 0; j < uninlinedArgs.Length; j++) {
									expr.Arguments.Add(new ILExpression(ILCode.Ldloc, uninlinedArgs[j]));
								}
							}
						}

						if (context.CalculateILRanges) {
							Utils.AddILRanges(block, block.Body, i, block.Body[i].ILRanges);
							Utils.AddILRanges(block, block.Body, i, copiedExpr.ILRanges);
						}
						block.Body.RemoveAt(i);
						if (uninlinedArgs.Length > 0) {
							// if we un-inlined stuff; we need to update the usage counters
							AnalyzeMethod();
						}
						InlineInto(block, block.Body, i, aggressive: false); // maybe inlining gets possible after the removal of block.Body[i]
						i -= uninlinedArgs.Length + 1;

						if (recalc) {
							recalc = false;
							newListTemp = method.GetSelfAndChildrenRecursive<ILNode>(newListTemp == newList ? (newListTemp = list_ILNode) : newListTemp);
						}
					}
				}
			}
		}
Ejemplo n.º 21
0
        /// <summary>
        /// Determines whether a variable should be inlined in non-aggressive mode, even though it is not a generated variable.
        /// </summary>
        /// <param name="next">The next top-level expression</param>
        /// <param name="loadInst">The load within 'next'</param>
        /// <param name="inlinedExpression">The expression being inlined</param>
        static bool NonAggressiveInlineInto(ILInstruction next, ILInstruction loadInst, ILInstruction inlinedExpression, ILVariable v)
        {
            Debug.Assert(loadInst.IsDescendantOf(next));

            // decide based on the source expression being inlined
            switch (inlinedExpression.OpCode)
            {
            case OpCode.DefaultValue:
            case OpCode.StObj:
            case OpCode.CompoundAssignmentInstruction:
            case OpCode.Await:
                return(true);

            case OpCode.LdLoc:
                if (v.StateMachineField == null && ((LdLoc)inlinedExpression).Variable.StateMachineField != null)
                {
                    // Roslyn likes to put the result of fetching a state machine field into a temporary variable,
                    // so inline more aggressively in such cases.
                    return(true);
                }
                break;
            }

            var parent = loadInst.Parent;

            if (NullableLiftingTransform.MatchNullableCtor(parent, out _, out _))
            {
                // inline into nullable ctor call in lifted operator
                parent = parent.Parent;
            }
            if (parent is ILiftableInstruction liftable && liftable.IsLifted)
            {
                return(true);                // inline into lifted operators
            }
            if (parent is NullCoalescingInstruction && NullableType.IsNullable(v.Type))
            {
                return(true);                // inline nullables into ?? operator
            }
            // decide based on the target into which we are inlining
            switch (next.OpCode)
            {
            case OpCode.Leave:
                return(parent == next);

            case OpCode.IfInstruction:
                while (parent.MatchLogicNot(out _))
                {
                    parent = parent.Parent;
                }
                return(parent == next);

            case OpCode.BlockContainer:
                if (((BlockContainer)next).EntryPoint.Instructions[0] is SwitchInstruction switchInst)
                {
                    next = switchInst;
                    goto case OpCode.SwitchInstruction;
                }
                else
                {
                    return(false);
                }

            case OpCode.SwitchInstruction:
                return(parent == next || (parent.MatchBinaryNumericInstruction(BinaryNumericOperator.Sub) && parent.Parent == next));

            default:
                return(false);
            }
        }
Ejemplo n.º 22
0
        /// <summary>
        /// Gets whether 'expressionBeingMoved' can be inlined into 'expr'.
        /// </summary>
        public static bool CanInlineInto(ILInstruction expr, ILVariable v, ILInstruction expressionBeingMoved)
        {
            ILInstruction loadInst;

            return(FindLoadInNext(expr, v, expressionBeingMoved, out loadInst) == true);
        }
Ejemplo n.º 23
0
 protected JSVariable DeclareVariable(ILVariable variable, MethodReference function)
 {
     return DeclareVariable(JSVariable.New(variable, function));
 }
        bool DoTransform(Block body, int pos)
        {
            ILInstruction inst = body.Instructions[pos];

            // Match stloc(v, newobj)
            if (inst.MatchStLoc(out var v, out var initInst) && (v.Kind == VariableKind.Local || v.Kind == VariableKind.StackSlot))
            {
                IType instType;
                switch (initInst)
                {
                case NewObj newObjInst:
                    if (newObjInst.ILStackWasEmpty && v.Kind == VariableKind.Local && !context.Function.Method.IsConstructor && !context.Function.Method.IsCompilerGeneratedOrIsInCompilerGeneratedClass())
                    {
                        // on statement level (no other expressions on IL stack),
                        // prefer to keep local variables (but not stack slots),
                        // unless we are in a constructor (where inlining object initializers might be critical
                        // for the base ctor call) or a compiler-generated delegate method, which might be used in a query expression.
                        return(false);
                    }
                    // Do not try to transform display class usages or delegate construction.
                    // DelegateConstruction transform cannot deal with this.
                    if (DelegateConstruction.IsSimpleDisplayClass(newObjInst.Method.DeclaringType))
                    {
                        return(false);
                    }
                    if (DelegateConstruction.IsDelegateConstruction(newObjInst) || DelegateConstruction.IsPotentialClosure(context, newObjInst))
                    {
                        return(false);
                    }
                    instType = newObjInst.Method.DeclaringType;
                    break;

                case DefaultValue defaultVal:
                    if (defaultVal.ILStackWasEmpty && v.Kind == VariableKind.Local && !context.Function.Method.IsConstructor)
                    {
                        // on statement level (no other expressions on IL stack),
                        // prefer to keep local variables (but not stack slots),
                        // unless we are in a constructor (where inlining object initializers might be critical
                        // for the base ctor call)
                        return(false);
                    }
                    instType = defaultVal.Type;
                    break;

                default:
                    return(false);
                }
                int initializerItemsCount = 0;
                var blockKind             = BlockKind.CollectionInitializer;
                possibleIndexVariables = new Dictionary <ILVariable, (int Index, ILInstruction Value)>();
                currentPath            = new List <AccessPathElement>();
                isCollection           = false;
                pathStack = new Stack <HashSet <AccessPathElement> >();
                pathStack.Push(new HashSet <AccessPathElement>());
                // Detect initializer type by scanning the following statements
                // each must be a callvirt with ldloc v as first argument
                // if the method is a setter we're dealing with an object initializer
                // if the method is named Add and has at least 2 arguments we're dealing with a collection/dictionary initializer
                while (pos + initializerItemsCount + 1 < body.Instructions.Count &&
                       IsPartOfInitializer(body.Instructions, pos + initializerItemsCount + 1, v, instType, ref blockKind))
                {
                    initializerItemsCount++;
                }
                // Do not convert the statements into an initializer if there's an incompatible usage of the initializer variable
                // directly after the possible initializer.
                if (IsMethodCallOnVariable(body.Instructions[pos + initializerItemsCount + 1], v))
                {
                    return(false);
                }
                // Calculate the correct number of statements inside the initializer:
                // All index variables that were used in the initializer have Index set to -1.
                // We fetch the first unused variable from the list and remove all instructions after its
                // first usage (i.e. the init store) from the initializer.
                var index = possibleIndexVariables.Where(info => info.Value.Index > -1).Min(info => (int?)info.Value.Index);
                if (index != null)
                {
                    initializerItemsCount = index.Value - pos - 1;
                }
                // The initializer would be empty, there's nothing to do here.
                if (initializerItemsCount <= 0)
                {
                    return(false);
                }
                context.Step("CollectionOrObjectInitializer", inst);
                // Create a new block and final slot (initializer target variable)
                var        initializerBlock = new Block(blockKind);
                ILVariable finalSlot        = context.Function.RegisterVariable(VariableKind.InitializerTarget, v.Type);
                initializerBlock.FinalInstruction = new LdLoc(finalSlot);
                initializerBlock.Instructions.Add(new StLoc(finalSlot, initInst.Clone()));
                // Move all instructions to the initializer block.
                for (int i = 1; i <= initializerItemsCount; i++)
                {
                    switch (body.Instructions[i + pos])
                    {
                    case CallInstruction call:
                        if (!(call is CallVirt || call is Call))
                        {
                            continue;
                        }
                        var newCall   = call;
                        var newTarget = newCall.Arguments[0];
                        foreach (var load in newTarget.Descendants.OfType <IInstructionWithVariableOperand>())
                        {
                            if ((load is LdLoc || load is LdLoca) && load.Variable == v)
                            {
                                load.Variable = finalSlot;
                            }
                        }
                        initializerBlock.Instructions.Add(newCall);
                        break;

                    case StObj stObj:
                        var newStObj = stObj;
                        foreach (var load in newStObj.Target.Descendants.OfType <IInstructionWithVariableOperand>())
                        {
                            if ((load is LdLoc || load is LdLoca) && load.Variable == v)
                            {
                                load.Variable = finalSlot;
                            }
                        }
                        initializerBlock.Instructions.Add(newStObj);
                        break;

                    case StLoc stLoc:
                        var newStLoc = stLoc;
                        initializerBlock.Instructions.Add(newStLoc);
                        break;
                    }
                }
                initInst.ReplaceWith(initializerBlock);
                body.Instructions.RemoveRange(pos + 1, initializerItemsCount);
                ILInlining.InlineIfPossible(body, pos, context);
            }
            return(true);
        }
Ejemplo n.º 25
0
 static bool Capture(ref ILVariable pmvar, ILVariable v)
 {
     if (pmvar != null) return pmvar == v;
     pmvar = v;
     return true;
 }
Ejemplo n.º 26
0
		/// <summary>
		/// Initializes the state range logic:
		/// Clears 'ranges' and sets 'ranges[entryPoint]' to the full range (int.MinValue to int.MaxValue)
		/// </summary>
		void InitStateRanges(ILNode entryPoint)
		{
			ranges = new DefaultDictionary<ILNode, StateRange>(n => new StateRange());
			ranges[entryPoint] = new StateRange(int.MinValue, int.MaxValue);
			rangeAnalysisStateVariable = null;
		}
Ejemplo n.º 27
0
        List<ILNode> ConvertToAst(List<ByteCode> body)
        {
            List<ILNode> ast = new List<ILNode>();

            // Convert stack-based IL code to ILAst tree
            foreach(ByteCode byteCode in body) {
                OpCode opCode  = byteCode.OpCode;
                object operand = byteCode.Operand;

                MethodBodyRocks.ExpandMacro(ref opCode, ref operand, methodDef.Body);

                ILExpression expr = new ILExpression(opCode, operand);
                expr.ILRanges.Add(new ILRange() { From = byteCode.Offset, To = byteCode.EndOffset });

                // Label for this instruction
                if (byteCode.Label != null) {
                    ast.Add(byteCode.Label);
                }

                // Reference arguments using temporary variables
                int popCount = byteCode.PopCount ?? byteCode.StackBefore.Count;
                for (int i = byteCode.StackBefore.Count - popCount; i < byteCode.StackBefore.Count; i++) {
                    StackSlot slot = byteCode.StackBefore[i];
                    if (slot.PushedBy != null) {
                        ILExpression ldExpr = new ILExpression(OpCodes.Ldloc, slot.LoadFrom);
                        expr.Arguments.Add(ldExpr);
                    } else {
                        ILExpression ldExpr = new ILExpression(OpCodes.Ldloc, new ILVariable() { Name = "ex", IsGenerated = true });
                        expr.Arguments.Add(ldExpr);
                    }
                }

                // Store the result to temporary variable(s) if needed
                if (byteCode.StoreTo == null || byteCode.StoreTo.Count == 0) {
                    ast.Add(expr);
                } else if (byteCode.StoreTo.Count == 1) {
                    ast.Add(new ILExpression(OpCodes.Stloc, byteCode.StoreTo[0], expr));
                } else {
                    ILVariable tmpVar = new ILVariable() { Name = "expr_" + byteCode.Offset.ToString("X2"), IsGenerated = true };
                    ast.Add(new ILExpression(OpCodes.Stloc, tmpVar, expr));
                    foreach(ILVariable storeTo in byteCode.StoreTo) {
                        ast.Add(new ILExpression(OpCodes.Stloc, storeTo, new ILExpression(OpCodes.Ldloc, tmpVar)));
                    }
                }
            }

            // Try to in-line stloc / ldloc pairs
            for(int i = 0; i < ast.Count - 1; i++) {
                if (i < 0) continue;

                ILExpression currExpr = ast[i] as ILExpression;
                ILExpression nextExpr = ast[i + 1] as ILExpression;

                if (currExpr != null && nextExpr != null && currExpr.OpCode.Code == Code.Stloc) {

                    // If the next expression is generated stloc, look inside
                    if (nextExpr.OpCode.Code == Code.Stloc && ((ILVariable)nextExpr.Operand).IsGenerated) {
                        nextExpr = nextExpr.Arguments[0];
                    }

                    // Find the use of the 'expr'
                    for(int j = 0; j < nextExpr.Arguments.Count; j++) {
                        ILExpression arg = nextExpr.Arguments[j];

                        // We are moving the expression evaluation past the other aguments.
                        // It is ok to pass ldloc because the expression can not contain stloc and thus the ldcoc will still return the same value
                        if (arg.OpCode.Code == Code.Ldloc) {
                            bool canInline;
                            allowInline.TryGetValue((ILVariable)arg.Operand, out canInline);
                            if (arg.Operand == currExpr.Operand && canInline) {
                                // Assigne the ranges for optimized away instrustions somewhere
                                currExpr.Arguments[0].ILRanges.AddRange(currExpr.ILRanges);
                                currExpr.Arguments[0].ILRanges.AddRange(nextExpr.Arguments[j].ILRanges);
                                ast.RemoveAt(i);
                                nextExpr.Arguments[j] = currExpr.Arguments[0]; // Inline the stloc body
                                i -= 2; // Try the same index again
                                break;  // Found
                            }
                        } else {
                            break;  // Side-effects
                        }
                    }
                }
            }

            return ast;
        }
Ejemplo n.º 28
0
		void AnalyzeMoveNext()
		{
			MethodDefinition moveNextMethod = enumeratorType.Methods.FirstOrDefault(m => m.Name == "MoveNext");
			ILBlock ilMethod = CreateILAst(moveNextMethod);
			
			if (ilMethod.Body.Count == 0)
				throw new YieldAnalysisFailedException();
			ILExpression lastReturnArg;
			if (!ilMethod.Body.Last().Match(ILCode.Ret, out lastReturnArg))
				throw new YieldAnalysisFailedException();
			
			// There are two possibilities:
			if (lastReturnArg.Code == ILCode.Ldloc) {
				// a) the compiler uses a variable for returns (in debug builds, or when there are try-finally blocks)
				returnVariable = (ILVariable)lastReturnArg.Operand;
				returnLabel = ilMethod.Body.ElementAtOrDefault(ilMethod.Body.Count - 2) as ILLabel;
				if (returnLabel == null)
					throw new YieldAnalysisFailedException();
			} else {
				// b) the compiler directly returns constants
				returnVariable = null;
				returnLabel = null;
				// In this case, the last return must return false.
				if (lastReturnArg.Code != ILCode.Ldc_I4 || (int)lastReturnArg.Operand != 0)
					throw new YieldAnalysisFailedException();
			}
			
			ILTryCatchBlock tryFaultBlock = ilMethod.Body[0] as ILTryCatchBlock;
			List<ILNode> body;
			int bodyLength;
			if (tryFaultBlock != null) {
				// there are try-finally blocks
				if (returnVariable == null) // in this case, we must use a return variable
					throw new YieldAnalysisFailedException();
				// must be a try-fault block:
				if (tryFaultBlock.CatchBlocks.Count != 0 || tryFaultBlock.FinallyBlock != null || tryFaultBlock.FaultBlock == null)
					throw new YieldAnalysisFailedException();
				
				ILBlock faultBlock = tryFaultBlock.FaultBlock;
				// Ensure the fault block contains the call to Dispose().
				if (faultBlock.Body.Count != 2)
					throw new YieldAnalysisFailedException();
				MethodReference disposeMethodRef;
				ILExpression disposeArg;
				if (!faultBlock.Body[0].Match(ILCode.Call, out disposeMethodRef, out disposeArg))
					throw new YieldAnalysisFailedException();
				if (GetMethodDefinition(disposeMethodRef) != disposeMethod || !LoadFromArgument.This.Match(disposeArg))
					throw new YieldAnalysisFailedException();
				if (!faultBlock.Body[1].Match(ILCode.Endfinally))
					throw new YieldAnalysisFailedException();
				
				body = tryFaultBlock.TryBlock.Body;
				bodyLength = body.Count;
			} else {
				// no try-finally blocks
				body = ilMethod.Body;
				if (returnVariable == null)
					bodyLength = body.Count - 1; // all except for the return statement
				else
					bodyLength = body.Count - 2; // all except for the return label and statement
			}
			
			// Now verify that the last instruction in the body is 'ret(false)'
			if (returnVariable != null) {
				// If we don't have a return variable, we already verified that above.
				// If we do have one, check for 'stloc(returnVariable, ldc.i4(0))'
				
				// Maybe might be a jump to the return label after the stloc:
				ILExpression leave = body.ElementAtOrDefault(bodyLength - 1) as ILExpression;
				if (leave != null && (leave.Code == ILCode.Br || leave.Code == ILCode.Leave) && leave.Operand == returnLabel)
					bodyLength--;
				ILExpression store0 = body.ElementAtOrDefault(bodyLength - 1) as ILExpression;
				if (store0 == null || store0.Code != ILCode.Stloc || store0.Operand != returnVariable)
					throw new YieldAnalysisFailedException();
				if (store0.Arguments[0].Code != ILCode.Ldc_I4 || (int)store0.Arguments[0].Operand != 0)
					throw new YieldAnalysisFailedException();
				
				bodyLength--; // don't conside the stloc instruction to be part of the body
			}
			// verify that the last element in the body is a label pointing to the 'ret(false)'
			returnFalseLabel = body.ElementAtOrDefault(bodyLength - 1) as ILLabel;
			if (returnFalseLabel == null)
				throw new YieldAnalysisFailedException();
			
			InitStateRanges(body[0]);
			int pos = AssignStateRanges(body, bodyLength, forDispose: false);
			if (pos > 0 && body[pos - 1] is ILLabel) {
				pos--;
			} else {
				// ensure that the first element at body[pos] is a label:
				ILLabel newLabel = new ILLabel();
				newLabel.Name = "YieldReturnEntryPoint";
				ranges[newLabel] = ranges[body[pos]]; // give the label the range of the instruction at body[pos]
				
				body.Insert(pos, newLabel);
				bodyLength++;
			}
			
			List<KeyValuePair<ILLabel, StateRange>> labels = new List<KeyValuePair<ILLabel, StateRange>>();
			for (int i = pos; i < bodyLength; i++) {
				ILLabel label = body[i] as ILLabel;
				if (label != null) {
					labels.Add(new KeyValuePair<ILLabel, StateRange>(label, ranges[label]));
				}
			}
			
			ConvertBody(body, pos, bodyLength, labels);
		}
		bool MatchFixedInitializer(List<ILNode> body, int i, out ILVariable pinnedVar, out ILExpression initValue, out int nextPos)
		{
			if (body[i].Match(ILCode.Stloc, out pinnedVar, out initValue) && pinnedVar.IsPinned && !IsNullOrZero(initValue)) {
				initValue = (ILExpression)body[i];
				nextPos = i + 1;
				HandleStringFixing(pinnedVar, body, ref nextPos, ref initValue);
				return true;
			}
			ILCondition ifStmt = body[i] as ILCondition;
			ILExpression arrayLoadingExpr;
			if (ifStmt != null && MatchFixedArrayInitializerCondition(ifStmt.Condition, out arrayLoadingExpr)) {
				ILVariable arrayVariable = (ILVariable)arrayLoadingExpr.Operand;
				ILExpression trueValue;
				if (ifStmt.TrueBlock != null && ifStmt.TrueBlock.Body.Count == 1
				    && ifStmt.TrueBlock.Body[0].Match(ILCode.Stloc, out pinnedVar, out trueValue)
				    && pinnedVar.IsPinned && IsNullOrZero(trueValue))
				{
					if (ifStmt.FalseBlock != null && ifStmt.FalseBlock.Body.Count == 1 && ifStmt.FalseBlock.Body[0] is ILFixedStatement) {
						ILFixedStatement fixedStmt = (ILFixedStatement)ifStmt.FalseBlock.Body[0];
						ILVariable stlocVar;
						ILExpression falseValue;
						if (fixedStmt.Initializers.Count == 1 && fixedStmt.BodyBlock.Body.Count == 0
						    && fixedStmt.Initializers[0].Match(ILCode.Stloc, out stlocVar, out falseValue) && stlocVar == pinnedVar)
						{
							ILVariable loadedVariable;
							if (falseValue.Code == ILCode.Ldelema
							    && falseValue.Arguments[0].Match(ILCode.Ldloc, out loadedVariable) && loadedVariable == arrayVariable
							    && IsNullOrZero(falseValue.Arguments[1]))
							{
								// OK, we detected the pattern for fixing an array.
								// Now check whether the loading expression was a store ot a temp. var
								// that can be eliminated.
								if (arrayLoadingExpr.Code == ILCode.Stloc) {
									ILInlining inlining = new ILInlining(method);
									if (inlining.numLdloc.GetOrDefault(arrayVariable) == 2 &&
									    inlining.numStloc.GetOrDefault(arrayVariable) == 1 && inlining.numLdloca.GetOrDefault(arrayVariable) == 0)
									{
										arrayLoadingExpr = arrayLoadingExpr.Arguments[0];
									}
								}
								initValue = new ILExpression(ILCode.Stloc, pinnedVar, arrayLoadingExpr);
								nextPos = i + 1;
								return true;
							}
						}
					}
				}
			}
			initValue = null;
			nextPos = -1;
			return false;
		}
Ejemplo n.º 30
0
		/// <summary>
		/// Inlines 'expr' into 'next', if possible.
		/// </summary>
		bool InlineIfPossible(ILVariable v, ILExpression inlinedExpression, ILNode next, bool aggressive)
		{
			// ensure the variable is accessed only a single time
			if (numStloc.GetOrDefault(v) != 1)
				return false;
			int ldloc = numLdloc.GetOrDefault(v);
			if (ldloc > 1 || ldloc + numLdloca.GetOrDefault(v) != 1)
				return false;
			
			if (next is ILCondition)
				next = ((ILCondition)next).Condition;
			else if (next is ILWhileLoop)
				next = ((ILWhileLoop)next).Condition;
			
			ILExpression parent;
			int pos;
			if (FindLoadInNext(next as ILExpression, v, inlinedExpression, out parent, out pos) == true) {
				if (ldloc == 0) {
					if (!IsGeneratedValueTypeTemporary((ILExpression)next, parent, pos, v, inlinedExpression))
						return false;
				} else {
					if (!aggressive && !v.GeneratedByDecompiler && !NonAggressiveInlineInto((ILExpression)next, parent, inlinedExpression))
						return false;
				}

				// Assign the ranges of the ldloc instruction:
				if (context.CalculateILRanges)
					parent.Arguments[pos].AddSelfAndChildrenRecursiveILRanges(inlinedExpression.ILRanges);
				
				if (ldloc == 0) {
					// it was an ldloca instruction, so we need to use the pseudo-opcode 'addressof' so that the types
					// comes out correctly
					parent.Arguments[pos] = new ILExpression(ILCode.AddressOf, null, inlinedExpression);
				} else {
					parent.Arguments[pos] = inlinedExpression;
				}
				return true;
			}
			return false;
		}
Ejemplo n.º 31
0
        bool HandleJaggedArrayInitializer(Block block, int pos, ILVariable store, int length, out ILVariable finalStore, out ILInstruction[] values, out int instructionsToRemove)
        {
            instructionsToRemove = 0;
            finalStore           = null;
            values = new ILInstruction[length];
            ILInstruction initializer;

            for (int i = 0; i < length; i++)
            {
                ILVariable    temp;
                ILInstruction storeLoad;
                // 1. Instruction: (optional) temporary copy of store
                bool hasTemporaryCopy = block.Instructions[pos].MatchStLoc(out temp, out storeLoad) && storeLoad.MatchLdLoc(store);
                if (hasTemporaryCopy)
                {
                    if (!MatchJaggedArrayStore(block, pos + 1, temp, i, out initializer))
                    {
                        return(false);
                    }
                }
                else
                {
                    if (!MatchJaggedArrayStore(block, pos, store, i, out initializer))
                    {
                        return(false);
                    }
                }
                values[i] = initializer;
                int inc = hasTemporaryCopy ? 3 : 2;
                pos += inc;
                instructionsToRemove += inc;
            }
            ILInstruction array;

            // In case there is an extra copy of the store variable
            // Remove it and use its value instead.
            if (block.Instructions[pos].MatchStLoc(out finalStore, out array))
            {
                instructionsToRemove++;
                return(array.MatchLdLoc(store));
            }
            finalStore = store;
            return(true);
        }
Ejemplo n.º 32
0
        Expression Convert(Expression expr)
        {
            InvocationExpression invocation = expr as InvocationExpression;

            if (invocation != null)
            {
                MethodReference mr = invocation.Annotation <MethodReference>();
                if (mr != null && mr.DeclaringType.FullName == "System.Linq.Expressions.Expression")
                {
                    switch (mr.Name)
                    {
                    case "Add":
                        return(ConvertBinaryOperator(invocation, BinaryOperatorType.Add, false));

                    case "AddChecked":
                        return(ConvertBinaryOperator(invocation, BinaryOperatorType.Add, true));

                    case "AddAssign":
                        return(ConvertAssignmentOperator(invocation, AssignmentOperatorType.Add, false));

                    case "AddAssignChecked":
                        return(ConvertAssignmentOperator(invocation, AssignmentOperatorType.Add, true));

                    case "And":
                        return(ConvertBinaryOperator(invocation, BinaryOperatorType.BitwiseAnd));

                    case "AndAlso":
                        return(ConvertBinaryOperator(invocation, BinaryOperatorType.ConditionalAnd));

                    case "AndAssign":
                        return(ConvertAssignmentOperator(invocation, AssignmentOperatorType.BitwiseAnd));

                    case "ArrayAccess":
                    case "ArrayIndex":
                        return(ConvertArrayIndex(invocation));

                    case "ArrayLength":
                        return(ConvertArrayLength(invocation));

                    case "Assign":
                        return(ConvertAssignmentOperator(invocation, AssignmentOperatorType.Assign));

                    case "Call":
                        return(ConvertCall(invocation));

                    case "Coalesce":
                        return(ConvertBinaryOperator(invocation, BinaryOperatorType.NullCoalescing));

                    case "Condition":
                        return(ConvertCondition(invocation));

                    case "Constant":
                        if (invocation.Arguments.Count >= 1)
                        {
                            return(invocation.Arguments.First().Clone());
                        }
                        else
                        {
                            return(NotSupported(expr));
                        }

                    case "Convert":
                        return(ConvertCast(invocation, false));

                    case "ConvertChecked":
                        return(ConvertCast(invocation, true));

                    case "Divide":
                        return(ConvertBinaryOperator(invocation, BinaryOperatorType.Divide));

                    case "DivideAssign":
                        return(ConvertAssignmentOperator(invocation, AssignmentOperatorType.Divide));

                    case "Equal":
                        return(ConvertBinaryOperator(invocation, BinaryOperatorType.Equality));

                    case "ExclusiveOr":
                        return(ConvertBinaryOperator(invocation, BinaryOperatorType.ExclusiveOr));

                    case "ExclusiveOrAssign":
                        return(ConvertAssignmentOperator(invocation, AssignmentOperatorType.ExclusiveOr));

                    case "Field":
                        return(ConvertField(invocation));

                    case "GreaterThan":
                        return(ConvertBinaryOperator(invocation, BinaryOperatorType.GreaterThan));

                    case "GreaterThanOrEqual":
                        return(ConvertBinaryOperator(invocation, BinaryOperatorType.GreaterThanOrEqual));

                    case "Invoke":
                        return(ConvertInvoke(invocation));

                    case "Lambda":
                        return(ConvertLambda(invocation));

                    case "LeftShift":
                        return(ConvertBinaryOperator(invocation, BinaryOperatorType.ShiftLeft));

                    case "LeftShiftAssign":
                        return(ConvertAssignmentOperator(invocation, AssignmentOperatorType.ShiftLeft));

                    case "LessThan":
                        return(ConvertBinaryOperator(invocation, BinaryOperatorType.LessThan));

                    case "LessThanOrEqual":
                        return(ConvertBinaryOperator(invocation, BinaryOperatorType.LessThanOrEqual));

                    case "ListInit":
                        return(ConvertListInit(invocation));

                    case "MemberInit":
                        return(ConvertMemberInit(invocation));

                    case "Modulo":
                        return(ConvertBinaryOperator(invocation, BinaryOperatorType.Modulus));

                    case "ModuloAssign":
                        return(ConvertAssignmentOperator(invocation, AssignmentOperatorType.Modulus));

                    case "Multiply":
                        return(ConvertBinaryOperator(invocation, BinaryOperatorType.Multiply, false));

                    case "MultiplyChecked":
                        return(ConvertBinaryOperator(invocation, BinaryOperatorType.Multiply, true));

                    case "MultiplyAssign":
                        return(ConvertAssignmentOperator(invocation, AssignmentOperatorType.Multiply, false));

                    case "MultiplyAssignChecked":
                        return(ConvertAssignmentOperator(invocation, AssignmentOperatorType.Multiply, true));

                    case "Negate":
                        return(ConvertUnaryOperator(invocation, UnaryOperatorType.Minus, false));

                    case "NegateChecked":
                        return(ConvertUnaryOperator(invocation, UnaryOperatorType.Minus, true));

                    case "New":
                        return(ConvertNewObject(invocation));

                    case "NewArrayBounds":
                        return(ConvertNewArrayBounds(invocation));

                    case "NewArrayInit":
                        return(ConvertNewArrayInit(invocation));

                    case "Not":
                        return(ConvertUnaryOperator(invocation, UnaryOperatorType.Not));

                    case "NotEqual":
                        return(ConvertBinaryOperator(invocation, BinaryOperatorType.InEquality));

                    case "OnesComplement":
                        return(ConvertUnaryOperator(invocation, UnaryOperatorType.BitNot));

                    case "Or":
                        return(ConvertBinaryOperator(invocation, BinaryOperatorType.BitwiseOr));

                    case "OrAssign":
                        return(ConvertAssignmentOperator(invocation, AssignmentOperatorType.BitwiseOr));

                    case "OrElse":
                        return(ConvertBinaryOperator(invocation, BinaryOperatorType.ConditionalOr));

                    case "Property":
                        return(ConvertProperty(invocation));

                    case "Quote":
                        if (invocation.Arguments.Count == 1)
                        {
                            return(Convert(invocation.Arguments.Single()));
                        }
                        else
                        {
                            return(NotSupported(invocation));
                        }

                    case "RightShift":
                        return(ConvertBinaryOperator(invocation, BinaryOperatorType.ShiftRight));

                    case "RightShiftAssign":
                        return(ConvertAssignmentOperator(invocation, AssignmentOperatorType.ShiftRight));

                    case "Subtract":
                        return(ConvertBinaryOperator(invocation, BinaryOperatorType.Subtract, false));

                    case "SubtractChecked":
                        return(ConvertBinaryOperator(invocation, BinaryOperatorType.Subtract, true));

                    case "SubtractAssign":
                        return(ConvertAssignmentOperator(invocation, AssignmentOperatorType.Subtract, false));

                    case "SubtractAssignChecked":
                        return(ConvertAssignmentOperator(invocation, AssignmentOperatorType.Subtract, true));

                    case "TypeAs":
                        return(ConvertTypeAs(invocation));

                    case "TypeIs":
                        return(ConvertTypeIs(invocation));
                    }
                }
            }
            IdentifierExpression ident = expr as IdentifierExpression;

            if (ident != null)
            {
                ILVariable v = ident.Annotation <ILVariable>();
                if (v != null)
                {
                    foreach (LambdaExpression lambda in activeLambdas)
                    {
                        foreach (ParameterDeclaration p in lambda.Parameters)
                        {
                            if (p.Annotation <ILVariable>() == v)
                            {
                                return(new IdentifierExpression(p.Name).WithAnnotation(v));
                            }
                        }
                    }
                }
            }
            return(NotSupported(expr));
        }
Ejemplo n.º 33
0
		int AssignStateRanges(List<ILNode> body, int bodyLength, bool forDispose)
		{
			if (bodyLength == 0)
				return 0;
			for (int i = 0; i < bodyLength; i++) {
				StateRange nodeRange = ranges[body[i]];
				nodeRange.Simplify();
				
				ILLabel label = body[i] as ILLabel;
				if (label != null) {
					ranges[body[i + 1]].UnionWith(nodeRange);
					continue;
				}
				
				ILTryCatchBlock tryFinally = body[i] as ILTryCatchBlock;
				if (tryFinally != null) {
					if (!forDispose || tryFinally.CatchBlocks.Count != 0 || tryFinally.FaultBlock != null || tryFinally.FinallyBlock == null)
						throw new YieldAnalysisFailedException();
					ranges[tryFinally.TryBlock].UnionWith(nodeRange);
					AssignStateRanges(tryFinally.TryBlock.Body, tryFinally.TryBlock.Body.Count, forDispose);
					continue;
				}
				
				ILExpression expr = body[i] as ILExpression;
				if (expr == null)
					throw new YieldAnalysisFailedException();
				switch (expr.Code) {
					case ILCode.Switch:
						{
							SymbolicValue val = Eval(expr.Arguments[0]);
							if (val.Type != SymbolicValueType.State)
								throw new YieldAnalysisFailedException();
							ILLabel[] targetLabels = (ILLabel[])expr.Operand;
							for (int j = 0; j < targetLabels.Length; j++) {
								int state = j - val.Constant;
								ranges[targetLabels[j]].UnionWith(nodeRange, state, state);
							}
							StateRange nextRange = ranges[body[i + 1]];
							nextRange.UnionWith(nodeRange, int.MinValue, -1 - val.Constant);
							nextRange.UnionWith(nodeRange, targetLabels.Length - val.Constant, int.MaxValue);
							break;
						}
					case ILCode.Br:
					case ILCode.Leave:
						ranges[(ILLabel)expr.Operand].UnionWith(nodeRange);
						break;
					case ILCode.Brtrue:
						{
							SymbolicValue val = Eval(expr.Arguments[0]);
							if (val.Type == SymbolicValueType.StateEquals) {
								ranges[(ILLabel)expr.Operand].UnionWith(nodeRange, val.Constant, val.Constant);
								StateRange nextRange = ranges[body[i + 1]];
								nextRange.UnionWith(nodeRange, int.MinValue, val.Constant - 1);
								nextRange.UnionWith(nodeRange, val.Constant + 1, int.MaxValue);
							} else if (val.Type == SymbolicValueType.StateInEquals) {
								ranges[body[i + 1]].UnionWith(nodeRange, val.Constant, val.Constant);
								StateRange targetRange = ranges[(ILLabel)expr.Operand];
								targetRange.UnionWith(nodeRange, int.MinValue, val.Constant - 1);
								targetRange.UnionWith(nodeRange, val.Constant + 1, int.MaxValue);
							} else {
								throw new YieldAnalysisFailedException();
							}
							break;
						}
					case ILCode.Nop:
						ranges[body[i + 1]].UnionWith(nodeRange);
						break;
					case ILCode.Ret:
						break;
					case ILCode.Stloc:
						{
							SymbolicValue val = Eval(expr.Arguments[0]);
							if (val.Type == SymbolicValueType.State && val.Constant == 0 && rangeAnalysisStateVariable == null)
								rangeAnalysisStateVariable = (ILVariable)expr.Operand;
							else
								throw new YieldAnalysisFailedException();
							goto case ILCode.Nop;
						}
					case ILCode.Call:
						// in some cases (e.g. foreach over array) the C# compiler produces a finally method outside of try-finally blocks
						if (forDispose) {
							MethodDefinition mdef = GetMethodDefinition(expr.Operand as MethodReference);
							if (mdef == null || finallyMethodToStateInterval.ContainsKey(mdef))
								throw new YieldAnalysisFailedException();
							finallyMethodToStateInterval.Add(mdef, nodeRange.ToEnclosingInterval());
						} else {
							throw new YieldAnalysisFailedException();
						}
						break;
					default:
						if (forDispose)
							throw new YieldAnalysisFailedException();
						else
							return i;
				}
			}
			return bodyLength;
		}
Ejemplo n.º 34
0
 internal static FindResult CanIntroduceNamedArgument(CallInstruction call, ILInstruction child, ILVariable v, ILInstruction expressionBeingMoved)
 {
     Debug.Assert(child.Parent == call);
     if (call.IsInstanceCall && child.ChildIndex == 0)
     {
         return(FindResult.Stop);                // cannot use named arg to move expressionBeingMoved before this pointer
     }
     if (call.Method.IsOperator || call.Method.IsAccessor)
     {
         return(FindResult.Stop);                // cannot use named arg for operators or accessors
     }
     if (call.Method is VarArgInstanceMethod)
     {
         return(FindResult.Stop);                // CallBuilder doesn't support named args when using varargs
     }
     if (call.Method.IsConstructor)
     {
         IType type = call.Method.DeclaringType;
         if (type.Kind == TypeKind.Delegate || type.IsAnonymousType())
         {
             return(FindResult.Stop);
         }
     }
     if (call.Method.Parameters.Any(p => string.IsNullOrEmpty(p.Name)))
     {
         return(FindResult.Stop);                // cannot use named arguments
     }
     for (int i = child.ChildIndex; i < call.Arguments.Count; i++)
     {
         var r = ILInlining.FindLoadInNext(call.Arguments[i], v, expressionBeingMoved, InliningOptions.None);
         if (r.Type == FindResultType.Found)
         {
             return(FindResult.NamedArgument(r.LoadInst, call.Arguments[i]));
         }
     }
     return(FindResult.Stop);
 }
Ejemplo n.º 35
0
		void AnalyzeMoveNext()
		{
			MethodDefinition moveNextMethod = enumeratorType.Methods.FirstOrDefault(m => m.Name == "MoveNext");
			ILBlock ilMethod = CreateILAst(moveNextMethod);
			
			if (ilMethod.Body.Count == 0)
				throw new SymbolicAnalysisFailedException();
			ILExpression lastReturnArg;
			if (!ilMethod.Body.Last().Match(ILCode.Ret, out lastReturnArg))
				throw new SymbolicAnalysisFailedException();
			
			// There are two possibilities:
			if (lastReturnArg.Code == ILCode.Ldloc) {
				// a) the compiler uses a variable for returns (in debug builds, or when there are try-finally blocks)
				returnVariable = (ILVariable)lastReturnArg.Operand;
				returnLabel = ilMethod.Body.ElementAtOrDefault(ilMethod.Body.Count - 2) as ILLabel;
				if (returnLabel == null)
					throw new SymbolicAnalysisFailedException();
			} else {
				// b) the compiler directly returns constants
				returnVariable = null;
				returnLabel = null;
				// In this case, the last return must return false.
				if (lastReturnArg.Code != ILCode.Ldc_I4 || (int)lastReturnArg.Operand != 0)
					throw new SymbolicAnalysisFailedException();
			}
			
			ILTryCatchBlock tryFaultBlock = ilMethod.Body[0] as ILTryCatchBlock;
			List<ILNode> body;
			int bodyLength;
			if (tryFaultBlock != null) {
				// there are try-finally blocks
				if (returnVariable == null) // in this case, we must use a return variable
					throw new SymbolicAnalysisFailedException();
				// must be a try-fault block:
				if (tryFaultBlock.CatchBlocks.Count != 0 || tryFaultBlock.FinallyBlock != null || tryFaultBlock.FaultBlock == null)
					throw new SymbolicAnalysisFailedException();
				
				ILBlock faultBlock = tryFaultBlock.FaultBlock;
				// Ensure the fault block contains the call to Dispose().
				if (faultBlock.Body.Count != 2)
					throw new SymbolicAnalysisFailedException();
				MethodReference disposeMethodRef;
				ILExpression disposeArg;
				if (!faultBlock.Body[0].Match(ILCode.Call, out disposeMethodRef, out disposeArg))
					throw new SymbolicAnalysisFailedException();
				if (GetMethodDefinition(disposeMethodRef) != disposeMethod || !disposeArg.MatchThis())
					throw new SymbolicAnalysisFailedException();
				if (!faultBlock.Body[1].Match(ILCode.Endfinally))
					throw new SymbolicAnalysisFailedException();
				
				body = tryFaultBlock.TryBlock.Body;
				bodyLength = body.Count;
			} else {
				// no try-finally blocks
				body = ilMethod.Body;
				if (returnVariable == null)
					bodyLength = body.Count - 1; // all except for the return statement
				else
					bodyLength = body.Count - 2; // all except for the return label and statement
			}
			
			// Now verify that the last instruction in the body is 'ret(false)'
			if (returnVariable != null) {
				// If we don't have a return variable, we already verified that above.
				// If we do have one, check for 'stloc(returnVariable, ldc.i4(0))'
				
				// Maybe might be a jump to the return label after the stloc:
				ILExpression leave = body.ElementAtOrDefault(bodyLength - 1) as ILExpression;
				if (leave != null && (leave.Code == ILCode.Br || leave.Code == ILCode.Leave) && leave.Operand == returnLabel)
					bodyLength--;
				ILExpression store0 = body.ElementAtOrDefault(bodyLength - 1) as ILExpression;
				if (store0 == null || store0.Code != ILCode.Stloc || store0.Operand != returnVariable)
					throw new SymbolicAnalysisFailedException();
				if (store0.Arguments[0].Code != ILCode.Ldc_I4 || (int)store0.Arguments[0].Operand != 0)
					throw new SymbolicAnalysisFailedException();
				
				bodyLength--; // don't conside the stloc instruction to be part of the body
			}
			// The last element in the body usually is a label pointing to the 'ret(false)'
			returnFalseLabel = body.ElementAtOrDefault(bodyLength - 1) as ILLabel;
			// Note: in Roslyn-compiled code, returnFalseLabel may be null.
			
			var rangeAnalysis = new StateRangeAnalysis(body[0], StateRangeAnalysisMode.IteratorMoveNext, stateField);
			int pos = rangeAnalysis.AssignStateRanges(body, bodyLength);
			rangeAnalysis.EnsureLabelAtPos(body, ref pos, ref bodyLength);
			
			var labels = rangeAnalysis.CreateLabelRangeMapping(body, pos, bodyLength);
			ConvertBody(body, pos, bodyLength, labels);
		}
Ejemplo n.º 36
0
        string GenerateNameForVariable(ILVariable variable)
        {
            string proposedName = null;

            if (variable.Type.IsKnownType(KnownTypeCode.Int32))
            {
                // test whether the variable might be a loop counter
                if (loopCounters.Contains(variable))
                {
                    // For loop variables, use i,j,k,l,m,n
                    for (char c = 'i'; c <= maxLoopVariableName; c++)
                    {
                        if (!reservedVariableNames.ContainsKey(c.ToString()))
                        {
                            proposedName = c.ToString();
                            break;
                        }
                    }
                }
            }
            // The ComponentResourceManager inside InitializeComponent must be named "resources",
            // otherwise the WinForms designer won't load the Form.
            if (CSharp.CSharpDecompiler.IsWindowsFormsInitializeComponentMethod(context.Function.Method) && variable.Type.FullName == "System.ComponentModel.ComponentResourceManager")
            {
                proposedName = "resources";
            }
            if (string.IsNullOrEmpty(proposedName))
            {
                var proposedNameForAddress = variable.AddressInstructions.OfType <LdLoca>()
                                             .Select(arg => arg.Parent is CallInstruction c ? c.GetParameter(arg.ChildIndex)?.Name : null)
                                             .Where(arg => !string.IsNullOrWhiteSpace(arg))
                                             .Except(currentFieldNames).ToList();
                if (proposedNameForAddress.Count > 0)
                {
                    proposedName = proposedNameForAddress[0];
                }
            }
            if (string.IsNullOrEmpty(proposedName))
            {
                var proposedNameForStores = variable.StoreInstructions.OfType <StLoc>()
                                            .Select(expr => GetNameFromInstruction(expr.Value))
                                            .Except(currentFieldNames).ToList();
                if (proposedNameForStores.Count == 1)
                {
                    proposedName = proposedNameForStores[0];
                }
            }
            if (string.IsNullOrEmpty(proposedName))
            {
                var proposedNameForLoads = variable.LoadInstructions
                                           .Select(arg => GetNameForArgument(arg.Parent, arg.ChildIndex))
                                           .Except(currentFieldNames).ToList();
                if (proposedNameForLoads.Count == 1)
                {
                    proposedName = proposedNameForLoads[0];
                }
            }
            if (string.IsNullOrEmpty(proposedName) && variable.Kind == VariableKind.StackSlot)
            {
                var proposedNameForStoresFromNewObj = variable.StoreInstructions.OfType <StLoc>()
                                                      .Select(expr => GetNameByType(GuessType(variable.Type, expr.Value, context)))
                                                      .Except(currentFieldNames).ToList();
                if (proposedNameForStoresFromNewObj.Count == 1)
                {
                    proposedName = proposedNameForStoresFromNewObj[0];
                }
            }
            if (string.IsNullOrEmpty(proposedName))
            {
                proposedName = GetNameByType(variable.Type);
            }

            // 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);
            }
        }
Ejemplo n.º 37
0
		/// <summary>
		/// Is this a temporary variable generated by the C# compiler for instance method calls on value type values
		/// </summary>
		/// <param name="next">The next top-level expression</param>
		/// <param name="parent">The direct parent of the load within 'next'</param>
		/// <param name="pos">Index of the load within 'parent'</param>
		/// <param name="v">The variable being inlined.</param>
		/// <param name="inlinedExpression">The expression being inlined</param>
		bool IsGeneratedValueTypeTemporary(ILExpression next, ILExpression parent, int pos, ILVariable v, ILExpression inlinedExpression)
		{
			if (pos == 0 && v.Type != null && DnlibExtensions.IsValueType(v.Type)) {
				// Inlining a value type variable is allowed only if the resulting code will maintain the semantics
				// that the method is operating on a copy.
				// Thus, we have to disallow inlining of other locals, fields, array elements, dereferenced pointers
				switch (inlinedExpression.Code) {
					case ILCode.Ldloc:
					case ILCode.Stloc:
					case ILCode.CompoundAssignment:
					case ILCode.Ldelem:
					case ILCode.Ldelem_I:
					case ILCode.Ldelem_I1:
					case ILCode.Ldelem_I2:
					case ILCode.Ldelem_I4:
					case ILCode.Ldelem_I8:
					case ILCode.Ldelem_R4:
					case ILCode.Ldelem_R8:
					case ILCode.Ldelem_Ref:
					case ILCode.Ldelem_U1:
					case ILCode.Ldelem_U2:
					case ILCode.Ldelem_U4:
					case ILCode.Ldobj:
					case ILCode.Ldind_Ref:
						return false;
					case ILCode.Ldfld:
					case ILCode.Stfld:
					case ILCode.Ldsfld:
					case ILCode.Stsfld:
						// allow inlining field access only if it's a readonly field
						FieldDef f = ((IField)inlinedExpression.Operand).Resolve();
						if (!(f != null && f.IsInitOnly))
							return false;
						break;
					case ILCode.Call:
					case ILCode.CallGetter:
						// inlining runs both before and after IntroducePropertyAccessInstructions,
						// so we have to handle both 'call' and 'callgetter'
						IMethod mr = (IMethod)inlinedExpression.Operand;
						// ensure that it's not an multi-dimensional array getter
						TypeSig ts;
						if (mr.DeclaringType is TypeSpec && (ts = ((TypeSpec)mr.DeclaringType).TypeSig.RemovePinnedAndModifiers()) != null && ts.IsSingleOrMultiDimensionalArray)
							return false;
						goto case ILCode.Callvirt;
					case ILCode.Callvirt:
					case ILCode.CallvirtGetter:
						// don't inline foreach loop variables:
						mr = (IMethod)inlinedExpression.Operand;
						if (mr.Name == "get_Current" && mr.MethodSig != null && mr.MethodSig.HasThis)
							return false;
						break;
					case ILCode.Castclass:
					case ILCode.Unbox_Any:
						// These are valid, but might occur as part of a foreach loop variable.
						ILExpression arg = inlinedExpression.Arguments[0];
						if (arg.Code == ILCode.CallGetter || arg.Code == ILCode.CallvirtGetter || arg.Code == ILCode.Call || arg.Code == ILCode.Callvirt) {
							mr = (IMethod)arg.Operand;
							if (mr.Name == "get_Current" && mr.MethodSig != null && mr.MethodSig.HasThis)
								return false; // looks like a foreach loop variable, so don't inline it
						}
						break;
				}
				
				// inline the compiler-generated variable that are used when accessing a member on a value type:
				switch (parent.Code) {
					case ILCode.Call:
					case ILCode.CallGetter:
					case ILCode.CallSetter:
					case ILCode.Callvirt:
					case ILCode.CallvirtGetter:
					case ILCode.CallvirtSetter:
						IMethod mr = parent.Operand as IMethod;
						return mr == null || mr.MethodSig == null ? false : mr.MethodSig.HasThis;
					case ILCode.Stfld:
					case ILCode.Ldfld:
					case ILCode.Ldflda:
					case ILCode.Await:
						return true;
				}
			}
			return false;
		}
Ejemplo n.º 38
0
        static Dictionary <string, int> CollectReservedVariableNames(ILFunction function, ILVariable existingVariable)
        {
            var reservedVariableNames = new Dictionary <string, int>();
            var rootFunction          = function.Ancestors.OfType <ILFunction>().Single(f => f.Parent == null);

            foreach (var f in rootFunction.Descendants.OfType <ILFunction>())
            {
                foreach (var p in rootFunction.Parameters)
                {
                    AddExistingName(reservedVariableNames, p.Name);
                }
                foreach (var v in f.Variables.Where(v => v.Kind != VariableKind.Parameter))
                {
                    if (v != existingVariable)
                    {
                        AddExistingName(reservedVariableNames, v.Name);
                    }
                }
            }
            foreach (var f in rootFunction.Method.DeclaringTypeDefinition.GetFields().Select(f => f.Name))
            {
                AddExistingName(reservedVariableNames, f);
            }
            return(reservedVariableNames);
        }
Ejemplo n.º 39
0
		/// <summary>
		/// Finds the position to inline to.
		/// </summary>
		/// <returns>true = found; false = cannot continue search; null = not found</returns>
		bool? FindLoadInNext(ILExpression expr, ILVariable v, ILExpression expressionBeingMoved, out ILExpression parent, out int pos)
		{
			parent = null;
			pos = 0;
			if (expr == null)
				return false;
			for (int i = 0; i < expr.Arguments.Count; i++) {
				// Stop when seeing an opcode that does not guarantee that its operands will be evaluated.
				// Inlining in that case might result in the inlined expresion not being evaluted.
				if (i == 1 && (expr.Code == ILCode.LogicAnd || expr.Code == ILCode.LogicOr || expr.Code == ILCode.TernaryOp || expr.Code == ILCode.NullCoalescing))
					return false;
				
				ILExpression arg = expr.Arguments[i];
				
				if ((arg.Code == ILCode.Ldloc || arg.Code == ILCode.Ldloca) && arg.Operand == v) {
					parent = expr;
					pos = i;
					return true;
				}
				bool? r = FindLoadInNext(arg, v, expressionBeingMoved, out parent, out pos);
				if (r != null)
					return r;
			}
			if (IsSafeForInlineOver(expr, expressionBeingMoved))
				return null; // continue searching
			else
				return false; // abort, inlining not possible
		}
Ejemplo n.º 40
0
        internal static string GenerateForeachVariableName(ILFunction function, ILInstruction valueContext, ILVariable existingVariable = null)
        {
            if (function == null)
            {
                throw new ArgumentNullException(nameof(function));
            }
            if (existingVariable != null && !existingVariable.HasGeneratedName)
            {
                return(existingVariable.Name);
            }
            var reservedVariableNames = CollectReservedVariableNames(function, existingVariable);

            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];

            if (count > 1)
            {
                return(proposedName + count.ToString());
            }
            else
            {
                return(proposedName);
            }
        }
Ejemplo n.º 41
0
		bool CanPerformCopyPropagation(ILExpression expr, ILVariable copyVariable)
		{
			switch (expr.Code) {
				case ILCode.Ldloca:
				case ILCode.Ldelema:
				case ILCode.Ldflda:
				case ILCode.Ldsflda:
					// All address-loading instructions always return the same value for a given operand/argument combination,
					// so they can be safely copied.
					return true;
				case ILCode.Ldloc:
					ILVariable v = (ILVariable)expr.Operand;
					if (v.IsParameter) {
						// Parameters can be copied only if they aren't assigned to (directly or indirectly via ldarga)
						return numLdloca.GetOrDefault(v) == 0 && numStloc.GetOrDefault(v) == 0;
					} else {
						// Variables are be copied only if both they and the target copy variable are generated,
						// and if the variable has only a single assignment
						return v.GeneratedByDecompiler && copyVariable.GeneratedByDecompiler && numLdloca.GetOrDefault(v) == 0 && numStloc.GetOrDefault(v) == 1;
					}
				default:
					return false;
			}
		}
Ejemplo n.º 42
0
        internal static string GenerateVariableName(ILFunction function, IType type, ILInstruction valueContext = null, ILVariable existingVariable = null)
        {
            if (function == null)
            {
                throw new ArgumentNullException(nameof(function));
            }
            var reservedVariableNames = CollectReservedVariableNames(function, existingVariable);

            string baseName = valueContext != null?GetNameFromInstruction(valueContext) ?? GetNameByType(type) : 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);
            }
        }
Ejemplo n.º 43
0
        protected JSExpression Translate_Ldloc(ILExpression node, ILVariable variable)
        {
            JSExpression result;
            JSVariable renamed;

            if (RenamedVariables.TryGetValue(variable, out renamed))
                result = new JSIndirectVariable(Variables, renamed.Identifier, ThisMethodReference);
            else
                result = new JSIndirectVariable(Variables, variable.Name, ThisMethodReference);

            var expectedType = node.ExpectedType ?? node.InferredType ?? variable.Type;
            if (!TypesAreAssignable(expectedType, variable.Type))
                result = Translate_Conv(result, expectedType);

            return result;
        }
Ejemplo n.º 44
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)))
            {
                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);
            }
        }
Ejemplo n.º 45
0
        protected JSExpression Translate_Stloc(ILExpression node, ILVariable variable)
        {
            if (node.Arguments[0].Code == ILCode.GetCallSite)
                DynamicCallSites.SetAlias(variable, (FieldReference)node.Arguments[0].Operand);

            // GetCallSite and CreateCallSite produce null expressions, so we want to ignore assignments containing them
            var value = TranslateNode(node.Arguments[0]);
            if ((value.IsNull) && !(value is JSUntranslatableExpression) && !(value is JSIgnoredMemberReference))
                return new JSNullExpression();

            var expectedType = node.ExpectedType ?? node.InferredType ?? variable.Type;
            if (!TypesAreAssignable(expectedType, value.GetExpectedType(TypeSystem)))
                value = Translate_Conv(value, expectedType);

            JSVariable jsv;

            if (RenamedVariables.TryGetValue(variable, out jsv))
                jsv = new JSIndirectVariable(Variables, jsv.Identifier, ThisMethodReference);
            else
                jsv = new JSIndirectVariable(Variables, variable.Name, ThisMethodReference);

            if (jsv.IsReference) {
                JSExpression materializedValue;
                if (!JSReferenceExpression.TryMaterialize(JSIL, value, out materializedValue))
                    Console.Error.WriteLine(String.Format("Cannot store a non-reference into variable {0}: {1}", jsv, value));
                else
                    value = materializedValue;
            }

            return new JSBinaryOperatorExpression(
                JSOperator.Assignment, jsv,
                value,
                value.GetExpectedType(TypeSystem)
            );
        }
Ejemplo n.º 46
0
 public void Propagate(ILVariable variable)
 {
     Debug.Assert(declaredVariable == null || (variable == null && declaredVariable.StateMachineField == null));
     this.declaredVariable = variable;
     this.CanPropagate     = variable != null;
 }
		/// <summary>
		/// Parses an object initializer.
		/// </summary>
		/// <param name="body">ILAst block</param>
		/// <param name="pos">
		/// Input: position of the instruction assigning to 'v'.
		/// Output: first position after the object initializer
		/// </param>
		/// <param name="v">The variable that holds the object being initialized</param>
		/// <param name="newObjExpr">The newobj instruction</param>
		/// <returns>InitObject instruction</returns>
		ILExpression ParseObjectInitializer(List<ILNode> body, ref int pos, ILVariable v, ILExpression newObjExpr, bool isCollection)
		{
			Debug.Assert(((ILExpression)body[pos]).Code == ILCode.Stloc);
			// Take care not to modify any existing ILExpressions in here.
			// We just construct new ones around the old ones, any modifications must wait until the whole
			// object/collection initializer was analyzed.
			ILExpression objectInitializer = new ILExpression(isCollection ? ILCode.InitCollection : ILCode.InitObject, null, newObjExpr);
			List<ILExpression> initializerStack = new List<ILExpression>();
			initializerStack.Add(objectInitializer);
			while (++pos < body.Count) {
				ILExpression nextExpr = body[pos] as ILExpression;
				if (IsSetterInObjectInitializer(nextExpr)) {
					if (!AdjustInitializerStack(initializerStack, nextExpr.Arguments[0], v, false)) {
						CleanupInitializerStackAfterFailedAdjustment(initializerStack);
						break;
					}
					initializerStack[initializerStack.Count - 1].Arguments.Add(nextExpr);
				} else if (IsAddMethodCall(nextExpr)) {
					if (!AdjustInitializerStack(initializerStack, nextExpr.Arguments[0], v, true)) {
						CleanupInitializerStackAfterFailedAdjustment(initializerStack);
						break;
					}
					initializerStack[initializerStack.Count - 1].Arguments.Add(nextExpr);
				} else {
					// can't match any more initializers: end of object initializer
					break;
				}
			}
			return objectInitializer;
		}
        void DeclareVariableInBlock(DefiniteAssignmentAnalysis daa, BlockStatement block, AstType type, string variableName, ILVariable v, bool allowPassIntoLoops)
        {
            // declarationPoint: The point where the variable would be declared, if we decide to declare it in this block
            Statement declarationPoint = null;
            // Check whether we can move down the variable into the sub-blocks
            bool canMoveVariableIntoSubBlocks = FindDeclarationPoint(daa, variableName, allowPassIntoLoops, block, out declarationPoint);

            if (declarationPoint == null)
            {
                // The variable isn't used at all
                return;
            }
            if (canMoveVariableIntoSubBlocks)
            {
                // Declare the variable within the sub-blocks
                foreach (Statement stmt in block.Statements)
                {
                    ForStatement forStmt = stmt as ForStatement;
                    if (forStmt != null && forStmt.Initializers.Count == 1)
                    {
                        // handle the special case of moving a variable into the for initializer
                        if (TryConvertAssignmentExpressionIntoVariableDeclaration(forStmt.Initializers.Single(), type, variableName))
                        {
                            continue;
                        }
                    }
                    UsingStatement usingStmt = stmt as UsingStatement;
                    if (usingStmt != null && usingStmt.ResourceAcquisition is AssignmentExpression)
                    {
                        // handle the special case of moving a variable into a using statement
                        if (TryConvertAssignmentExpressionIntoVariableDeclaration((Expression)usingStmt.ResourceAcquisition, type, variableName))
                        {
                            continue;
                        }
                    }
                    foreach (AstNode child in stmt.Children)
                    {
                        BlockStatement subBlock = child as BlockStatement;
                        if (subBlock != null)
                        {
                            DeclareVariableInBlock(daa, subBlock, type, variableName, v, allowPassIntoLoops);
                        }
                        else if (HasNestedBlocks(child))
                        {
                            foreach (BlockStatement nestedSubBlock in child.Children.OfType <BlockStatement>())
                            {
                                DeclareVariableInBlock(daa, nestedSubBlock, type, variableName, v, allowPassIntoLoops);
                            }
                        }
                    }
                }
            }
            else
            {
                // Try converting an assignment expression into a VariableDeclarationStatement
                if (!TryConvertAssignmentExpressionIntoVariableDeclaration(declarationPoint, type, variableName))
                {
                    // Declare the variable in front of declarationPoint
                    variablesToDeclare.Add(new VariableToDeclare {
                        Type = type, Name = variableName, ILVariable = v, InsertionPoint = declarationPoint
                    });
                }
            }
        }
Ejemplo n.º 49
0
 void Reset()
 {
     this.A = null;
     this.B = null;
     this.Operator = null;
     this.SimpleOperand = null;
     this.SimpleLeftOperand = false;
 }
Ejemplo n.º 50
0
 /// <summary>
 /// Block entryPoint (incoming: 1)  {
 ///   stloc temp(isinst exceptionType(ldloc exceptionVar))
 ///   if (comp(ldloc temp != ldnull)) br whenConditionBlock
 ///   br falseBlock
 /// }
 /// </summary>
 bool MatchCatchWhenEntryPoint(ILVariable exceptionVar, BlockContainer container, Block entryPoint, out IType exceptionType, out ILInstruction exceptionSlot, out Block whenConditionBlock)
 {
     exceptionType      = null;
     exceptionSlot      = null;
     whenConditionBlock = null;
     if (entryPoint == null || entryPoint.IncomingEdgeCount != 1)
     {
         return(false);
     }
     if (entryPoint.Instructions.Count == 3)
     {
         // stloc temp(isinst exceptionType(ldloc exceptionVar))
         // if (comp(ldloc temp != ldnull)) br whenConditionBlock
         // br falseBlock
         if (!entryPoint.Instructions[0].MatchStLoc(out var temp, out var isinst) ||
             temp.Kind != VariableKind.StackSlot || !isinst.MatchIsInst(out exceptionSlot, out exceptionType))
         {
             return(false);
         }
         if (!exceptionSlot.MatchLdLoc(exceptionVar))
         {
             return(false);
         }
         if (!entryPoint.Instructions[1].MatchIfInstruction(out var condition, out var branch))
         {
             return(false);
         }
         if (!condition.MatchCompNotEquals(out var left, out var right))
         {
             return(false);
         }
         if (!entryPoint.Instructions[2].MatchBranch(out var falseBlock) || !MatchFalseBlock(container, falseBlock, out var returnVar, out var exitBlock))
         {
             return(false);
         }
         if ((left.MatchLdNull() && right.MatchLdLoc(temp)) || (right.MatchLdNull() && left.MatchLdLoc(temp)))
         {
             return(branch.MatchBranch(out whenConditionBlock));
         }
     }
     else if (entryPoint.Instructions.Count == 2)
     {
         // if (comp(isinst exceptionType(ldloc exceptionVar) != ldnull)) br whenConditionBlock
         // br falseBlock
         if (!entryPoint.Instructions[0].MatchIfInstruction(out var condition, out var branch))
         {
             return(false);
         }
         if (!condition.MatchCompNotEquals(out var left, out var right))
         {
             return(false);
         }
         if (!entryPoint.Instructions[1].MatchBranch(out var falseBlock) || !MatchFalseBlock(container, falseBlock, out var returnVar, out var exitBlock))
         {
             return(false);
         }
         if (!left.MatchIsInst(out exceptionSlot, out exceptionType))
         {
             return(false);
         }
         if (!exceptionSlot.MatchLdLoc(exceptionVar))
         {
             return(false);
         }
         if (right.MatchLdNull())
         {
             return(branch.MatchBranch(out whenConditionBlock));
         }
     }
     return(false);
 }
Ejemplo n.º 51
0
		public void AddStateVariable(ILVariable v)
		{
			if (!stateVariables.Contains(v))
				stateVariables.Add(v);
		}
Ejemplo n.º 52
0
 public DisplayClass(ILVariable variable, ITypeDefinition type)
 {
     Variable           = variable;
     Type               = type;
     VariablesToDeclare = new Dictionary <IField, VariableToDeclare>();
 }
Ejemplo n.º 53
0
 public void SetAlias (ILVariable variable, FieldReference fieldReference) {
     Aliases[variable.Name] = fieldReference;
 }
Ejemplo n.º 54
0
 public void Propagate(ILVariable variable)
 {
     this.declaredVariable = variable;
     this.CanPropagate     = variable != null;
 }
Ejemplo n.º 55
0
        List<ByteCode> StackAnalysis(MethodDefinition methodDef)
        {
            // Create temporary structure for the stack analysis
            List<ByteCode> body = new List<ByteCode>(methodDef.Body.Instructions.Count);
            foreach(Instruction inst in methodDef.Body.Instructions) {
                OpCode opCode  = inst.OpCode;
                object operand = inst.Operand;
                MethodBodyRocks.ExpandMacro(ref opCode, ref operand, methodDef.Body);
                ByteCode byteCode = new ByteCode() {
                    Offset      = inst.Offset,
                    EndOffset   = inst.Next != null ? inst.Next.Offset : methodDef.Body.CodeSize,
                    OpCode      = opCode,
                    Operand     = operand,
                    PopCount    = inst.GetPopCount(),
                    PushCount   = inst.GetPushCount()
                };
                instrToByteCode[inst] = byteCode;
                body.Add(byteCode);
            }
            for (int i = 0; i < body.Count - 1; i++) {
                body[i].Next = body[i + 1];
            }

            Queue<ByteCode> agenda = new Queue<ByteCode>();

            // Add known states
            body[0].StackBefore = new List<StackSlot>();
            agenda.Enqueue(body[0]);

            if(methodDef.Body.HasExceptionHandlers) {
                foreach(ExceptionHandler ex in methodDef.Body.ExceptionHandlers) {
                    ByteCode tryStart = instrToByteCode[ex.TryStart];
                    tryStart.StackBefore = new List<StackSlot>();
                    agenda.Enqueue(tryStart);

                    ByteCode handlerStart = instrToByteCode[ex.HandlerType == ExceptionHandlerType.Filter ? ex.FilterStart : ex.HandlerStart];
                    handlerStart.StackBefore = new List<StackSlot>();
                    if (ex.HandlerType == ExceptionHandlerType.Catch || ex.HandlerType == ExceptionHandlerType.Filter) {
                        handlerStart.StackBefore.Add(new StackSlot(null));
                    }
                    agenda.Enqueue(handlerStart);

                    // Control flow is not required to reach endfilter
                    if (ex.HandlerType == ExceptionHandlerType.Filter) {
                        ByteCode endFilter = instrToByteCode[ex.FilterEnd.Previous];
                        endFilter.StackBefore = new List<StackSlot>();
                    }
                }
            }

            // Process agenda
            while(agenda.Count > 0) {
                ByteCode byteCode = agenda.Dequeue();

                // Calculate new stack
                List<StackSlot> newStack = byteCode.CloneStack(byteCode.PopCount);
                for (int i = 0; i < byteCode.PushCount; i++) {
                    newStack.Add(new StackSlot(byteCode));
                }

                // Apply the state to any successors
                List<ByteCode> branchTargets = new List<ByteCode>();
                if (byteCode.OpCode.CanFallThough()) {
                    branchTargets.Add(byteCode.Next);
                }
                if (byteCode.OpCode.IsBranch()) {
                    if (byteCode.Operand is Instruction[]) {
                        foreach(Instruction inst in (Instruction[])byteCode.Operand) {
                            ByteCode target = instrToByteCode[inst];
                            branchTargets.Add(target);
                            // The target of a branch must have label
                            if (target.Label == null) {
                                target.Label = new ILLabel() { Name = target.Name };
                            }
                        }
                    } else {
                        ByteCode target = instrToByteCode[(Instruction)byteCode.Operand];
                        branchTargets.Add(target);
                        // The target of a branch must have label
                        if (target.Label == null) {
                            target.Label = new ILLabel() { Name = target.Name };
                        }
                    }
                }
                foreach (ByteCode branchTarget in branchTargets) {
                    if (branchTarget.StackBefore == null) {
                        branchTarget.StackBefore = newStack;
                        // Do not share one stack for several bytecodes
                        if (branchTargets.Count > 1) {
                            branchTarget.StackBefore = branchTarget.CloneStack(0);
                        }
                        agenda.Enqueue(branchTarget);
                    } else {
                        if (branchTarget.StackBefore.Count != newStack.Count) {
                            throw new Exception("Inconsistent stack size at " + byteCode.Name);
                        }

                        // Merge stacks
                        bool modified = false;
                        for (int i = 0; i < newStack.Count; i++) {
                            List<ByteCode> oldPushedBy = branchTarget.StackBefore[i].PushedBy;
                            List<ByteCode> newPushedBy = oldPushedBy.Union(newStack[i].PushedBy).ToList();
                            if (newPushedBy.Count > oldPushedBy.Count) {
                                branchTarget.StackBefore[i].PushedBy = newPushedBy;
                                modified = true;
                            }
                        }

                        if (modified) {
                            agenda.Enqueue(branchTarget);
                        }
                    }
                }
            }

            // Genertate temporary variables to replace stack
            foreach(ByteCode byteCode in body) {
                int argIdx = 0;
                int popCount = byteCode.PopCount ?? byteCode.StackBefore.Count;
                for (int i = byteCode.StackBefore.Count - popCount; i < byteCode.StackBefore.Count; i++) {
                    StackSlot arg = byteCode.StackBefore[i];
                    ILVariable tmpVar = new ILVariable() { Name = string.Format("arg_{0:X2}_{1}", byteCode.Offset, argIdx), IsGenerated = true };
                    arg.LoadFrom = tmpVar;
                    foreach(ByteCode pushedBy in arg.PushedBy) {
                        // TODO: Handle exception variables
                        if (pushedBy != null) {
                            if (pushedBy.StoreTo == null) {
                                pushedBy.StoreTo = new List<ILVariable>(1);
                            }
                            pushedBy.StoreTo.Add(tmpVar);
                        }
                    }
                    if (arg.PushedBy.Count == 1) {
                        allowInline[tmpVar] = true;
                    }
                    argIdx++;
                }
            }

            // Convert local varibles
            Variables = methodDef.Body.Variables.Select(v => new ILVariable() { Name = string.IsNullOrEmpty(v.Name) ?  "var_" + v.Index : v.Name, Type = v.VariableType }).ToList();
            int[] numReads  = new int[Variables.Count];
            int[] numWrites = new int[Variables.Count];
            foreach(ByteCode byteCode in body) {
                if (byteCode.OpCode == OpCodes.Ldloc) {
                    int index = ((VariableDefinition)byteCode.Operand).Index;
                    byteCode.Operand = Variables[index];
                    numReads[index]++;
                }
                if (byteCode.OpCode == OpCodes.Stloc) {
                    int index = ((VariableDefinition)byteCode.Operand).Index;
                    byteCode.Operand = Variables[index];
                    numWrites[index]++;
                }
            }

            // Find which variables we can inline
            if (this.optimize) {
                for (int i = 0; i < Variables.Count; i++) {
                    if (numReads[i] == 1 && numWrites[i] == 1) {
                        allowInline[Variables[i]] = true;
                    }
                }
            }

            // Convert branch targets to labels
            foreach(ByteCode byteCode in body) {
                if (byteCode.Operand is Instruction[]) {
                    List<ILLabel> newOperand = new List<ILLabel>();
                    foreach(Instruction target in (Instruction[])byteCode.Operand) {
                        newOperand.Add(instrToByteCode[target].Label);
                    }
                    byteCode.Operand = newOperand.ToArray();
                } else if (byteCode.Operand is Instruction) {
                    byteCode.Operand = instrToByteCode[(Instruction)byteCode.Operand].Label;
                }
            }

            return body;
        }
Ejemplo n.º 56
0
        /// <summary>
        /// Fill <c>allStores</c> and <c>storeIndexMap</c>.
        /// </summary>
        static List <ILInstruction>[] FindAllStoresByVariable(ILFunction scope, BitSet activeVariables, CancellationToken cancellationToken)
        {
            // For each variable, find the list of ILInstructions storing to that variable
            List <ILInstruction>[] storesByVar = new List <ILInstruction> [scope.Variables.Count];
            for (int vi = 0; vi < storesByVar.Length; vi++)
            {
                if (activeVariables[vi])
                {
                    storesByVar[vi] = new List <ILInstruction> {
                        null
                    }
                }
                ;
            }
            foreach (var inst in scope.Descendants)
            {
                if (inst.HasDirectFlag(InstructionFlags.MayWriteLocals))
                {
                    cancellationToken.ThrowIfCancellationRequested();
                    ILVariable v = ((IInstructionWithVariableOperand)inst).Variable;
                    if (v.Function == scope && activeVariables[v.IndexInFunction])
                    {
                        storesByVar[v.IndexInFunction].Add(inst);
                    }
                }
            }
            return(storesByVar);
        }

        /// <summary>
        /// Create the initial state (reachable bit + uninit variable bits set, store bits unset).
        /// </summary>
        State CreateInitialState()
        {
            BitSet initialState = new BitSet(allStores.Length);

            initialState.Set(ReachableBit);
            for (int vi = 0; vi < scope.Variables.Count; vi++)
            {
                if (analyzedVariables[vi])
                {
                    Debug.Assert(allStores[firstStoreIndexForVariable[vi]] == null);
                    initialState.Set(firstStoreIndexForVariable[vi]);
                }
            }
            return(new State(initialState));
        }

        #endregion

        #region Analysis
        void HandleStore(ILInstruction inst, ILVariable v)
        {
            cancellationToken.ThrowIfCancellationRequested();
            if (v.Function == scope && analyzedVariables[v.IndexInFunction] && state.IsReachable)
            {
                // Clear the set of stores for this variable:
                state.KillStores(firstStoreIndexForVariable[v.IndexInFunction], firstStoreIndexForVariable[v.IndexInFunction + 1]);
                // And replace it with this store:
                int si = storeIndexMap[inst];
                state.SetStore(si);

                // We should call PropagateStateOnException() here because we changed the state.
                // But that's equal to: currentStateOnException.UnionWith(state);

                // Because we're already guaranteed that state.LessThanOrEqual(currentStateOnException)
                // when entering HandleStore(), all we really need to do to achieve what PropagateStateOnException() does
                // is to add the single additional store to the exceptional state as well:
                currentStateOnException.SetStore(si);
            }
        }
		bool StoreCanBeConvertedToAssignment(ILExpression store, ILVariable exprVar)
		{
			if (store == null)
				return false;
			switch (store.Code) {
				case ILCode.Stloc:
				case ILCode.Stfld:
				case ILCode.Stsfld:
				case ILCode.Stobj:
				case ILCode.CallSetter:
				case ILCode.CallvirtSetter:
					break;
				default:
					if (!store.Code.IsStoreToArray())
						return false;
					break;
			}
			return store.Arguments.Last().Code == ILCode.Ldloc && store.Arguments.Last().Operand == exprVar;
		}
Ejemplo n.º 58
0
 public bool IsAnalyzedVariable(ILVariable v)
 {
     return(v.Function == scope && analyzedVariables[v.IndexInFunction]);
 }
		bool HandleStringFixing(ILVariable pinnedVar, List<ILNode> body, ref int pos, ref ILExpression fixedStmtInitializer)
		{
			// fixed (stloc(pinnedVar, ldloc(text))) {
			//   var1 = var2 = conv.i(ldloc(pinnedVar))
			//   if (logicnot(logicnot(var1))) {
			//     var2 = add(var1, call(RuntimeHelpers::get_OffsetToStringData))
			//   }
			//   stloc(ptrVar, var2)
			//   ...
			
			if (pos >= body.Count)
				return false;
			
			ILVariable var1, var2;
			ILExpression varAssignment, ptrInitialization;
			if (!(body[pos].Match(ILCode.Stloc, out var1, out varAssignment) && varAssignment.Match(ILCode.Stloc, out var2, out ptrInitialization)))
				return false;
			if (!(var1.IsGenerated && var2.IsGenerated))
				return false;
			if (ptrInitialization.Code == ILCode.Conv_I || ptrInitialization.Code == ILCode.Conv_U)
				ptrInitialization = ptrInitialization.Arguments[0];
			if (!ptrInitialization.MatchLdloc(pinnedVar))
				return false;
			
			ILCondition ifStmt = body[pos + 1] as ILCondition;
			if (!(ifStmt != null && ifStmt.TrueBlock != null && ifStmt.TrueBlock.Body.Count == 1 && (ifStmt.FalseBlock == null || ifStmt.FalseBlock.Body.Count == 0)))
				return false;
			if (!UnpackDoubleNegation(ifStmt.Condition).MatchLdloc(var1))
				return false;
			ILVariable assignedVar;
			ILExpression assignedExpr;
			if (!(ifStmt.TrueBlock.Body[0].Match(ILCode.Stloc, out assignedVar, out assignedExpr) && assignedVar == var2 && assignedExpr.Code == ILCode.Add))
				return false;
			MethodReference calledMethod;
			if (!(assignedExpr.Arguments[0].MatchLdloc(var1)))
				return false;
			if (!(assignedExpr.Arguments[1].Match(ILCode.Call, out calledMethod) || assignedExpr.Arguments[1].Match(ILCode.CallGetter, out calledMethod)))
				return false;
			if (!(calledMethod.Name == "get_OffsetToStringData" && calledMethod.DeclaringType.FullName == "System.Runtime.CompilerServices.RuntimeHelpers"))
				return false;
			
			ILVariable pointerVar;
			if (body[pos + 2].Match(ILCode.Stloc, out pointerVar, out assignedExpr) && assignedExpr.MatchLdloc(var2)) {
				pos += 3;
				fixedStmtInitializer.Operand = pointerVar;
				return true;
			}
			return false;
		}
Ejemplo n.º 60
0
 /// <summary>
 /// Determines a list of all store instructions that write to a given <paramref name="returnVar"/>.
 /// Returns false if any of these instructions does not meet the following criteria:
 /// - must be a stloc
 /// - must be a direct child of a block
 /// - must be the penultimate instruction
 /// - must be followed by a branch instruction to <paramref name="leaveBlock"/>
 /// - must have a BlockContainer as ancestor.
 /// Returns true, if all instructions meet these criteria, and <paramref name="instructionsToModify"/> contains a list of 3-tuples.
 /// Each tuple consists of the target block container, the leave block, and the branch instruction that should be modified.
 /// </summary>
 static bool CanModifyInstructions(ILVariable returnVar, Block leaveBlock, out List <(BlockContainer, Block, Branch)> instructionsToModify)