private void Layout(ScopeBlock methodBlock) { var lastProtectedBlocks = new List <ScopeBlock>(); int index = 0; _basicBlocks = new List <BasicBlock>(); foreach (var block in methodBlock.Enumerate <Block>()) { if (block is BasicBlock basicBlock) { basicBlock.Contexts.Set(this, new BlockContext(index, basicBlock.BranchOpcode, lastProtectedBlocks)); _basicBlocks.Add(basicBlock); lastProtectedBlocks.Clear(); index++; } else if (block.Type == BlockType.Protected) { lastProtectedBlocks.Add((ScopeBlock)block); } } }
/// <summary> /// Sorts all blocks in <paramref name="methodBlock"/> /// NOTICE: Do NOT use it to remove unsed blocks! Please call <see cref="BlockCleaner.RemoveUnusedBlocks(ScopeBlock)"/> first! /// </summary> /// <param name="methodBlock"></param> public static void Sort(ScopeBlock methodBlock) { if (methodBlock is null) { throw new ArgumentNullException(nameof(methodBlock)); } if (methodBlock.Type != BlockType.Method) { throw new ArgumentException($"{nameof(methodBlock)} is not a method block"); } object contextKey = new object(); foreach (var basicBlock in methodBlock.Enumerate <BasicBlock>()) { if (basicBlock.Successors.Count == 0) { basicBlock.Contexts.Set(contextKey, BlockContext.Empty); continue; } var block = (Block)basicBlock; // block is jump source (jump from) bool added; /* * There are three situations and they appear in order * 1. Jump out of scope * 2. Add target(s) successfully (only appear once) * 3. Self-loop * When we add target(s) successfully, we should break do-while loop. */ do { if (!block.Contexts.TryGet <BlockContext>(contextKey, out var context)) { context = block.Contexts.Set(contextKey, new BlockContext()); } var targets = context.Targets; var scope = block.Scope; added = AddTarget(targets, scope, basicBlock.FallThroughNoThrow); // target is jump destination (jump to) if (added) { // If fall through is added successfully, then we can try adding other targets AddTarget(targets, scope, basicBlock.CondTargetNoThrow); var switchTargets = basicBlock.SwitchTargetsNoThrow; if (!(switchTargets is null)) { foreach (var switchTarget in switchTargets) { AddTarget(targets, scope, switchTarget); } } } else { block = block.Scope.Scope; // Gets upper protected block as jump source, not its child blocks (try, catch, ...) } } while (!added && block.Type != BlockType.Method);