Exemple #1
0
 public IILLabel DefineLabel(string name = null)
 {
     var result = new ILLabel(name, _lastLabelIndex);
     _lastLabelIndex++;
     _instructions.Add(result);
     return result;
 }
        public ILLabelWrapper(ILLabel source, ILPanelEditor editor, string path, string name = null, string label = null)
            : base(source, editor, path, BuildName(name, editor.Panel, source, "Label"),
                   String.IsNullOrEmpty(label) ? GetLabel(source) : label)
        {
            this.source = source;

            this.source.MouseDoubleClick += OnMouseDoubleClick;
        }
		ControlFlowGraph BuildGraph(List<ILNode> nodes, ILLabel entryLabel)
		{
			int index = 0;
			List<ControlFlowNode> cfNodes = new List<ControlFlowNode>();
			ControlFlowNode entryPoint = new ControlFlowNode(index++, 0, ControlFlowNodeType.EntryPoint);
			cfNodes.Add(entryPoint);
			ControlFlowNode regularExit = new ControlFlowNode(index++, -1, ControlFlowNodeType.RegularExit);
			cfNodes.Add(regularExit);
			ControlFlowNode exceptionalExit = new ControlFlowNode(index++, -1, ControlFlowNodeType.ExceptionalExit);
			cfNodes.Add(exceptionalExit);
			
			// Create graph nodes
			labelToCfNode = new Dictionary<ILLabel, ControlFlowNode>();
			Dictionary<ILNode, ControlFlowNode> astNodeToCfNode = new Dictionary<ILNode, ControlFlowNode>();
			foreach(ILBasicBlock node in nodes) {
				ControlFlowNode cfNode = new ControlFlowNode(index++, -1, ControlFlowNodeType.Normal);
				cfNodes.Add(cfNode);
				astNodeToCfNode[node] = cfNode;
				cfNode.UserData = node;
				
				// Find all contained labels
                foreach (ILLabel label in node.EnumerateSelfAndChildrenRecursive().OfType<ILLabel>())
                {
					labelToCfNode[label] = cfNode;
				}
			}
			
			// Entry endge
			ControlFlowNode entryNode = labelToCfNode[entryLabel];
			ControlFlowEdge entryEdge = new ControlFlowEdge(entryPoint, entryNode, JumpType.Normal);
			entryPoint.Outgoing.Add(entryEdge);
			entryNode.Incoming.Add(entryEdge);
			
			// Create edges
			foreach(ILBasicBlock node in nodes) {
				ControlFlowNode source = astNodeToCfNode[node];

                var allBranchTargets =
                    from e in node.EnumerateSelfAndChildrenRecursive().OfType<ILExpression>()
                    where e.IsBranch()
                    from t in e.GetBranchTargets()
                    select t;

				// Find all branches
				foreach(ILLabel target in allBranchTargets) {
					ControlFlowNode destination;
					// Labels which are out of out scope will not be int the collection
					// Insert self edge only if we are sure we are a loop
					if (labelToCfNode.TryGetValue(target, out destination) && (destination != source || target == node.Body.FirstOrDefault())) {
						ControlFlowEdge edge = new ControlFlowEdge(source, destination, JumpType.Normal);
						source.Outgoing.Add(edge);
						destination.Incoming.Add(edge);
					}
				}
			}
			
			return new ControlFlowGraph(cfNodes.ToArray());
		}
Exemple #4
0
        ControlFlowGraph BuildGraph(List<ILNode> nodes, ILLabel entryLabel)
        {
            int index = 0;
            List<ControlFlowNode> cfNodes = new List<ControlFlowNode>();
            ControlFlowNode entryPoint = new ControlFlowNode(index++, 0, ControlFlowNodeType.EntryPoint);
            cfNodes.Add(entryPoint);
            ControlFlowNode regularExit = new ControlFlowNode(index++, -1, ControlFlowNodeType.RegularExit);
            cfNodes.Add(regularExit);
            ControlFlowNode exceptionalExit = new ControlFlowNode(index++, -1, ControlFlowNodeType.ExceptionalExit);
            cfNodes.Add(exceptionalExit);

            // Create graph nodes
            labelToCfNode = new Dictionary<ILLabel, ControlFlowNode>();
            Dictionary<ILNode, ControlFlowNode>  astNodeToCfNode = new Dictionary<ILNode, ControlFlowNode>();
            foreach(ILNode node in nodes) {
                ControlFlowNode cfNode = new ControlFlowNode(index++, -1, ControlFlowNodeType.Normal);
                cfNodes.Add(cfNode);
                astNodeToCfNode[node] = cfNode;
                cfNode.UserData = node;

                // Find all contained labels
                foreach(ILLabel label in node.GetSelfAndChildrenRecursive<ILLabel>()) {
                    labelToCfNode[label] = cfNode;
                }
            }

            // Entry endge
            ControlFlowNode entryNode = labelToCfNode[entryLabel];
            ControlFlowEdge entryEdge = new ControlFlowEdge(entryPoint, entryNode, JumpType.Normal);
            entryPoint.Outgoing.Add(entryEdge);
            entryNode.Incoming.Add(entryEdge);

            // Create edges
            foreach(ILNode node in nodes) {
                ControlFlowNode source = astNodeToCfNode[node];

                // Find all branches
                foreach(ILExpression child in node.GetSelfAndChildrenRecursive<ILExpression>()) {
                    IEnumerable<ILLabel> targets = child.GetBranchTargets();
                    if (targets != null) {
                        foreach(ILLabel target in targets) {
                            ControlFlowNode destination;
                            // Labels which are out of out scope will not be int the collection
                            if (labelToCfNode.TryGetValue(target, out destination) && destination != source) {
                                ControlFlowEdge edge = new ControlFlowEdge(source, destination, JumpType.Normal);
                                source.Outgoing.Add(edge);
                                destination.Incoming.Add(edge);
                            }
                        }
                    }
                }
            }

            return new ControlFlowGraph(cfNodes.ToArray());
        }
