📄 flowanalysis.cs
字号:
public void SetFieldAssigned (VariableInfo var, string name) { if (!var.IsParameter && Reachability.IsUnreachable) return; IsDirty = true; var.SetFieldAssigned (var.IsParameter ? parameters : locals, name); } public Reachability Reachability { get { return reachability; } } public void Return () { if (!reachability.IsUnreachable) { IsDirty = true; reachability.SetReturns (); } } public void Break () { if (!reachability.IsUnreachable) { IsDirty = true; reachability.SetBreaks (); } } public void Throw () { if (!reachability.IsUnreachable) { IsDirty = true; reachability.SetThrows (); } } public void Goto () { if (!reachability.IsUnreachable) { IsDirty = true; reachability.SetBarrier (); } } // <summary> // Merges a child branching. // </summary> public UsageVector MergeChild (FlowBranching branching) { UsageVector result = branching.Merge (); Report.Debug (2, " MERGING CHILD", this, branching, IsDirty, result.ParameterVector, result.LocalVector, result.Reachability, reachability, Type); Reachability new_r = result.Reachability; if (branching.Type == BranchingType.Loop) { bool may_leave_loop = new_r.MayBreak; new_r.ResetBreaks (); if (branching.Infinite && !may_leave_loop) { if (new_r.Returns == FlowReturns.Sometimes) { // If we're an infinite loop and do not break, // the code after the loop can never be reached. // However, if we may return from the loop, // then we do always return (or stay in the // loop forever). new_r.SetReturns (); } new_r.SetBarrier (); } if (may_leave_loop) new_r.ResetBarrier (); } else if (branching.Type == BranchingType.Switch) { if (new_r.MayBreak || new_r.MayReturn) new_r.ResetBarrier (); new_r.ResetBreaks (); } // // We've now either reached the point after the branching or we will // never get there since we always return or always throw an exception. // // If we can reach the point after the branching, mark all locals and // parameters as initialized which have been initialized in all branches // we need to look at (see above). // if ((Type == SiblingType.SwitchSection) && !new_r.IsUnreachable) { Report.Error (163, Location, "Control cannot fall through from one " + "case label to another"); return result; } if (locals != null && result.LocalVector != null) locals.Or (result.LocalVector); if (result.ParameterVector != null) parameters.Or (result.ParameterVector); if ((branching.Type == BranchingType.Block) && branching.Block.Implicit) reachability = new_r.Clone (); else reachability.Or (new_r); Report.Debug (2, " MERGING CHILD DONE", this, result, new_r, reachability); IsDirty = true; return result; } protected void MergeFinally (FlowBranching branching, UsageVector f_origins, MyBitVector f_params) { for (UsageVector vector = f_origins; vector != null; vector = vector.Next) { MyBitVector temp_params = f_params.Clone (); temp_params.Or (vector.Parameters); } } public void MergeFinally (FlowBranching branching, UsageVector f_vector, UsageVector f_origins) { if (parameters != null) { if (f_vector != null) { MergeFinally (branching, f_origins, f_vector.Parameters); MyBitVector.Or (ref parameters, f_vector.ParameterVector); } else MergeFinally (branching, f_origins, parameters); } if (f_vector != null && f_vector.LocalVector != null) MyBitVector.Or (ref locals, f_vector.LocalVector); } // <summary> // Tells control flow analysis that the current code position may be reached with // a forward jump from any of the origins listed in `origin_vectors' which is a // list of UsageVectors. // // This is used when resolving forward gotos - in the following example, the // variable `a' is uninitialized in line 8 becase this line may be reached via // the goto in line 4: // // 1 int a; // // 3 if (something) // 4 goto World; // // 6 a = 5; // // 7 World: // 8 Console.WriteLine (a); // // </summary> public void MergeJumpOrigins (UsageVector o_vectors) { Report.Debug (1, " MERGING JUMP ORIGINS", this); reachability = Reachability.Never (); if (o_vectors == null) { reachability.SetBarrier (); return; } bool first = true; for (UsageVector vector = o_vectors; vector != null; vector = vector.Next) { Report.Debug (1, " MERGING JUMP ORIGIN", vector, first, locals, vector.Locals); if (first) { if (locals != null && vector.Locals != null) locals.Or (vector.locals); if (parameters != null) parameters.Or (vector.parameters); first = false; } else { if (locals != null) locals.And (vector.locals); if (parameters != null) parameters.And (vector.parameters); } Reachability.And (ref reachability, vector.Reachability, true); Report.Debug (1, " MERGING JUMP ORIGIN #1", vector); } Report.Debug (1, " MERGING JUMP ORIGINS DONE", this); } // <summary> // This is used at the beginning of a finally block if there were // any return statements in the try block or one of the catch blocks. // </summary> public void MergeFinallyOrigins (UsageVector f_origins) { Report.Debug (1, " MERGING FINALLY ORIGIN", this); reachability = Reachability.Never (); for (UsageVector vector = f_origins; vector != null; vector = vector.Next) { Report.Debug (1, " MERGING FINALLY ORIGIN", vector); if (parameters != null) parameters.And (vector.parameters); Reachability.And (ref reachability, vector.Reachability, true); } Report.Debug (1, " MERGING FINALLY ORIGIN DONE", this); } public void MergeBreakOrigins (FlowBranching branching, UsageVector o_vectors) { Report.Debug (1, " MERGING BREAK ORIGINS", this); if (o_vectors == null) return; bool first = branching.Infinite; for (UsageVector vector = o_vectors; vector != null; vector = vector.Next) { Report.Debug (1, " MERGING BREAK ORIGIN", vector, first); if (first) { if (locals != null && vector.Locals != null) locals.Or (vector.locals); if (parameters != null) parameters.Or (vector.parameters); first = false; } else { if (locals != null && vector.Locals != null) locals.And (vector.locals); if (parameters != null) parameters.And (vector.parameters); } reachability.And (vector.Reachability, false); } Report.Debug (1, " MERGING BREAK ORIGINS DONE", this); } public void CheckOutParameters (FlowBranching branching) { if (parameters != null) branching.CheckOutParameters (parameters, branching.Location); } // <summary> // Performs an `or' operation on the locals and the parameters. // </summary> public void Or (UsageVector new_vector) { IsDirty = true; locals.Or (new_vector.locals); if (parameters != null) parameters.Or (new_vector.parameters); } // <summary> // Performs an `and' operation on the locals. // </summary> public void AndLocals (UsageVector new_vector) { IsDirty = true; locals.And (new_vector.locals); } public bool HasParameters { get { return parameters != null; } } public bool HasLocals { get { return locals != null; } } // <summary> // Returns a deep copy of the parameters. // </summary> public MyBitVector Parameters { get { if (parameters != null) return parameters.Clone (); else return null; } } // <summary> // Returns a deep copy of the locals. // </summary> public MyBitVector Locals { get { if (locals != null) return locals.Clone (); else return null; } } public MyBitVector ParameterVector { get { return parameters; } } public MyBitVector LocalVector { get { return locals; } } // // Debugging stuff. // public override string ToString () { StringBuilder sb = new StringBuilder (); sb.Append ("Vector ("); sb.Append (Type); sb.Append (","); sb.Append (id); sb.Append (","); sb.Append (IsDirty); sb.Append (","); sb.Append (reachability); if (parameters != null) { sb.Append (" - "); sb.Append (parameters); } sb.Append (" - "); sb.Append (locals); sb.Append (")"); return sb.ToString (); } } // <summary> // Creates a new flow branching which is contained in `parent'. // You should only pass non-null for the `block' argument if this block // introduces any new variables - in this case, we need to create a new // usage vector with a different size than our parent's one. // </summary> protected FlowBranching (FlowBranching parent, BranchingType type, SiblingType stype, Block block, Location loc) { Parent = parent; Block = block; Location = loc; Type = type; id = ++next_id; UsageVector vector; if (Block != null) { param_map = Block.ParameterMap; local_map = Block.LocalMap; UsageVector parent_vector = parent != null ? parent.CurrentUsageVector : null; vector = new UsageVector ( stype, parent_vector, Block, loc, param_map.Length, local_map.Length); } else { param_map = Parent.param_map; local_map = Parent.local_map; vector = new UsageVector ( stype, Parent.CurrentUsageVector, null, loc); } AddSibling (vector); } public abstract UsageVector CurrentUsageVector { get; } // <summary> // Creates a sibling of the current usage vector. // </summary> public virtual void CreateSibling (Block block, SiblingType type) { UsageVector vector = new UsageVector ( type, Parent.CurrentUsageVector, block, Location); AddSibling (vector); Report.Debug (1, " CREATED SIBLING", CurrentUsageVector); } public void CreateSibling () { CreateSibling (null, SiblingType.Conditional); } protected abstract void AddSibling (UsageVector uv); public virtual LabeledStatement LookupLabel (string name, Location loc) { if (Parent != null) return Parent.LookupLabel (name, loc); Report.Error ( 159, loc, "No such label `" + name + "' in this scope"); return null; } public abstract void Label (UsageVector origin_vectors); // <summary> // Check whether all `out' parameters have been assigned. // </summary> public void CheckOutParameters (MyBitVector parameters, Location loc) { for (int i = 0; i < param_map.Count; i++) { VariableInfo var = param_map [i]; if (var == null) continue; if (var.IsAssigned (parameters)) continue; Report.Error (177, loc, "The out parameter `{0}' must be assigned to before control leaves the current method", var.Name); } } protected UsageVector Merge (UsageVector sibling_list) { if (sibling_list.Next == null) return sibling_list; MyBitVector locals = null; MyBitVector parameters = null; Reachability reachability = null; Report.Debug (2, " MERGING SIBLINGS", this, Name); for (UsageVector child = sibling_list; child != null; child = child.Next) { bool do_break = (Type != BranchingType.Switch) && (Type != BranchingType.Loop); Report.Debug (2, " MERGING SIBLING ", child, child.ParameterVector, child.LocalVector, reachability, child.Reachability, do_break); Reachability.And (ref reachability, child.Reachability, do_break); // A local variable is initialized after a flow branching if it // has been initialized in all its branches which do neither // always return or always throw an exception. // // If a branch may return, but does not always return, then we // can treat it like a never-returning branch here: control will // only reach the code position after the branching if we did not // return here. // // It's important to distinguish between always and sometimes // returning branches here: // // 1 int a; // 2 if (something) { // 3 return; // 4 a = 5; // 5 } // 6 Console.WriteLine (a); // // The if block in lines 3-4 always returns, so we must not look // at the initialization of `a' in line 4 - thus it'll still be // uninitialized in line 6. // // On the other hand, the following is allowed: // // 1 int a; // 2 if (something) // 3 a = 5; // 4 else // 5 return; // 6 Console.WriteLine (a); // // Here, `a' is initialized in line 3 and we must not look at // line 5 since it always returns. // bool do_break_2 = (child.Type != SiblingType.Block) && (child.Type != SiblingType.SwitchSection); bool always_throws = (child.Type != SiblingType.Try) && child.Reachability.AlwaysThrows; bool unreachable = always_throws || (do_break_2 && child.Reachability.AlwaysBreaks) || child.Reachability.AlwaysReturns || child.Reachability.AlwaysHasBarrier; Report.Debug (2, " MERGING SIBLING #1", reachability, Type, child.Type, child.Reachability.IsUnreachable, do_break_2, always_throws, unreachable); if (!unreachable && (child.LocalVector != null)) MyBitVector.And (ref locals, child.LocalVector); // An `out' parameter must be assigned in all branches which do // not always throw an exception. if ((child.ParameterVector != null) && !child.Reachability.AlwaysThrows) MyBitVector.And (ref parameters, child.ParameterVector); Report.Debug (2, " MERGING SIBLING #2", parameters, locals); } if (reachability == null) reachability = Reachability.Never (); Report.Debug (2, " MERGING SIBLINGS DONE", parameters, locals, reachability, Infinite); return new UsageVector ( parameters, locals, reachability, null, Location); } protected abstract UsageVector Merge (); // <summary> // Merge a child branching. // </summary> public UsageVector MergeChild (FlowBranching child) { return CurrentUsageVector.MergeChild (child); } // <summary> // Does the toplevel merging. // </summary> public Reachability MergeTopBlock () { if ((Type != BranchingType.Block) || (Block == null)) throw new NotSupportedException (); UsageVector vector = new UsageVector ( SiblingType.Block, null, Block, Location, param_map.Length, local_map.Length); UsageVector result = vector.MergeChild (this); Report.Debug (4, "MERGE TOP BLOCK", Location, vector, result.Reachability); if ((vector.Reachability.Throws != FlowReturns.Always) && (vector.Reachability.Barrier != FlowReturns.Always)) CheckOutParameters (vector.Parameters, Location); return result.Reachability; } // // Checks whether we're in a `try' block. // public virtual bool InTryOrCatch (bool is_return) { if ((Block != null) && Block.IsDestructor) return true;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -