Jo Shields a575963da9 Imported Upstream version 3.6.0
Former-commit-id: da6be194a6b1221998fc28233f2503bd61dd9d14
2014-08-13 10:39:27 +01:00

209 lines
8.4 KiB
C#

//
// SubroutineWithHandlers.cs
//
// Authors:
// Alexander Chebaturkin (chebaturkin@gmail.com)
//
// Copyright (C) 2011 Alexander Chebaturkin
//
// Permission is hereby granted, free of charge, to any person obtaining
// a copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to
// permit persons to whom the Software is furnished to do so, subject to
// the following conditions:
//
// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
//
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using Mono.CodeContracts.Static.Analysis;
using Mono.CodeContracts.Static.ControlFlow.Blocks;
using Mono.CodeContracts.Static.ControlFlow.Subroutines.Builders;
using Mono.CodeContracts.Static.DataStructures;
using Mono.CodeContracts.Static.Providers;
namespace Mono.CodeContracts.Static.ControlFlow.Subroutines {
abstract class SubroutineWithHandlers<Label, Handler> : SubroutineBase<Label> {
protected readonly Dictionary<Handler, BlockWithLabels<Label>> CatchFilterHeaders = new Dictionary<Handler, BlockWithLabels<Label>> ();
public readonly Dictionary<Handler, Subroutine> FaultFinallySubroutines = new Dictionary<Handler, Subroutine> ();
protected readonly Dictionary<Handler, BlockWithLabels<Label>> FilterCodeBlocks = new Dictionary<Handler, BlockWithLabels<Label>> ();
public readonly Dictionary<CFGBlock, Sequence<Handler>> ProtectingHandlers = new Dictionary<CFGBlock, Sequence<Handler>> ();
public Sequence<Handler> CurrentProtectingHandlers = Sequence<Handler>.Empty;
protected SubroutineWithHandlers (SubroutineFacade subroutineFacade)
: base (subroutineFacade)
{
}
protected SubroutineWithHandlers (SubroutineFacade subroutineFacade,
Label startLabel,
SubroutineBuilder<Label> builder)
: base (subroutineFacade, startLabel, builder)
{
}
protected new IMethodCodeProvider<Label, Handler> CodeProvider
{
get { return (IMethodCodeProvider<Label, Handler>) base.CodeProvider; }
}
private bool IsFault (Handler handler)
{
return CodeProvider.IsFaultHandler (handler);
}
private Sequence<Handler> ProtectingHandlerList (CFGBlock block)
{
Sequence<Handler> list;
this.ProtectingHandlers.TryGetValue (block, out list);
return list;
}
public BlockWithLabels<Label> CreateCatchFilterHeader (Handler handler, Label label)
{
BlockWithLabels<Label> block;
if (!this.LabelsThatStartBlocks.TryGetValue (label, out block)) {
block = new CatchFilterEntryBlock<Label> (this, ref this.BlockIdGenerator);
this.CatchFilterHeaders.Add (handler, block);
this.LabelsThatStartBlocks.Add (label, block);
if (CodeProvider.IsFilterHandler (handler)) {
BlockWithLabels<Label> targetBlock = GetTargetBlock (CodeProvider.FilterExpressionStart (handler));
this.FilterCodeBlocks.Add (handler, targetBlock);
}
}
return block;
}
public override IEnumerable<Subroutine> UsedSubroutines (HashSet<int> alreadySeen)
{
return this.FaultFinallySubroutines.Values.Concat (base.UsedSubroutines (alreadySeen));
}
public override Sequence<Pair<EdgeTag, Subroutine>> EdgeSubroutinesOuterToInner (CFGBlock current, CFGBlock succ,
out bool isExceptionHandlerEdge, Sequence<Edge<CFGBlock, EdgeTag>> context)
{
if (current.Subroutine != this)
return current.Subroutine.EdgeSubroutinesOuterToInner (current, succ, out isExceptionHandlerEdge, context);
Sequence<Handler> l1 = ProtectingHandlerList (current);
Sequence<Handler> l2 = ProtectingHandlerList (succ);
isExceptionHandlerEdge = IsCatchFilterHeader (succ);
Sequence<Pair<EdgeTag, Subroutine>> result = GetOrdinaryEdgeSubroutines (current, succ, context);
while (l1 != l2) {
if (l1.Length () >= l2.Length ()) {
Handler head = l1.Head;
if (IsFaultOrFinally (head) && (!IsFault (head) || isExceptionHandlerEdge))
result = result.Cons (new Pair<EdgeTag, Subroutine> (EdgeTag.Finally, this.FaultFinallySubroutines [head]));
l1 = l1.Tail;
} else
l2 = l2.Tail;
}
return result;
}
private bool IsFaultOrFinally (Handler handler)
{
return CodeProvider.IsFaultHandler (handler) || CodeProvider.IsFinallyHandler (handler);
}
public override IEnumerable<Pair<Dummy, CFGBlock>> Successors (CFGBlock node)
{
foreach (var pair in SuccessorEdges [node])
yield return new Pair<Dummy, CFGBlock> (Dummy.Value, pair.Value);
foreach (Handler handler in ProtectingHandlerList (node).AsEnumerable ()) {
if (!IsFaultOrFinally (handler))
yield return new Pair<Dummy, CFGBlock> (Dummy.Value, this.CatchFilterHeaders [handler]);
}
if (node != ExceptionExit)
yield return new Pair<Dummy, CFGBlock> (Dummy.Value, ExceptionExit);
}
public override IEnumerable<CFGBlock> ExceptionHandlers<Data, TType> (CFGBlock block, Subroutine innerSubroutine,
Data data, IHandlerFilter<Data> handlerPredicate)
{
IHandlerFilter<Data> handleFilter = handlerPredicate;
Sequence<Handler> protectingHandlers = ProtectingHandlerList (block);
if (innerSubroutine != null && innerSubroutine.IsFaultFinally) {
for (; protectingHandlers != null; protectingHandlers = protectingHandlers.Tail) {
if (IsFaultOrFinally (protectingHandlers.Head) && this.FaultFinallySubroutines [protectingHandlers.Head] == innerSubroutine) {
protectingHandlers = protectingHandlers.Tail;
break;
}
}
}
for (; protectingHandlers != null; protectingHandlers = protectingHandlers.Tail) {
Handler handler = protectingHandlers.Head;
if (!IsFaultOrFinally (handler)) {
if (handleFilter != null) {
bool stopPropagation;
if (CodeProvider.IsCatchHandler (handler)) {
if (handleFilter.Catch (data, CodeProvider.CatchType (handler), out stopPropagation))
yield return this.CatchFilterHeaders [handler];
} else if (handleFilter.Filter (data, new APC (this.FilterCodeBlocks [handler], 0, null), out stopPropagation))
yield return this.CatchFilterHeaders [handler];
if (stopPropagation)
yield break;
} else
yield return this.CatchFilterHeaders [handler];
if (CodeProvider.IsCatchAllHandler (handler))
yield break;
}
}
yield return ExceptionExit;
}
protected override void PrintReferencedSubroutines (TextWriter tw, HashSet<Subroutine> subs, ILPrinter<APC> printer,
Func<CFGBlock, IEnumerable<Sequence<Edge<CFGBlock, EdgeTag>>>> contextLookup,
Sequence<Edge<CFGBlock, EdgeTag>> context,
HashSet<Pair<Subroutine, Sequence<Edge<CFGBlock, EdgeTag>>>> printed)
{
foreach (Subroutine sub in this.FaultFinallySubroutines.Values) {
if (contextLookup == null)
sub.Print (tw, printer, contextLookup, context, printed);
else {
foreach (var ctx in contextLookup (sub.Entry))
sub.Print (tw, printer, contextLookup, ctx, printed);
}
}
base.PrintReferencedSubroutines (tw, subs, printer, contextLookup, context, printed);
}
protected override void PrintHandlers (TextWriter tw, BlockWithLabels<Label> block)
{
tw.Write (" Handlers: ");
foreach (Handler handler in ProtectingHandlerList (block).AsEnumerable ()) {
if (IsFaultOrFinally (handler))
tw.Write ("SR{0} ", this.FaultFinallySubroutines [handler].Id);
else
tw.Write ("{0} ", this.CatchFilterHeaders [handler].Index);
}
if (block != ExceptionExit)
tw.Write ("{0} ", ExceptionExit.Index);
tw.WriteLine ();
}
}
}