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

782 lines
27 KiB
C#

//
// SubroutineBase.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.AST;
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 SubroutineBase<Label> : Subroutine, IGraph<CFGBlock, Dummy>, IStackInfo, IEdgeSubroutineAdaptor {
private const int UnusedBlockIndex = Int32.MaxValue - 1;
protected readonly Label StartLabel;
public readonly SubroutineFacade SubroutineFacade;
private readonly Dictionary<Pair<CFGBlock, CFGBlock>, Sequence<Pair<EdgeTag, Subroutine>>> edge_subroutines
= new Dictionary<Pair<CFGBlock, CFGBlock>, Sequence<Pair<EdgeTag, Subroutine>>> ();
private readonly BlockWithLabels<Label> entry;
private readonly BlockWithLabels<Label> entry_after_requires;
private readonly BlockWithLabels<Label> exception_exit;
private readonly BlockWithLabels<Label> exit;
private readonly List<Edge<CFGBlock, EdgeTag>> successors = new List<Edge<CFGBlock, EdgeTag>> ();
protected int BlockIdGenerator;
protected Dictionary<Label, BlockWithLabels<Label>> LabelsThatStartBlocks = new Dictionary<Label, BlockWithLabels<Label>> ();
private CFGBlock[] blocks;
private DepthFirst.Visitor<CFGBlock, Dummy> edge_info;
private EdgeMap<EdgeTag> predecessor_edges;
private EdgeMap<EdgeTag> successor_edges;
protected SubroutineBase (SubroutineFacade subroutineFacade)
{
this.SubroutineFacade = subroutineFacade;
this.entry = new EntryBlock<Label> (this, ref this.BlockIdGenerator);
this.exit = new EntryExitBlock<Label> (this, ref this.BlockIdGenerator);
this.exception_exit = new CatchFilterEntryBlock<Label> (this, ref this.BlockIdGenerator);
}
protected SubroutineBase (SubroutineFacade facade,
Label startLabel, SubroutineBuilder<Label> builder)
: this (facade)
{
this.StartLabel = startLabel;
Builder = builder;
CodeProvider = builder.CodeProvider;
this.entry_after_requires = GetTargetBlock (startLabel);
AddSuccessor (this.entry, EdgeTag.Entry, this.entry_after_requires);
}
public override bool HasContextDependentStackDepth
{
get { return true; }
}
public override bool HasReturnValue
{
get { return false; }
}
public override int StackDelta
{
get { return 0; }
}
protected SubroutineBuilder<Label> Builder { get; set; }
public override DepthFirst.Visitor<CFGBlock, Dummy> EdgeInfo
{
get { return this.edge_info; }
}
public ICodeProvider<Label> CodeProvider { get; private set; }
public override int BlockCount
{
get { return this.blocks.Length; }
}
public override IEnumerable<CFGBlock> Blocks
{
get { return this.blocks; }
}
public override string Name
{
get { return "SR" + Id; }
}
public override EdgeMap<EdgeTag> SuccessorEdges
{
get { return this.successor_edges; }
}
public override EdgeMap<EdgeTag> PredecessorEdges
{
get
{
if (this.predecessor_edges == null)
this.predecessor_edges = this.successor_edges.Reverse ();
return this.predecessor_edges;
}
}
#region Main Blocks
public override CFGBlock Entry
{
get { return this.entry; }
}
public override CFGBlock EntryAfterRequires
{
get
{
if (this.entry_after_requires != null)
return this.entry_after_requires;
return Entry;
}
}
public override CFGBlock Exit
{
get { return this.exit; }
}
public override CFGBlock ExceptionExit
{
get { return this.exception_exit; }
}
#endregion
#region IEdgeSubroutineAdaptor Members
public Sequence<Pair<EdgeTag, Subroutine>> GetOrdinaryEdgeSubroutinesInternal (CFGBlock from, CFGBlock to, Sequence<Edge<CFGBlock, EdgeTag>> context)
{
Sequence<Pair<EdgeTag, Subroutine>> list;
this.edge_subroutines.TryGetValue (new Pair<CFGBlock, CFGBlock> (from, to), out list);
if (list != null && context != null)
list = list.Where (FilterRecursiveContracts (to, context));
return list;
}
#endregion
#region IGraph<CFGBlock,Dummy> Members
public IEnumerable<CFGBlock> Nodes
{
get { return this.blocks; }
}
public virtual IEnumerable<Pair<Dummy, CFGBlock>> Successors (CFGBlock node)
{
foreach (var pair in this.successor_edges [node])
yield return new Pair<Dummy, CFGBlock> (Dummy.Value, pair.Value);
if (node != this.exception_exit)
yield return new Pair<Dummy, CFGBlock> (Dummy.Value, this.exception_exit);
}
#endregion
#region IStackInfo Members
bool IStackInfo.IsCallOnThis (APC apc)
{
return false;
}
#endregion
public override IEnumerable<CFGBlock> SuccessorBlocks (CFGBlock block)
{
return SuccessorEdges [block].Select (it => it.Value);
}
public override bool HasSingleSuccessor (APC point, out APC ifFound)
{
if (point.Index < point.Block.Count) {
ifFound = new APC (point.Block, point.Index + 1, point.SubroutineContext);
return true;
}
if (IsSubroutineEnd (point.Block)) {
if (point.SubroutineContext == null) {
ifFound = APC.Dummy;
return false;
}
ifFound = ComputeSubroutineContinuation (point);
return true;
}
BlockWithLabels<Label> onlyOne = null;
foreach (BlockWithLabels<Label> successor in point.Block.Subroutine.SuccessorBlocks (point.Block)) {
if (onlyOne == null)
onlyOne = successor;
else {
ifFound = APC.Dummy;
return false;
}
}
if (onlyOne != null) {
ifFound = ComputeTargetFinallyContext (point, onlyOne);
return true;
}
ifFound = APC.Dummy;
return false;
}
public override bool HasSinglePredecessor (APC point, out APC ifFound)
{
if (point.Index > 0) {
ifFound = new APC (point.Block, point.Index - 1, point.SubroutineContext);
return true;
}
if (IsSubroutineStart (point.Block)) {
if (point.SubroutineContext == null) {
ifFound = APC.Dummy;
return false;
}
bool hasSinglePredecessor;
ifFound = ComputeSubroutinePreContinuation (point, out hasSinglePredecessor);
return hasSinglePredecessor;
}
CFGBlock onlyOne = null;
foreach (CFGBlock predecessor in point.Block.Subroutine.PredecessorBlocks (point.Block)) {
if (onlyOne != null) {
ifFound = APC.Dummy;
return false;
}
onlyOne = predecessor;
}
if (onlyOne == null) {
ifFound = APC.Dummy;
return false;
}
Sequence<Pair<EdgeTag, Subroutine>> list = EdgeSubroutinesOuterToInner (onlyOne, point.Block, point.SubroutineContext);
if (list.IsEmpty ()) {
ifFound = APC.ForEnd (onlyOne, point.SubroutineContext);
return true;
}
var edge = new Edge<CFGBlock, EdgeTag> (onlyOne, point.Block, list.Head.Key);
Subroutine sub = list.Head.Value;
ifFound = APC.ForEnd (sub.Exit, point.SubroutineContext.Cons (edge));
return true;
}
private APC ComputeSubroutinePreContinuation (APC point, out bool hasSinglePredecessor)
{
Edge<CFGBlock, EdgeTag> head = point.SubroutineContext.Head;
bool isExceptionHandlerEdge;
Sequence<Edge<CFGBlock, EdgeTag>> tail = point.SubroutineContext.Tail;
Sequence<Pair<EdgeTag, Subroutine>> flist = EdgeSubroutinesOuterToInner (head.From, head.To, out isExceptionHandlerEdge, tail);
while (flist.Head.Value != this)
flist = flist.Tail;
if (flist.Tail.IsEmpty ()) {
if (isExceptionHandlerEdge && head.From.Count > 1) {
hasSinglePredecessor = false;
return APC.Dummy;
}
hasSinglePredecessor = true;
return APC.ForEnd (head.From, tail);
}
Pair<EdgeTag, Subroutine> first = flist.Tail.Head;
Subroutine sub = first.Value;
hasSinglePredecessor = true;
return APC.ForEnd (sub.Exit, point.SubroutineContext.Cons (new Edge<CFGBlock, EdgeTag> (head.From, head.To, first.Key)));
}
private APC ComputeSubroutineContinuation (APC point)
{
Edge<CFGBlock, EdgeTag> head = point.SubroutineContext.Head;
Sequence<Edge<CFGBlock, EdgeTag>> tail = point.SubroutineContext.Tail;
Sequence<Pair<EdgeTag, Subroutine>> outerToInner = EdgeSubroutinesOuterToInner (head.From, head.To, tail);
if (outerToInner.Head.Value == this)
return new APC (head.To, 0, tail);
while (outerToInner.Tail.Head.Value != this)
outerToInner = outerToInner.Tail;
return new APC (outerToInner.Head.Value.Entry, 0, tail.Cons (new Edge<CFGBlock, EdgeTag> (head.From, head.To, outerToInner.Head.Key)));
}
public override IEnumerable<CFGBlock> PredecessorBlocks (CFGBlock block)
{
return PredecessorEdges [block].Select (it => it.Value);
}
public override bool IsJoinPoint (CFGBlock block)
{
if (IsCatchFilterHeader (block) || IsSubroutineStart (block) || IsSubroutineEnd (block))
return true;
return PredecessorEdges [block].Count > 1;
}
public override bool IsSubroutineEnd (CFGBlock block)
{
return block == this.exit || block == this.exception_exit;
}
public override bool IsSubroutineStart (CFGBlock block)
{
return block == this.entry;
}
public override bool IsSplitPoint (CFGBlock block)
{
if (IsSubroutineStart (block) || IsSubroutineEnd (block))
return true;
return SuccessorEdges [block].Count > 1;
}
public override bool IsCatchFilterHeader (CFGBlock block)
{
return block is CatchFilterEntryBlock<Label>;
}
public void AddSuccessor (CFGBlock from, EdgeTag tag, CFGBlock to)
{
AddNormalControlFlowEdge (this.successors, from, tag, to);
}
private void AddNormalControlFlowEdge (List<Edge<CFGBlock, EdgeTag>> succs, CFGBlock from, EdgeTag tag, CFGBlock to)
{
succs.Add (new Edge<CFGBlock, EdgeTag> (from, to, tag));
}
public virtual void AddReturnBlock (BlockWithLabels<Label> block)
{
}
public BlockWithLabels<Label> GetTargetBlock (Label label)
{
return GetBlock (label);
}
public BlockWithLabels<Label> GetBlock (Label label)
{
IMetaDataProvider metadataDecoder = this.SubroutineFacade.MetaDataProvider;
BlockWithLabels<Label> block;
if (!this.LabelsThatStartBlocks.TryGetValue (label, out block)) {
Pair<Method, bool> methodVirtualPair;
Method constructor;
if (Builder == null)
throw new InvalidOperationException ("Builder must be not null");
if (Builder.IsMethodCallSite (label, out methodVirtualPair)) {
int parametersCount = metadataDecoder.Parameters (methodVirtualPair.Key).Count;
block = new MethodCallBlock<Label> (methodVirtualPair.Key, this, ref this.BlockIdGenerator, parametersCount, methodVirtualPair.Value);
} else if (Builder.IsNewObjSite (label, out constructor)) {
int parametersCount = metadataDecoder.Parameters (constructor).Count;
block = new NewObjCallBlock<Label> (constructor, parametersCount, this, ref this.BlockIdGenerator);
} else
block = NewBlock ();
if (Builder.IsTargetLabel (label))
this.LabelsThatStartBlocks.Add (label, block);
}
return block;
}
public virtual BlockWithLabels<Label> NewBlock ()
{
return new BlockWithLabels<Label> (this, ref this.BlockIdGenerator);
}
public AssumeBlock<Label> NewAssumeBlock (Label pc, EdgeTag tag)
{
return new AssumeBlock<Label> (this, pc, tag, ref this.BlockIdGenerator);
}
public override sealed void AddEdgeSubroutine (CFGBlock from, CFGBlock to, Subroutine subroutine, EdgeTag tag)
{
if (subroutine == null)
return;
var key = Pair.From (from, to);
Sequence<Pair<EdgeTag, Subroutine>> list;
this.edge_subroutines.TryGetValue (key, out list);
this.edge_subroutines[key] = list.Cons (Pair.From (tag, subroutine));
}
public override IEnumerable<APC> Successors (APC pc)
{
APC singleNext;
if (HasSingleSuccessor (pc, out singleNext))
yield return singleNext;
else {
foreach (CFGBlock block in pc.Block.Subroutine.SuccessorBlocks (pc.Block))
yield return pc.Block.Subroutine.ComputeTargetFinallyContext (pc, block);
}
}
public override IEnumerable<APC> Predecessors (APC pc)
{
if (pc.Index > 0)
yield return new APC (pc.Block, pc.Index - 1, pc.SubroutineContext);
else if (IsSubroutineStart (pc.Block)) {
if (!pc.SubroutineContext.IsEmpty ()) {
foreach (APC apc in ComputeSubroutinePreContinuation (pc))
yield return apc;
}
} else {
foreach (CFGBlock block in pc.Block.Subroutine.PredecessorBlocks (pc.Block)) {
Sequence<Pair<EdgeTag, Subroutine>> diffs = EdgeSubroutinesOuterToInner (block, pc.Block, pc.SubroutineContext);
if (diffs.IsEmpty ())
yield return APC.ForEnd (block, pc.SubroutineContext);
else {
Subroutine sub = diffs.Head.Value;
var edge = new Edge<CFGBlock, EdgeTag> (block, pc.Block, diffs.Head.Key);
yield return APC.ForEnd (sub.Exit, pc.SubroutineContext.Cons (edge));
}
}
}
}
private IEnumerable<APC> ComputeSubroutinePreContinuation (APC point)
{
Edge<CFGBlock, EdgeTag> edge = point.SubroutineContext.Head;
Sequence<Edge<CFGBlock, EdgeTag>> tail = point.SubroutineContext.Tail;
bool isHandlerEdge;
Sequence<Pair<EdgeTag, Subroutine>> diffs = EdgeSubroutinesOuterToInner (edge.From, edge.To, out isHandlerEdge, tail);
while (diffs.Head.Value != this)
diffs = diffs.Tail;
if (diffs.Tail == null) {
if (isHandlerEdge) {
for (int i = 0; i < edge.From.Count; i++)
yield return new APC (edge.From, i, tail);
} else
yield return APC.ForEnd (edge.From, tail);
} else {
Pair<EdgeTag, Subroutine> first = diffs.Tail.Head;
Subroutine nextSubroutine = first.Value;
yield return APC.ForEnd (nextSubroutine.Exit, point.SubroutineContext.Cons (new Edge<CFGBlock, EdgeTag> (edge.From, edge.To, first.Key)));
}
}
public override APC ComputeTargetFinallyContext (APC pc, CFGBlock succ)
{
Sequence<Pair<EdgeTag, Subroutine>> list = EdgeSubroutinesOuterToInner (pc.Block, succ, pc.SubroutineContext);
if (list.IsEmpty ())
return new APC (succ, 0, pc.SubroutineContext);
Pair<EdgeTag, Subroutine> last = list.Last ();
return new APC (last.Value.Entry, 0, pc.SubroutineContext.Cons (new Edge<CFGBlock, EdgeTag> (pc.Block, succ, last.Key)));
}
private Sequence<Pair<EdgeTag, Subroutine>> EdgeSubroutinesOuterToInner (CFGBlock from, CFGBlock succ, Sequence<Edge<CFGBlock, EdgeTag>> subroutineContext)
{
bool isExceptionHandlerEdge;
return EdgeSubroutinesOuterToInner (from, succ, out isExceptionHandlerEdge, subroutineContext);
}
public override Sequence<Pair<EdgeTag, Subroutine>> EdgeSubroutinesOuterToInner (CFGBlock from, CFGBlock succ, out bool isExceptionHandlerEdge, Sequence<Edge<CFGBlock, EdgeTag>> context)
{
if (from.Subroutine != this)
return from.Subroutine.EdgeSubroutinesOuterToInner (from, succ, out isExceptionHandlerEdge, context);
isExceptionHandlerEdge = IsCatchFilterHeader (succ);
return GetOrdinaryEdgeSubroutines (from, succ, context);
}
public override Sequence<Pair<EdgeTag, Subroutine>> GetOrdinaryEdgeSubroutines (CFGBlock from, CFGBlock to, Sequence<Edge<CFGBlock, EdgeTag>> context)
{
IMetaDataProvider metadataDecoder = this.SubroutineFacade.MetaDataProvider;
var apc = new APC (to, 0, context);
DecoratorHelper.Push (this);
try {
Sequence<Pair<EdgeTag, Subroutine>> list = DecoratorHelper.Dispatch<IEdgeSubroutineAdaptor> (this).GetOrdinaryEdgeSubroutinesInternal (from, to, context);
if (apc.InsideContract) {
if (context != null && !list.IsEmpty ()) {
Method calledMethod;
bool isNewObj;
bool isVirtual;
if (@from.IsMethodCallBlock (out calledMethod, out isNewObj, out isVirtual) && isVirtual && ((IStackInfo) this).IsCallOnThis (new APC (@from, 0, null))) {
TypeNode type = metadataDecoder.DeclaringType (calledMethod);
do {
if (context.Head.Tag.Is (EdgeTag.InheritedMask) || context.Head.Tag.Is (EdgeTag.ExtraMask) || context.Head.Tag.Is (EdgeTag.OldMask))
context = context.Tail;
else {
Method calledMethod2;
bool isNewObj2;
bool isVirtual2;
if (context.Head.Tag.Is (EdgeTag.AfterMask) && context.Head.From.IsMethodCallBlock (out calledMethod2, out isNewObj2, out isVirtual2)) {
TypeNode sub = metadataDecoder.DeclaringType (calledMethod2);
if (metadataDecoder.DerivesFrom (sub, type))
type = sub;
if (!DecoratorHelper.Dispatch<IStackInfo> (this).IsCallOnThis (new APC (context.Head.From, 0, null)))
break;
} else if (context.Head.Tag.Is (EdgeTag.BeforeMask) && context.Head.To.IsMethodCallBlock (out calledMethod2, out isNewObj2, out isVirtual2)) {
TypeNode sub = metadataDecoder.DeclaringType (calledMethod2);
if (metadataDecoder.DerivesFrom (sub, type))
type = sub;
if (!DecoratorHelper.Dispatch<IStackInfo> (this).IsCallOnThis (new APC (context.Head.To, 0, null)))
break;
} else if (context.Head.Tag == EdgeTag.Exit) {
var methodInfo = context.Head.From.Subroutine as IMethodInfo;
if (methodInfo != null) {
TypeNode sub = metadataDecoder.DeclaringType (methodInfo.Method);
if (metadataDecoder.DerivesFrom (sub, type))
type = sub;
}
break;
} else {
if (context.Head.Tag != EdgeTag.Entry)
return list;
var methodInfo = context.Head.From.Subroutine as IMethodInfo;
if (methodInfo != null) {
TypeNode sub = metadataDecoder.DeclaringType (methodInfo.Method);
if (metadataDecoder.DerivesFrom (sub, type))
type = sub;
}
break;
}
context = context.Tail;
}
} while (!context.IsEmpty ());
Method implementingMethod;
if (!metadataDecoder.Equal (type, metadataDecoder.DeclaringType (calledMethod)) &&
metadataDecoder.TryGetImplementingMethod (type, calledMethod, out implementingMethod))
list = SpecializedEnsures (list, this.SubroutineFacade.GetEnsures (calledMethod), this.SubroutineFacade.GetEnsures (implementingMethod));
}
}
} else {
Method calledMethod;
bool isNewObj;
bool isVirtual;
if (@from.IsMethodCallBlock (out calledMethod, out isNewObj, out isVirtual)) {
if (DecoratorHelper.Dispatch<IStackInfo> (this).IsCallOnThis (new APC (@from, 0, null))) {
var methodInfo = @from.Subroutine as IMethodInfo;
if (methodInfo != null) {
TypeNode bestType = metadataDecoder.DeclaringType (methodInfo.Method);
Method implementingMethod;
if (isVirtual && metadataDecoder.TryGetImplementingMethod (bestType, calledMethod, out implementingMethod))
list = SpecializedEnsures (list, this.SubroutineFacade.GetEnsures (calledMethod), this.SubroutineFacade.GetEnsures (implementingMethod));
list = InsertInvariant (@from, list, calledMethod, ref bestType, context);
}
}
}
}
return list;
} finally {
DecoratorHelper.Pop ();
}
}
private Sequence<Pair<EdgeTag, Subroutine>> InsertInvariant (CFGBlock from, Sequence<Pair<EdgeTag, Subroutine>> list,
Method calledMethod, ref TypeNode type,
Sequence<Edge<CFGBlock, EdgeTag>> context)
{
IMetaDataProvider metadataDecoder = this.SubroutineFacade.MetaDataProvider;
Property property;
if (metadataDecoder.IsPropertySetter (calledMethod, out property)
&& (metadataDecoder.IsAutoPropertyMember (calledMethod) || WithinConstructor (from, context)))
return list;
if (metadataDecoder.IsConstructor (calledMethod))
type = metadataDecoder.DeclaringType (calledMethod);
Subroutine invariant = this.SubroutineFacade.GetInvariant (type);
if (invariant != null) {
var methodCallBlock = from as MethodCallBlock<Label>;
if (methodCallBlock != null) {
EdgeTag first = methodCallBlock.IsNewObj ? EdgeTag.AfterNewObj : EdgeTag.AfterCall;
return list.Cons (new Pair<EdgeTag, Subroutine> (first, invariant));
}
}
return list;
}
private bool WithinConstructor (CFGBlock current, Sequence<Edge<CFGBlock, EdgeTag>> context)
{
return new APC (current, 0, context).InsideConstructor;
}
private Sequence<Pair<EdgeTag, Subroutine>> SpecializedEnsures (Sequence<Pair<EdgeTag, Subroutine>> subroutines,
Subroutine toReplace, Subroutine specializedEnsures)
{
return subroutines.Select (pair => new Pair<EdgeTag, Subroutine> (pair.Key, pair.Value == toReplace ? specializedEnsures : pair.Value));
}
private static Predicate<Pair<EdgeTag, Subroutine>> FilterRecursiveContracts (CFGBlock from, Sequence<Edge<CFGBlock, EdgeTag>> context)
{
return (candidate) => {
Subroutine sub = candidate.Value;
if (!sub.IsContract)
return true;
if (sub == @from.Subroutine)
return false;
if (context.Any (ctx => sub == ctx.From.Subroutine))
return false;
return true;
};
}
public abstract override void Initialize ();
public virtual void Commit ()
{
PostProcessBlocks ();
}
protected void PostProcessBlocks ()
{
var blockStack = new Stack<CFGBlock> ();
this.successor_edges = new EdgeMap<EdgeTag> (this.successors);
this.edge_info = new DepthFirst.Visitor<CFGBlock, Dummy> (this, null, (block) => blockStack.Push (block), null);
this.edge_info.VisitSubGraphNonRecursive (this.exception_exit);
this.edge_info.VisitSubGraphNonRecursive (this.exit);
this.edge_info.VisitSubGraphNonRecursive (this.entry);
foreach (var successorEdge in this.successor_edges) {
int idGen = UnusedBlockIndex;
successorEdge.From.Renumber (ref idGen);
}
int idGen1 = 0;
foreach (CFGBlock cfgBlock in blockStack)
cfgBlock.Renumber (ref idGen1);
SuccessorEdges.Filter ((e) => e.From.Index != UnusedBlockIndex);
this.predecessor_edges = this.successor_edges.Reverse ();
int finishTime = 0;
var visitor = new DepthFirst.Visitor<CFGBlock, EdgeTag> (this.predecessor_edges, null, block => block.ReversePostOrderIndex = finishTime++, null);
visitor.VisitSubGraphNonRecursive (this.exit);
foreach (CFGBlock node in blockStack)
visitor.VisitSubGraphNonRecursive (node);
SuccessorEdges.Resort ();
this.blocks = blockStack.ToArray ();
this.LabelsThatStartBlocks = null;
Builder = null;
}
public override IEnumerable<Subroutine> UsedSubroutines (HashSet<int> alreadySeen)
{
foreach (var list in this.edge_subroutines.Values) {
foreach (var pair in list.AsEnumerable ()) {
Subroutine sub = pair.Value;
if (!alreadySeen.Contains (sub.Id)) {
alreadySeen.Add (sub.Id);
yield return sub;
}
}
}
}
public override IEnumerable<CFGBlock> ExceptionHandlers<Data, TType> (CFGBlock block, Subroutine innerSubroutine,
Data data, IHandlerFilter<Data> handlerPredicate)
{
yield return this.exception_exit;
}
public override void Print (TextWriter tw, ILPrinter<APC> printer, Func<CFGBlock,
IEnumerable<Sequence<Edge<CFGBlock, EdgeTag>>>> contextLookup,
Sequence<Edge<CFGBlock, EdgeTag>> context,
HashSet<Pair<Subroutine, Sequence<Edge<CFGBlock, EdgeTag>>>> printed)
{
var element = new Pair<Subroutine, Sequence<Edge<CFGBlock, EdgeTag>>> (this, context);
if (printed.Contains (element))
return;
printed.Add (element);
var subs = new HashSet<Subroutine> ();
var methodInfo = this as IMethodInfo;
string method = (methodInfo != null) ? String.Format ("({0})", this.SubroutineFacade.MetaDataProvider.FullName (methodInfo.Method)) : null;
tw.WriteLine ("Subroutine SR{0} {1} {2}", Id, Kind, method);
tw.WriteLine ("-------------");
foreach (BlockWithLabels<Label> block in this.blocks) {
tw.Write ("Block {0} ({1})", block.Index, block.ReversePostOrderIndex);
if (this.edge_info.DepthFirstInfo (block).TargetOfBackEdge)
tw.WriteLine (" (target of backedge)");
else if (IsJoinPoint (block))
tw.WriteLine (" (join point)");
else
tw.WriteLine ();
tw.Write (" Predecessors: ");
foreach (var edge in block.Subroutine.PredecessorEdges [block])
tw.Write ("({0}, {1}) ", edge.Key, edge.Value.Index);
tw.WriteLine ();
PrintHandlers (tw, block);
tw.WriteLine (" Code:");
foreach (APC apc in block.APCs ())
printer (apc, " ", tw);
tw.Write (" Successors: ");
foreach (var edge in block.Subroutine.SuccessorEdges [block]) {
tw.Write ("({0}, {1}", edge.Key, edge.Value.Index);
if (this.edge_info.IsBackEdge (block, Dummy.Value, edge.Value))
tw.Write (" BE");
for (Sequence<Pair<EdgeTag, Subroutine>> list = GetOrdinaryEdgeSubroutines (block, edge.Value, context); list != null; list = list.Tail) {
subs.Add (list.Head.Value);
tw.Write (" SR{0}({1})", list.Head.Value.Id, list.Head.Key);
}
tw.Write (") ");
}
tw.WriteLine ();
}
PrintReferencedSubroutines (tw, subs, printer, contextLookup, context, printed);
}
protected virtual 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 subroutine in subs) {
if (contextLookup == null)
subroutine.Print (tw, printer, contextLookup, context, printed);
else {
foreach (var ctx in contextLookup (subroutine.Entry))
subroutine.Print (tw, printer, contextLookup, ctx, printed);
}
}
}
protected virtual void PrintHandlers (TextWriter tw, BlockWithLabels<Label> block)
{
tw.Write (" Handlers: ");
if (block != ExceptionExit)
tw.Write ("{0} ", ExceptionExit.Index);
tw.WriteLine ();
}
public int GetILOffset (Label label)
{
return CodeProvider.GetILOffset (label);
}
}
}