/// <summary>
        /// Applies all edits to the control flow graph.
        /// </summary>
        /// <param name="graph">The graph to apply the transaction on.</param>
        /// <exception cref="InvalidOperationException">Occurs when the transaction was already applied.</exception>
        /// <remarks>
        /// When an exception occurs within one of the edits, all edits previously applied will be reverted.
        /// </remarks>
        public void Apply(ControlFlowGraph <TInstruction> graph)
        {
            if (IsCompleted)
            {
                throw new InvalidOperationException("The transaction is already applied.");
            }

            var context = new ControlFlowGraphEditContext <TInstruction>(graph);
            int index   = 0;

            try
            {
                for (; index < _actions.Count; index++)
                {
                    var edit = _actions[index];
                    edit.Apply(context);
                }

                IsCompleted = true;
            }
            catch
            {
                index--;
                for (; index >= 0; index--)
                {
                    _actions[index].Revert(context);
                }
                throw;
            }
        }
Beispiel #2
0
        /// <inheritdoc />
        protected override void OnRevert(ControlFlowGraphEditContext <TInstruction> context)
        {
            var origin = context.FindNode(OriginOffset);
            var target = context.FindNodeOrSplit(TargetOffset, out _);

            origin.ConnectWith(target, EdgeType);
        }
        /// <inheritdoc />
        public void Revert(ControlFlowGraphEditContext <TInstruction> context)
        {
            if (!_isApplied)
            {
                throw new InvalidOperationException("Operation is not applied yet.");
            }

            var node = context.FindNode(BranchOffset);

            // Re-merge node if it was split.
            if (_hasSplit)
            {
                var newNeighbour = node.FallThroughNeighbour;
                node.FallThroughNeighbour = null;
                context.RemoveNodeFromIndex(newNeighbour.Offset);
                newNeighbour.MergeWithPredecessor();
            }

            // Restore original fallthrough neighbour.
            node.FallThroughNeighbour = _oldFallThroughOffset.HasValue
                ? context.FindNode(_oldFallThroughOffset.Value)
                : null;

            _isApplied = false;
        }
Beispiel #4
0
 /// <inheritdoc />
 public void Apply(ControlFlowGraphEditContext <TInstruction> context)
 {
     if (_isApplied)
     {
         throw new InvalidOperationException("Operation is already applied.");
     }
     context.FindNodeOrSplit(SplitOffset, out _hasSplit);
     _isApplied = true;
 }
Beispiel #5
0
        /// <inheritdoc />
        public void Revert(ControlFlowGraphEditContext <TInstruction> context)
        {
            if (!_isApplied)
            {
                throw new InvalidOperationException("Operation is not applied yet.");
            }

            OnRevert(context);

            _isApplied = false;
        }
Beispiel #6
0
        /// <inheritdoc />
        public void Apply(ControlFlowGraphEditContext <TInstruction> context)
        {
            if (_isApplied)
            {
                throw new InvalidOperationException("Operation is already applied.");
            }

            OnApply(context);

            _isApplied = true;
        }
Beispiel #7
0
        /// <inheritdoc />
        public void Revert(ControlFlowGraphEditContext <TInstruction> context)
        {
            if (!_isApplied)
            {
                throw new InvalidOperationException("Operation is not applied yet.");
            }

            if (_hasSplit)
            {
                var node = context.Graph.Nodes[SplitOffset];
                context.RemoveNodeFromIndex(SplitOffset);
                node.MergeWithPredecessor();
            }
        }
        /// <inheritdoc />
        public void Apply(ControlFlowGraphEditContext <TInstruction> context)
        {
            if (_isApplied)
            {
                throw new InvalidOperationException("Operation is already applied.");
            }

            var node = context.FindNode(BranchOffset);

            // Save original fallthrough node offset.
            _oldFallThroughOffset = node.FallThroughNeighbour?.Offset;

            // Set new fallthrough neighbour.
            node.FallThroughNeighbour = NewFallThroughOffset.HasValue
                ? context.FindNodeOrSplit(NewFallThroughOffset.Value, out _hasSplit)
                : null;

            _isApplied = true;
        }
Beispiel #9
0
        /// <inheritdoc />
        protected override void OnRevert(ControlFlowGraphEditContext <TInstruction> context)
        {
            var origin = context.FindNode(OriginOffset);
            var target = context.Graph.Nodes[TargetOffset];

            var collection = EdgeType switch
            {
                ControlFlowEdgeType.Conditional => origin.ConditionalEdges,
                ControlFlowEdgeType.Abnormal => origin.AbnormalEdges,
                _ => throw new ArgumentOutOfRangeException()
            };

            collection.Remove(collection.GetEdgesToNeighbour(target).First());

            if (_hasSplit)
            {
                context.RemoveNodeFromIndex(target.Offset);
                target.MergeWithPredecessor();
            }
        }
Beispiel #10
0
        /// <inheritdoc />
        protected override void OnApply(ControlFlowGraphEditContext <TInstruction> context)
        {
            var origin = context.FindNode(OriginOffset);
            var target = context.Graph.Nodes[TargetOffset];

            var collection = EdgeType switch
            {
                ControlFlowEdgeType.Conditional => origin.ConditionalEdges,
                ControlFlowEdgeType.Abnormal => origin.AbnormalEdges,
                _ => throw new ArgumentOutOfRangeException()
            };

            collection.Remove(collection.GetEdgesToNeighbour(target).First());

            var incomingEdges = target.GetIncomingEdges().ToArray();

            if (incomingEdges.Length == 1 && incomingEdges[0].Type == ControlFlowEdgeType.FallThrough)
            {
                context.RemoveNodeFromIndex(target.Offset);
                target.MergeWithPredecessor();
            }
        }
Beispiel #11
0
 /// <summary>
 /// Reverts the update to the adjacency list of the node.
 /// </summary>
 /// <param name="context">The editing context.</param>
 /// <remarks>
 /// This method is guaranteed to be called after <see cref="Apply"/>.
 /// </remarks>
 protected abstract void OnRevert(ControlFlowGraphEditContext <TInstruction> context);