private Expression GetIdentifierReference(VariableReference identifierReference, ref Expression target) { V_0 = target as MethodInvocationExpression; if (V_0 == null || V_0.get_MethodExpression().get_MethodDefinition() == null || !V_0.get_MethodExpression().get_MethodDefinition().get_IsStatic() || !String.op_Equality(V_0.get_MethodExpression().get_MethodDefinition().get_DeclaringType().get_FullName(), "System.Linq.Enumerable") && !String.op_Equality(V_0.get_MethodExpression().get_MethodDefinition().get_DeclaringType().get_FullName(), "System.Linq.Queryable") || !String.op_Equality(V_0.get_MethodExpression().get_Method().get_Name(), "Cast")) { return(new VariableReferenceExpression(identifierReference, null)); } target = V_0.get_Arguments().get_Item(0); dummyVar0 = this.methodContext.get_UndeclaredLinqVariables().Remove(identifierReference.Resolve()); return(new VariableDeclarationExpression(identifierReference.Resolve(), null)); }
private Expression GetIdentifierReference(VariableReference identifierReference, ref Expression target) { MethodInvocationExpression targetInvocation = target as MethodInvocationExpression; if (targetInvocation != null && targetInvocation.MethodExpression.MethodDefinition != null && targetInvocation.MethodExpression.MethodDefinition.IsStatic && (targetInvocation.MethodExpression.MethodDefinition.DeclaringType.FullName == "System.Linq.Enumerable" || targetInvocation.MethodExpression.MethodDefinition.DeclaringType.FullName == "System.Linq.Queryable") && targetInvocation.MethodExpression.Method.Name == "Cast") { target = targetInvocation.Arguments[0]; methodContext.UndeclaredLinqVariables.Remove(identifierReference.Resolve()); return(new VariableDeclarationExpression(identifierReference.Resolve(), null)); } return(new VariableReferenceExpression(identifierReference, null)); }
private bool IsTempVariable(VariableReference variable) { V_0 = this.methodContext.get_VariableDefinitionToNameMap().get_Item(variable.Resolve()); if (!V_0.StartsWith("CS$") && !V_0.StartsWith("VB$") && V_0.IndexOf("__init") <= 0 && !V_0.StartsWith("stackVariable") && !V_0.StartsWith("exception_")) { return(false); } return(true); }
public void Collect(VariableReference vari) { VariableDefinition def; if ((def = vari as VariableDefinition ?? vari.Resolve()) != null) { Collect(def); } }
//x = cond ? y : z; // //== // //if(cond) //{ // x = y; //} //else //{ // x = z; //} // //x - phi variable //y, z - expressions public bool TryMatchInternal(IfStatement theIfStatement, out Statement result) { result = null; if (theIfStatement == null) { return(false); } VariableReference xVariableReference = null; VariableReference x1VariableReference = null; Expression yExpressionValue; Expression zExpressionValue; if (theIfStatement.Else == null || theIfStatement.Then.Statements.Count != 1 || theIfStatement.Else.Statements.Count != 1 || theIfStatement.Then.Statements[0].CodeNodeType != CodeNodeType.ExpressionStatement || theIfStatement.Else.Statements[0].CodeNodeType != CodeNodeType.ExpressionStatement) { return(false); } BinaryExpression thenAssignExpression = (theIfStatement.Then.Statements[0] as ExpressionStatement).Expression as BinaryExpression; BinaryExpression elseAssignExpression = (theIfStatement.Else.Statements[0] as ExpressionStatement).Expression as BinaryExpression; if (!IsAssignToVariableExpression(thenAssignExpression, out x1VariableReference) || !IsAssignToVariableExpression(elseAssignExpression, out xVariableReference)) { return(false); } if (xVariableReference != x1VariableReference) { return(false); } if (!ShouldInlineExpressions(thenAssignExpression, elseAssignExpression)) { /// Although correct syntax, nesting ternary expressions makes the code very unreadable. return(false); } yExpressionValue = GetRightExpressionMapped(thenAssignExpression); zExpressionValue = GetRightExpressionMapped(elseAssignExpression); ConditionExpression ternaryConditionExpression = new ConditionExpression(theIfStatement.Condition, yExpressionValue, zExpressionValue, null); BinaryExpression ternaryAssign = new BinaryExpression(BinaryOperator.Assign, new VariableReferenceExpression(xVariableReference, null), ternaryConditionExpression, this.typeSystem, null); result = new ExpressionStatement(ternaryAssign) { Parent = theIfStatement.Parent }; FixContext(xVariableReference.Resolve(), 1, 0, result as ExpressionStatement); return(true); }
public static VariableDefinition TryResolve(this VariableReference r) { try { return(r.Resolve()); } catch (Exception) { return(null); } }
private bool IsTempVariable(VariableReference variable) { var name = methodContext.VariableDefinitionToNameMap[variable.Resolve()]; if (name.StartsWith("CS$") || name.StartsWith("VB$") || name.IndexOf("__init") > 0 || name.StartsWith("stackVariable") || name.StartsWith("exception_")) { return(true); } return(false); }
public static string GetName(this VariableReference self, MethodBody body) { if (self == null) { return(String.Empty); } var def = self.Resolve(); if (def == null) { return(self.ToString()); } return(GetVariableName(def, body)); }
private void ProcessVariableReferenceExpression(VariableReferenceExpression variableReferenceExpression) { VariableReference variableReference = variableReferenceExpression.Variable; if (this.variableToAssignedCodeNodeTypeMap.ContainsKey(variableReference)) { CodeNodeType variableAssignmentType = this.variableToAssignedCodeNodeTypeMap[variableReference]; VariableDefinition variable = variableReference.Resolve(); if (!this.variablesToNotInline.Contains(variable)) { if (!this.language.IsValidLineStarter(variableAssignmentType)) { this.variablesToNotInline.Add(variable); } } } }
private bool IsOnlyAssignedOnce(VariableReference variable, out TypeReference type) { type = null; StackVariableDefineUseInfo defineUseInfo; if (!context.MethodContext.StackData.VariableToDefineUseInfo.TryGetValue(variable.Resolve(), out defineUseInfo)) { throw new Exception("Define/use info not found."); } if (defineUseInfo.DefinedAt.Count != 1) { return(false); } type = offsetToExpression[First(defineUseInfo.DefinedAt)].ExpressionType; return(true); }
private bool IsOnlyUsedOnce(VariableReference variable, out TypeReference type) { type = null; StackVariableDefineUseInfo defineUseInfo; if (!context.MethodContext.StackData.VariableToDefineUseInfo.TryGetValue(variable.Resolve(), out defineUseInfo)) { throw new Exception("Define/use info not found."); } if (defineUseInfo.UsedAt.Count != 1) { return(false); } int instructionOffset = First(defineUseInfo.UsedAt); UsedAsTypeHelper uath = new UsedAsTypeHelper(context.MethodContext); Instruction instruction = context.MethodContext.ControlFlowGraph.OffsetToInstruction[instructionOffset]; type = uath.GetUseExpressionTypeNode(instruction, offsetToExpression[instructionOffset], variable); return(true); }
/// <summary> /// Check if the local variable has a name which was generated by the compiler. /// Note that this will return true for all variables if debugging information is not present. /// </summary> /// <param name="self">The VariableReference on which the extension method can be called.</param> /// <returns>True if the field name was generated by the compiler, False otherwise</returns> public static bool IsGeneratedName(this VariableReference self, MethodBody body) { if (self == null) { return(false); } var def = self.Resolve(); if (def == null) { return(false); } string name = GetVariableName(def, body); if (String.IsNullOrEmpty(name)) { return(true); } return((name [0] == '<') || (name.IndexOf('$') != -1)); }
private bool IsOnlyUsedOnce(VariableReference variable, out TypeReference type) { type = null; if (!this.context.get_MethodContext().get_StackData().get_VariableToDefineUseInfo().TryGetValue(variable.Resolve(), out V_0)) { throw new Exception("Define/use info not found."); } if (V_0.get_UsedAt().get_Count() != 1) { return(false); } V_1 = this.First <int>(V_0.get_UsedAt()); V_2 = new UsedAsTypeHelper(this.context.get_MethodContext()); V_3 = this.context.get_MethodContext().get_ControlFlowGraph().get_OffsetToInstruction().get_Item(V_1); type = V_2.GetUseExpressionTypeNode(V_3, this.offsetToExpression.get_Item(V_1), variable); return(true); }
private LinqQueryExpression RemoveTransparentIdentifiers(LinqQueryExpression originalQuery) { LinqQueryExpression linqQuery = (LinqQueryExpression)originalQuery.Clone(); List <VariableReference> identifiers = new List <VariableReference>(); TransparentIdentifierCleaner cleaner = new TransparentIdentifierCleaner(); HashSet <VariableReference> transparentIdentifiers = new HashSet <VariableReference>(); for (int i = 0; i < linqQuery.Clauses.Count; i++) { linqQuery.Clauses[i] = (QueryClause)cleaner.Visit(linqQuery.Clauses[i]); QueryClause currentClause = linqQuery.Clauses[i]; if (currentClause.CodeNodeType == CodeNodeType.FromClause) { identifiers.Add(GetVariableReference((currentClause as FromClause).Identifier)); } else if (currentClause.CodeNodeType == CodeNodeType.JoinClause) { if (linqQuery.Clauses[i + 1].CodeNodeType != CodeNodeType.IntoClause) { identifiers.Add(GetVariableReference((currentClause as JoinClause).InnerIdentifier)); } else { identifiers.Add(((IntoClause)linqQuery.Clauses[i + 1]).Identifier.Variable); i++; } } else if (currentClause.CodeNodeType == CodeNodeType.SelectClause && i != linqQuery.Clauses.Count - 1) { VariableReference intoIdentifier = ((IntoClause)linqQuery.Clauses[i + 1]).Identifier.Variable; if (IsTransparentIdentifier(intoIdentifier)) { Dictionary <PropertyDefinition, Expression> propertyToValueMap = GetPropertyToValueMap((currentClause as SelectClause).Expression); if (propertyToValueMap == null) { return(originalQuery); } if (identifiers.Count == 2) { if (!RemoveIdentifier(propertyToValueMap, identifiers)) { return(originalQuery); } linqQuery.Clauses.RemoveAt(i); linqQuery.Clauses.RemoveAt(i); i--; } else if (identifiers.Count == 1) { LetClause letClause = GenerateLetClause(propertyToValueMap, identifiers[0]); if (letClause == null) { return(originalQuery); } linqQuery.Clauses[i] = letClause; linqQuery.Clauses.RemoveAt(i + 1); } else { return(originalQuery); } this.methodContext.VariablesToRename.Add(intoIdentifier.Resolve()); transparentIdentifiers.Add(intoIdentifier); identifiers.Clear(); identifiers.Add(intoIdentifier); UpdateCleaner(cleaner, intoIdentifier, propertyToValueMap); } } else if (currentClause.CodeNodeType == CodeNodeType.IntoClause) { identifiers.Clear(); identifiers.Add(((IntoClause)currentClause).Identifier.Variable); } } TransparentIdentifierFinder finder = new TransparentIdentifierFinder(transparentIdentifiers); if (finder.ContainsTransparentIdentifiers(linqQuery)) { return(originalQuery); } return(linqQuery); }
/// <summary> /// A cecil variable reference will be directed to this method. /// </summary> /// <param name="item">Cecil reference.</param> /// <param name="resolvedItem">Output parameter that will be populated with the resolved cecil definition.</param> /// <returns><c>true</c></returns> private static bool TryResolve(VariableReference item, out object resolvedItem) { resolvedItem = item.Resolve(); return(true); }
internal void RemoveVariable(VariableReference reference) { this.RemoveVariable(reference.Resolve()); return; }
private bool ProcessDelegateAllocation(AssemblyProcessorContext context, MethodDefinition method, Instruction delegateAllocationInstruction) { // The instruction must be a delegate allocation // If not, this might be a static delegate, or some unsupported construct if (delegateAllocationInstruction.OpCode != OpCodes.Newobj) { return(false); } var delegateInstanceConstructor = (MethodReference)delegateAllocationInstruction.Operand; var delegateInstanceType = delegateInstanceConstructor.DeclaringType; // The previous instruction pushes the delegate method onto the stack var functionPointerInstruction = delegateAllocationInstruction.Previous; if (functionPointerInstruction.OpCode != OpCodes.Ldftn) { return(false); } var delegateMethod = (MethodReference)functionPointerInstruction.Operand; // The previous instruction pushes the target onto the stack // If it's the this-parameter, we can create an instance field, and reuse the same delegate var loadClosureInstruction = functionPointerInstruction.Previous; if ((loadClosureInstruction.OpCode == OpCodes.Ldarg_0 || loadClosureInstruction.OpCode == OpCodes.Ldnull) && !method.IsStatic) { // TODO: Handle generic methods/delegates // TODO: Handle multiple constructors propertly var constructor = method.DeclaringType.Methods.FirstOrDefault(x => x.Name == ".ctor" && !x.HasParameters); var retInstruction3 = constructor?.Body.Instructions.FirstOrDefault(x => x.OpCode == OpCodes.Ret); if (retInstruction3 == null) { return(false); } // Create an instance field for the shared delegate var sharedDelegateField = new FieldDefinition($"<delegate>{delegateMethod.Name}", FieldAttributes.Private, delegateInstanceType); method.DeclaringType.Fields.Add(sharedDelegateField); // Create and store the delegate in constructor var ilProcessor5 = constructor.Body.GetILProcessor(); ilProcessor5.InsertBefore(retInstruction3, ilProcessor5.Create(OpCodes.Ldarg_0)); ilProcessor5.InsertBefore(retInstruction3, ilProcessor5.Create(loadClosureInstruction.OpCode)); ilProcessor5.InsertBefore(retInstruction3, ilProcessor5.Create(OpCodes.Ldftn, delegateMethod)); ilProcessor5.InsertBefore(retInstruction3, ilProcessor5.Create(OpCodes.Newobj, delegateInstanceConstructor)); ilProcessor5.InsertBefore(retInstruction3, ilProcessor5.Create(OpCodes.Stfld, sharedDelegateField)); // Load from field instead of allocating var ilProcessor4 = method.Body.GetILProcessor(); ilProcessor4.Remove(functionPointerInstruction); loadClosureInstruction.OpCode = OpCodes.Ldarg_0; // In case it was a ldnull ilProcessor4.Replace(delegateAllocationInstruction, ilProcessor4.Create(OpCodes.Ldfld, sharedDelegateField)); return(true); } // If the target is a compiler generated closure, we only handle local variable load instructions int variableIndex; OpCode storeOpCode; if (!TryGetStoreOpcode(loadClosureInstruction, out storeOpCode, out variableIndex)) { return(false); } // Find the instruction that stores the closure variable var storeClosureInstruction = loadClosureInstruction.Previous; VariableReference closureVarible = null; while (storeClosureInstruction != null) { closureVarible = storeClosureInstruction.Operand as VariableReference; if (storeClosureInstruction.OpCode == storeOpCode && (closureVarible == null || variableIndex == closureVarible.Index)) { break; } storeClosureInstruction = storeClosureInstruction.Previous; } if (storeClosureInstruction == null) { return(false); } var closureInstanceType = method.Body.Variables[variableIndex].VariableType; var closureType = closureInstanceType.Resolve(); var genericParameters = closureType.GenericParameters.Cast <TypeReference>().ToArray(); // Patch closure var closure = ProcessClosure(context, closureType, genericParameters); // Create delegate field var delegateFieldType = ChangeGenericArguments(context, delegateInstanceType, closureInstanceType); var delegateField = new FieldDefinition($"<delegate>{delegateMethod.Name}", FieldAttributes.Public, delegateFieldType); closureType.Fields.Add(delegateField); var localDelegateFieldInstance = delegateField.MakeGeneric(genericParameters); // Initialize delegate field (the closure instance (local 0) is already on the stack) var delegateConstructorInstance = (MethodReference)delegateAllocationInstruction.Operand; var delegateGenericArguments = (delegateFieldType as GenericInstanceType)?.GenericArguments.ToArray() ?? new TypeReference[0]; var genericDelegateConstructor = context.Assembly.MainModule.ImportReference(delegateConstructorInstance.Resolve()).MakeGeneric(delegateGenericArguments); var methodInstance = (MethodReference)functionPointerInstruction.Operand; var genericMethod = methodInstance.Resolve().MakeGeneric(closureType.GenericParameters.ToArray()); if (methodInstance is GenericInstanceMethod) { throw new NotImplementedException(); } var ilProcessor3 = closure.FactoryMethod.Body.GetILProcessor(); var returnInstruction = ilProcessor3.Body.Instructions.FirstOrDefault(x => x.OpCode == OpCodes.Ret); ilProcessor3.InsertBefore(returnInstruction, ilProcessor3.Create(OpCodes.Ldloc_0)); ilProcessor3.InsertBefore(returnInstruction, ilProcessor3.Create(OpCodes.Ldftn, genericMethod)); ilProcessor3.InsertBefore(returnInstruction, ilProcessor3.Create(OpCodes.Newobj, genericDelegateConstructor)); ilProcessor3.InsertBefore(returnInstruction, ilProcessor3.Create(OpCodes.Stfld, localDelegateFieldInstance)); ilProcessor3.InsertBefore(returnInstruction, ilProcessor3.Create(OpCodes.Ldloc_0)); var ilProcessor = method.Body.GetILProcessor(); Func <Instruction> generateClosureVariable = () => closureVarible == null?ilProcessor.Create(loadClosureInstruction.OpCode) : ilProcessor.Create(loadClosureInstruction.OpCode, closureVarible.Resolve()); // Retrieve from pool var closureGenericArguments = (closureInstanceType as GenericInstanceType)?.GenericArguments.ToArray() ?? new TypeReference[0]; var closureAllocation = storeClosureInstruction.Previous; if (closureAllocation.OpCode == OpCodes.Newobj) { // Retrieve closure from pool, instead of allocating ilProcessor.Replace(storeClosureInstruction, ilProcessor.Create(OpCodes.Nop)); var acquireClosure = ilProcessor.Create(OpCodes.Callvirt, poolAcquireMethod.MakeGeneric(closureInstanceType)); var methodPreviousStart = ilProcessor.Body.Instructions.First(); ilProcessor.InsertBefore(methodPreviousStart, ilProcessor.Create(OpCodes.Nop)); ilProcessor.InsertBefore(methodPreviousStart, ilProcessor.Create(OpCodes.Ldsfld, closure.PoolField.MakeGeneric(closureGenericArguments))); ilProcessor.InsertBefore(methodPreviousStart, acquireClosure); ilProcessor.InsertBefore(methodPreviousStart, storeClosureInstruction); closureAllocation.OpCode = OpCodes.Nop; // Change to Nop instead of removing it, as this instruction might be reference somewhere? closureAllocation.Operand = null; // Add a reference ilProcessor.InsertBefore(methodPreviousStart, generateClosureVariable()); ilProcessor.InsertBefore(methodPreviousStart, ilProcessor.Create(OpCodes.Callvirt, closure.AddReferenceMethod.MakeGeneric(closureGenericArguments))); // TODO: Multiple returns + try/finally // Release reference var retInstructions = method.Body.Instructions.Where(x => x.OpCode == OpCodes.Ret).ToArray(); Instruction beforeReturn = generateClosureVariable(); Instruction newReturnInstruction = ilProcessor.Create(OpCodes.Ret); ilProcessor.Append(beforeReturn); ilProcessor.Append(ilProcessor.Create(OpCodes.Ldnull)); ilProcessor.Append(ilProcessor.Create(OpCodes.Beq, newReturnInstruction)); ilProcessor.Append(generateClosureVariable()); ilProcessor.Append(ilProcessor.Create(OpCodes.Callvirt, closure.ReleaseMethod.MakeGeneric(closureGenericArguments))); ilProcessor.Append(newReturnInstruction); foreach (var retInstruction2 in retInstructions) { retInstruction2.OpCode = OpCodes.Br; retInstruction2.Operand = beforeReturn; } } // Get delegate from closure, instead of allocating ilProcessor.Remove(functionPointerInstruction); ilProcessor.Replace(delegateAllocationInstruction, ilProcessor.Create(OpCodes.Ldfld, delegateField.MakeGeneric(closureGenericArguments))); // Closure object is already on the stack return(true); }
private bool IsStackVariable(VariableReference varRef) { return(methodContext.StackData.VariableToDefineUseInfo.ContainsKey(varRef.Resolve())); }
private bool IsStackVariable(VariableReference varRef) { return(this.methodContext.get_StackData().get_VariableToDefineUseInfo().ContainsKey(varRef.Resolve())); }
public void RemoveVariable(VariableReference reference) { RemoveVariable(reference.Resolve()); }
private bool IsOnlyAssignedOnce(VariableReference variable, out TypeReference type) { type = null; if (!this.context.get_MethodContext().get_StackData().get_VariableToDefineUseInfo().TryGetValue(variable.Resolve(), out V_0)) { throw new Exception("Define/use info not found."); } if (V_0.get_DefinedAt().get_Count() != 1) { return(false); } type = this.offsetToExpression.get_Item(this.First <int>(V_0.get_DefinedAt())).get_ExpressionType(); return(true); }
internal void RemoveVariable(VariableReference reference) { RemoveVariable(reference.Resolve()); }