public void SplittingNodeShouldPreserveParentRegion() { var graph = new ControlFlowGraph <int>(IntArchitecture.Instance); var n1 = new ControlFlowNode <int>(0, 0, 2, 3, 4); var n2 = new ControlFlowNode <int>(5, 5, 6, 7, 8); var region = new ExceptionHandlerRegion <int>(); graph.Regions.Add(region); var handler = new HandlerRegion <int>(); region.Handlers.Add(handler); graph.Nodes.AddRange(new[] { n1, n2 }); region.ProtectedRegion.Nodes.Add(n1); handler.Contents.Nodes.Add(n2); n1.ConnectWith(n2, ControlFlowEdgeType.Abnormal); graph.Entrypoint = n1; var(first, second) = n1.SplitAtIndex(2); Assert.Equal(first.ParentRegion, second.ParentRegion); Assert.Equal(first.ParentRegion, region.ProtectedRegion); Assert.Equal(2, region.ProtectedRegion.Nodes.Count); }
private static Dictionary <AddressRange, BasicControlFlowRegion <TInstruction> > CreateEHRegions <TInstruction>( ControlFlowGraph <TInstruction> cfg, IReadOnlyList <ExceptionHandlerRange> sortedRanges) { var rangeToRegion = new Dictionary <AddressRange, BasicControlFlowRegion <TInstruction> >(); var ehRegions = new Dictionary <AddressRange, ExceptionHandlerRegion <TInstruction> >(); for (int i = 0; i < sortedRanges.Count; i++) { var currentEHRange = sortedRanges[i]; if (!ehRegions.TryGetValue(currentEHRange.ProtectedRange, out var ehRegion)) { // Register new EH region for the protected range. ehRegion = new ExceptionHandlerRegion <TInstruction>(); ehRegions.Add(currentEHRange.ProtectedRange, ehRegion); rangeToRegion.Add(currentEHRange.ProtectedRange, ehRegion.ProtectedRegion); // Since the ranges are sorted by enclosing EHs first, we can backtrack the list of ranges to find. // the parent region (if there is any). BasicControlFlowRegion <TInstruction> parentRegion = null; for (int j = i; j >= 0 && parentRegion is null; j--) { var potentialParentRange = sortedRanges[j]; if (potentialParentRange.ProtectedRange.Contains(currentEHRange.ProtectedRange)) { parentRegion = rangeToRegion[potentialParentRange.ProtectedRange]; } if (potentialParentRange.HandlerRange.Contains(currentEHRange.HandlerRange)) { parentRegion = rangeToRegion[potentialParentRange.HandlerRange]; } } // Insert region into graph or parent region. if (parentRegion is null) { cfg.Regions.Add(ehRegion); } else { parentRegion.Regions.Add(ehRegion); } } // Register handler region. var handlerRegion = new BasicControlFlowRegion <TInstruction>(); handlerRegion.Tag = currentEHRange.UserData; ehRegion.HandlerRegions.Add(handlerRegion); rangeToRegion.Add(currentEHRange.HandlerRange, handlerRegion); } return(rangeToRegion); }
private static void EnterExceptionHandlerRegion <TInstruction>( IndexableStack <ScopeInfo <TInstruction> > scopeStack, ExceptionHandlerRegion <TInstruction> ehRegion) { var ehBlock = new ExceptionHandlerBlock <TInstruction> { Tag = ehRegion.Tag }; scopeStack.Peek().AddBlock(ehBlock); scopeStack.Push(new ScopeInfo <TInstruction>(ehRegion, ehBlock)); }
private static void EnterExceptionHandlerSubRegion <TInstruction>( IndexableStack <ScopeInfo <TInstruction> > scopeStack, ExceptionHandlerRegion <TInstruction> parentRegion, IControlFlowRegion <TInstruction> enteredRegion) { IBlock <TInstruction> enteredBlock; IControlFlowRegion <TInstruction> enteredSubRegion; if (!(scopeStack.Peek().Block is ExceptionHandlerBlock <TInstruction> ehBlock)) { throw new InvalidOperationException("The parent scope is not an exception handler scope."); } // Did we enter the protected region, or one of the handler regions? if (parentRegion.ProtectedRegion == enteredRegion) { // We entered the protected region. enteredBlock = ehBlock.ProtectedBlock; enteredSubRegion = parentRegion.ProtectedRegion; } else { // We entered a handler region. var handlerRegion = parentRegion.Handlers.First(r => r == enteredRegion); var handlerBlock = new HandlerBlock <TInstruction> { Tag = handlerRegion.Tag }; enteredBlock = handlerBlock; enteredSubRegion = handlerRegion; ehBlock.Handlers.Add(handlerBlock); } // Sanity check: If the entered subregion's parent is the exception handler region but the region // isn't a protected, prologue, epilogue nor one of the handler regions, that would mean that // something went *seriously* wrong. if (enteredSubRegion is null) { throw new InvalidOperationException( "Entered subregion of exception handler doesn't belong to any of its regions!?"); } // Push the entered scope. scopeStack.Push(new ScopeInfo <TInstruction>(enteredSubRegion, enteredBlock)); }
public void ExceptionHandler() { var cfg = new ControlFlowGraph <int>(IntArchitecture.Instance); for (int i = 0; i < 7; i++) { cfg.Nodes.Add(new ControlFlowNode <int>(i)); } cfg.Entrypoint = cfg.Nodes[0]; cfg.Nodes[0].ConnectWith(cfg.Nodes[1]); cfg.Nodes[1].ConnectWith(cfg.Nodes[2], ControlFlowEdgeType.Conditional); cfg.Nodes[1].ConnectWith(cfg.Nodes[3], ControlFlowEdgeType.FallThrough); cfg.Nodes[2].ConnectWith(cfg.Nodes[4], ControlFlowEdgeType.Unconditional); cfg.Nodes[3].ConnectWith(cfg.Nodes[4], ControlFlowEdgeType.FallThrough); cfg.Nodes[4].ConnectWith(cfg.Nodes[6], ControlFlowEdgeType.Unconditional); cfg.Nodes[5].ConnectWith(cfg.Nodes[6], ControlFlowEdgeType.Unconditional); var ehRegion = new ExceptionHandlerRegion <int>(); cfg.Regions.Add(ehRegion); ehRegion.ProtectedRegion.Entrypoint = cfg.Nodes[1]; ehRegion.ProtectedRegion.Nodes.AddRange(new[] { cfg.Nodes[1], cfg.Nodes[2], cfg.Nodes[3], cfg.Nodes[4], }); var handler = new HandlerRegion <int>(); ehRegion.Handlers.Add(handler); handler.Contents.Nodes.Add(cfg.Nodes[5]); handler.Contents.Entrypoint = cfg.Nodes[5]; var tree = DominatorTree <int> .FromGraph(cfg); Assert.True(tree.Dominates(cfg.Nodes[1], cfg.Nodes[6])); Assert.False(tree.Dominates(cfg.Nodes[4], cfg.Nodes[6])); Assert.False(tree.Dominates(cfg.Nodes[5], cfg.Nodes[6])); }
private ControlFlowRegion <Statement <TInstruction> > TransformRegion(IControlFlowRegion <TInstruction> region) { switch (region) { case BasicControlFlowRegion <TInstruction> basicRegion: // Create new basic region. var newBasicRegion = new BasicControlFlowRegion <Statement <TInstruction> >(); TransformSubRegions(basicRegion, newBasicRegion); // Register basic region pair. _context.RegionsMapping[basicRegion] = newBasicRegion; return(newBasicRegion); case ExceptionHandlerRegion <TInstruction> ehRegion: var newEhRegion = new ExceptionHandlerRegion <Statement <TInstruction> >(); // ProtectedRegion is read-only, so instead we just transform all sub regions and add it to the // existing protected region. TransformSubRegions(ehRegion.ProtectedRegion, newEhRegion.ProtectedRegion); _context.RegionsMapping[ehRegion.ProtectedRegion] = newEhRegion.ProtectedRegion; // Add handler regions. foreach (var subRegion in ehRegion.HandlerRegions) { newEhRegion.HandlerRegions.Add(TransformRegion(subRegion)); } return(newEhRegion); default: throw new ArgumentOutOfRangeException(nameof(region)); } void TransformSubRegions( BasicControlFlowRegion <TInstruction> originalRegion, BasicControlFlowRegion <Statement <TInstruction> > newRegion) { foreach (var subRegion in originalRegion.Regions) { newRegion.Regions.Add(TransformRegion(subRegion)); } } }
private static Dictionary <AddressRange, ScopeRegion <TInstruction> > CreateEHRegions <TInstruction>( ControlFlowGraph <TInstruction> cfg, IReadOnlyList <ExceptionHandlerRange> sortedRanges) { var result = new Dictionary <AddressRange, ScopeRegion <TInstruction> >(); var ehRegions = new Dictionary <AddressRange, ExceptionHandlerRegion <TInstruction> >(); for (int i = 0; i < sortedRanges.Count; i++) { var currentEHRange = sortedRanges[i]; // We want to merge exception handlers that have the exact same protected region. // This allows for exception handler constructs that have multiple handler blocks. // Check if we have already created the EH region in an earlier iteration: if (!ehRegions.TryGetValue(currentEHRange.ProtectedRange, out var ehRegion)) { // If not, create and register a new EH region for the protected range. ehRegion = new ExceptionHandlerRegion <TInstruction>(); ehRegions.Add(currentEHRange.ProtectedRange, ehRegion); result.Add(currentEHRange.ProtectedRange, ehRegion.ProtectedRegion); // We need to add the EH region to a parent region. This can either be the CFG itself, or a // sub region that was previously added. var parentRegion = FindParentRegion(result, sortedRanges, i); if (parentRegion is null) { cfg.Regions.Add(ehRegion); } else { parentRegion.Regions.Add(ehRegion); } } // Create and add new handler region from the range. var handlerRegion = new HandlerRegion <TInstruction>(); handlerRegion.Tag = currentEHRange.UserData; ehRegion.Handlers.Add(handlerRegion); result.Add(currentEHRange.HandlerRange, handlerRegion.Contents); // Do we need to add a prologue block? if (currentEHRange.PrologueRange != AddressRange.NilRange) { handlerRegion.Prologue = new ScopeRegion <TInstruction>(); ehRegions.Add(currentEHRange.PrologueRange, ehRegion); result.Add(currentEHRange.PrologueRange, handlerRegion.Prologue); } // Do we need to add an epilogue block? if (currentEHRange.EpilogueRange != AddressRange.NilRange) { handlerRegion.Epilogue = new ScopeRegion <TInstruction>(); ehRegions.Add(currentEHRange.EpilogueRange, ehRegion); result.Add(currentEHRange.EpilogueRange, handlerRegion.Epilogue); } } return(result); }