Exemple #5
0
		ControlFlowGraph BuildGraph(List<ILNode> nodes, ILLabel entryLabel)
		{
			cached_ControlFlowGraph.Nodes.Clear();
			int index = 0;
			var cfNodes = cached_ControlFlowGraph.Nodes;
			ControlFlowNode entryPoint = new ControlFlowNode(index++, 0, ControlFlowNodeType.EntryPoint);
			cfNodes.Add(entryPoint);
			ControlFlowNode regularExit = new ControlFlowNode(index++, null, ControlFlowNodeType.RegularExit);
			cfNodes.Add(regularExit);
			ControlFlowNode exceptionalExit = new ControlFlowNode(index++, null, ControlFlowNodeType.ExceptionalExit);
			cfNodes.Add(exceptionalExit);

			// Create graph nodes
			labelToCfNode.Clear();
			Dictionary<ILNode, ControlFlowNode> astNodeToCfNode = new Dictionary<ILNode, ControlFlowNode>();
			List<ILLabel> listLabels = null;
			foreach(ILBasicBlock node in nodes) {
				ControlFlowNode cfNode = new ControlFlowNode(index++, null, ControlFlowNodeType.Normal);
				cfNodes.Add(cfNode);
				astNodeToCfNode[node] = cfNode;
				cfNode.UserData = node;
				
				// Find all contained labels
				foreach(ILLabel label in node.GetSelfAndChildrenRecursive<ILLabel>(listLabels ?? (listLabels = new List<ILLabel>()))) {
					labelToCfNode[label] = cfNode;
				}
			}
			
			// Entry endge
			ControlFlowNode entryNode = labelToCfNode[entryLabel];
			ControlFlowEdge entryEdge = new ControlFlowEdge(entryPoint, entryNode, JumpType.Normal);
			entryPoint.Outgoing.Add(entryEdge);
			entryNode.Incoming.Add(entryEdge);

			// Create edges
			List<ILExpression> listExpressions = null;
			foreach(ILBasicBlock node in nodes) {
				ControlFlowNode source = astNodeToCfNode[node];
				
				// Find all branches
				foreach(ILLabel target in node.GetSelfAndChildrenRecursive<ILExpression>(listExpressions ?? (listExpressions = new List<ILExpression>()), e => e.IsBranch()).SelectMany(e => e.GetBranchTargets())) {
					ControlFlowNode destination;
					// Labels which are out of out scope will not be in the collection
					// Insert self edge only if we are sure we are a loop
					if (labelToCfNode.TryGetValue(target, out destination) && (destination != source || target == node.Body.FirstOrDefault())) {
						ControlFlowEdge edge = new ControlFlowEdge(source, destination, JumpType.Normal);
						source.Outgoing.Add(edge);
						destination.Incoming.Add(edge);
					}
				}
			}

			return cached_ControlFlowGraph;
		}
        /// <summary>
        /// Generates CIL for the statement.
        /// </summary>
        /// <param name="generator"> The generator to output the CIL to. </param>
        /// <param name="optimizationInfo"> Information about any optimizations that should be performed. </param>
        public override void GenerateCode(ILGenerator generator, OptimizationInfo optimizationInfo)
        {
            // Generate code for the start of the statement.
            var statementLocals = new StatementLocals() { NonDefaultSourceSpanBehavior = true };
            GenerateStartOfStatement(generator, optimizationInfo, statementLocals);

            // Unlike in .NET, in javascript there are no restrictions on what can appear inside
            // try, catch and finally blocks.  The one restriction which causes problems is the
            // inability to jump out of .NET finally blocks.  This is required when break, continue
            // or return statements appear inside of a finally block.  To work around this, when
            // inside a finally block these instructions throw an exception instead.

            // Setting the InsideTryCatchOrFinally flag converts BR instructions into LEAVE
            // instructions so that the finally block is executed correctly.
            var previousInsideTryCatchOrFinally = optimizationInfo.InsideTryCatchOrFinally;
            optimizationInfo.InsideTryCatchOrFinally = true;

            // Finally requires two exception nested blocks.
            if (this.FinallyBlock != null)
                generator.BeginExceptionBlock();

            // Begin the exception block.
            generator.BeginExceptionBlock();

            // Generate code for the try block.
            this.TryBlock.GenerateCode(generator, optimizationInfo);

            // Generate code for the catch block.
            if (this.CatchBlock != null)
            {
                // Begin a catch block.  The exception is on the top of the stack.
                generator.BeginCatchBlock(typeof(JavaScriptException));

                // Create a new DeclarativeScope.
                this.CatchScope.GenerateScopeCreation(generator, optimizationInfo);

                // Store the error object in the variable provided.
                generator.Call(ReflectionHelpers.JavaScriptException_ErrorObject);
                var catchVariable = new NameExpression(this.CatchScope, this.CatchVariableName);
                catchVariable.GenerateSet(generator, optimizationInfo, PrimitiveType.Any, false);

                // Make sure the scope is reverted even if an exception is thrown.
                generator.BeginExceptionBlock();

                // Emit code for the statements within the catch block.
                this.CatchBlock.GenerateCode(generator, optimizationInfo);

                // Revert the scope.
                generator.BeginFinallyBlock();
                this.CatchScope.GenerateScopeDestruction(generator, optimizationInfo);
                generator.EndExceptionBlock();
            }

            // Generate code for the finally block.
            if (this.FinallyBlock != null)
            {
                generator.BeginFinallyBlock();

                var branches = new List<ILLabel>();
                var previousStackSize = optimizationInfo.LongJumpStackSizeThreshold;
                optimizationInfo.LongJumpStackSizeThreshold = optimizationInfo.BreakOrContinueStackSize;
                var previousCallback = optimizationInfo.LongJumpCallback;
                optimizationInfo.LongJumpCallback = (generator2, label) =>
                    {
                        // It is not possible to branch out of a finally block - therefore instead of
                        // generating LEAVE instructions we throw an exception then catch it to transfer
                        // control out of the finally block.
                        generator2.LoadInt32(branches.Count);
                        generator2.NewObject(ReflectionHelpers.LongJumpException_Constructor);
                        generator2.Throw();

                        // Record any branches that are made within the finally code.
                        branches.Add(label);
                    };

                // Emit code for the finally block.
                this.FinallyBlock.GenerateCode(generator, optimizationInfo);

                // End the main exception block.
                generator.EndExceptionBlock();

                // Begin a catch block to catch any LongJumpExceptions. The exception object is on
                // the top of the stack.
                generator.BeginCatchBlock(typeof(LongJumpException));

                if (branches.Count > 0)
                {
                    // switch (exception.RouteID)
                    // {
                    //    case 0: goto label1;
                    //    case 1: goto label2;
                    // }
                    ILLabel[] switchLabels = new ILLabel[branches.Count];
                    for (int i = 0; i < branches.Count; i++)
                        switchLabels[i] = generator.CreateLabel();
                    generator.Call(ReflectionHelpers.LongJumpException_RouteID);
                    generator.Switch(switchLabels);
                    for (int i = 0; i < branches.Count; i++)
                    {
                        generator.DefineLabelPosition(switchLabels[i]);
                        generator.Leave(branches[i]);
                    }
                }

                // Reset the state we clobbered.
                optimizationInfo.LongJumpStackSizeThreshold = previousStackSize;
                optimizationInfo.LongJumpCallback = previousCallback;
            }

            // End the exception block.
            generator.EndExceptionBlock();

            // Reset the InsideTryCatchOrFinally flag.
            optimizationInfo.InsideTryCatchOrFinally = previousInsideTryCatchOrFinally;

            // Generate code for the end of the statement.
            GenerateEndOfStatement(generator, optimizationInfo, statementLocals);
        }
Exemple #7
0
 protected  ILExpression CreateExpression(GMCode code,  GM_Type[] types, ILLabel operand)
 {
     Debug.Assert(operand != null);
     ILExpression e = new ILExpression(code, operand);
     e.Types = types;
     e.Extra = (int)(CurrentRaw & 0xFFFF);
     e.AddILRange(CurrentPC);
     return e;
 }
Exemple #8
0
 /// <summary>
 /// Defines the position of the given label.
 /// </summary>
 /// <param name="label"> The label to define. </param>
 public abstract void DefineLabelPosition(ILLabel label);
		void AnalyzeMoveNext()
		{
			MethodDefinition moveNextMethod = enumeratorType.Methods.FirstOrDefault(m => m.Name == "MoveNext");
			ILBlock ilMethod = CreateILAst(moveNextMethod);
			
			if (ilMethod.Body.Count == 0)
				throw new SymbolicAnalysisFailedException();
			ILExpression lastReturnArg;
			if (!ilMethod.Body.Last().Match(ILCode.Ret, out lastReturnArg))
				throw new SymbolicAnalysisFailedException();
			
			// There are two possibilities:
			if (lastReturnArg.Code == ILCode.Ldloc) {
				// a) the compiler uses a variable for returns (in debug builds, or when there are try-finally blocks)
				returnVariable = (ILVariable)lastReturnArg.Operand;
				returnLabel = ilMethod.Body.ElementAtOrDefault(ilMethod.Body.Count - 2) as ILLabel;
				if (returnLabel == null)
					throw new SymbolicAnalysisFailedException();
			} else {
				// b) the compiler directly returns constants
				returnVariable = null;
				returnLabel = null;
				// In this case, the last return must return false.
				if (lastReturnArg.Code != ILCode.Ldc_I4 || (int)lastReturnArg.Operand != 0)
					throw new SymbolicAnalysisFailedException();
			}
			
			ILTryCatchBlock tryFaultBlock = ilMethod.Body[0] as ILTryCatchBlock;
			List<ILNode> body;
			int bodyLength;
			if (tryFaultBlock != null) {
				// there are try-finally blocks
				if (returnVariable == null) // in this case, we must use a return variable
					throw new SymbolicAnalysisFailedException();
				// must be a try-fault block:
				if (tryFaultBlock.CatchBlocks.Count != 0 || tryFaultBlock.FinallyBlock != null || tryFaultBlock.FaultBlock == null)
					throw new SymbolicAnalysisFailedException();
				
				ILBlock faultBlock = tryFaultBlock.FaultBlock;
				// Ensure the fault block contains the call to Dispose().
				if (faultBlock.Body.Count != 2)
					throw new SymbolicAnalysisFailedException();
				MethodReference disposeMethodRef;
				ILExpression disposeArg;
				if (!faultBlock.Body[0].Match(ILCode.Call, out disposeMethodRef, out disposeArg))
					throw new SymbolicAnalysisFailedException();
				if (GetMethodDefinition(disposeMethodRef) != disposeMethod || !disposeArg.MatchThis())
					throw new SymbolicAnalysisFailedException();
				if (!faultBlock.Body[1].Match(ILCode.Endfinally))
					throw new SymbolicAnalysisFailedException();
				
				body = tryFaultBlock.TryBlock.Body;
				bodyLength = body.Count;
			} else {
				// no try-finally blocks
				body = ilMethod.Body;
				if (returnVariable == null)
					bodyLength = body.Count - 1; // all except for the return statement
				else
					bodyLength = body.Count - 2; // all except for the return label and statement
			}
			
			// Now verify that the last instruction in the body is 'ret(false)'
			if (returnVariable != null) {
				// If we don't have a return variable, we already verified that above.
				// If we do have one, check for 'stloc(returnVariable, ldc.i4(0))'
				
				// Maybe might be a jump to the return label after the stloc:
				ILExpression leave = body.ElementAtOrDefault(bodyLength - 1) as ILExpression;
				if (leave != null && (leave.Code == ILCode.Br || leave.Code == ILCode.Leave) && leave.Operand == returnLabel)
					bodyLength--;
				ILExpression store0 = body.ElementAtOrDefault(bodyLength - 1) as ILExpression;
				if (store0 == null || store0.Code != ILCode.Stloc || store0.Operand != returnVariable)
					throw new SymbolicAnalysisFailedException();
				if (store0.Arguments[0].Code != ILCode.Ldc_I4 || (int)store0.Arguments[0].Operand != 0)
					throw new SymbolicAnalysisFailedException();
				
				bodyLength--; // don't conside the stloc instruction to be part of the body
			}
			// The last element in the body usually is a label pointing to the 'ret(false)'
			returnFalseLabel = body.ElementAtOrDefault(bodyLength - 1) as ILLabel;
			// Note: in Roslyn-compiled code, returnFalseLabel may be null.
			
			var rangeAnalysis = new StateRangeAnalysis(body[0], StateRangeAnalysisMode.IteratorMoveNext, stateField);
			int pos = rangeAnalysis.AssignStateRanges(body, bodyLength);
			rangeAnalysis.EnsureLabelAtPos(body, ref pos, ref bodyLength);
			
			var labels = rangeAnalysis.CreateLabelRangeMapping(body, pos, bodyLength);
			ConvertBody(body, pos, bodyLength, labels);
		}
 /// <summary>
 /// Unconditionally branches to the given label.
 /// </summary>
 /// <param name="label"> The label to branch to. </param>
 public override void Branch(ILLabel label)
 {
     Log("br", label);
     this.generator.Branch(label);
 }
Exemple #11
0
 /// <summary>
 /// Branches to the given label if the two values on the top of the stack are not equal.
 /// </summary>
 /// <param name="label"> The label to branch to. </param>
 public abstract void BranchIfNotEqual(ILLabel label);
 /// <summary>
 /// Unconditionally branches to the given label.  Unlike the regular branch instruction,
 /// this instruction can exit out of try, filter and catch blocks.
 /// </summary>
 /// <param name="label"> The label to branch to. </param>
 public override void Leave(ILLabel label)
 {
     Log("leave", label);
     this.generator.Leave(label);
 }
 /// <summary>
 /// Outputs an instruction and a label to the log.
 /// </summary>
 /// <param name="instruction"> The instruction to output. </param>
 /// <param name="label"> The label to output. </param>
 private void Log(string instruction, ILLabel label)
 {
     LogInstruction(instruction, string.Empty);
     AppendLabel(label);
 }
Exemple #14
0
        public bool DetectSwitch_GenerateBranches(IList <ILNode> body, ILBasicBlock head, int pos)
        {
            bool         modified = false;
            ILExpression condition;
            ILLabel      trueLabel;
            ILLabel      falseLabel;
            ILLabel      fallThough;

            //    Debug.Assert(head.EntryLabel().Name != "Block_473");
            if (MatchSwitchCase(head, out trueLabel, out fallThough, out condition))   // we ignore this first match, but remember the position
            {
                List <ILExpression> cases        = new List <ILExpression>();
                List <ILNode>       caseBlocks   = new List <ILNode>();
                ILLabel             prev         = head.EntryLabel();
                ILBasicBlock        startOfCases = head;
                cases.Add(PreSetUpCaseBlock(startOfCases, condition));
                caseBlocks.Add(startOfCases);

                for (int i = pos - 1; i >= 0; i--)
                {
                    ILBasicBlock bb = body[i] as ILBasicBlock;
                    if (MatchSwitchCase(bb, out trueLabel, out falseLabel, out condition))
                    {
                        caseBlocks.Add(bb);
                        cases.Add(PreSetUpCaseBlock(bb, condition));

                        Debug.Assert(falseLabel == prev);
                        prev         = bb.EntryLabel();
                        startOfCases = bb;
                    }
                    else
                    {
                        break;
                    }
                }
                // we have all the cases
                // head is at the "head" of the cases
                ILExpression left;
                if (startOfCases.Body[startOfCases.Body.Count - 3].Match(GMCode.Push, out left))
                {
                    startOfCases.Body.RemoveAt(startOfCases.Body.Count - 3);
                    foreach (var e in cases)
                    {
                        e.Arguments.Insert(0, new ILExpression(left));                     // add the expression to all the branches
                    }
                }
                else
                {
                    throw new Exception("switch failure");
                }
                // It seems GM makes a default case that just jumps to the end of the switch but I cannot
                // rely on it always being there
                ILBasicBlock default_case = body[pos + 1] as ILBasicBlock;
                Debug.Assert(default_case.EntryLabel() == head.GotoLabel());
                ILBasicBlock end_of_switch = labelToBasicBlock[default_case.GotoLabel()];
                if ((end_of_switch.Body[1] as ILExpression).Code == GMCode.Popz)
                {
                    end_of_switch.Body.RemoveAt(1); // yeaa!
                }
                else // booo
                { // We have a default case so now we have to find where the popz ends,
                    // this could be bad if we had a wierd generated for loop, but we are just doing stupid search
                    ILBasicBlock test1 = FindEndOfSwitch(end_of_switch);
                    // we take a sample from one of the cases to make sure we do end up at the same place
                    ILBasicBlock test2 = FindEndOfSwitch(head);
                    if (test1 == test2)
                    {                           // two matches are good enough for me
                        test1.Body.RemoveAt(1); // yeaa!
                    }
                    else
                    {
                        error.Error("Cannot find end of switch", end_of_switch); // booo
                    }
                }
                // tricky part, finding that damn popz

                // Ok, we have all the case blocks, they are all fixed, and its like a big chain of ifs now.
                // But for anything OTHER than lua that has switch statments, we want to mark this for latter

                modified |= true;
            }
            return(modified);
        }
