782 lines
27 KiB
C#
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);
|
||
|
}
|
||
|
}
|
||
|
}
|