internal LoopGotoTargets(string label, Block breakTarget, Block continueTarget) { this.Label = label; this.BreakTarget = breakTarget; this.ContinueTarget = continueTarget; }
internal static void VisitDepthFirstOrder(Block block, List<Block> visitData) { if (ReferenceEquals(block._visitData, visitData)) return; block._visitData = visitData; foreach (Block succ in block._successors) { VisitDepthFirstOrder(succ, visitData); } visitData.Add(block); block.PostOrder = count; count += 1; }
/// <summary> /// Visit binary expression /// </summary> /// <param name="binaryExpressionAst"></param> /// <returns></returns> public object VisitBinaryExpression(BinaryExpressionAst binaryExpressionAst) { if (binaryExpressionAst == null) return null; if (binaryExpressionAst.Operator == TokenKind.And || binaryExpressionAst.Operator == TokenKind.Or) { // Logical and/or are short circuit operators, so we need to simulate the control flow. The // left operand is always evaluated, visit it's expression in the current block. binaryExpressionAst.Left.Visit(this.Decorator); // The right operand is conditionally evaluated. We aren't generating any code here, just // modeling the flow graph, so we just visit the right operand in a new block, and have // both the current and new blocks both flow to a post-expression block. var targetBlock = new Block(); var nextBlock = new Block(); _currentBlock.FlowsTo(targetBlock); _currentBlock.FlowsTo(nextBlock); _currentBlock = nextBlock; binaryExpressionAst.Right.Visit(this.Decorator); _currentBlock.FlowsTo(targetBlock); _currentBlock = targetBlock; } else { binaryExpressionAst.Left.Visit(this.Decorator); binaryExpressionAst.Right.Visit(this.Decorator); } return null; }
/// <summary> /// Rename each variable (each assignment will give variable a new name). /// Also rename the phi function in each block as well /// </summary> /// <param name="block"></param> internal static void RenameVariables(Block block) { if (block._visited) { return; } block._visited = true; // foreach phi node generate new name foreach (var phi in block.Phis) { phi.Name = GenerateNewName(phi.RealName, block); } foreach (object ast in block._asts) { AssignmentTarget assignTarget = ast as AssignmentTarget; VariableTarget varTarget = null; if (assignTarget != null && !String.IsNullOrEmpty(assignTarget.Name)) { assignTarget.Name = GenerateNewName(assignTarget.Name, block); varTarget = assignTarget._rightHandSideVariable; } varTarget = (varTarget != null) ? varTarget : ast as VariableTarget; if (varTarget != null) { // If stack is empty then variable was not initialized; if (SSADictionary[varTarget.RealName].Count == 0) { VariablesDictionary[VariableAnalysis.AnalysisDictionaryKey(varTarget.VarAst)] = new VariableAnalysisDetails { Name = varTarget.Name, DefinedBlock = null, Type = varTarget.Type, RealName = null }; } else { VariableAnalysisDetails previous = SSADictionary[varTarget.RealName].Peek(); varTarget.Name = previous.Name; if (previous.DefinedBlock != null) { previous.DefinedBlock.SSASuccessors.Add(block); } VariablesDictionary[VariableAnalysis.AnalysisDictionaryKey(varTarget.VarAst)] = previous; } } } foreach (var successor in block._successors) { int index = successor._predecessors.IndexOf(block); foreach (var phi in successor.Phis) { // Stacks may be empty when variable was not initialized on all paths; if (SSADictionary[phi.RealName].Count != 0) { VariableAnalysisDetails previous = SSADictionary[phi.RealName].Peek(); if (previous.DefinedBlock != null) { previous.DefinedBlock.SSASuccessors.Add(successor); } phi.Operands[index] = new VariableTarget(previous); } else { phi.Operands[index] = new VariableTarget(); phi.Operands[index].Name = GenerateNewName(phi.RealName, null); } } } // Preorder travel along the dominator tree foreach (var successor in block.DominatorSuccessors) { RenameVariables(successor); } foreach (var phi in block.Phis) { SSADictionary[phi.RealName].Pop(); } foreach (object ast in block._asts) { AssignmentTarget assignTarget = ast as AssignmentTarget; if (assignTarget != null && !String.IsNullOrEmpty(assignTarget.RealName)) { SSADictionary[assignTarget.RealName].Pop(); } } }
/// <summary> /// Sparse simple constant algorithm using use-def chain from SSA graph. /// </summary> /// <param name="Variables"></param> /// <param name="Entry"></param> /// <param name="Classes"></param> /// <returns></returns> #if PSV3 internal static Tuple<Dictionary<string, VariableAnalysisDetails>, Dictionary<string, VariableAnalysisDetails>> SparseSimpleConstants( Dictionary<string, VariableAnalysisDetails> Variables, Block Entry)
/// <summary> /// Fill in the DominanceFrontiersSet of each block. /// </summary> /// <param name="Blocks"></param> /// <param name="Entry"></param> internal static void DominanceFrontiers(List<Block> Blocks, Block Entry) { Block[] dominators = SetDominators(Entry, Blocks); foreach (Block block in Blocks) { if (block._predecessors.Count >= 2) { foreach (Block pred in block._predecessors) { Block runner = pred; while (runner != dominators[block.PostOrder]) { runner.dominanceFrontierSet.Add(block); runner = dominators[block.PostOrder]; } } } } }
/// <summary> /// Given two nodes, return the postorder number of the closest node /// that dominates both. /// </summary> /// <param name="block1"></param> /// <param name="block2"></param> /// <param name="Dominators"></param> /// <returns></returns> internal static int Intersect(Block block1, Block block2, Block[] Dominators) { int b1 = block1.PostOrder; int b2 = block2.PostOrder; while (b1 != b2) { while (b1 < b2) { b1 = Dominators[b1].PostOrder; } while (b2 < b1) { b2 = Dominators[b2].PostOrder; } } return b1; }
internal void GenerateWhileLoop(string loopLabel, Action generateCondition, Action generateLoopBody, Ast continueAction = null) { // We model the flow graph like this (if continueAction is null, the first part is slightly different): // goto L // :ContinueTarget // continueAction // :L // if (condition) // { // loop body // // break -> goto BreakTarget // // continue -> goto ContinueTarget // goto ContinueTarget // } // :BreakTarget var continueBlock = new Block(); if (continueAction != null) { var blockAfterContinue = new Block(); // Represent the goto over the condition before the first iteration. _currentBlock.FlowsTo(blockAfterContinue); _currentBlock = continueBlock; continueAction.Visit(this.Decorator); _currentBlock.FlowsTo(blockAfterContinue); _currentBlock = blockAfterContinue; } else { _currentBlock.FlowsTo(continueBlock); _currentBlock = continueBlock; } var bodyBlock = new Block(); var breakBlock = new Block(); // Condition can be null from an uncommon for loop: for() {} if (generateCondition != null) { generateCondition(); _currentBlock.FlowsTo(breakBlock); } _loopTargets.Add(new LoopGotoTargets(loopLabel ?? "", breakBlock, continueBlock)); _currentBlock.FlowsTo(bodyBlock); _currentBlock = bodyBlock; generateLoopBody(); _currentBlock.FlowsTo(continueBlock); _currentBlock = breakBlock; _loopTargets.RemoveAt(_loopTargets.Count - 1); }
internal void GenerateDoLoop(LoopStatementAst loopStatement) { // We model the flow graph like this: // :RepeatTarget // loop body // // break -> goto BreakTarget // // continue -> goto ContinueTarget // :ContinueTarget // if (condition) // { // goto RepeatTarget // } // :BreakTarget var continueBlock = new Block(); var bodyBlock = new Block(); var breakBlock = new Block(); var gotoRepeatTargetBlock = new Block(); _loopTargets.Add(new LoopGotoTargets(loopStatement.Label ?? "", breakBlock, continueBlock)); _currentBlock.FlowsTo(bodyBlock); _currentBlock = bodyBlock; loopStatement.Body.Visit(this.Decorator); _currentBlock.FlowsTo(continueBlock); _currentBlock = continueBlock; loopStatement.Condition.Visit(this.Decorator); _currentBlock.FlowsTo(breakBlock); _currentBlock.FlowsTo(gotoRepeatTargetBlock); _currentBlock = gotoRepeatTargetBlock; _currentBlock.FlowsTo(bodyBlock); _currentBlock = breakBlock; _loopTargets.RemoveAt(_loopTargets.Count - 1); }
/// <summary> /// Visit if statement /// </summary> /// <param name="ifStmtAst"></param> /// <returns></returns> public object VisitIfStatement(IfStatementAst ifStmtAst) { if (ifStmtAst == null) return null; Block afterStmt = new Block(); if (ifStmtAst.ElseClause == null) { // There is no else, flow can go straight to afterStmt. _currentBlock.FlowsTo(afterStmt); } int clauseCount = ifStmtAst.Clauses.Count; for (int i = 0; i < clauseCount; i++) { var clause = ifStmtAst.Clauses[i]; bool isLastClause = (i == (clauseCount - 1) && ifStmtAst.ElseClause == null); Block clauseBlock = new Block(); Block nextBlock = isLastClause ? afterStmt : new Block(); clause.Item1.Visit(this); _currentBlock.FlowsTo(clauseBlock); _currentBlock.FlowsTo(nextBlock); _currentBlock = clauseBlock; clause.Item2.Visit(this); _currentBlock.FlowsTo(afterStmt); _currentBlock = nextBlock; } if (ifStmtAst.ElseClause != null) { ifStmtAst.ElseClause.Visit(this); _currentBlock.FlowsTo(afterStmt); } _currentBlock = afterStmt; return null; }
/// <summary> /// Visit switch statement /// </summary> /// <param name="switchStatementAst"></param> /// <returns></returns> public object VisitSwitchStatement(SwitchStatementAst switchStatementAst) { if (switchStatementAst == null) return null; Action generateCondition = () => { switchStatementAst.Condition.Visit(this.Decorator); // $switch is set after evaluating the condition. _currentBlock.AddAst(new AssignmentTarget(SpecialVars.@switch, typeof(IEnumerator))); }; Action switchBodyGenerator = () => { bool hasDefault = (switchStatementAst.Default != null); Block afterStmt = new Block(); int clauseCount = switchStatementAst.Clauses.Count; for (int i = 0; i < clauseCount; i++) { var clause = switchStatementAst.Clauses[i]; Block clauseBlock = new Block(); bool isLastClause = (i == (clauseCount - 1) && !hasDefault); Block nextBlock = isLastClause ? afterStmt : new Block(); clause.Item1.Visit(this.Decorator); _currentBlock.FlowsTo(nextBlock); _currentBlock.FlowsTo(clauseBlock); _currentBlock = clauseBlock; clause.Item2.Visit(this.Decorator); if (!isLastClause) { _currentBlock.FlowsTo(nextBlock); _currentBlock = nextBlock; } } if (hasDefault) { // If any clause was executed, we skip the default, so there is always a branch over the default. _currentBlock.FlowsTo(afterStmt); switchStatementAst.Default.Visit(this.Decorator); } _currentBlock.FlowsTo(afterStmt); _currentBlock = afterStmt; }; GenerateWhileLoop(switchStatementAst.Label, generateCondition, switchBodyGenerator); return null; }
/// <summary> /// Visit script block /// </summary> /// <param name="scriptBlockAst"></param> /// <returns></returns> public object VisitScriptBlock(ScriptBlockAst scriptBlockAst) { if (scriptBlockAst == null) return null; _currentBlock = _entryBlock; if (scriptBlockAst.DynamicParamBlock != null) { scriptBlockAst.DynamicParamBlock.Visit(this.Decorator); } if (scriptBlockAst.BeginBlock != null) { scriptBlockAst.BeginBlock.Visit(this.Decorator); } if (scriptBlockAst.ProcessBlock != null) { scriptBlockAst.ProcessBlock.Visit(this.Decorator); } if (scriptBlockAst.EndBlock != null) { scriptBlockAst.EndBlock.Visit(this.Decorator); } _currentBlock.FlowsTo(_exitBlock); return null; }
/// <summary> /// Initialize the data flow construction /// </summary> public void Init() { _entryBlock = Block.NewEntryBlock(); _exitBlock = new Block(); }
/// <summary> /// Start the data flow graph. /// </summary> public void Start() { Init(); _currentBlock = _entryBlock; }
/// <summary> /// Constructor /// </summary> /// <param name="VarName"></param> /// <param name="block"></param> internal Phi(String VarName, Block block) { Name = VarName; Operands = new VariableTarget[block._predecessors.Count()]; for (int i = 0; i < Operands.Length; i += 1) { Operands[i] = new VariableTarget(); } RealName = Name; DefinedBlock = block; }
/// <summary> /// Visit foreach statement /// </summary> /// <param name="forEachStatementAst"></param> /// <returns></returns> public object VisitForEachStatement(ForEachStatementAst forEachStatementAst) { if (forEachStatementAst == null) return null; var afterFor = new Block(); Action generateCondition = () => { forEachStatementAst.Condition.Visit(this.Decorator); // The loop might not be executed, so add flow around the loop. _currentBlock.FlowsTo(afterFor); // $foreach and the iterator variable are set after evaluating the condition. _currentBlock.AddAst(new AssignmentTarget(SpecialVars.@foreach, typeof(IEnumerator))); _currentBlock.AddAst(new AssignmentTarget(forEachStatementAst.Variable)); }; GenerateWhileLoop(forEachStatementAst.Label, generateCondition, () => forEachStatementAst.Body.Visit(this.Decorator)); _currentBlock.FlowsTo(afterFor); _currentBlock = afterFor; return null; }
/// <summary> /// Tell flow analysis that this block can flow to next block. /// </summary> /// <param name="next"></param> internal void FlowsTo(Block next) { if (_successors.IndexOf(next) < 0) { if (!_unreachable) { next._unreachable = false; } _successors.Add(next); next._predecessors.Add(this); } }
/// <summary> /// Visit try statement /// </summary> /// <param name="tryStatementAst"></param> /// <returns></returns> public object VisitTryStatement(TryStatementAst tryStatementAst) { if (tryStatementAst == null) return null; // We don't attempt to accurately model flow in a try catch because every statement // can flow to each catch. Instead, we'll assume the try block is not executed (because the very first statement // may throw), and have the data flow assume the block before the try is all that can reach the catches and finally. var blockBeforeTry = _currentBlock; _currentBlock = new Block(); blockBeforeTry.FlowsTo(_currentBlock); tryStatementAst.Body.Visit(this.Decorator); Block lastBlockInTry = _currentBlock; var finallyFirstBlock = tryStatementAst.Finally == null ? null : new Block(); Block finallyLastBlock = null; // This is the first block after all the catches and finally (if present). var afterTry = new Block(); bool isCatchAllPresent = false; foreach (var catchAst in tryStatementAst.CatchClauses) { if (catchAst.IsCatchAll) { isCatchAllPresent = true; } // Any statement in the try block could throw and reach the catch, so assume the worst (from a data // flow perspective) and make the predecessor to the catch the block before entering the try. _currentBlock = new Block(); blockBeforeTry.FlowsTo(_currentBlock); catchAst.Visit(this.Decorator); _currentBlock.FlowsTo(finallyFirstBlock ?? afterTry); } if (finallyFirstBlock != null) { lastBlockInTry.FlowsTo(finallyFirstBlock); _currentBlock = finallyFirstBlock; tryStatementAst.Finally.Visit(this.Decorator); _currentBlock.FlowsTo(afterTry); finallyLastBlock = _currentBlock; // For finally block, there are 2 cases: when try-body throw and when it doesn't. // For these two cases value of 'finallyLastBlock._throws' would be different. if (!isCatchAllPresent) { // This flow exist only, if there is no catch for all exceptions. blockBeforeTry.FlowsTo(finallyFirstBlock); var rethrowAfterFinallyBlock = new Block(); finallyLastBlock.FlowsTo(rethrowAfterFinallyBlock); rethrowAfterFinallyBlock._throws = true; rethrowAfterFinallyBlock.FlowsTo(_exitBlock); } // This flow always exists. finallyLastBlock.FlowsTo(afterTry); } else { lastBlockInTry.FlowsTo(afterTry); } _currentBlock = afterTry; return null; }
/// <summary> /// Returns the immediate dominator of each block. The array returned is /// indexed by postorder number of each block. /// Based on http://www.cs.rice.edu/~keith/Embed/dom.pdf /// </summary> /// <param name="entry"></param> /// <param name="Blocks"></param> /// <returns></returns> internal static Block[] SetDominators(Block entry, List<Block> Blocks) { Block[] dominators = new Block[Blocks.Count]; foreach (var block in Blocks) { dominators[block.PostOrder] = null; } dominators[entry.PostOrder] = entry; bool updated = true; while (updated) { updated = false; foreach (var block in Blocks) { if (block == entry) { continue; } if (block._predecessors.Count == 0) { continue; } Block dom = block._predecessors[0]; // Get first processed node foreach (var pred in block._predecessors) { if (dominators[pred.PostOrder] != null) { dom = pred; break; } } Block firstSelected = dom; foreach (var pred in block._predecessors) { if (firstSelected != pred && dominators[pred.PostOrder] != null) { // The order is reversed so we have to subtract from total dom = Blocks[Blocks.Count - Intersect(pred, dom, dominators) - 1]; } } if (dominators[block.PostOrder] != dom) { dominators[block.PostOrder] = dom; updated = true; } } } // Construct dominator tree foreach (var block in Blocks) { dominators[block.PostOrder].DominatorSuccessors.Add(block); } return dominators; }
void BreakOrContinue(ExpressionAst label, Func<LoopGotoTargets, Block> fieldSelector) { Block targetBlock = null; if (label != null) { label.Visit(this.Decorator); if (_loopTargets.Any()) { var labelStrAst = label as StringConstantExpressionAst; if (labelStrAst != null) { targetBlock = (from t in _loopTargets where t.Label.Equals(labelStrAst.Value, StringComparison.OrdinalIgnoreCase) select fieldSelector(t)).LastOrDefault(); } } } else if (_loopTargets.Count > 0) { targetBlock = fieldSelector(_loopTargets.Last()); } if (targetBlock == null) { _currentBlock.FlowsTo(_exitBlock); _currentBlock._throws = true; } else { _currentBlock.FlowsTo(targetBlock); } // The next block is unreachable, but is necessary to keep the flow graph correct. _currentBlock = new Block(); }
/// <summary> /// Generate new name for each assignment using the counters. /// </summary> /// <param name="VarName"></param> /// <param name="DefinedBlock"></param> /// <returns></returns> internal static string GenerateNewName(string VarName, Block DefinedBlock) { int i = Counters[VarName]; Counters[VarName] += 1; string newName = String.Format(CultureInfo.CurrentCulture, "{0}{1}", VarName, i); var varAnalysis = new VariableAnalysisDetails { Name = newName, DefinedBlock = DefinedBlock, RealName = VarName }; SSADictionary[VarName].Push(varAnalysis); InternalVariablesDictionary[newName] = varAnalysis; return newName; }
internal Block ControlFlowStatement(PipelineBaseAst pipelineAst) { if (pipelineAst != null) { pipelineAst.Visit(this.Decorator); } _currentBlock.FlowsTo(_exitBlock); var lastBlockInStatement = _currentBlock; // The next block is unreachable, but is necessary to keep the flow graph correct. _currentBlock = new Block(); return lastBlockInStatement; }
/// <summary> /// Initialize SSA /// </summary> /// <param name="VariableAnalysis"></param> /// <param name="Entry"></param> /// <param name="Blocks"></param> internal static void InitializeSSA(Dictionary<string, VariableAnalysisDetails> VariableAnalysis, Block Entry, List<Block> Blocks) { VariablesDictionary = new Dictionary<string, VariableAnalysisDetails>(StringComparer.OrdinalIgnoreCase); foreach (var block in Blocks) { List<Block> _unreachables = new List<Block>(); foreach (var pred in block._predecessors) { if (pred._unreachable) { _unreachables.Add(pred); pred._successors.Remove(block); } } foreach (var pred in _unreachables) { block._predecessors.Remove(pred); } } InternalVariablesDictionary.Clear(); SSADictionary.Clear(); Counters.Clear(); DominanceFrontiers(Blocks, Entry); InsertPhiNodes(VariableAnalysis); foreach (var key in VariableAnalysis.Keys.ToList()) { SSADictionary[key] = new Stack<VariableAnalysisDetails>(); Counters[key] = 0; } RenameVariables(Entry); }
/// <summary> /// Visit pipeline /// </summary> /// <param name="pipelineAst"></param> /// <returns></returns> public object VisitPipeline(PipelineAst pipelineAst) { if (pipelineAst == null) return null; bool invokesCommand = false; foreach (var command in pipelineAst.PipelineElements) { command.Visit(this.Decorator); if (command is CommandAst) { invokesCommand = true; } foreach (var redir in command.Redirections) { redir.Visit(this.Decorator); } } // Because non-local gotos are supported, we must model them in the flow graph. We can't detect them // in general, so we must be pessimistic and assume any command invocation could result in non-local // break or continue, so add the appropriate edges to our graph. These edges occur after visiting // the command elements because command arguments could create new blocks, and we won't have executed // the command yet. if (invokesCommand && _loopTargets.Any()) { foreach (var loopTarget in _loopTargets) { _currentBlock.FlowsTo(loopTarget.BreakTarget); _currentBlock.FlowsTo(loopTarget.ContinueTarget); } // The rest of the block is potentially unreachable, so split the current block. var newBlock = new Block(); _currentBlock.FlowsTo(newBlock); _currentBlock = newBlock; } return null; }
internal static Tuple<Dictionary<string, VariableAnalysisDetails>, Dictionary<string, VariableAnalysisDetails>> SparseSimpleConstants( Dictionary<string, VariableAnalysisDetails> Variables, Block Entry, List<TypeDefinitionAst> Classes) #endif { List<Block> blocks = GenerateReverseDepthFirstOrder(Entry); // Populate unreached variable with type from variables foreach (var block in blocks) { foreach (var ast in block._asts) { VariableTarget varTarget = (ast is AssignmentTarget) ? (ast as AssignmentTarget)._rightHandSideVariable : (ast as VariableTarget); if (varTarget != null && varTarget.Type == typeof(Unreached) && Variables.ContainsKey(varTarget.Name)) { varTarget.Type = Variables[varTarget.Name].Type; } } } InitializeSSA(Variables, Entry, blocks); LinkedList<Tuple<Block, Block>> workLists = new LinkedList<Tuple<Block, Block>>(); foreach (var block in blocks) { // Add a worklist from a block to itself to force analysis when variable is initialized but not used. // This is useful in the case where the variable is used in the inner function workLists.AddLast(Tuple.Create(block, block)); foreach (var ssaSucc in block.SSASuccessors) { if (ssaSucc != block) { workLists.AddLast(Tuple.Create(block, ssaSucc)); } } } // Initialize variables in internal dictionary to undetermined foreach (var key in InternalVariablesDictionary.Keys.ToList()) { InternalVariablesDictionary[key].Constant = Undetermined.UndeterminedConstant; InternalVariablesDictionary[key].Type = typeof(Undetermined); } // Initialize DefinedBlock of phi function. If it is null then that phi function is not initialized; foreach (var block in blocks) { foreach (var phi in block.Phis) { foreach (var operand in phi.Operands) { phi.DefinedBlock = operand.DefinedBlock; if (phi.DefinedBlock == null) { break; } } InternalVariablesDictionary[phi.Name].DefinedBlock = phi.DefinedBlock; } } while (workLists.Count != 0) { Tuple<Block, Block> SSAEdge = workLists.Last.Value; workLists.RemoveLast(); Block start = SSAEdge.Item1; Block end = SSAEdge.Item2; HashSet<string> defVariables = new HashSet<string>(); foreach (var obj in start._asts) { var assigned = obj as AssignmentTarget; if (assigned != null && assigned.Name != null && InternalVariablesDictionary.ContainsKey(assigned.Name)) { VariableAnalysisDetails varAnalysis = InternalVariablesDictionary[assigned.Name]; // For cases where the type or constant of the rhs is initialized not through assignment. if (assigned._rightHandSideVariable != null && !InternalVariablesDictionary.ContainsKey(assigned._rightHandSideVariable.Name) && Variables.ContainsKey(assigned._rightHandSideVariable.Name)) { VariableAnalysisDetails rhsAnalysis = Variables[assigned._rightHandSideVariable.Name]; assigned.Type = rhsAnalysis.Type; assigned.Constant = rhsAnalysis.Constant; } varAnalysis.Constant = assigned.Constant; varAnalysis.Type = assigned.Type; defVariables.Add(assigned.Name); } } foreach (var phi in start.Phis) { EvaluatePhiConstant(phi); EvaluatePhiType(phi); defVariables.Add(phi.Name); } bool updated = false; List<VariableTarget> varTargets = new List<VariableTarget>(); varTargets.AddRange(end._asts.Where(item => item is VariableTarget).Cast<VariableTarget>()); foreach (var phi in end.Phis) { varTargets.AddRange(phi.Operands); } foreach (var varTarget in varTargets) { if (defVariables.Contains(varTarget.Name)) { var analysisDetails = InternalVariablesDictionary[varTarget.Name]; if (!VariableDetails.SameConstantAndType(varTarget, analysisDetails)) { updated = true; } varTarget.Constant = analysisDetails.Constant; varTarget.Type = analysisDetails.Type; VariablesDictionary[VariableAnalysis.AnalysisDictionaryKey(varTarget.VarAst)] = InternalVariablesDictionary[varTarget.Name]; } } foreach (var ast in end._asts) { var assigned = ast as AssignmentTarget; if (assigned != null && assigned.Name != null && assigned._leftHandSideVariable != null) { // Handle cases like $b = $a after we found out the value of $a if (assigned._rightHandSideVariable != null && defVariables.Contains(assigned._rightHandSideVariable.Name)) { // Ignore assignments like $a = $a if (!String.Equals(assigned._rightHandSideVariable.Name, assigned.Name, StringComparison.OrdinalIgnoreCase)) { if (!InternalVariablesDictionary.ContainsKey(assigned._rightHandSideVariable.Name)) { continue; } var analysisDetails = InternalVariablesDictionary[assigned._rightHandSideVariable.Name]; if (!VariableDetails.SameConstantAndType(assigned, analysisDetails)) { updated = true; } assigned.Constant = analysisDetails.Constant; assigned.Type = analysisDetails.Type; } continue; } //TODO // Handle cases like $b = $a.SomeMethod or $a.SomeType after we found out the value of $a if (assigned._rightAst != null) { CommandExpressionAst cmeAst = assigned._rightAst as CommandExpressionAst; MemberExpressionAst memAst = (cmeAst != null) ? (cmeAst.Expression as MemberExpressionAst) : null; // Don't handle the this case because this is handled in assignment target if (memAst != null && memAst.Expression is VariableExpressionAst) { VariableAnalysisDetails analysis = VariablesDictionary[VariableAnalysis.AnalysisDictionaryKey(memAst.Expression as VariableExpressionAst)]; #if PSV3 Type possibleType = AssignmentTarget.GetTypeFromMemberExpressionAst(memAst, analysis); #else TypeDefinitionAst psClass = Classes.FirstOrDefault(item => String.Equals(item.Name, analysis.Type.FullName, StringComparison.OrdinalIgnoreCase)); Type possibleType = AssignmentTarget.GetTypeFromMemberExpressionAst(memAst, analysis, psClass); #endif if (possibleType != null && possibleType != assigned.Type) { assigned.Type = possibleType; updated = true; continue; } } } } } if (updated) { foreach (var block in end.SSASuccessors) { // Add to the front instead of the end since we are removing from end. workLists.AddFirst(Tuple.Create(end, block)); } } } return Tuple.Create(VariablesDictionary, InternalVariablesDictionary); }
internal static List<Block> GenerateReverseDepthFirstOrder(Block block) { count = 0; List<Block> result = new List<Block>(); VisitDepthFirstOrder(block, result); result.Reverse(); for (int i = 0; i < result.Count; i++) { result[i]._visitData = null; } return result; }