Exemple #15
0
        public bool DetectSwitch_GenerateSwitch(IList <ILNode> body, ILBasicBlock head, int pos)
        {
            ILExpression condition;
            ILLabel      trueLabel;
            ILLabel      fallThough;

            // REMEMBER:  The searching goes backwards, so we find the FIRST case here, so here is the problem
            // Evey time we run this, we have to search for the first block of the case statement backwards and if
            // the push var is not resolved, we have to drop out... evey single time till the push IS resolved
            // so be sure to run this at the bottom of the decision chain.  Its fine if the push is a simple var
            // but I can bet cash this runs 2-3 times if the push is some kind of expression like 5 + (3 % switch_var))
            // we could change the way the optimizing loop works by going from the start and building a que of things
            // to remove, delete or change hummm...  Take longer but it would make building this functions MUCH simpler
            if (MatchSwitchCase(head, out trueLabel, out fallThough, out condition) &&
                !MatchSwitchCase(body.ElementAtOrDefault(pos - 1) as ILBasicBlock, out trueLabel, out fallThough, out condition)
                )  // && head.MatchLastAt(6, GMCode.Push,out switch_expr))
            {
                List <ILBasicBlock> caseBlocks = GetAllCaseBlocks(body, head, pos, out condition, out fallThough);
                if (caseBlocks == null)
                {
                    return(false);
                }
                ILExpression fswitch = new ILExpression(GMCode.Switch, null);
                FakeSwitch   args    = new FakeSwitch();
                args.SwitchExpression = condition;
                args.CaseExpressions  = caseBlocks.Select(bb =>
                                                          new KeyValuePair <ILExpression, ILLabel>((bb.ElementAtLast(3) as ILExpression).Arguments[0], (bb.ElementAtLast(1) as ILExpression).Operand as ILLabel)
                                                          ).ToList();

                fswitch.Operand = args;
                // search the blocks for ending popz's and remove the popz
                HashSet <ILBasicBlock> blocks_done = new HashSet <ILBasicBlock>();
                Stack <ILBasicBlock>   agenda      = new Stack <ILBasicBlock>(caseBlocks);
                while (agenda.Count > 0)
                {
                    ILBasicBlock bb = agenda.Pop();
                    if (blocks_done.Contains(bb))
                    {
                        continue;                           // already did it
                    }
                    ILExpression popz = bb.Body.OfType <ILExpression>().Where(e => e.Code == GMCode.Popz).SingleOrDefault();
                    if (popz != null)
                    {
                        bb.Body.Remove(popz); // remove it
                    }
                    else
                    {
                        ILLabel exit = bb.OperandLabelLastAt(0);
                        if (exit != null && !blocks_done.Contains(labelToBasicBlock[exit]))
                        {
                            agenda.Push(labelToBasicBlock[exit]);
                        }
                        exit = bb.OperandLabelLastAt(1); // check if we have a bt or something
                        if (exit != null && !blocks_done.Contains(labelToBasicBlock[exit]))
                        {
                            agenda.Push(labelToBasicBlock[exit]);
                        }
                    }
                    blocks_done.Add(bb);
                }
                ILBasicBlock startOfAllCases = caseBlocks.First();
                caseBlocks.Remove(startOfAllCases);
                startOfAllCases.Body.RemoveTail(GMCode.Dup, GMCode.Push, GMCode.Seq, GMCode.Bt, GMCode.B);
                startOfAllCases.Body.Add(fswitch);
                startOfAllCases.Body.Add(new ILExpression(GMCode.B, fallThough)); //  end_of_switch.EntryLabel()));
                body.RemoveAll(caseBlocks);

                return(true);
            }


            return(false);
        }
Exemple #16
0
        public List <ILBasicBlock> GetAllCaseBlocks(IList <ILNode> body, ILBasicBlock head, int pos, out ILExpression condition, out ILLabel fallout)
        {
            ILExpression        fswitch    = new ILExpression(GMCode.Switch, null);
            List <ILBasicBlock> caseBlocks = new List <ILBasicBlock>();
            int     swtichStart            = pos;
            ILLabel trueLabel;
            ILLabel falseLabel;

            while (MatchSwitchCase(head, out trueLabel, out falseLabel, out condition))
            {
                caseBlocks.Add(head);
                head = body.ElementAtOrDefault(++swtichStart) as ILBasicBlock;
            }
            ILBasicBlock switchHead = caseBlocks.First();

            if (!switchHead.ElementAtLastOrDefault(5).isNodeResolved())
            {
                fallout = null; condition = null; return(null);
            }
            //   caseBlocks.Reverse(); // reverse the order so its correct
            Debug.Assert(switchHead.MatchLastAt(6, GMCode.Push, out condition)); // return false;
            switchHead.RemoveAt(switchHead.Body.Count - 6);                      // ugh, might have to change the matchLastAt
            fallout = caseBlocks.Last().OperandLabelLastAt(0);
            return(caseBlocks);
        }
Exemple #17
0
 /// <summary>
 /// Branches to the given label if the first value on the stack is greater than the second
 /// value on the stack.  If the operands are integers then they are treated as if they are
 /// unsigned.  If the operands are floating point numbers then a NaN value will trigger a
 /// branch.
 /// </summary>
 /// <param name="label"> The label to branch to. </param>
 public abstract void BranchIfGreaterThanUnsigned(ILLabel label);
 /// <summary>
 /// Branches to the given label if the value on the top of the stack is zero.
 /// </summary>
 /// <param name="label"> The label to branch to. </param>
 public override void BranchIfZero(ILLabel label)
 {
     Log("brfalse", label);
     this.generator.BranchIfZero(label);
 }
Exemple #19
0
 /// <summary>
 /// Branches to the given label if the first value on the stack is less than or equal to
 /// the second value on the stack.
 /// </summary>
 /// <param name="label"> The label to branch to. </param>
 public abstract void BranchIfLessThanOrEqual(ILLabel label);
 /// <summary>
 /// Branches to the given label if the value on the top of the stack is non-zero, true or
 /// non-null.
 /// </summary>
 /// <param name="label"> The label to branch to. </param>
 public override void BranchIfNotZero(ILLabel label)
 {
     Log("brtrue", label);
     this.generator.BranchIfNotZero(label);
 }
Exemple #21
0
 /// <summary>
 /// Branches to the given label if the value on the top of the stack is non-zero, true or
 /// non-null.
 /// </summary>
 /// <param name="label"> The label to branch to. </param>
 public void BranchIfTrue(ILLabel label)
 {
     BranchIfNotZero(label);
 }
 /// <summary>
 /// Branches to the given label if the two values on the top of the stack are not equal.
 /// </summary>
 /// <param name="label"> The label to branch to. </param>
 public override void BranchIfNotEqual(ILLabel label)
 {
     Log("bne", label);
     this.generator.BranchIfNotEqual(label);
 }
Exemple #23
0
 /// <summary>
 /// Creates a jump table.  A value is popped from the stack - this value indicates the
 /// index of the label in the <paramref name="labels"/> array to jump to.
 /// </summary>
 /// <param name="labels"> A array of labels. </param>
 public abstract void Switch(ILLabel[] labels);
 /// <summary>
 /// Branches to the given label if the first value on the stack is greater than the second
 /// value on the stack.
 /// </summary>
 /// <param name="label"> The label to branch to. </param>
 public override void BranchIfGreaterThan(ILLabel label)
 {
     Log("bgt", label);
     this.generator.BranchIfGreaterThan(label);
 }
		ILExpression MakeGoTo(ILLabel targetLabel)
		{
			Debug.Assert(targetLabel != null);
			if (targetLabel == returnFalseLabel)
				return new ILExpression(ILCode.YieldBreak, null);
			else
				return new ILExpression(ILCode.Br, targetLabel);
		}
 /// <summary>
 /// Branches to the given label if the first value on the stack is greater than the second
 /// value on the stack.  If the operands are integers then they are treated as if they are
 /// unsigned.  If the operands are floating point numbers then a NaN value will trigger a
 /// branch.
 /// </summary>
 /// <param name="label"> The label to branch to. </param>
 public override void BranchIfGreaterThanUnsigned(ILLabel label)
 {
     Log("bgt.un", label);
     this.generator.BranchIfGreaterThanUnsigned(label);
 }
