X-Git-Url: http://wien.tomnetworks.com/gitweb/?a=blobdiff_plain;f=mcs%2Fgmcs%2Fflowanalysis.cs;h=bc7f898d76a7ca61dd3529478be69450a2d5a421;hb=35c139e3eba84b5e3a33d242964b6c5fdce90035;hp=fdcbf56c745b77b311688435a248051c943c57a9;hpb=0d9ba2239a123b04a37c6081445a48d79556f11c;p=mono.git diff --git a/mcs/gmcs/flowanalysis.cs b/mcs/gmcs/flowanalysis.cs index fdcbf56c745..bc7f898d76a 100644 --- a/mcs/gmcs/flowanalysis.cs +++ b/mcs/gmcs/flowanalysis.cs @@ -79,7 +79,7 @@ namespace Mono.CSharp public sealed class Reachability { - FlowReturns returns, breaks, throws, barrier, reachable; + FlowReturns returns, breaks, throws, barrier; public FlowReturns Returns { get { return returns; } @@ -93,10 +93,6 @@ namespace Mono.CSharp public FlowReturns Barrier { get { return barrier; } } - public FlowReturns Reachable { - get { return reachable; } - } - public Reachability (FlowReturns returns, FlowReturns breaks, FlowReturns throws, FlowReturns barrier) { @@ -104,15 +100,11 @@ namespace Mono.CSharp this.breaks = breaks; this.throws = throws; this.barrier = barrier; - - update (); } public Reachability Clone () { - Reachability cloned = new Reachability (returns, breaks, throws, barrier); - cloned.reachable = reachable; - return cloned; + return new Reachability (returns, breaks, throws, barrier); } // @@ -176,10 +168,15 @@ namespace Mono.CSharp return; } + a.And (b, do_break); + } + + public void And (Reachability b, bool do_break) + { // // `break' does not "break" in a Switch or a LoopBlock // - bool a_breaks = do_break && a.AlwaysBreaks; + bool a_breaks = do_break && AlwaysBreaks; bool b_breaks = do_break && b.AlwaysBreaks; bool a_has_barrier, b_has_barrier; @@ -188,50 +185,55 @@ namespace Mono.CSharp // This is the normal case: the code following a barrier // cannot be reached. // - a_has_barrier = a.AlwaysHasBarrier; + a_has_barrier = AlwaysHasBarrier; b_has_barrier = b.AlwaysHasBarrier; } else { // // Special case for Switch and LoopBlocks: we can reach the // code after the barrier via the `break'. // - a_has_barrier = !a.AlwaysBreaks && a.AlwaysHasBarrier; + a_has_barrier = !AlwaysBreaks && AlwaysHasBarrier; b_has_barrier = !b.AlwaysBreaks && b.AlwaysHasBarrier; } - bool a_unreachable = a_breaks || a.AlwaysThrows || a_has_barrier; + bool a_unreachable = a_breaks || AlwaysThrows || a_has_barrier; bool b_unreachable = b_breaks || b.AlwaysThrows || b_has_barrier; // // Do all code paths always return ? // - if (a.AlwaysReturns) { + if (AlwaysReturns) { if (b.AlwaysReturns || b_unreachable) - a.returns = FlowReturns.Always; + returns = FlowReturns.Always; else - a.returns = FlowReturns.Sometimes; + returns = FlowReturns.Sometimes; } else if (b.AlwaysReturns) { - if (a.AlwaysReturns || a_unreachable) - a.returns = FlowReturns.Always; + if (AlwaysReturns || a_unreachable) + returns = FlowReturns.Always; else - a.returns = FlowReturns.Sometimes; - } else if (!a.MayReturn) { + returns = FlowReturns.Sometimes; + } else if (!MayReturn) { if (b.MayReturn) - a.returns = FlowReturns.Sometimes; + returns = FlowReturns.Sometimes; else - a.returns = FlowReturns.Never; + returns = FlowReturns.Never; } else if (!b.MayReturn) { - if (a.MayReturn) - a.returns = FlowReturns.Sometimes; + if (MayReturn) + returns = FlowReturns.Sometimes; else - a.returns = FlowReturns.Never; + returns = FlowReturns.Never; } - a.breaks = AndFlowReturns (a.breaks, b.breaks); - a.throws = AndFlowReturns (a.throws, b.throws); - a.barrier = AndFlowReturns (a.barrier, b.barrier); + breaks = AndFlowReturns (breaks, b.breaks); + throws = AndFlowReturns (throws, b.throws); + barrier = AndFlowReturns (barrier, b.barrier); - a.reachable = AndFlowReturns (a.reachable, b.reachable); + if (a_unreachable && b_unreachable) + barrier = FlowReturns.Always; + else if (a_unreachable || b_unreachable) + barrier = FlowReturns.Sometimes; + else + barrier = FlowReturns.Never; } public void Or (Reachability b) @@ -240,8 +242,6 @@ namespace Mono.CSharp breaks = OrFlowReturns (breaks, b.breaks); throws = OrFlowReturns (throws, b.throws); barrier = OrFlowReturns (barrier, b.barrier); - - update (); } public static Reachability Never () @@ -251,16 +251,21 @@ namespace Mono.CSharp FlowReturns.Never, FlowReturns.Never); } - void update () - { - if ((returns == FlowReturns.Always) || (breaks == FlowReturns.Always) || - (throws == FlowReturns.Always) || (barrier == FlowReturns.Always)) - reachable = FlowReturns.Never; - else if ((returns == FlowReturns.Never) && (breaks == FlowReturns.Never) && - (throws == FlowReturns.Never) && (barrier == FlowReturns.Never)) - reachable = FlowReturns.Always; + public FlowReturns Reachable { + get { + if ((returns == FlowReturns.Always) || + (breaks == FlowReturns.Always) || + (throws == FlowReturns.Always) || + (barrier == FlowReturns.Always)) + return FlowReturns.Never; + else if ((returns == FlowReturns.Never) && + (breaks == FlowReturns.Never) && + (throws == FlowReturns.Never) && + (barrier == FlowReturns.Never)) + return FlowReturns.Always; else - reachable = FlowReturns.Sometimes; + return FlowReturns.Sometimes; + } } public bool AlwaysBreaks { @@ -296,43 +301,47 @@ namespace Mono.CSharp } public bool IsUnreachable { - get { return reachable == FlowReturns.Never; } + get { return Reachable == FlowReturns.Never; } } public void SetReturns () { returns = FlowReturns.Always; - update (); } public void SetReturnsSometimes () { returns = FlowReturns.Sometimes; - update (); } public void SetBreaks () { breaks = FlowReturns.Always; - update (); } public void ResetBreaks () { breaks = FlowReturns.Never; - update (); } public void SetThrows () { throws = FlowReturns.Always; - update (); + } + + public void SetThrowsSometimes () + { + throws = FlowReturns.Sometimes; } public void SetBarrier () { barrier = FlowReturns.Always; - update (); + } + + public void ResetBarrier () + { + barrier = FlowReturns.Never; } static string ShortName (FlowReturns returns) @@ -352,7 +361,7 @@ namespace Mono.CSharp return String.Format ("[{0}:{1}:{2}:{3}:{4}]", ShortName (returns), ShortName (breaks), ShortName (throws), ShortName (barrier), - ShortName (reachable)); + ShortName (Reachable)); } } @@ -360,10 +369,10 @@ namespace Mono.CSharp { switch (type) { case BranchingType.Exception: - return new FlowBranchingException (parent, block, loc); + throw new InvalidOperationException (); case BranchingType.Switch: - return new FlowBranchingBlock (parent, type, SiblingType.SwitchSection, block, loc); + return new FlowBranchingSwitch (parent, block, loc); case BranchingType.SwitchSection: return new FlowBranchingBlock (parent, type, SiblingType.Block, block, loc); @@ -371,6 +380,9 @@ namespace Mono.CSharp case BranchingType.Block: return new FlowBranchingBlock (parent, type, SiblingType.Block, block, loc); + case BranchingType.Loop: + return new FlowBranchingLoop (parent, block, loc); + default: return new FlowBranchingBlock (parent, type, SiblingType.Conditional, block, loc); } @@ -425,6 +437,11 @@ namespace Mono.CSharp // public readonly Location Location; + // + // This is only valid for SwitchSection, Try, Catch and Finally. + // + public readonly Block Block; + // // If this is true, then the usage vector has been modified and must be // merged when we're done with this branching. @@ -465,9 +482,12 @@ namespace Mono.CSharp // // Normally, you should not use any of these constructors. // - public UsageVector (SiblingType type, UsageVector parent, Location loc, int num_params, int num_locals) + public UsageVector (SiblingType type, UsageVector parent, + Block block, Location loc, + int num_params, int num_locals) { this.Type = type; + this.Block = block; this.Location = loc; this.InheritsFrom = parent; this.CountParameters = num_params; @@ -494,15 +514,19 @@ namespace Mono.CSharp id = ++next_id; } - public UsageVector (SiblingType type, UsageVector parent, Location loc) - : this (type, parent, loc, parent.CountParameters, parent.CountLocals) + public UsageVector (SiblingType type, UsageVector parent, + Block block, Location loc) + : this (type, parent, block, loc, + parent.CountParameters, parent.CountLocals) { } public UsageVector (MyBitVector parameters, MyBitVector locals, - Reachability reachability, Location loc) + Reachability reachability, Block block, + Location loc) { this.Type = SiblingType.Block; this.Location = loc; + this.Block = block; this.reachability = reachability; this.parameters = parameters; @@ -516,7 +540,9 @@ namespace Mono.CSharp // public UsageVector Clone () { - UsageVector retval = new UsageVector (Type, null, Location, CountParameters, CountLocals); + UsageVector retval = new UsageVector ( + Type, null, Block, Location, + CountParameters, CountLocals); if (retval.locals != null) retval.locals = locals.Clone (); @@ -531,7 +557,7 @@ namespace Mono.CSharp public bool IsAssigned (VariableInfo var) { - if (!var.IsParameter && Reachability.AlwaysBreaks) + if (!var.IsParameter && Reachability.IsUnreachable) return true; return var.IsAssigned (var.IsParameter ? parameters : locals); @@ -539,7 +565,7 @@ namespace Mono.CSharp public void SetAssigned (VariableInfo var) { - if (!var.IsParameter && Reachability.AlwaysBreaks) + if (!var.IsParameter && Reachability.IsUnreachable) return; IsDirty = true; @@ -548,7 +574,7 @@ namespace Mono.CSharp public bool IsFieldAssigned (VariableInfo var, string name) { - if (!var.IsParameter && Reachability.AlwaysBreaks) + if (!var.IsParameter && Reachability.IsUnreachable) return true; return var.IsFieldAssigned (var.IsParameter ? parameters : locals, name); @@ -556,7 +582,7 @@ namespace Mono.CSharp public void SetFieldAssigned (VariableInfo var, string name) { - if (!var.IsParameter && Reachability.AlwaysBreaks) + if (!var.IsParameter && Reachability.IsUnreachable) return; IsDirty = true; @@ -608,7 +634,7 @@ namespace Mono.CSharp { UsageVector result = branching.Merge (); - Report.Debug (2, " MERGING CHILD", this, IsDirty, + Report.Debug (2, " MERGING CHILD", this, branching, IsDirty, result.ParameterVector, result.LocalVector, result.Reachability, reachability, Type); @@ -626,17 +652,19 @@ namespace Mono.CSharp // then we do always return (or stay in the // loop forever). new_r.SetReturns (); - } + } new_r.SetBarrier (); - } else { - if (new_r.Returns == FlowReturns.Always) { - // We're either finite or we may leave the loop. - new_r.SetReturnsSometimes (); - } - } - } else if (branching.Type == BranchingType.Switch) + } + + 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 @@ -660,7 +688,10 @@ namespace Mono.CSharp if (result.ParameterVector != null) parameters.Or (result.ParameterVector); - reachability.Or (new_r); + 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); @@ -714,35 +745,41 @@ namespace Mono.CSharp // 8 Console.WriteLine (a); // // - public void MergeJumpOrigins (ICollection origin_vectors) + public void MergeJumpOrigins (UsageVector o_vectors) { Report.Debug (1, " MERGING JUMP ORIGINS", this); reachability = Reachability.Never (); - if (origin_vectors == null) + if (o_vectors == null) { + reachability.SetBarrier (); return; + } bool first = true; - foreach (UsageVector vector in origin_vectors) { - Report.Debug (1, " MERGING JUMP ORIGIN", vector); + 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); + 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); - } + 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); @@ -770,6 +807,39 @@ namespace Mono.CSharp 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) @@ -893,13 +963,14 @@ namespace Mono.CSharp local_map = Block.LocalMap; UsageVector parent_vector = parent != null ? parent.CurrentUsageVector : null; - vector = new UsageVector (stype, parent_vector, loc, param_map.Length, local_map.Length); - - + 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, loc); + vector = new UsageVector ( + stype, Parent.CurrentUsageVector, null, loc); } AddSibling (vector); @@ -912,16 +983,34 @@ namespace Mono.CSharp // // Creates a sibling of the current usage vector. // - public virtual void CreateSibling (SiblingType type) + public virtual void CreateSibling (Block block, SiblingType type) { - AddSibling (new UsageVector (type, Parent.CurrentUsageVector, Location)); + 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 abstract void Label (ArrayList origin_vectors); + 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); // // Check whether all `out' parameters have been assigned. @@ -939,7 +1028,7 @@ namespace Mono.CSharp Report.Error (177, loc, "The out parameter `" + var.Name + "' must be " + - "assigned before control leave the current method."); + "assigned before control leaves the current method."); } } @@ -1030,7 +1119,8 @@ namespace Mono.CSharp Report.Debug (2, " MERGING SIBLINGS DONE", parameters, locals, reachability, Infinite); - return new UsageVector (parameters, locals, reachability, Location); + return new UsageVector ( + parameters, locals, reachability, null, Location); } protected abstract UsageVector Merge (); @@ -1052,13 +1142,15 @@ namespace Mono.CSharp throw new NotSupportedException (); UsageVector vector = new UsageVector ( - SiblingType.Conditional, null, Location, param_map.Length, local_map.Length); + 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) + if ((vector.Reachability.Throws != FlowReturns.Always) && + (vector.Reachability.Barrier != FlowReturns.Always)) CheckOutParameters (vector.Parameters, Location); return result.Reachability; @@ -1080,29 +1172,11 @@ namespace Mono.CSharp return false; } - // - // Checks whether we're in a `catch' block. - // - public virtual bool InCatch () + public virtual bool InTryWithCatch () { if (Parent != null) - return Parent.InCatch (); - else - return false; - } - - // - // Checks whether we're in a `finally' block. - // - public virtual bool InFinally (bool is_return) - { - if (!is_return && - ((Type == BranchingType.Loop) || (Type == BranchingType.Switch))) - return false; - else if (Parent != null) - return Parent.InFinally (is_return); - else - return false; + return Parent.InTryWithCatch (); + return false; } public virtual bool InLoop () @@ -1143,6 +1217,20 @@ namespace Mono.CSharp throw new NotSupportedException (); } + public virtual void AddBreakVector (UsageVector vector) + { + if (Parent != null) + Parent.AddBreakVector (vector); + else if ((Block == null) || !Block.IsDestructor) + throw new NotSupportedException (); + } + + public virtual void StealFinallyClauses (ref ArrayList list) + { + if (Parent != null) + Parent.StealFinallyClauses (ref list); + } + public bool IsAssigned (VariableInfo vi) { return CurrentUsageVector.IsAssigned (vi); @@ -1216,12 +1304,24 @@ namespace Mono.CSharp sibling_list = sibling; } - public override void Label (ArrayList origin_vectors) + public override LabeledStatement LookupLabel (string name, Location loc) + { + if (Block == null) + return base.LookupLabel (name, loc); + + LabeledStatement s = Block.LookupLabel (name); + if (s != null) + return s; + + return base.LookupLabel (name, loc); + } + + public override void Label (UsageVector origin_vectors) { if (!CurrentUsageVector.Reachability.IsUnreachable) { - if (origin_vectors == null) - origin_vectors = new ArrayList (1); - origin_vectors.Add (CurrentUsageVector.Clone ()); + UsageVector vector = CurrentUsageVector.Clone (); + vector.Next = origin_vectors; + origin_vectors = vector; } CurrentUsageVector.MergeJumpOrigins (origin_vectors); @@ -1233,32 +1333,85 @@ namespace Mono.CSharp } } + public class FlowBranchingLoop : FlowBranchingBlock + { + UsageVector break_origins; + + public FlowBranchingLoop (FlowBranching parent, Block block, Location loc) + : base (parent, BranchingType.Loop, SiblingType.Conditional, block, loc) + { } + + public override void AddBreakVector (UsageVector vector) + { + vector = vector.Clone (); + vector.Next = break_origins; + break_origins = vector; + } + + protected override UsageVector Merge () + { + UsageVector vector = base.Merge (); + + vector.MergeBreakOrigins (this, break_origins); + + return vector; + } + } + + public class FlowBranchingSwitch : FlowBranchingBlock + { + UsageVector break_origins; + + public FlowBranchingSwitch (FlowBranching parent, Block block, Location loc) + : base (parent, BranchingType.Switch, SiblingType.SwitchSection, block, loc) + { } + + public override void AddBreakVector (UsageVector vector) + { + vector = vector.Clone (); + vector.Next = break_origins; + break_origins = vector; + } + + protected override UsageVector Merge () + { + UsageVector vector = base.Merge (); + + vector.MergeBreakOrigins (this, break_origins); + + return vector; + } + } + public class FlowBranchingException : FlowBranching { + ExceptionStatement stmt; UsageVector current_vector; UsageVector catch_vectors; UsageVector finally_vector; UsageVector finally_origins; - bool in_try; + bool emit_finally; - public FlowBranchingException (FlowBranching parent, Block block, Location loc) - : base (parent, BranchingType.Exception, SiblingType.Try, block, loc) - { } + public FlowBranchingException (FlowBranching parent, + ExceptionStatement stmt) + : base (parent, BranchingType.Exception, SiblingType.Try, + null, stmt.loc) + { + this.stmt = stmt; + this.emit_finally = true; + } protected override void AddSibling (UsageVector sibling) { if (sibling.Type == SiblingType.Try) { sibling.Next = catch_vectors; catch_vectors = sibling; - in_try = true; } else if (sibling.Type == SiblingType.Catch) { sibling.Next = catch_vectors; catch_vectors = sibling; - in_try = false; } else if (sibling.Type == SiblingType.Finally) { sibling.MergeFinallyOrigins (finally_origins); finally_vector = sibling; - in_try = false; } else throw new InvalidOperationException (); @@ -1274,14 +1427,18 @@ namespace Mono.CSharp return finally_vector == null; } - public override bool InCatch () + public override bool InTryWithCatch () { - return !in_try && (finally_vector == null); - } + if (finally_vector == null) { + Try t = stmt as Try; + if (t != null && t.HasCatch) + return true; + } - public override bool InFinally (bool is_return) - { - return finally_vector != null; + if (Parent != null) + return Parent.InTryWithCatch (); + + return false; } public override bool BreakCrossesTryCatchBoundary () @@ -1296,7 +1453,39 @@ namespace Mono.CSharp finally_origins = vector; } - public override void Label (ArrayList origin_vectors) + public override void StealFinallyClauses (ref ArrayList list) + { + if (list == null) + list = new ArrayList (); + list.Add (stmt); + emit_finally = false; + base.StealFinallyClauses (ref list); + } + + public bool EmitFinally { + get { return emit_finally; } + } + + public override LabeledStatement LookupLabel (string name, Location loc) + { + if (current_vector.Block == null) + return base.LookupLabel (name, loc); + + LabeledStatement s = current_vector.Block.LookupLabel (name); + if (s != null) + return s; + + if (finally_vector != null) { + Report.Error ( + 157, loc, "Control can not leave the body " + + "of the finally block"); + return null; + } + + return base.LookupLabel (name, loc); + } + + public override void Label (UsageVector origin_vectors) { CurrentUsageVector.MergeJumpOrigins (origin_vectors); } @@ -1500,13 +1689,15 @@ namespace Mono.CSharp if (type is TypeBuilder) { TypeContainer tc = TypeManager.LookupTypeContainer (type); - ArrayList fields = tc.Fields; + ArrayList fields = null; + if (tc != null) + fields = tc.Fields; ArrayList public_fields = new ArrayList (); ArrayList non_public_fields = new ArrayList (); if (fields != null) { - foreach (Field field in fields) { + foreach (FieldMember field in fields) { if ((field.ModFlags & Modifiers.STATIC) != 0) continue; if ((field.ModFlags & Modifiers.PUBLIC) != 0) @@ -1523,6 +1714,10 @@ namespace Mono.CSharp Fields = new FieldInfo [Count]; public_fields.CopyTo (Fields, 0); non_public_fields.CopyTo (Fields, CountPublic); + } else if (type is GenericTypeParameterBuilder) { + CountPublic = CountNonPublic = Count = 0; + + Fields = new FieldInfo [0]; } else { FieldInfo[] public_fields = type.GetFields ( BindingFlags.Instance|BindingFlags.Public); @@ -2031,7 +2226,12 @@ namespace Mono.CSharp // public void And (MyBitVector new_vector) { - BitArray new_array = new_vector.Vector; + BitArray new_array; + + if (new_vector != null) + new_array = new_vector.Vector; + else + new_array = new BitArray (Count, false); initialize_vector ();