public static void Run(ILFunction function, ILTransformContext context) { if (!context.Settings.AwaitInCatchFinally) { return; } HashSet <BlockContainer> changedContainers = new HashSet <BlockContainer>(); // analyze all try-catch statements in the function foreach (var tryCatch in function.Descendants.OfType <TryCatch>().ToArray()) { if (!(tryCatch.Parent?.Parent is BlockContainer container)) { continue; } // Detect all handlers that contain an await expression AnalyzeHandlers(tryCatch.Handlers, out var catchHandlerIdentifier, out var transformableCatchBlocks); var cfg = new ControlFlowGraph(container, context.CancellationToken); if (transformableCatchBlocks.Count > 0) { changedContainers.Add(container); } foreach (var result in transformableCatchBlocks) { var node = cfg.GetNode(result.RealCatchBlockEntryPoint); context.Step("Inline catch block with await", result.Handler); // Remove the IfInstruction from the jump table and eliminate all branches to the block. var jumpTableBlock = (Block)result.JumpTableEntry.Parent; jumpTableBlock.Instructions.RemoveAt(result.JumpTableEntry.ChildIndex); foreach (var branch in tryCatch.Descendants.OfType <Branch>()) { if (branch.TargetBlock == jumpTableBlock) { if (result.NextBlockOrExitContainer is BlockContainer exitContainer) { branch.ReplaceWith(new Leave(exitContainer)); } else { branch.ReplaceWith(new Branch((Block)result.NextBlockOrExitContainer)); } } } // Add the real catch block entry-point to the block container var catchBlockHead = ((BlockContainer)result.Handler.Body).Blocks.Last(); result.RealCatchBlockEntryPoint.Remove(); ((BlockContainer)result.Handler.Body).Blocks.Insert(0, result.RealCatchBlockEntryPoint); // Remove the generated catch block catchBlockHead.Remove(); // Inline all blocks that are dominated by the entrypoint of the real catch block foreach (var n in cfg.cfg) { if (((Block)n.UserData).Parent == result.Handler.Body) { continue; } if (node.Dominates(n)) { MoveBlock((Block)n.UserData, (BlockContainer)result.Handler.Body); } } // Remove all assignments to the common object variable that stores the exception object. if (result.ObjectVariableStore != null) { foreach (var load in result.ObjectVariableStore.Variable.LoadInstructions.ToArray()) { if (load.Parent is CastClass cc && cc.Type == result.Handler.Variable.Type) { cc.ReplaceWith(new LdLoc(result.Handler.Variable)); } else { load.ReplaceWith(new LdLoc(result.Handler.Variable)); } } } }