Exemple #27
0
        List<ILNode> FindLoops(HashSet<ControlFlowNode> nodes, ControlFlowNode entryPoint, bool excludeEntryPoint)
        {
            List<ILNode> result = new List<ILNode>();

            Queue<ControlFlowNode> agenda  = new Queue<ControlFlowNode>();
            agenda.Enqueue(entryPoint);
            while(agenda.Count > 0) {
                ControlFlowNode node = agenda.Dequeue();

                if (nodes.Contains(node)
                        && node.DominanceFrontier.Contains(node)
                        && (node != entryPoint || !excludeEntryPoint))
                {
                    HashSet<ControlFlowNode> loopContents = new HashSet<ControlFlowNode>();
                    FindLoopContents(nodes, loopContents, node, node);

                    // Move the content into loop block
                    nodes.ExceptWith(loopContents);
                    ILLabel entryLabel = new ILLabel() { Name = "Loop_" + (nextBlockIndex++) };
                    ((ILBlock)node.UserData).Body.Insert(0, entryLabel);
                    result.Add(new ILLoop() { ContentBlock = new ILBlock(FindLoops(loopContents, node, true)) { EntryPoint = entryLabel } });
                }

                // Using the dominator tree should ensure we find the the widest loop first
                foreach(var child in node.DominatorTreeChildren) {
                    agenda.Enqueue(child);
                }
            }

            // Add whatever is left
            foreach(var node in nodes) {
                result.Add((ILNode)node.UserData);
            }

            return result;
        }
 /// <summary>
 /// Branches to the given label if the first value on the stack is greater than or equal to
 /// the second value on the stack.
 /// </summary>
 /// <param name="label"> The label to branch to. </param>
 public override void BranchIfGreaterThanOrEqual(ILLabel label)
 {
     Log("bge", label);
     this.generator.BranchIfGreaterThanOrEqual(label);
 }
Exemple #29
0
        /// <summary>
        /// Searches for the given label in the break/continue stack.
        /// </summary>
        /// <param name="label"></param>
        /// <returns> The depth of the label in the stack.  Zero indicates the bottom of the stack.
        /// <c>-1</c> is returned if the label was not found. </returns>
        private int GetBreakOrContinueLabelDepth(ILLabel label)
        {
            if (label == null)
                throw new ArgumentNullException("label");

            int depth = this.breakOrContinueStack.Count - 1;
            foreach (var info in this.breakOrContinueStack)
            {
                if (info.BreakTarget == label)
                    return depth;
                if (info.ContinueTarget == label)
                    return depth;
                depth --;
            }
            return -1;
        }
 /// <summary>
 /// Branches to the given label if the first value on the stack is less than the second
 /// value on the stack.
 /// </summary>
 /// <param name="label"> The label to branch to. </param>
 public override void BranchIfLessThan(ILLabel label)
 {
     Log("blt", label);
     this.generator.BranchIfLessThan(label);
 }
Exemple #31
0
        public bool DetectSwitchAndConvertToBranches(IList <ILNode> body, ILBasicBlock head, int pos)
        {
            ILExpression condition;
            ILLabel      trueLabel;
            ILLabel      fallThough;

            // REMEMBER:  The searching goes backwards, so we find the LAST case here, so here is the problem
            // Evey time we run this, we have to search for the first block of the case statement backwards and if
            // the push var is not resolved, we have to drop out... evey single time till the push IS resolved
            // so be sure to run this at the bottom of the decision chain.  Its fine if the push is a simple var
            // but I can bet cash this runs 2-3 times if the push is some kind of expression like 5 + (3 % switch_var))
            // we could change the way the optimizing loop works by going from the start and building a que of things
            // to remove, delete or change hummm...  Take longer but it would make building this functions MUCH simpler
            if (MatchSwitchCase(head, out trueLabel, out fallThough, out condition))  // && head.MatchLastAt(6, GMCode.Push,out switch_expr))
            {
                List <ILBasicBlock> caseBlocks = GetAllCaseBlocks(body, head, pos, out condition, out fallThough);

                foreach (var bb in caseBlocks) // replace the dup statements
                {
                    Debug.Assert(bb.MatchLastAt(5, GMCode.Dup));
                    bb.Body[bb.Body.Count - 5] = new ILExpression(GMCode.Push, null, condition);
                    ILExpression expr = bb.Body[bb.Body.Count - 3] as ILExpression;
                    //   expr.Code = GMCode.Case; // conver the equals to a case
                }
                // search the blocks for ending popz's
                HashSet <ILBasicBlock> blocks_done = new HashSet <ILBasicBlock>();
                Stack <ILBasicBlock>   agenda      = new Stack <ILBasicBlock>(caseBlocks);
                while (agenda.Count > 0)
                {
                    ILBasicBlock bb = agenda.Pop();
                    if (blocks_done.Contains(bb))
                    {
                        continue;                           // already did it
                    }
                    ILExpression popz = bb.Body.OfType <ILExpression>().Where(e => e.Code == GMCode.Popz).SingleOrDefault();
                    if (popz != null)
                    {
                        bb.Body.Remove(popz); // remove it
                        blocks_done.Add(bb);
                    }
                    else
                    {
                        ILLabel exit = bb.OperandLabelLastAt(0);
                        if (exit != null && !blocks_done.Contains(labelToBasicBlock[exit]))
                        {
                            agenda.Push(labelToBasicBlock[exit]);
                        }
                        exit = bb.OperandLabelLastAt(1); // check if we have a bt or something
                        if (exit != null && !blocks_done.Contains(labelToBasicBlock[exit]))
                        {
                            agenda.Push(labelToBasicBlock[exit]);
                        }
                    }
                }


                return(true);
            }


            return(false);
        }
 /// <summary>
 /// Branches to the given label if the first value on the stack is less than or equal to
 /// the second value on the stack.
 /// </summary>
 /// <param name="label"> The label to branch to. </param>
 public override void BranchIfLessThanOrEqual(ILLabel label)
 {
     Log("ble", label);
     this.generator.BranchIfLessThanOrEqual(label);
 }
Exemple #33
0
 /// <summary>
 /// Branches to the given label if the first value on the stack is greater than or equal to
 /// the second value on the stack.
 /// </summary>
 /// <param name="label"> The label to branch to. </param>
 public abstract void BranchIfGreaterThanOrEqual(ILLabel label);
 /// <summary>
 /// Branches to the given label if the first value on the stack is less than or equal to
 /// the second value on the stack.  If the operands are integers then they are treated as
 /// if they are unsigned.  If the operands are floating point numbers then a NaN value will
 /// trigger a branch.
 /// </summary>
 /// <param name="label"> The label to branch to. </param>
 public override void BranchIfLessThanOrEqualUnsigned(ILLabel label)
 {
     Log("ble.un", label);
     this.generator.BranchIfLessThanOrEqualUnsigned(label);
 }
Exemple #35
0
 /// <summary>
 /// Branches to the given label if the first value on the stack is less than the second
 /// value on the stack.
 /// </summary>
 /// <param name="label"> The label to branch to. </param>
 public abstract void BranchIfLessThan(ILLabel label);
Exemple #36
0
 /// <summary>
 /// Branches to the given label if the value on the top of the stack is zero, false or
 /// null.
 /// </summary>
 /// <param name="label"> The label to branch to. </param>
 public void BranchIfFalse(ILLabel label)
 {
     BranchIfZero(label);
 }
Exemple #37
0
 /// <summary>
 /// Branches to the given label if the first value on the stack is less than the second
 /// value on the stack.  If the operands are integers then they are treated as if they are
 /// unsigned.  If the operands are floating point numbers then a NaN value will trigger a
 /// branch.
 /// </summary>
 /// <param name="label"> The label to branch to. </param>
 public abstract void BranchIfLessThanUnsigned(ILLabel label);
Exemple #38
0
 /// <summary>
 /// Branches to the given label if the value on the top of the stack is non-zero, true or
 /// non-null.
 /// </summary>
 /// <param name="label"> The label to branch to. </param>
 public void BranchIfTrue(ILLabel label)
 {
     BranchIfNotZero(label);
 }
Exemple #39
0
 /// <summary>
 /// Branches to the given label if the value on the top of the stack is zero, false or
 /// null.
 /// </summary>
 /// <param name="label"> The label to branch to. </param>
 public void BranchIfNull(ILLabel label)
 {
     BranchIfZero(label);
 }
Exemple #40
0
 /// <summary>
 /// Branches to the given label if the value on the top of the stack is non-zero, true or
 /// non-null.
 /// </summary>
 /// <param name="label"> The label to branch to. </param>
 public void BranchIfNotNull(ILLabel label)
 {
     BranchIfNotZero(label);
 }
