|
// Copyright (c) .NET Foundation and contributors. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
using System;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Diagnostics.CodeAnalysis;
// This is needed due to NativeAOT which doesn't enable nullable globally yet
#nullable enable
namespace ILLink.Shared.DataFlow
{
public enum RegionKind
{
Try,
Catch,
Filter,
Finally
}
public enum ConditionKind
{
Unconditional,
WhenFalse,
WhenTrue,
Unknown
}
public interface IRegion<TRegion> : IEquatable<TRegion>
{
RegionKind Kind { get; }
}
public interface IBlock<TBlock> : IEquatable<TBlock>
{
}
public interface IControlFlowGraph<TBlock, TRegion>
where TBlock : struct, IBlock<TBlock>
where TRegion : IRegion<TRegion>
{
// Represents an edge in the control flow graph, from a source to a destination basic block.
public readonly struct ControlFlowBranch : IEquatable<ControlFlowBranch>
{
public readonly TBlock Source;
// Might be null in a 'throw' branch.
public readonly TBlock? Destination;
public readonly ConditionKind ConditionKind;
// The finally regions exited when control flows through this edge.
// For example:
//
// try {
// try {
// Source();
// }
// finally {}
// } finally {}
// Target();
//
// There will be an edge in the CRFG from the block that calls
// Source() to the block that calls Target(), which exits both
// finally regions.
public readonly ImmutableArray<TRegion> FinallyRegions;
public ControlFlowBranch (TBlock source, TBlock? destination, ImmutableArray<TRegion> finallyRegions, ConditionKind conditionKind)
{
Source = source;
Destination = destination;
FinallyRegions = finallyRegions;
ConditionKind = conditionKind;
}
public bool Equals (ControlFlowBranch other)
{
if (!Source.Equals (other.Source))
return false;
if (ConditionKind != other.ConditionKind)
return false;
if (Destination == null)
return other.Destination == null;
return Destination.Equals (other.Destination);
}
public override bool Equals (object? obj)
{
return obj is ControlFlowBranch other && Equals (other);
}
public override int GetHashCode ()
{
return HashUtils.Combine (
Source.GetHashCode (),
Destination?.GetHashCode () ?? typeof (ControlFlowBranch).GetHashCode (),
ConditionKind.GetHashCode ());
}
}
IEnumerable<TBlock> Blocks { get; }
TBlock Entry { get; }
// This does not include predecessor edges for exceptional control flow into
// catch regions or finally regions. It also doesn't include edges for non-exceptional
// control flow from try -> finally or from catch -> finally.
IEnumerable<ControlFlowBranch> GetPredecessors (TBlock block);
IEnumerable<ControlFlowBranch> GetSuccessors (TBlock block);
bool TryGetEnclosingTryOrCatchOrFilter (TBlock block, [NotNullWhen (true)] out TRegion? tryOrCatchOrFilterRegion);
bool TryGetEnclosingTryOrCatchOrFilter (TRegion region, [NotNullWhen (true)] out TRegion? tryOrCatchOrFilterRegion);
bool TryGetEnclosingFinally (TBlock block, [NotNullWhen (true)] out TRegion? region);
TRegion GetCorrespondingTry (TRegion cathOrFilterOrFinallyRegion);
IEnumerable<TRegion> GetPreviousFilters (TRegion catchOrFilterRegion);
bool HasFilter (TRegion catchRegion);
TBlock FirstBlock (TRegion region);
TBlock LastBlock (TRegion region);
}
}
|