public override bool Transform(MethodCompileInfo methodCompileInfo) { throw new NotImplementedException(); /* // TODO: This could be done a lot better. Just because a loop is most "inner" doesn't mean that it dominates execution time. Use a cost-based approach here. foreach (LoopTreeVertex loopTreeVertex in compileInfo.LoopTree.Vertices) { if (compileInfo.LoopTree.OutDegree(loopTreeVertex) > 1) { // this is not an innermost loop, so skip it continue; } // now.. lets turn this loop upside down! } */ // match while statement (while0) // find condition // condition must be a binary binaryExpression with the left side being a field reference binaryExpression or a variable reference binaryExpression (iterator), the operator being <, <=, >, >= (op), and right side being a field or variable reference binaryExpression (bound) // build a new block statement (block1) // create new variable (v1) // add new assignstatement (v1 = (bound-iterator) % 8) to block1 // add new while statement to block1 (while1) // set while1 condition to while0 condition // copy while0 body into while1 body // add new assignstatement (v1 = parseInt(bound-iterator) / 8)) to block1 // duplicate while1 (while2) // duplicate while2 body within itself 7 times // add while2 to block1 }
public override void Transform(MethodCompileInfo compileInfo) { _compileInfo = compileInfo; IAssemblyResolver resolver = _compileInfo.Method.DeclaringType.Module.Assembly.Resolver; foreach (MethodCompileInfo.TryBlockInfo tryBlockInfo in _compileInfo.TryStarts.Values) { foreach (CFGNode node in tryBlockInfo.HandlerStarts) { node.BasicBlock.Statements.Add(new AssignStatement(new FrameSlotReferenceExpression(FrameSlot.Exception), new NullLiteralExpression())); } } }
public override bool Transform(MethodCompileInfo compileInfo) { _methodCompileInfo = compileInfo; IAssemblyResolver resolver = _methodCompileInfo.Method.DeclaringType.Module.Assembly.Resolver; BuildConsolidatedCatchBlocksAndFinallyBlocks(); BuildTryBlockInfoTree(); if (DebugSettings.Graph) { new XaeiO.Compiler.Helpers.CFGRenderer(_methodCompileInfo.CFG, _methodCompileInfo).Render("exception-handling-initializing-transformation.png"); } return true; }
public static void PerformTransformation(ITransformation transformation, MethodCompileInfo methodCompileInfo) { // TODO: Find and error out on circular transformation dependencies // make sure all required transformations are consistent foreach (Type requiredTransformationType in transformation.Requires) { if (!methodCompileInfo.ConsistentTransformationTypes.Contains(requiredTransformationType)) { // this required transformation is not consistent, perform the transformation PerformTransformation((ITransformation)Activator.CreateInstance(requiredTransformationType), methodCompileInfo); } } transformation.Transform(methodCompileInfo); methodCompileInfo.ConsistentTransformationTypes.Add(transformation.GetType()); methodCompileInfo.ConsistentTransformationTypes -= transformation.Corrupts; }
private int CalculateCost(MethodCompileInfo methodCompileInfo) { int cost = 0; foreach (CFGNode node in methodCompileInfo.CFG.Vertices) { cost += _backend.CalculateStatementCost(node.BasicBlock); } return cost; }
public BooleanExpressionPattern(MethodCompileInfo compileInfo) : base(compileInfo) { }
public InterferenceGraphRenderer(InterferenceGraph graph, MethodCompileInfo methodCompileInfo) { Graph = graph; MethodCompileInfo = methodCompileInfo; }
public abstract bool Transform(MethodCompileInfo methodCompileInfo);
public override bool Transform(MethodCompileInfo compileInfo) { _compileInfo = compileInfo; IAssemblyResolver resolver = _compileInfo.Method.DeclaringType.Module.Assembly.Resolver; TypeReference varType = CoreTypes.GetCoreType("System.var"); foreach (CFGNode node in _compileInfo.TopologicalSort) { if (_compileInfo.DeadCode.Contains(node)) { continue; } Definition definition; if (node.TryGetDefinition(out definition)) { IMethodInvokeExpression methodInvokeExpression = definition.Expression as IMethodInvokeExpression; if (methodInvokeExpression != null) { IMethodReferenceExpression methodReferenceExpression = methodInvokeExpression.Method as IMethodReferenceExpression; if (methodReferenceExpression != null) { MethodDefinition methodDefinition; if (ReferenceResolver.TryResolveMethodReference(methodReferenceExpression.Method, resolver, out methodDefinition)) { // dummy? if (XaeiOSBackEnd.HasDummyAttribute(methodDefinition)) { _compileInfo.DeadCode.Add(node); } // var.cast? else if(methodDefinition.Name == "Cast" && ReferenceComparer.TypeReferenceEquals(methodDefinition.DeclaringType, varType)) { if (methodDefinition.HasThis) { definition.Expression = ((IMethodReferenceExpression)methodInvokeExpression.Method).Target; } else { definition.Expression = methodInvokeExpression.Arguments[0]; } node.FlowControl = FlowControl.Next; } // cast operator? else if (methodDefinition.HasThis == false && methodDefinition.IsSpecialName && methodDefinition.Name.StartsWith("op_")) { bool hasIntrinsicAttribute = AttributeHelper.HasCustomAttribute(methodDefinition, "System.Runtime.InteropServices", "IntrinsicAttribute"); if (methodDefinition.Name == "op_Explicit" || methodDefinition.Name == "op_Implicit") { // intrinsic attribute? if (hasIntrinsicAttribute) { // this is an intrinsic cast definition.Expression = methodInvokeExpression.Arguments[0]; node.FlowControl = FlowControl.Next; // here we assume the flow control was previous FlowControl.Call } else { // number conversion? TypeReference fromType = methodInvokeExpression.Arguments[0].Type; TypeReference toType = methodDefinition.ReturnType.ReturnType; // int 32 conversion if (ReferenceComparer.TypeReferenceEquals(fromType, toType) && ReferenceComparer.TypeReferenceEquals(fromType, CoreTypes.Int32)) { definition.Expression = methodInvokeExpression.Arguments[0]; node.FlowControl = FlowControl.Next; // here we assume the flow control was previous FlowControl.Call } // TODO: more number conversions } } else if(hasIntrinsicAttribute) { switch (methodDefinition.Name) { case "op_Addition": { definition.Expression = new BinaryExpression(methodInvokeExpression.Arguments[0], BinaryOperator.Add, methodInvokeExpression.Arguments[1]); node.FlowControl = FlowControl.Next; break; } case "op_Subtraction": { definition.Expression = new BinaryExpression(methodInvokeExpression.Arguments[0], BinaryOperator.Subtract, methodInvokeExpression.Arguments[1]); node.FlowControl = FlowControl.Next; break; } case "op_Division": { definition.Expression = new BinaryExpression(methodInvokeExpression.Arguments[0], BinaryOperator.Divide, methodInvokeExpression.Arguments[1]); node.FlowControl = FlowControl.Next; break; } case "op_Multiply": { definition.Expression = new BinaryExpression(methodInvokeExpression.Arguments[0], BinaryOperator.Multiply, methodInvokeExpression.Arguments[1]); node.FlowControl = FlowControl.Next; break; } case "op_GreaterThan": { definition.Expression = new BinaryExpression(methodInvokeExpression.Arguments[0], BinaryOperator.GreaterThan, methodInvokeExpression.Arguments[1]); node.FlowControl = FlowControl.Next; break; } default: { break; } } } } } } } } else { if (node.BasicBlock.Statements.Count > 0) { IExpressionStatement expressionStatement = node.BasicBlock.Statements[0] as IExpressionStatement; if (expressionStatement != null) { IMethodInvokeExpression methodInvokeExpression = expressionStatement.Expression as IMethodInvokeExpression; if (methodInvokeExpression != null) { IMethodReferenceExpression methodReferenceExpression = methodInvokeExpression.Method as IMethodReferenceExpression; if (methodReferenceExpression != null) { MethodDefinition methodDefinition; if (ReferenceResolver.TryResolveMethodReference(methodReferenceExpression.Method, resolver, out methodDefinition)) { // dummy? if (XaeiOSBackEnd.HasDummyAttribute(methodDefinition)) { _compileInfo.DeadCode.Add(node); } // constructor call to intrinsic type? else if (methodDefinition.IsConstructor && AttributeHelper.HasCustomAttribute(ReferenceResolver.ResolveTypeReference(methodDefinition.DeclaringType), "System.Runtime.InteropServices", "IntrinsicAttribute")) { _compileInfo.DeadCode.Add(node); } } } } } } } } return true; }
public override bool Transform(MethodCompileInfo callerMethodCompileInfo) { List<CFGNode> callerNodes = new List<CFGNode>(); foreach (CFGNode node in callerMethodCompileInfo.CFG.Vertices) { callerNodes.Add(node); } foreach (CFGNode callerNode in callerNodes) { BasicBlock bb = callerNode.BasicBlock; // TODO: For now assume that the only statement is an assignstatement if (bb.Statements.Count != 1) { continue; } IAssignStatement assignStatement = bb.Statements[0] as IAssignStatement; if (assignStatement == null) { continue; } IMethodInvokeExpression methodInvokeExpression = assignStatement.Expression as IMethodInvokeExpression; if (methodInvokeExpression == null) { continue; } IMethodReferenceExpression methodReferenceExpression = methodInvokeExpression.Method as IMethodReferenceExpression; if (methodReferenceExpression == null) { continue; } MethodDefinition methodDefinition; if (!ReferenceResolver.TryResolveMethodReference(methodReferenceExpression.Method, callerMethodCompileInfo.AssemblyCompileInfo.Assembly.Resolver, out methodDefinition)) { continue; } MethodCompileInfo calleeMethodCompileInfo; if (!callerMethodCompileInfo.AssemblyCompileInfo.MethodCompileInfos.TryGetValue(methodDefinition, out calleeMethodCompileInfo)) { continue; } if (callerNode.FlowControl != FlowControl.Call) { continue; } if (!CanBeInlined(calleeMethodCompileInfo, callerMethodCompileInfo)) { continue; } // graft the callee CFG into the caller CFG Debug.Assert(callerNode.SuccessorCount == 1); CFGNode successorNode = callerNode.Successors[0]; // TODO: Write GetOnlySuccessor() method CFGNode newCallerNode = callerNode.Graph.AddNode(); newCallerNode.BasicBlock.Statements.Add(new NopStatement()); CFGNodeSet newNodes = new CFGNodeSet(newCallerNode.Graph); newNodes.Add(newCallerNode); IExpression thisReplacement = calleeMethodCompileInfo.Method.IsStatic ? null : methodReferenceExpression.Target; Dictionary<string, IExpression> argumentReplacements; if (methodDefinition.Parameters.Count > 0) { argumentReplacements = new Dictionary<string, IExpression>(); foreach (ParameterDefinition parameterDefinition in methodDefinition.Parameters) { argumentReplacements[parameterDefinition.Name] = methodInvokeExpression.Arguments[parameterDefinition.Sequence - 1]; } } else { argumentReplacements = null; } try { CFGNode calleeNode = ProcessCFGNode( calleeMethodCompileInfo.CFG.Root, newCallerNode, successorNode, thisReplacement, assignStatement.Target, calleeMethodCompileInfo, callerMethodCompileInfo, new Dictionary<string, VariableDefinition>(), new Dictionary<string, VariableReference>(), argumentReplacements, new Dictionary<CFGNode, CFGNode>(), newNodes ); foreach (CFGEdge inEdge in callerNode.Graph.InEdges(callerNode)) { callerNode.Graph.AddEdge(inEdge.Source, newCallerNode, inEdge.BranchCondition); } newCallerNode.Graph.AddEdge(newCallerNode, calleeNode); newCallerNode.FlowControl = FlowControl.Next; callerNode.Graph.RemoveVertex(callerNode); //Console.WriteLine("Inlined method " + calleeMethodCompileInfo + " in method " + callerMethodCompileInfo); } catch (CannotInlineMethodException e) { //Console.WriteLine("Cannot inline method " + calleeMethodCompileInfo + " in method " + calleeMethodCompileInfo + ": " + e); // inlining failed, let's clean up any nodes we created foreach (CFGNode newNode in newNodes) { newNode.Graph.RemoveVertex(newNode); } }; } return true; }
protected BlockStatementPattern(MethodCompileInfo compileInfo) : base(compileInfo) { }
public SwitchStatementPattern(MethodCompileInfo compileInfo) : base(compileInfo) { }
public void BuildCFG(MethodCompileInfo compileInfo) { if (Compiler.Options.Verbocity > 0) { Console.WriteLine("CecilFrontEnd: " + compileInfo.Method); } _methodCompileInfo = compileInfo; _methodDefinition = compileInfo.Method; _body = _methodDefinition.Body; _cfg = new CFG(); _instructionMap = new Dictionary<Instruction, CFGNodeCluster>(); _handlerStarts = new Dictionary<Instruction, ExceptionHandler>(); Dictionary<Instruction, ExceptionHandler> finallyStarts = new Dictionary<Instruction, ExceptionHandler>(); _instructionsWithMultiplePredecessors = new Set<Instruction>(); _stackAlignmentNodes = new Set<CFGNode>(); Set<Instruction> hasPredecessor = new Set<Instruction>(); // find instructions with multiple predecessors foreach (Instruction instr in _body.Instructions) { switch (instr.OpCode.FlowControl) { case Mono.Cecil.Cil.FlowControl.Next: { if (hasPredecessor.Contains(instr.Next)) { _instructionsWithMultiplePredecessors.Add(instr.Next); } else { hasPredecessor.Add(instr.Next); } break; } case Mono.Cecil.Cil.FlowControl.Branch: { if (hasPredecessor.Contains((Instruction)instr.Operand)) { _instructionsWithMultiplePredecessors.Add((Instruction)instr.Operand); } else { hasPredecessor.Add((Instruction)instr.Operand); } break; } case Mono.Cecil.Cil.FlowControl.Cond_Branch: { if (hasPredecessor.Contains(instr.Next)) { _instructionsWithMultiplePredecessors.Add(instr.Next); } else { hasPredecessor.Add(instr.Next); } Instruction branchTarget = instr.Operand as Instruction; if (branchTarget != null) { if (hasPredecessor.Contains(branchTarget)) { _instructionsWithMultiplePredecessors.Add(branchTarget); } else { hasPredecessor.Add(branchTarget); } } else { Instruction[] switchTargets = instr.Operand as Instruction[]; if (switchTargets != null) { throw new NotImplementedException("Switch is not yet supported"); } else { throw new CompilerException("Unable to follow conditional branch flow"); } } break; } case Mono.Cecil.Cil.FlowControl.Call: { if (hasPredecessor.Contains(instr.Next)) { _instructionsWithMultiplePredecessors.Add(instr.Next); } else { hasPredecessor.Add(instr.Next); } break; } case Mono.Cecil.Cil.FlowControl.Return: { break; } case Mono.Cecil.Cil.FlowControl.Throw: { break; } default: { throw new CompilerException("Invalid FlowControl"); } } } // find beginnings of filter/catch/finally clauses foreach (ExceptionHandler handler in _body.ExceptionHandlers) { switch (handler.Type) { case ExceptionHandlerType.Catch: { _handlerStarts.Add(handler.HandlerStart, handler); break; } case ExceptionHandlerType.Fault: { throw new NotImplementedException(); } case ExceptionHandlerType.Filter: { _handlerStarts.Add(handler.FilterStart, handler); break; } case ExceptionHandlerType.Finally: { finallyStarts.Add(handler.HandlerStart, handler); break; } default: { throw new CompilerException("Invalid exception handler type: " + handler.Type); } } } if (DebugSettings.FrontEndGraph) { new XaeiO.Compiler.Helpers.CFGRenderer(_cfg, _methodCompileInfo).Render("frontend-initial.png"); } // start at the first instruction and follow the control path to build the CFG // most of the work is done here FollowControlFlowPath(new Stack<IExpression>(), _body.Instructions[0]); if (DebugSettings.FrontEndGraph) { new XaeiO.Compiler.Helpers.CFGRenderer(_cfg, _methodCompileInfo).Render("frontend-follow-root.png"); } // add left over instructions to the CFG - these are typically catch/finally clauses that aren't explicitly branched to in IL code foreach (Instruction instr in _body.Instructions) { FollowControlFlowPath(new Stack<IExpression>(), instr); } if (DebugSettings.FrontEndGraph) { new XaeiO.Compiler.Helpers.CFGRenderer(_cfg, _methodCompileInfo).Render("frontend-follow-remainder.png"); } // set up TryBlockInfos Dictionary<CFGNode, TryBlockInfo> tryBlockInfoMap = new Dictionary<CFGNode,TryBlockInfo>(); // set up handlers - we also set up the associated TryBlockInfos here and add them to the MethodCompileInfo foreach (KeyValuePair<Instruction, ExceptionHandler> handlerStart in _handlerStarts) { CFGNode tryStartNode = GetMappedCFGNodeCluster(handlerStart.Value.TryStart).Start; TryBlockInfo tryBlockInfo; if (!tryBlockInfoMap.TryGetValue(tryStartNode, out tryBlockInfo)) { tryBlockInfo = new TryBlockInfo(); tryBlockInfo.TryBlock = new CFGNodeCluster(); tryBlockInfo.TryBlock.Start = tryStartNode; tryBlockInfo.TryBlock.End = GetMappedCFGNodeCluster(handlerStart.Value.TryEnd.Previous).End; _methodCompileInfo.TryBlockInfos.Add(tryBlockInfo); tryBlockInfoMap[tryStartNode] = tryBlockInfo; } // add the handler to the tryBlockInfo tryBlockInfo.Handlers.Add( new CFGNodeCluster( GetMappedCFGNodeCluster(handlerStart.Value.HandlerStart), GetMappedCFGNodeCluster(handlerStart.Value.HandlerEnd.Previous) ), handlerStart.Value ); } // set up finally blocks - we also implicity set up the associated TryBlockInfos here (if they haven't already been set up by a handler) foreach (KeyValuePair<Instruction, ExceptionHandler> finallyStart in finallyStarts) { CFGNode tryStartNode = GetMappedCFGNodeCluster(finallyStart.Value.TryStart).Start; TryBlockInfo tryBlockInfo; if (!tryBlockInfoMap.TryGetValue(tryStartNode, out tryBlockInfo)) { tryBlockInfo = new TryBlockInfo(); tryBlockInfo.TryBlock = new CFGNodeCluster(); tryBlockInfo.TryBlock.Start = tryStartNode; tryBlockInfo.TryBlock.End = GetMappedCFGNodeCluster(finallyStart.Value.TryEnd.Previous).End; _methodCompileInfo.TryBlockInfos.Add(tryBlockInfo); tryBlockInfoMap[tryStartNode] = tryBlockInfo; } tryBlockInfo.FinallyBlock = new CFGNodeCluster( GetMappedCFGNodeCluster(finallyStart.Value.HandlerStart), GetMappedCFGNodeCluster(finallyStart.Value.HandlerEnd.Previous) ); } // add branch edges foreach (Instruction instr in _body.Instructions) { CFGNodeCluster cluster = GetMappedCFGNodeCluster(instr); switch (instr.OpCode.FlowControl) { case Mono.Cecil.Cil.FlowControl.Next: { cluster.End.FlowControl = FlowControl.Next; AddEdge(cluster.End, GetMappedCFGNodeCluster(instr.Next).Start); break; } case Mono.Cecil.Cil.FlowControl.Branch: { cluster.End.FlowControl = FlowControl.Branch; AddEdge(cluster.End, GetMappedCFGNodeCluster((Instruction)instr.Operand).Start); break; } case Mono.Cecil.Cil.FlowControl.Cond_Branch: { CFGNode current = cluster.End; Debug.Assert(cluster.End.BasicBlock.Statements.Count == 1); ConditionalBranchExpressionStatement conditionalBranchExpressionStatement = (ConditionalBranchExpressionStatement)cluster.End.BasicBlock.Statements[0]; cluster.End.FlowControl = FlowControl.ConditionalBranch; CFGEdge falseEdge = AddEdge(cluster.End, GetMappedCFGNodeCluster(instr.Next).Start); falseEdge.BranchCondition = new BranchCondition(BranchConditionType.False); falseEdge.BranchCondition.Data = conditionalBranchExpressionStatement; CFGEdge trueEdge = AddEdge(cluster.End, GetMappedCFGNodeCluster((Instruction)instr.Operand).Start); trueEdge.BranchCondition = new BranchCondition(BranchConditionType.True); trueEdge.BranchCondition.Data = conditionalBranchExpressionStatement; break; } case Mono.Cecil.Cil.FlowControl.Call: { cluster.End.FlowControl = FlowControl.Call; AddEdge(cluster.End, GetMappedCFGNodeCluster(instr.Next).Start); break; } case Mono.Cecil.Cil.FlowControl.Return: { cluster.End.FlowControl = FlowControl.Return; break; } case Mono.Cecil.Cil.FlowControl.Throw: { cluster.End.FlowControl = FlowControl.Throw; break; } default: { throw new CompilerException("Invalid FlowControl"); } } } if (DebugSettings.FrontEndGraph) { new XaeiO.Compiler.Helpers.CFGRenderer(_cfg, _methodCompileInfo).Render("frontend-final.png"); } _cfg.Root = GetMappedCFGNodeCluster(_body.Instructions[0]).Start; _methodCompileInfo.CFG = _cfg; }
public override bool Transform(MethodCompileInfo compileInfo) { throw new NotImplementedException(); }
private bool CanBeInlined(MethodCompileInfo calleeMethodCompileInfo, MethodCompileInfo callerMethodCompileInfo) { if (calleeMethodCompileInfo.CFG == null) { return false; } CustomAttribute customAttribute = AttributeHelper.GetCustomAttribute(calleeMethodCompileInfo.Method, "System.Runtime.CompilerServices", "XaeiOSMethodImplAttribute"); if (customAttribute != null) { if (customAttribute.ConstructorParameters.Count > 0) { MethodImplOptions methodImplOptions = (MethodImplOptions)customAttribute.ConstructorParameters[0]; if ((methodImplOptions & MethodImplOptions.NoInlining) > 0) { return false; } } } if (!calleeMethodCompileInfo.Method.IsPublic) { // non-public methods should only be inlined within the same assembly // this prevents references to internal/private members within the callee assembly from being leaked to the caller assembly if (!ReferenceComparer.AssemblyNameReferenceEquals(calleeMethodCompileInfo.Method.DeclaringType.Module.Assembly.Name, callerMethodCompileInfo.Method.DeclaringType.Module.Assembly.Name)) { return false; } } if (CalculateCost(calleeMethodCompileInfo) > InliningCostThreshold) { return false; } if (calleeMethodCompileInfo.Method.IsVirtual) { return false; } // disable inlining methods with loops because we can get an infinite loop in ProcessNode // TODO: Fix this infinite loop if (calleeMethodCompileInfo.Loop.Count != 0) { return false; } // don't inline methods that have multiple roots (try/catch/finally blocks) if (calleeMethodCompileInfo.Roots.Count > 1) { return false; } // this method will be inlined anyway if (XaeiOSBackEnd.HasInlineImplementation(calleeMethodCompileInfo.Method)) { return false; } // don't do inlining with non-preemptive methods if (XaeiOSBackEnd.MethodIsNonPreemptive(calleeMethodCompileInfo.Method) || XaeiOSBackEnd.MethodIsNonPreemptive(callerMethodCompileInfo.Method)) { return false; } // don't inline a method into itself if (ReferenceComparer.MethodReferenceEquals(calleeMethodCompileInfo.Method, callerMethodCompileInfo.Method)) { return false; } // disable inlining methods with locals because we are not properly remapping local vars in ProcessNode // TODO: properly remap local vars /*if (calleeMethodCompileInfo.Method.Body.Variables.Count != 0) { Console.WriteLine("6"); return false; }*/ return true; }
private CFGNode ProcessCFGNode( CFGNode calleeNode, CFGNode callerNode, CFGNode callerSuccessorNode, IExpression thisReplacement, IExpression returnValueTarget, MethodCompileInfo calleeMethodCompileInfo, MethodCompileInfo callerMethodCompileInfo, Dictionary<string, VariableDefinition> renamedLocalsMap, Dictionary<string, VariableReference> variableReplacements, Dictionary<string, IExpression> argumentReplacements, Dictionary<CFGNode, CFGNode> processedNodes, CFGNodeSet newNodes ) { CFGNode inlinedNode; if (processedNodes.TryGetValue(calleeNode, out inlinedNode)) { // we've already seen this node // don't inline it again otherwise we'll end up in an infinite recursion return inlinedNode; } CFG cfg = callerNode.Graph; inlinedNode = cfg.AddNode(); inlinedNode.FlowControl = calleeNode.FlowControl; inlinedNode.BasicBlock = CodeUtility.CloneCode<BasicBlock>(calleeNode.BasicBlock); processedNodes[calleeNode] = inlinedNode; newNodes.Add(inlinedNode); Debug.Assert( inlinedNode.BasicBlock.Statements.Count == calleeNode.BasicBlock.Statements.Count, string.Format("Clone code produced {0} statements instead of {1}", inlinedNode.BasicBlock.Statements.Count, calleeNode.BasicBlock.Statements.Count) ); // rename all variables in callee so they don't clash with variables in caller CodeUtility.MatchAndReplaceCode<IVariableReferenceExpression>( inlinedNode.BasicBlock, delegate(IVariableReferenceExpression expression) { return true; }, delegate(IVariableReferenceExpression expression) { VariableReference variableReplacement; if (!variableReplacements.TryGetValue(expression.Variable.Name, out variableReplacement)) { if (callerMethodCompileInfo.IsTemporary(expression.Variable)) { variableReplacement = callerMethodCompileInfo.NewTemporary(expression.Variable.VariableType); } else if (callerMethodCompileInfo.IsFrozen(expression.Variable)) { variableReplacement = callerMethodCompileInfo.NewFrozen(expression.Variable.VariableType); } else { VariableDefinition variableDefinition; if (!renamedLocalsMap.TryGetValue(expression.Variable.Name, out variableDefinition)) { int index = callerMethodCompileInfo.Method.Body.Variables.Count; string name = "V_" + index; // TODO: Extract into constant and helper method TypeReference type = expression.Variable.VariableType; variableDefinition = new VariableDefinition(name, index, callerMethodCompileInfo.Method, type); callerMethodCompileInfo.Method.Body.Variables.Add(variableDefinition); renamedLocalsMap[expression.Variable.Name] = variableDefinition; } variableReplacement = variableDefinition; } variableReplacements[expression.Variable.Name] = variableReplacement; } expression.Variable = variableReplacement; return expression; }, true ); // replace all instances of "this" in callee with the target object if (thisReplacement != null) { CodeUtility.MatchAndReplaceCode<IExpression>( inlinedNode.BasicBlock, delegate(IExpression expression) { return expression is IThisReferenceExpression; }, delegate(IExpression expression) { return thisReplacement; }, true ); } // replace all arguments references if (argumentReplacements != null) { CodeUtility.MatchAndReplaceCode<IExpression>( inlinedNode.BasicBlock, delegate(IExpression expression) { return expression is IArgumentReferenceExpression; }, delegate(IExpression expression) { IArgumentReferenceExpression argumentReferenceExpression = (IArgumentReferenceExpression)expression; IExpression replacementExpression; if (!argumentReplacements.TryGetValue(argumentReferenceExpression.Parameter.Name, out replacementExpression)) { throw new CompilerException( string.Format( "Error while inlining call to {0}. Could not find argument replacement for parameter \"{1}\". Parameter sequence is {2}.", calleeMethodCompileInfo.Method, argumentReferenceExpression.Parameter.Name, argumentReferenceExpression.Parameter.Sequence ) ); } else { return replacementExpression; } }, true ); } if (inlinedNode.FlowControl == FlowControl.Throw) { // TODO: fixup exception handling info throw new CannotInlineMethodException("Contain throw statement"); } else if (inlinedNode.FlowControl == FlowControl.ConditionalBranch) { // TODO: Fix this so that conditioanl branches can be inlined throw new CannotInlineMethodException("Contains a conditional branch"); } else if (inlinedNode.FlowControl == FlowControl.Return) { // replace return statement with assignment to variable being assigned to in caller Debug.Assert(inlinedNode.BasicBlock.Statements.Count == 1, string.Format("Return basic block has {0} statements", inlinedNode.BasicBlock.Statements.Count)); Debug.Assert(inlinedNode.BasicBlock.Statements[0] is IMethodReturnStatement); IMethodReturnStatement methodReturnStatement = (IMethodReturnStatement)inlinedNode.BasicBlock.Statements[0]; inlinedNode.BasicBlock.Statements.Clear(); inlinedNode.BasicBlock.Statements.Add(new AssignStatement(returnValueTarget, methodReturnStatement.Expression)); // add edge between this return node and the caller node's successor Debug.Assert(inlinedNode.SuccessorCount == 0); Debug.Assert(callerSuccessorNode != null); cfg.AddEdge(inlinedNode, callerSuccessorNode); // flow control is no longer return inlinedNode.FlowControl = FlowControl.Next; } foreach (CFGEdge outEdge in calleeNode.Graph.OutEdges(calleeNode)) { CFGNode newSuccessorNode = ProcessCFGNode( outEdge.Target, callerNode, callerSuccessorNode, thisReplacement, returnValueTarget, calleeMethodCompileInfo, callerMethodCompileInfo, renamedLocalsMap, variableReplacements, argumentReplacements, processedNodes, newNodes ); cfg.AddEdge(inlinedNode, newSuccessorNode, outEdge.BranchCondition); } return inlinedNode; }
public AnyExpressionPattern(MethodCompileInfo compileInfo) : base(compileInfo) { }
public ConditionStatementPattern(MethodCompileInfo compileInfo) : base(compileInfo) { }
public override bool Transform(MethodCompileInfo methodCompileInfo) { _methodCompileInfo = methodCompileInfo; CFGNodeSet wholeSet = new CFGNodeSet(_methodCompileInfo.CFG); List<CFGNode> sortedNodes = new List<CFGNode>(); CFGNodeSet roots = new CFGNodeSet(_methodCompileInfo.CFG.Root);//_compileInfo.Roots; try { QuickGraph.Algorithms.TopologicalSortAlgorithm sortAlgorithm = new QuickGraph.Algorithms.TopologicalSortAlgorithm(_methodCompileInfo.CFG); sortAlgorithm.Compute(); foreach (CFGNode node in sortAlgorithm.SortedVertices) { if (!roots.Contains(node)) { sortedNodes.Add(node); } wholeSet.Add(node); } } catch (QuickGraph.Exceptions.NonAcyclicGraphException) { foreach (QuickGraph.Concepts.IVertex vertex in _methodCompileInfo.CFG.Vertices) { if (!roots.Contains((CFGNode)vertex)) { sortedNodes.Add((CFGNode)vertex); } wholeSet.Add((CFGNode)vertex); } } Dictionary<CFGNode, CFGNodeSet> domMap = _methodCompileInfo.Dominators; domMap.Clear(); foreach (CFGNode root in roots) { // root only dominated by itself domMap[root] = new CFGNodeSet(root); } Dictionary<CFGNode, CFGNode[]> predecessorMap = new Dictionary<CFGNode, CFGNode[]>(); foreach (CFGNode node in sortedNodes) { predecessorMap[node] = node.Predecessors; } Dictionary<CFGNode, CFGNodeSet> domMapPrime = new Dictionary<CFGNode, CFGNodeSet>(); foreach (KeyValuePair<CFGNode, CFGNodeSet> entry in domMap) { domMapPrime.Add(entry.Key, entry.Value.Clone()); } // initialize to the whole set foreach (CFGNode node in sortedNodes) { domMap[node] = wholeSet; } do { bool changed = false; for (int i = 0; i < sortedNodes.Count; i++) { CFGNode n = sortedNodes[i]; domMapPrime[n] = domMap[n]; domMap[n] = new CFGNodeSet(n); if (predecessorMap[n].Length > 0) { CFGNode[] predecessors = predecessorMap[n]; CFGNodeSet predDomSet = domMap[predecessors[0]].Clone(); for (int j = 1; j < predecessors.Length; j++) { predDomSet = predDomSet & domMap[predecessors[j]]; } domMap[n] += predDomSet; } if (!changed && domMap[n] != domMapPrime[n]) { changed = true; } } if (changed) { continue; } } while (!DominatorMapsEquals(domMap, domMapPrime)); // TODO: can we find idom at the same time as we find dominator set? // find immediate dominators Dictionary<CFGNode, CFGNode> idomMap = _methodCompileInfo.ImmediateDominator; for (int i = 0; i < sortedNodes.Count; i++) { CFGNode n = sortedNodes[i]; CFGNode immediateDominator = null; foreach (CFGNode dominator in domMap[n]) { if (dominator == n) { continue; } if (immediateDominator == null) { immediateDominator = dominator; } else { if (domMap[dominator].Contains(immediateDominator)) { immediateDominator = dominator; } } } idomMap[n] = immediateDominator; } // dominator frontier Dictionary<CFGNode, CFGNodeSet> frontierMap = _methodCompileInfo.DominatorFrontier; frontierMap.Clear(); for (int i = 0; i < sortedNodes.Count; i++) { CFGNode n = sortedNodes[i]; if (predecessorMap[n].Length >= 2) { CFGNode immediateDominator = idomMap[n]; foreach (CFGNode predecessor in predecessorMap[n]) { CFGNode runner = predecessor; while (runner != immediateDominator && idomMap.ContainsKey(runner)) { CFGNodeSet frontier; if (!frontierMap.TryGetValue(runner, out frontier)) { frontier = new CFGNodeSet(_methodCompileInfo.CFG); frontierMap[runner] = frontier; } frontier.Add(n); runner = idomMap[runner]; } } } } return true; }
protected ExpressionPattern(MethodCompileInfo compileInfo) : base(compileInfo) { }
public CostRestrictedStatementPattern(MethodCompileInfo compileInfo) : base(compileInfo) { }
public CFGRenderer(CFG graph, MethodCompileInfo compileInfo) { Graph = graph; MethodCompileInfo = compileInfo; }
public override void Transform(MethodCompileInfo compileInfo) { _compileInfo = compileInfo; bool changed; do { changed = false; foreach (CFGNode node in _compileInfo.CFG.Vertices) { if (_compileInfo.DeadCode.Contains(node)) { continue; } IExpression replacement = null; CodeMatching.MatchAndReplaceCode<IExpression>(node.BasicBlock, delegate(IExpression expression, ICodeObject context) { IBinaryExpression binaryExpression = expression as IBinaryExpression; if (binaryExpression != null) { ILiteralExpression rightLiteral = binaryExpression.Right as ILiteralExpression; if (rightLiteral != null && rightLiteral.Value is int && (int)rightLiteral.Value == 0) { bool isInequality = (binaryExpression.Operator == BinaryOperator.ValueInequality) || (binaryExpression.Operator == BinaryOperator.IdentityInequality); bool isEquality = (!isInequality) && ((binaryExpression.Operator == BinaryOperator.ValueEquality) || (binaryExpression.Operator == BinaryOperator.IdentityEquality)); if ((isInequality || isEquality) && ReferenceComparer.TypeReferenceEquals(binaryExpression.Left.Type, CoreTypes.Boolean)) { if (isInequality) { replacement = binaryExpression.Left; } else { replacement = new UnaryExpression(binaryExpression.Left, UnaryOperator.BooleanNot); } return true; } } return false; } IConditionExpression conditionExpression = expression as IConditionExpression; if (conditionExpression != null) { if (ReferenceComparer.TypeReferenceEquals(conditionExpression.Condition.Type, CoreTypes.Boolean)) { ILiteralExpression thenLiteralExpression = conditionExpression.Then as ILiteralExpression; ILiteralExpression elseLiteralExpression = conditionExpression.Else as ILiteralExpression; if (thenLiteralExpression != null && elseLiteralExpression != null) { if (thenLiteralExpression.Value is int && elseLiteralExpression.Value is int) { if (((int)thenLiteralExpression.Value) == 1 && ((int)elseLiteralExpression.Value) == 0) { replacement = conditionExpression.Condition; return true; } } } } return false; } return false; }, delegate(IExpression expression, ICodeObject context) { IExpression ret = replacement; replacement = null; changed = true; return ret; }, true); } } while (changed); }
void CompileMethod(MethodCompileInfo method, MethodBuilder nMethod, ModuleBuilder mb) { var siDbCommandExecuteNonQuery = typeof(IDbCommand).GetMethod("ExecuteNonQuery"); var siDbCommandExecuteScalar = typeof(IDbCommand).GetMethod("ExecuteScalar"); var siDbCommandExecuteReader = typeof(IDbCommand).GetMethod("ExecuteReader", new Type[0]); var il = nMethod.GetILGenerator(); var i = 0; foreach (var parm in method.Parms) { il.Emit(OpCodes.Ldarg_0); il.Emit(OpCodes.Ldfld, method.PrsField); il.Emit(OpCodes.Ldc_I4, i); il.Emit(OpCodes.Ldelem_Ref); il.Emit(OpCodes.Ldarg, i + 1); if (parm.ParameterType.IsValueType) { il.Emit(OpCodes.Box, parm.ParameterType); } il.Emit(OpCodes.Callvirt, _siDataParameterSetValue); i++; } il.Emit(OpCodes.Ldarg_0); il.Emit(OpCodes.Ldfld, method.CmdField); if (method.RetEnumType != null) { var enumeratorT = EnumeratorCompiler.Compile(method.RetEnumType, mb); il.Emit(OpCodes.Callvirt, siDbCommandExecuteReader); il.Emit(OpCodes.Newobj, enumeratorT.GetConstructor(new[] { typeof(IDataReader) })); il.Emit(OpCodes.Ret); } else { switch (method.Infos.ReturnType.Name) { case "Void": il.Emit(OpCodes.Callvirt, siDbCommandExecuteNonQuery); il.Emit(OpCodes.Pop); il.Emit(OpCodes.Ret); break; case "Object": il.Emit(OpCodes.Callvirt, siDbCommandExecuteScalar); il.Emit(OpCodes.Ret); break; case "IDataReader": il.Emit(OpCodes.Callvirt, siDbCommandExecuteReader); il.Emit(OpCodes.Ret); break; default: throw new ArgumentException("Method " + method.Infos.Name + " returns incompatible type " + method.Infos.ReturnType.Name); } } }
public WhileStatementPattern(MethodCompileInfo compileInfo) : base(compileInfo) { }