Exemple #41
0
 /// <summary>
 /// Branches to the given label if the value on the top of the stack is zero, false or
 /// null.
 /// </summary>
 /// <param name="label"> The label to branch to. </param>
 public abstract void BranchIfZero(ILLabel label);
Exemple #42
0
 /// <summary>
 /// Branches to the given label if the two values on the top of the stack are not equal.
 /// </summary>
 /// <param name="label"> The label to branch to. </param>
 public abstract void BranchIfNotEqual(ILLabel label);
Exemple #43
0
 /// <summary>
 /// Unconditionally branches to the given label.  Unlike the regular branch instruction,
 /// this instruction can exit out of try, filter and catch blocks.
 /// </summary>
 /// <param name="label"> The label to branch to. </param>
 public abstract void Leave(ILLabel label);
Exemple #44
0
 /// <summary>
 /// Branches to the given label if the first value on the stack is greater than the second
 /// value on the stack.
 /// </summary>
 /// <param name="label"> The label to branch to. </param>
 public abstract void BranchIfGreaterThan(ILLabel label);
		void AnalyzeMoveNext()
		{
			MethodDefinition moveNextMethod = enumeratorType.Methods.FirstOrDefault(m => m.Name == "MoveNext");
			ILBlock ilMethod = CreateILAst(moveNextMethod);
			
			if (ilMethod.Body.Count == 0)
				throw new YieldAnalysisFailedException();
			ILExpression lastReturnArg;
			if (!ilMethod.Body.Last().Match(ILCode.Ret, out lastReturnArg))
				throw new YieldAnalysisFailedException();
			
			// There are two possibilities:
			if (lastReturnArg.Code == ILCode.Ldloc) {
				// a) the compiler uses a variable for returns (in debug builds, or when there are try-finally blocks)
				returnVariable = (ILVariable)lastReturnArg.Operand;
				returnLabel = ilMethod.Body.ElementAtOrDefault(ilMethod.Body.Count - 2) as ILLabel;
				if (returnLabel == null)
					throw new YieldAnalysisFailedException();
			} else {
				// b) the compiler directly returns constants
				returnVariable = null;
				returnLabel = null;
				// In this case, the last return must return false.
				if (lastReturnArg.Code != ILCode.Ldc_I4 || (int)lastReturnArg.Operand != 0)
					throw new YieldAnalysisFailedException();
			}
			
			ILTryCatchBlock tryFaultBlock = ilMethod.Body[0] as ILTryCatchBlock;
			List<ILNode> body;
			int bodyLength;
			if (tryFaultBlock != null) {
				// there are try-finally blocks
				if (returnVariable == null) // in this case, we must use a return variable
					throw new YieldAnalysisFailedException();
				// must be a try-fault block:
				if (tryFaultBlock.CatchBlocks.Count != 0 || tryFaultBlock.FinallyBlock != null || tryFaultBlock.FaultBlock == null)
					throw new YieldAnalysisFailedException();
				
				ILBlock faultBlock = tryFaultBlock.FaultBlock;
				// Ensure the fault block contains the call to Dispose().
				if (faultBlock.Body.Count != 2)
					throw new YieldAnalysisFailedException();
				MethodReference disposeMethodRef;
				ILExpression disposeArg;
				if (!faultBlock.Body[0].Match(ILCode.Call, out disposeMethodRef, out disposeArg))
					throw new YieldAnalysisFailedException();
				if (GetMethodDefinition(disposeMethodRef) != disposeMethod || !LoadFromArgument.This.Match(disposeArg))
					throw new YieldAnalysisFailedException();
				if (!faultBlock.Body[1].Match(ILCode.Endfinally))
					throw new YieldAnalysisFailedException();
				
				body = tryFaultBlock.TryBlock.Body;
				bodyLength = body.Count;
			} else {
				// no try-finally blocks
				body = ilMethod.Body;
				if (returnVariable == null)
					bodyLength = body.Count - 1; // all except for the return statement
				else
					bodyLength = body.Count - 2; // all except for the return label and statement
			}
			
			// Now verify that the last instruction in the body is 'ret(false)'
			if (returnVariable != null) {
				// If we don't have a return variable, we already verified that above.
				// If we do have one, check for 'stloc(returnVariable, ldc.i4(0))'
				
				// Maybe might be a jump to the return label after the stloc:
				ILExpression leave = body.ElementAtOrDefault(bodyLength - 1) as ILExpression;
				if (leave != null && (leave.Code == ILCode.Br || leave.Code == ILCode.Leave) && leave.Operand == returnLabel)
					bodyLength--;
				ILExpression store0 = body.ElementAtOrDefault(bodyLength - 1) as ILExpression;
				if (store0 == null || store0.Code != ILCode.Stloc || store0.Operand != returnVariable)
					throw new YieldAnalysisFailedException();
				if (store0.Arguments[0].Code != ILCode.Ldc_I4 || (int)store0.Arguments[0].Operand != 0)
					throw new YieldAnalysisFailedException();
				
				bodyLength--; // don't conside the stloc instruction to be part of the body
			}
			// verify that the last element in the body is a label pointing to the 'ret(false)'
			returnFalseLabel = body.ElementAtOrDefault(bodyLength - 1) as ILLabel;
			if (returnFalseLabel == null)
				throw new YieldAnalysisFailedException();
			
			InitStateRanges(body[0]);
			int pos = AssignStateRanges(body, bodyLength, forDispose: false);
			if (pos > 0 && body[pos - 1] is ILLabel) {
				pos--;
			} else {
				// ensure that the first element at body[pos] is a label:
				ILLabel newLabel = new ILLabel();
				newLabel.Name = "YieldReturnEntryPoint";
				ranges[newLabel] = ranges[body[pos]]; // give the label the range of the instruction at body[pos]
				
				body.Insert(pos, newLabel);
				bodyLength++;
			}
			
			List<KeyValuePair<ILLabel, StateRange>> labels = new List<KeyValuePair<ILLabel, StateRange>>();
			for (int i = pos; i < bodyLength; i++) {
				ILLabel label = body[i] as ILLabel;
				if (label != null) {
					labels.Add(new KeyValuePair<ILLabel, StateRange>(label, ranges[label]));
				}
			}
			
			ConvertBody(body, pos, bodyLength, labels);
		}
Exemple #46
0
 /// <summary>
 /// Branches to the given label if the first value on the stack is greater than or equal to
 /// the second value on the stack.  If the operands are integers then they are treated as
 /// if they are unsigned.  If the operands are floating point numbers then a NaN value will
 /// trigger a branch.
 /// </summary>
 /// <param name="label"> The label to branch to. </param>
 public abstract void BranchIfGreaterThanOrEqualUnsigned(ILLabel label);
		void ConvertBody(List<ILNode> body, int startPos, int bodyLength, List<KeyValuePair<ILLabel, StateRange>> labels)
		{
			newBody = new List<ILNode>();
			newBody.Add(MakeGoTo(labels, 0));
			List<SetState> stateChanges = new List<SetState>();
			int currentState = -1;
			// Copy all instructions from the old body to newBody.
			for (int pos = startPos; pos < bodyLength; pos++) {
				ILExpression expr = body[pos] as ILExpression;
				if (expr != null && expr.Code == ILCode.Stfld && expr.Arguments[0].MatchThis()) {
					// Handle stores to 'state' or 'current'
					if (GetFieldDefinition(expr.Operand as FieldReference) == stateField) {
						if (expr.Arguments[1].Code != ILCode.Ldc_I4)
							throw new SymbolicAnalysisFailedException();
						currentState = (int)expr.Arguments[1].Operand;
						stateChanges.Add(new SetState(newBody.Count, currentState));
					} else if (GetFieldDefinition(expr.Operand as FieldReference) == currentField) {
						newBody.Add(new ILExpression(ILCode.YieldReturn, null, expr.Arguments[1]));
					} else {
						newBody.Add(body[pos]);
					}
				} else if (returnVariable != null && expr != null && expr.Code == ILCode.Stloc && expr.Operand == returnVariable) {
					// handle store+branch to the returnVariable
					ILExpression br = body.ElementAtOrDefault(++pos) as ILExpression;
					if (br == null || !(br.Code == ILCode.Br || br.Code == ILCode.Leave) || br.Operand != returnLabel || expr.Arguments[0].Code != ILCode.Ldc_I4)
						throw new SymbolicAnalysisFailedException();
					int val = (int)expr.Arguments[0].Operand;
					if (val == 0) {
						newBody.Add(new ILExpression(ILCode.YieldBreak, null));
					} else if (val == 1) {
						newBody.Add(MakeGoTo(labels, currentState));
					} else {
						throw new SymbolicAnalysisFailedException();
					}
				} else if (expr != null && expr.Code == ILCode.Ret) {
					if (expr.Arguments.Count != 1 || expr.Arguments[0].Code != ILCode.Ldc_I4)
						throw new SymbolicAnalysisFailedException();
					// handle direct return (e.g. in release builds)
					int val = (int)expr.Arguments[0].Operand;
					if (val == 0) {
						newBody.Add(new ILExpression(ILCode.YieldBreak, null));
					} else if (val == 1) {
						newBody.Add(MakeGoTo(labels, currentState));
					} else {
						throw new SymbolicAnalysisFailedException();
					}
				} else if (expr != null && expr.Code == ILCode.Call && expr.Arguments.Count == 1 && expr.Arguments[0].MatchThis()) {
					MethodDefinition method = GetMethodDefinition(expr.Operand as MethodReference);
					if (method == null)
						throw new SymbolicAnalysisFailedException();
					StateRange stateRange;
					if (method == disposeMethod) {
						// Explicit call to dispose is used for "yield break;" within the method.
						ILExpression br = body.ElementAtOrDefault(++pos) as ILExpression;
						if (br == null || !(br.Code == ILCode.Br || br.Code == ILCode.Leave) || br.Operand != returnFalseLabel)
							throw new SymbolicAnalysisFailedException();
						newBody.Add(new ILExpression(ILCode.YieldBreak, null));
					} else if (finallyMethodToStateRange.TryGetValue(method, out stateRange)) {
						// Call to Finally-method
						int index = stateChanges.FindIndex(ss => stateRange.Contains(ss.NewState));
						if (index < 0)
							throw new SymbolicAnalysisFailedException();
						
						ILLabel label = new ILLabel();
						label.Name = "JumpOutOfTryFinally" + stateChanges[index].NewState;
						newBody.Add(new ILExpression(ILCode.Leave, label));
						
						SetState stateChange = stateChanges[index];
						// Move all instructions from stateChange.Pos to newBody.Count into a try-block
						stateChanges.RemoveRange(index, stateChanges.Count - index); // remove all state changes up to the one we found
						ILTryCatchBlock tryFinally = new ILTryCatchBlock();
						tryFinally.TryBlock = new ILBlock(newBody.GetRange(stateChange.NewBodyPos, newBody.Count - stateChange.NewBodyPos));
						newBody.RemoveRange(stateChange.NewBodyPos, newBody.Count - stateChange.NewBodyPos); // remove all nodes that we just moved into the try block
						tryFinally.CatchBlocks = new List<ILTryCatchBlock.CatchBlock>();
						tryFinally.FinallyBlock = ConvertFinallyBlock(method);
						newBody.Add(tryFinally);
						newBody.Add(label);
					}
				} else {
					newBody.Add(body[pos]);
				}
			}
			newBody.Add(new ILExpression(ILCode.YieldBreak, null));
		}
Exemple #48
0
 /// <summary>
 /// Branches to the given label if the first value on the stack is less than the second
 /// value on the stack.
 /// </summary>
 /// <param name="label"> The label to branch to. </param>
 public abstract void BranchIfLessThan(ILLabel label);
 protected JSExpression Translate_Br(ILExpression node, ILLabel targetLabel)
 {
     return new JSGotoExpression(targetLabel.Name);
 }
Exemple #50
0
 /// <summary>
 /// Branches to the given label if the first value on the stack is less than or equal to
 /// the second value on the stack.  If the operands are integers then they are treated as
 /// if they are unsigned.  If the operands are floating point numbers then a NaN value will
 /// trigger a branch.
 /// </summary>
 /// <param name="label"> The label to branch to. </param>
 public abstract void BranchIfLessThanOrEqualUnsigned(ILLabel label);
Exemple #51
0
 protected ILLabel GetLabel(int position)
 {
     ILLabel l;
     if (!labels.TryGetValue(position, out l)) labels[position] = l = new ILLabel(position);
     return l;
 }
Exemple #52
0
 /// <summary>
 /// Defines the position of the given label.
 /// </summary>
 /// <param name="label"> The label to define. </param>
 public abstract void DefineLabelPosition(ILLabel label);
Exemple #53
0
        /// <summary>
        /// Group input into a set of blocks that can be later arbitraliby schufled.
        /// The method adds necessary branches to make control flow between blocks
        /// explicit and thus order independent.
        /// </summary>
        void SplitToMovableBlocks(ILBlock block)
        {
            // Remve no-ops
            // TODO: Assign the no-op range to someting
            block.Body = block.Body.Where(n => !(n is ILExpression && ((ILExpression)n).OpCode == OpCodes.Nop)).ToList();

            List<ILNode> moveableBlocks = new List<ILNode>();

            ILMoveableBlock moveableBlock = new ILMoveableBlock() { OriginalOrder = (nextBlockIndex++) };
            moveableBlocks.Add(moveableBlock);
            block.EntryPoint = new ILLabel() { Name = "Block_" + moveableBlock.OriginalOrder };
            moveableBlock.Body.Add(block.EntryPoint);

            if (block.Body.Count > 0) {
                moveableBlock.Body.Add(block.Body[0]);

                for (int i = 1; i < block.Body.Count; i++) {
                    ILNode lastNode = block.Body[i - 1];
                    ILNode currNode = block.Body[i];

                    // Insert split
                    if ((currNode is ILLabel && !(lastNode is ILLabel)) ||
                        lastNode is ILTryCatchBlock ||
                        currNode is ILTryCatchBlock ||
                        (lastNode is ILExpression) && ((ILExpression)lastNode).OpCode.IsBranch() ||
                        (currNode is ILExpression) && ((ILExpression)currNode).OpCode.IsBranch())
                    {
                        ILBlock lastBlock = moveableBlock;
                        moveableBlock = new ILMoveableBlock() { OriginalOrder = (nextBlockIndex++) };
                        moveableBlocks.Add(moveableBlock);

                        // Explicit branch from one block to other
                        // (unless the last expression was unconditional branch)
                        if (!(lastNode is ILExpression) || ((ILExpression)lastNode).OpCode.CanFallThough()) {
                            ILLabel blockLabel = new ILLabel() { Name = "Block_" + moveableBlock.OriginalOrder };
                            lastBlock.Body.Add(new ILExpression(OpCodes.Br, blockLabel));
                            moveableBlock.Body.Add(blockLabel);
                        }
                    }

                    moveableBlock.Body.Add(currNode);
                }
            }

            block.Body = moveableBlocks;
            return;
        }
Exemple #54
0
 /// <summary>
 /// Unconditionally branches to the given label.
 /// </summary>
 /// <param name="label"> The label to branch to. </param>
 public abstract void Branch(ILLabel label);
Exemple #55
0
        /// <summary>
        /// Pushes information about break or continue targets to a stack.
        /// </summary>
        /// <param name="labelNames"> The label names associated with the break or continue target.
        /// Can be <c>null</c>. </param>
        /// <param name="breakTarget"> The IL label to jump to if a break statement is encountered. </param>
        /// <param name="continueTarget"> The IL label to jump to if a continue statement is
        /// encountered.  Can be <c>null</c>. </param>
        /// <param name="labelledOnly"> <c>true</c> if break or continue statements without a label
        /// should ignore this entry; <c>false</c> otherwise. </param>
        public void PushBreakOrContinueInfo(IList<string> labelNames, ILLabel breakTarget, ILLabel continueTarget, bool labelledOnly)
        {
            if (breakTarget == null)
                throw new ArgumentNullException("breakTarget");

            // Check the label doesn't already exist.
            if (labelNames != null)
            {
                foreach (var labelName in labelNames)
                    foreach (var info in this.breakOrContinueStack)
                        if (info.LabelNames != null && info.LabelNames.Contains(labelName) == true)
                            throw new JavaScriptException(this.Engine, "SyntaxError", string.Format("Label '{0}' has already been declared", labelName));
            }

            // Push the info to the stack.
            this.breakOrContinueStack.Push(new BreakOrContinueInfo()
            {
                LabelNames = labelNames,
                LabelledOnly = labelledOnly,
                BreakTarget = breakTarget,
                ContinueTarget = continueTarget
            });
        }
