private static void EnterNextRegion <TInstruction>( IndexableStack <ScopeInfo <TInstruction> > scopeStack, IControlFlowRegion <TInstruction>[] activeRegions) { var enteredRegion = activeRegions[scopeStack.Count]; // Add new scope block to the current scope. var currentScope = scopeStack.Peek(); if (enteredRegion is ExceptionHandlerRegion <TInstruction> ehRegion) { // We entered an exception handler region. var ehBlock = new ExceptionHandlerBlock <TInstruction>(); currentScope.AddBlock(ehBlock); scopeStack.Push(new ScopeInfo <TInstruction>(ehRegion, ehBlock)); } else if (enteredRegion.ParentRegion is ExceptionHandlerRegion <TInstruction> parentEhRegion) { // We entered one of the exception handler sub regions. Figure out which one it is. ScopeBlock <TInstruction> enteredBlock; if (!(currentScope.Block is ExceptionHandlerBlock <TInstruction> ehBlock)) { throw new InvalidOperationException("The parent scope is not an exception handler scope."); } if (parentEhRegion.ProtectedRegion == enteredRegion) { // We entered the protected region. enteredBlock = ehBlock.ProtectedBlock; } else { // We entered a handler region. enteredBlock = new ScopeBlock <TInstruction>(); ehBlock.HandlerBlocks.Add(enteredBlock); } // Push the entered scope. scopeStack.Push(new ScopeInfo <TInstruction>(parentEhRegion.ProtectedRegion, enteredBlock)); } else { // Fall back method: just enter a new scope block. var scopeBlock = new ScopeBlock <TInstruction>(); currentScope.AddBlock(scopeBlock); scopeStack.Push(new ScopeInfo <TInstruction>(enteredRegion, scopeBlock)); } }
private static ScopeBlock <TInstruction> BuildBlocksFromSortedNodes <TInstruction>( ControlFlowGraph <TInstruction> cfg, IEnumerable <ControlFlowNode <TInstruction> > sorting) { // We maintain a stack of scope information. Every time we enter a new region, we enter a new scope, // and similarly, we leave a scope when we leave a region. var rootScope = new ScopeBlock <TInstruction>(); var scopeStack = new IndexableStack <ScopeInfo <TInstruction> >(); scopeStack.Push(new ScopeInfo <TInstruction>(cfg, rootScope)); // Add the nodes in the order of the sorting. foreach (var node in sorting) { var currentScope = scopeStack.Peek(); if (node.ParentRegion != currentScope.Region) { UpdateScopeStack(scopeStack, node); currentScope = scopeStack.Peek(); } currentScope.AddBlock(node.Contents); } return(rootScope); }
private static void EnterGenericRegion <TInstruction>(IndexableStack <ScopeInfo <TInstruction> > scopeStack, IControlFlowRegion <TInstruction> enteredRegion) { var scopeBlock = new ScopeBlock <TInstruction>(); scopeStack.Peek().AddBlock(scopeBlock); scopeStack.Push(new ScopeInfo <TInstruction>(enteredRegion, scopeBlock)); }
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)); }
private static void EnterHandlerSubRegion <TInstruction>( IndexableStack <ScopeInfo <TInstruction> > scopeStack, HandlerRegion <TInstruction> parentRegion, IControlFlowRegion <TInstruction> enteredRegion) { IBlock <TInstruction> enteredBlock; IControlFlowRegion <TInstruction> enteredSubRegion; if (!(scopeStack.Peek().Block is HandlerBlock <TInstruction> handlerBlock)) { throw new InvalidOperationException("The parent scope is not a handler scope."); } if (parentRegion.Prologue == enteredRegion) { // We entered the prologue. handlerBlock.Prologue = new ScopeBlock <TInstruction>(); enteredBlock = handlerBlock.Prologue; enteredSubRegion = parentRegion.Prologue; } else if (parentRegion.Contents == enteredRegion) { // We entered the contents. enteredBlock = handlerBlock.Contents; enteredSubRegion = parentRegion.Contents; } else if (parentRegion.Epilogue == enteredRegion) { // We entered the epilogue. handlerBlock.Epilogue = new ScopeBlock <TInstruction>(); enteredBlock = handlerBlock.Epilogue; enteredSubRegion = parentRegion.Epilogue; } else { // Exhaustive search, this should never happen. throw new InvalidOperationException( "Entered subregion of handler doesn't belong to any of its regions."); } // Push the entered scope. scopeStack.Push(new ScopeInfo <TInstruction>(enteredSubRegion, enteredBlock)); }
/// <summary> /// Constructs the tree of scopes and basic blocks based on the provided control flow graph. /// </summary> /// <param name="cfg">The control flow graph.</param> /// <returns>The root scope.</returns> public ScopeBlock <TInstruction> ConstructBlocks(ControlFlowGraph <TInstruction> cfg) { // Sort the nodes in topological order, where we ignore cyclic dependencies. var sorter = new TopologicalSorter <ControlFlowNode <TInstruction> >(ChildrenLister) { IgnoreCycles = true }; var sorting = sorter .GetTopologicalSorting(cfg.Entrypoint) .Reverse() #if DEBUG .ToArray() #endif ; // We maintain a stack of scope information. Every time we enter a new region, we enter a new scope, // and similarly, we leave a scope when we leave a region. var rootScope = new ScopeBlock <TInstruction>(); var scopeStack = new IndexableStack <ScopeInfo>(); scopeStack.Push(new ScopeInfo(cfg, rootScope)); // Add the nodes in the order of the sorting. foreach (var node in sorting) { var currentScope = scopeStack.Peek(); if (node.ParentRegion != currentScope.Region) { UpdateScopeStack(node, scopeStack); currentScope = scopeStack.Peek(); } currentScope.AddBlock(node.Contents); } return(rootScope); }
private void UpdateScopeStack(ControlFlowNode <TInstruction> node, IndexableStack <ScopeInfo> scopeStack) { var activeRegions = node.GetSituatedRegions() .Reverse() .ToArray(); int largestPossibleCommonDepth = Math.Min(scopeStack.Count, activeRegions.Length); // Figure out common region depth. int commonDepth = 1; while (commonDepth < largestPossibleCommonDepth) { if (scopeStack[commonDepth].Region != activeRegions[commonDepth]) { break; } commonDepth++; } // Leave for every left region a scope block. while (scopeStack.Count > commonDepth) { scopeStack.Pop(); } // Enter for every entered region a new block. while (scopeStack.Count < activeRegions.Length) { // Create new scope block. var enteredRegion = activeRegions[scopeStack.Count]; // Add new cope block to the current scope. var currentScope = scopeStack.Peek(); if (enteredRegion is ExceptionHandlerRegion <TInstruction> ehRegion) { // We entered an exception handler region. var ehBlock = new ExceptionHandlerBlock <TInstruction>(); currentScope.AddBlock(ehBlock); scopeStack.Push(new ScopeInfo(ehRegion, ehBlock)); } else if (enteredRegion.ParentRegion is ExceptionHandlerRegion <TInstruction> parentEhRegion) { // We entered one of the exception handler sub regions. Figure out which one it is. var enteredBlock = default(ScopeBlock <TInstruction>); if (!(currentScope.Block is ExceptionHandlerBlock <TInstruction> ehBlock)) { throw new InvalidOperationException("The parent scope is not an exception handler scope."); } if (parentEhRegion.ProtectedRegion == enteredRegion) { // We entered the protected region. enteredBlock = ehBlock.ProtectedBlock; } else { // We entered a handler region. enteredBlock = new ScopeBlock <TInstruction>(); ehBlock.HandlerBlocks.Add(enteredBlock); } // Push the entered scope. scopeStack.Push(new ScopeInfo(parentEhRegion.ProtectedRegion, enteredBlock)); } else { // Fall back method: just enter a new scope block. var scopeBlock = new ScopeBlock <TInstruction>(); currentScope.AddBlock(scopeBlock); scopeStack.Push(new ScopeInfo(enteredRegion, scopeBlock)); } } }