X-Git-Url: http://wien.tomnetworks.com/gitweb/?a=blobdiff_plain;f=mcs%2Fgmcs%2Fflowanalysis.cs;h=73aefac0b373f1e7403c243ef5008593a0980d23;hb=11ebc5207de0ac675d6bc0240fc8a25ac4fb7c5c;hp=8f0e94e0e6434f73af909c01176258cb950dfc6d;hpb=b7c17c47e6b3c02192e64175cb5ee0ce7f7dda1b;p=mono.git diff --git a/mcs/gmcs/flowanalysis.cs b/mcs/gmcs/flowanalysis.cs index 8f0e94e0e64..73aefac0b37 100644 --- a/mcs/gmcs/flowanalysis.cs +++ b/mcs/gmcs/flowanalysis.cs @@ -168,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; @@ -180,55 +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); if (a_unreachable && b_unreachable) - a.barrier = FlowReturns.Always; + barrier = FlowReturns.Always; else if (a_unreachable || b_unreachable) - a.barrier = FlowReturns.Sometimes; + barrier = FlowReturns.Sometimes; else - a.barrier = FlowReturns.Never; + barrier = FlowReturns.Never; } public void Or (Reachability b) @@ -258,7 +263,7 @@ namespace Mono.CSharp (throws == FlowReturns.Never) && (barrier == FlowReturns.Never)) return FlowReturns.Always; - else + else return FlowReturns.Sometimes; } } @@ -334,6 +339,11 @@ namespace Mono.CSharp barrier = FlowReturns.Always; } + public void ResetBarrier () + { + barrier = FlowReturns.Never; + } + static string ShortName (FlowReturns returns) { switch (returns) { @@ -359,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); @@ -485,7 +495,7 @@ namespace Mono.CSharp if (parent != null) { if (num_locals > 0) - locals = new MyBitVector (parent.locals, CountLocals); + locals = new MyBitVector (parent.locals, CountLocals); if (num_params > 0) parameters = new MyBitVector (parent.parameters, num_params); @@ -493,7 +503,7 @@ namespace Mono.CSharp reachability = parent.Reachability.Clone (); } else { if (num_locals > 0) - locals = new MyBitVector (null, CountLocals); + locals = new MyBitVector (null, CountLocals); if (num_params > 0) parameters = new MyBitVector (null, num_params); @@ -535,7 +545,7 @@ namespace Mono.CSharp CountParameters, CountLocals); if (retval.locals != null) - retval.locals = locals.Clone (); + retval.locals = locals.Clone (); if (parameters != null) retval.parameters = parameters.Clone (); @@ -624,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); @@ -642,21 +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 (); - } - if (new_r.Throws == FlowReturns.Always) { - // We're either finite or we may leave the loop. - new_r.SetThrowsSometimes (); - } - } - } 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 @@ -670,9 +678,9 @@ namespace Mono.CSharp if ((Type == SiblingType.SwitchSection) && !new_r.IsUnreachable) { Report.Error (163, Location, "Control cannot fall through from one " + - "case label to another"); + "case label to another"); return result; - } + } if (locals != null && result.LocalVector != null) locals.Or (result.LocalVector); @@ -680,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); @@ -688,7 +699,7 @@ namespace Mono.CSharp IsDirty = true; return result; - } + } protected void MergeFinally (FlowBranching branching, UsageVector f_origins, MyBitVector f_params) @@ -740,30 +751,35 @@ namespace Mono.CSharp reachability = Reachability.Never (); - if (o_vectors == null) + 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); + 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); @@ -780,7 +796,7 @@ namespace Mono.CSharp reachability = Reachability.Never (); for (UsageVector vector = f_origins; vector != null; vector = vector.Next) { - Report.Debug (1, " MERGING FINALLY ORIGIN", vector); + Report.Debug (1, " MERGING FINALLY ORIGIN", vector); if (parameters != null) parameters.And (vector.parameters); @@ -791,18 +807,18 @@ namespace Mono.CSharp Report.Debug (1, " MERGING FINALLY ORIGIN DONE", this); } - public void MergeBreakOrigins (UsageVector o_vectors) + public void MergeBreakOrigins (FlowBranching branching, UsageVector o_vectors) { Report.Debug (1, " MERGING BREAK ORIGINS", this); if (o_vectors == null) return; - bool first = true; + bool first = branching.Infinite; for (UsageVector vector = o_vectors; vector != null; vector = vector.Next) { - Report.Debug (1, " MERGING BREAK ORIGIN", vector); + Report.Debug (1, " MERGING BREAK ORIGIN", vector, first); if (first) { if (locals != null && vector.Locals != null) @@ -817,6 +833,8 @@ namespace Mono.CSharp if (parameters != null) parameters.And (vector.parameters); } + + reachability.And (vector.Reachability, false); } Report.Debug (1, " MERGING BREAK ORIGINS DONE", this); @@ -878,7 +896,7 @@ namespace Mono.CSharp public MyBitVector Locals { get { if (locals != null) - return locals.Clone (); + return locals.Clone (); else return null; } @@ -1008,14 +1026,13 @@ namespace Mono.CSharp if (var.IsAssigned (parameters)) continue; - Report.Error (177, loc, "The out parameter `" + - var.Name + "' must be " + - "assigned before control leaves the current method."); + 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; @@ -1029,13 +1046,13 @@ namespace Mono.CSharp 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. @@ -1124,7 +1141,7 @@ namespace Mono.CSharp throw new NotSupportedException (); UsageVector vector = new UsageVector ( - SiblingType.Conditional, null, Block, Location, + SiblingType.Block, null, Block, Location, param_map.Length, local_map.Length); UsageVector result = vector.MergeChild (this); @@ -1154,29 +1171,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 () @@ -1225,6 +1224,12 @@ namespace Mono.CSharp 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); @@ -1316,7 +1321,7 @@ namespace Mono.CSharp UsageVector vector = CurrentUsageVector.Clone (); vector.Next = origin_vectors; origin_vectors = vector; - } + } CurrentUsageVector.MergeJumpOrigins (origin_vectors); } @@ -1346,7 +1351,32 @@ namespace Mono.CSharp { UsageVector vector = base.Merge (); - vector.MergeBreakOrigins (break_origins); + 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; } @@ -1354,30 +1384,33 @@ namespace Mono.CSharp 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 (); @@ -1393,14 +1426,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 () @@ -1415,6 +1452,19 @@ namespace Mono.CSharp finally_origins = vector; } + 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) @@ -1425,9 +1475,8 @@ namespace Mono.CSharp return s; if (finally_vector != null) { - Report.Error ( - 157, loc, "Control can not leave the body " + - "of the finally block"); + Report.Error (157, loc, + "Control cannot leave the body of a finally clause"); return null; } @@ -1594,9 +1643,8 @@ namespace Mono.CSharp if (!branching.IsFieldAssigned (vi, field.Name)) { Report.Error (171, loc, - "Field `" + TypeManager.CSharpName (Type) + - "." + field.Name + "' must be fully initialized " + - "before control leaves the constructor"); + "Field `{0}' must be fully assigned before control leaves the constructor", + TypeManager.GetFullNameSignature (field)); ok = false; } } @@ -1638,13 +1686,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) @@ -1697,7 +1747,7 @@ namespace Mono.CSharp field_hash.Add (field.Name, ++Length); else if (sinfo [i].InTransit) { Report.Error (523, String.Format ( - "Struct member '{0}.{1}' of type '{2}' causes " + + "Struct member `{0}.{1}' of type `{2}' causes " + "a cycle in the structure layout", type, field.Name, sinfo [i].Type)); sinfo [i] = null; @@ -1849,7 +1899,9 @@ namespace Mono.CSharp public bool IsAssigned (EmitContext ec) { - return !ec.DoFlowAnalysis || ec.CurrentBranching.IsAssigned (this); + return !ec.DoFlowAnalysis || + ec.OmitStructFlowAnalysis && TypeInfo.IsStruct || + ec.CurrentBranching.IsAssigned (this); } public bool IsAssigned (EmitContext ec, Location loc) @@ -1909,7 +1961,9 @@ namespace Mono.CSharp public bool IsFieldAssigned (EmitContext ec, string name, Location loc) { - if (!ec.DoFlowAnalysis || ec.CurrentBranching.IsFieldAssigned (this, name)) + if (!ec.DoFlowAnalysis || + ec.OmitStructFlowAnalysis && TypeInfo.IsStruct || + ec.CurrentBranching.IsFieldAssigned (this, name)) return true; Report.Error (170, loc, @@ -1979,7 +2033,7 @@ namespace Mono.CSharp VariableInfo[] map; - public VariableMap (InternalParameters ip) + public VariableMap (Parameters ip) { Count = ip != null ? ip.Count : 0; @@ -1992,7 +2046,7 @@ namespace Mono.CSharp for (int i = 0; i < Count; i++) { Parameter.Modifier mod = ip.ParameterModifier (i); - if ((mod & Parameter.Modifier.OUT) == 0) + if ((mod & Parameter.Modifier.OUT) != Parameter.Modifier.OUT) continue; // Dont allocate till we find an out var. @@ -2173,7 +2227,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 (); @@ -2244,7 +2303,7 @@ namespace Mono.CSharp { if (vector != null) return; - + vector = new BitArray (Count, false); if (InheritsFrom != null) Vector = InheritsFrom.Vector;