Example #1
0
        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;
        }
Example #4
0
        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)
 {
 }
Example #7
0
 public InterferenceGraphRenderer(InterferenceGraph graph, MethodCompileInfo methodCompileInfo)
 {
     Graph = graph;
     MethodCompileInfo = methodCompileInfo;
 }
Example #8
0
 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;
        }
Example #11
0
 protected BlockStatementPattern(MethodCompileInfo compileInfo)
     : base(compileInfo)
 {
 }
Example #12
0
 public SwitchStatementPattern(MethodCompileInfo compileInfo)
     : base(compileInfo)
 {
 }
Example #13
0
        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;
        }
Example #14
0
 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;
        }
Example #17
0
 public AnyExpressionPattern(MethodCompileInfo compileInfo)
     : base(compileInfo)
 {
 }
 public ConditionStatementPattern(MethodCompileInfo compileInfo)
     : base(compileInfo)
 {
 }
Example #19
0
        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;
        }
Example #20
0
 protected ExpressionPattern(MethodCompileInfo compileInfo)
     : base(compileInfo)
 {
 }
 public CostRestrictedStatementPattern(MethodCompileInfo compileInfo)
     : base(compileInfo)
 {
 }
Example #22
0
 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);
        }
Example #24
0
        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);
                }
            }
        }
Example #25
0
 public WhileStatementPattern(MethodCompileInfo compileInfo)
     : base(compileInfo)
 {
 }