+ bool code_follows;
+
+ protected abstract void EmitPreTryBody (EmitContext ec);
+ protected abstract void EmitTryBody (EmitContext ec);
+ protected abstract void EmitFinallyBody (EmitContext ec);
+
+ protected sealed override void DoEmit (EmitContext ec)
+ {
+ ILGenerator ig = ec.ig;
+
+ EmitPreTryBody (ec);
+
+ if (resume_points != null) {
+ IntConstant.EmitInt (ig, (int) Iterator.State.Running);
+ ig.Emit (OpCodes.Stloc, ec.CurrentIterator.CurrentPC);
+ }
+
+ ig.BeginExceptionBlock ();
+
+ if (resume_points != null) {
+ ig.MarkLabel (resume_point);
+
+ // For normal control flow, we want to fall-through the Switch
+ // So, we use CurrentPC rather than the $PC field, and initialize it to an outside value above
+ ig.Emit (OpCodes.Ldloc, ec.CurrentIterator.CurrentPC);
+ IntConstant.EmitInt (ig, first_resume_pc);
+ ig.Emit (OpCodes.Sub);
+
+ Label [] labels = new Label [resume_points.Count];
+ for (int i = 0; i < resume_points.Count; ++i)
+ labels [i] = ((ResumableStatement) resume_points [i]).PrepareForEmit (ec);
+ ig.Emit (OpCodes.Switch, labels);
+ }
+
+ EmitTryBody (ec);
+
+ ig.BeginFinallyBlock ();
+
+ Label start_finally = ec.ig.DefineLabel ();
+ if (resume_points != null) {
+ ig.Emit (OpCodes.Ldloc, ec.CurrentIterator.SkipFinally);
+ ig.Emit (OpCodes.Brfalse_S, start_finally);
+ ig.Emit (OpCodes.Endfinally);
+ }
+
+ ig.MarkLabel (start_finally);
+ EmitFinallyBody (ec);
+
+ ig.EndExceptionBlock ();
+ }
+
+ public void SomeCodeFollows ()
+ {
+ code_follows = true;
+ }
+
+ protected void ResolveReachability (EmitContext ec)
+ {
+ // System.Reflection.Emit automatically emits a 'leave' at the end of a try clause
+ // So, ensure there's some IL code after this statement.
+ if (!code_follows && resume_points == null && ec.CurrentBranching.CurrentUsageVector.IsUnreachable)
+ ec.NeedReturnLabel ();
+
+ }
+
+ ArrayList resume_points;
+ int first_resume_pc;
+ public void AddResumePoint (ResumableStatement stmt, Location loc, int pc)
+ {
+ if (resume_points == null) {
+ resume_points = new ArrayList ();
+ first_resume_pc = pc;
+ }