Exemple #56
0
        public bool MatchRepeatStructure(IList <ILNode> body, ILBasicBlock head, int pos)
        {
            ILExpression rcount;
            ILExpression pushZero;
            int          dupMode = 0;
            ILLabel      fallthough;
            ILLabel      repeatBlock;

            if (head.MatchLastAt(6, GMCode.Push, out rcount) && // header for a repeat, sets it up
                head.MatchLastAt(5, GMCode.Dup, out dupMode) &&
                head.MatchLastAt(4, GMCode.Push, out pushZero) &&
                pushZero.Code == GMCode.Constant && (pushZero.Operand as ILValue).IntValue == 0 &&
                head.MatchLastAt(3, GMCode.Sle) &&
                head.MatchLastAndBr(GMCode.Bt, out fallthough, out repeatBlock))
            {
                // We have to seeperate the head from other bits of the block
                // humm, mabye have to put this in the general build routine like we did with push V:(
                head.Body.RemoveTail(GMCode.Push, GMCode.Dup, GMCode.Push, GMCode.Sle, GMCode.Bt, GMCode.B);

                ILBasicBlock header_block;
                ILLabel      header_label;
                if (head.Body.Count == 1)
                {// The head only has the label, so its safe to use this as the header
                    header_block = head;
                    header_label = head.EntryLabel();
                }
                else
                {
                    header_label = ILLabel.Generate("R");
                    // We have to seperate the head.
                    header_block = new ILBasicBlock();
                    head.Body.Add(new ILExpression(GMCode.B, header_label));
                    header_block.Body.Add(header_label);
                    body.Insert(pos + 1, header_block); // insert before the block so it looks in order
                }

                header_block.Body.Add(new ILExpression(GMCode.Repeat, repeatBlock, rcount));
                header_block.Body.Add(new ILExpression(GMCode.B, fallthough));

                // NOW we got to find the block that matches

                ILExpression subOneConstant;
                ILLabel      footerContinue, footerfallThough;

                /*
                 *
                 *
                 * while (!(start.MatchLastAt(5, GMCode.Push, out subOneConstant) &&
                 *   subOneConstant.Code == GMCode.Constant && (subOneConstant.Operand as ILValue).IntValue == 1 &&
                 *   start.MatchLastAt(4, GMCode.Sub) &&
                 *   start.MatchLastAt(3, GMCode.Dup, out dupMode) && dupMode == 0 &&
                 *  start.MatchLastAndBr(GMCode.Bt, out footerContinue, out footerfallThough)))
                 * {
                 *  ILLabel next = start.GotoLabel();
                 *  start = labelToBasicBlock[next];
                 * }
                 */// ok, on more complicated stuf like an internal loop, this f***s up, so we are going to do a hack
                // The popz fallthough comes RIGHT after the decrment for the repeate loop, so we are going to move up one from that
                // then check it
                ILBasicBlock popzBlock = labelToBasicBlock[fallthough]; //
                Debug.Assert((popzBlock.Body[1] as ILExpression).Code == GMCode.Popz);
                popzBlock.Body.RemoveAt(1);                             // remove the popz
                ILBasicBlock footer = body[body.IndexOf(popzBlock) - 1] as ILBasicBlock;

                if (footer.MatchLastAt(5, GMCode.Push, out subOneConstant) &&
                    subOneConstant.Code == GMCode.Constant && (subOneConstant.Operand as ILValue).IntValue == 1 &&
                    footer.MatchLastAt(4, GMCode.Sub) &&
                    footer.MatchLastAt(3, GMCode.Dup, out dupMode) && dupMode == 0 &&
                    footer.MatchLastAndBr(GMCode.Bt, out footerContinue, out footerfallThough))
                {
                    Debug.Assert(footerfallThough == fallthough && repeatBlock == footerContinue); // sanity check
                    footer.Body.RemoveTail(GMCode.Push, GMCode.Sub, GMCode.Dup, GMCode.Bt, GMCode.B);
                    footer.Body.Add(new ILExpression(GMCode.B, header_block.EntryLabel()));
                }
                else
                {
                    throw new Exception("F**k me");
                }


                // Found!  Some sanity checks thogh

                /* MAJOR BUG UNFINSHED WORK ALERT!
                 * Ok, so this isn't used in undertale, but at some point, somone might want to do a break or continue
                 * Inside of a repeat statment.  I have NO clue why though, use a while?
                 * Anyway, if thats the case then you MUST change the target label of evetyhing going to start, to fallthough, otherwise
                 * the goto cleaner will start screaming at you and do alot of weird stuff
                 * fyi, like the with statments, I am converting this thing into a while loop so I don't have to have
                 * custom loop graph code for these things
                 * So, for now? convert start to loop back to head, head jumps to fallthough, and we remove the popz from the fall though
                 */
                //   ILLabel.Generate("Block_", nextLabelIndex++);



                return(true);
            }
            return(false);
        }
Exemple #57
0
 /// <summary>
 /// Emits code to branch between statements, even if code generation is within a finally
 /// block (where unconditional branches are not allowed).
 /// </summary>
 /// <param name="generator"> The generator to output the CIL to. </param>
 /// <param name="targetLabel"> The label to jump to. </param>
 public void EmitLongJump(ILGenerator generator, ILLabel targetLabel)
 {
     if (this.LongJumpCallback == null)
     {
         // Code generation is not inside a finally block.
         if (this.InsideTryCatchOrFinally == true)
             generator.Leave(targetLabel);
         else
             generator.Branch(targetLabel);
     }
     else
     {
         // The long jump is occurring within a finally block.
         // Check if the target is inside or outside the finally block.
         int depth = this.GetBreakOrContinueLabelDepth(targetLabel);
         if (depth < this.LongJumpStackSizeThreshold)
         {
             // The target label is outside the finally block.  Call the callback to emit
             // the jump.
             this.LongJumpCallback(generator, targetLabel);
         }
         else
         {
             // The target label is inside the finally block.
             if (this.InsideTryCatchOrFinally == true)
                 generator.Leave(targetLabel);
             else
                 generator.Branch(targetLabel);
         }
     }
 }
Exemple #58
0
 /// <summary>
 /// Branches to the given label if the value on the top of the stack is non-zero, true or
 /// non-null.
 /// </summary>
 /// <param name="label"> The label to branch to. </param>
 public abstract void BranchIfNotZero(ILLabel label);
Exemple #59
0
 /// <summary>
 /// Unconditionally branches to the given label.  Unlike the regular branch instruction,
 /// this instruction can exit out of try, filter and catch blocks.
 /// </summary>
 /// <param name="label"> The label to branch to. </param>
 public abstract void Leave(ILLabel label);
Exemple #60
0
        bool MatchSwitchCaseAndBuildExpression(ILBasicBlock head, out ILLabel trueLabel, out ILLabel falseLabel, out ILExpression expr)
        {
            ILExpression condition;

            if (MatchSwitchCase(head, out trueLabel, out falseLabel, out condition))
            {
                var ranges = head.JoinILRangesFromTail(5);
                expr = new ILExpression(GMCode.Bt, trueLabel, new ILExpression(GMCode.Seq, null, condition));
                expr.WithILRanges(ranges);
                return(true);
            }
            trueLabel  = default(ILLabel);
            falseLabel = default(ILLabel);
            expr       = default(ILExpression);
            return(false);
        }