private void PreprocessMethod() { if (ContextAnnotations.AwaitInExceptionHandler(_method.Method)) { AsyncExceptionHandlerRewriter.Rewrite(_method.Method); } AwaitExpressionSpiller.Rewrite(_method.Method); }
/// <summary> /// Lower a block of code by performing local rewritings. /// The goal is to not have exception handlers that contain awaits in them. /// /// 1) Await containing ensure blocks: /// The general strategy is to rewrite await containing handlers into synthetic handlers. /// Synthetic handlers are not handlers in IL sense so it is ok to have awaits in them. /// Since synthetic handlers are just blocks, we have to deal with pending exception/branch/return manually /// (this is the hard part of the rewrite). /// /// try: /// code /// ensure: /// handler /// /// Into ===> /// /// ex as Exception = null /// pendingBranch as int = 0 /// /// try: /// code // any gotos/returns are rewritten to code that pends the necessary info and goes to finallyLabel /// goto finallyLabel /// except ex: // essentially pend the currently active exception /// pass /// /// :finallyLabel /// handler /// if ex != null: raise ex // unpend the exception /// unpend branches/return /// /// 2) Await containing catches: /// try: /// code /// except ex as Exception: /// handler /// raise /// /// /// Into ===> /// /// pendingException as Object /// pendingCatch as int = 0 /// /// try: /// code /// except temp as Exception: // essentially pend the currently active exception /// pendingException = temp /// pendingCatch = 1 /// /// if pendingCatch == 1: /// var ex = pendingException cast Exception /// handler /// raise pendingException /// </summary> public static void Rewrite(Method containingMethod) { if (containingMethod == null) { throw new ArgumentNullException("containingMethod"); } var body = containingMethod.Body; var analysis = new AwaitInFinallyAnalysis(body); if (analysis.ContainsAwaitInHandlers()) { var factory = CompilerContext.Current.CodeBuilder; var rewriter = new AsyncExceptionHandlerRewriter(containingMethod, factory, analysis); containingMethod.Body = (Block)rewriter.Visit(body); } }