}
//
- // Iterators are implemented as hidden anonymous block
+ // Iterators are implemented as state machine blocks
//
public class Iterator : StateMachineInitializer
{
+ sealed class TryFinallyBlockProxyStatement : Statement
+ {
+ TryFinallyBlock block;
+ Iterator iterator;
+
+ public TryFinallyBlockProxyStatement (Iterator iterator, TryFinallyBlock block)
+ {
+ this.iterator = iterator;
+ this.block = block;
+ }
+
+ protected override void CloneTo (CloneContext clonectx, Statement target)
+ {
+ throw new NotSupportedException ();
+ }
+
+ protected override void DoEmit (EmitContext ec)
+ {
+ //
+ // Restore redirection for any captured variables
+ //
+ ec.CurrentAnonymousMethod = iterator;
+
+ using (ec.With (BuilderContext.Options.OmitDebugInfo, false)) {
+ block.EmitFinallyBody (ec);
+ }
+ }
+ }
+
public readonly IMethodData OriginalMethod;
public readonly bool IsEnumerable;
public readonly TypeSpec OriginalIteratorType;
+ int finally_hosts_counter;
public Iterator (ParametersBlock block, IMethodData method, TypeDefinition host, TypeSpec iterator_type, bool is_enumerable)
: base (block, host, host.Compiler.BuiltinTypes.Bool)
this.type = method.ReturnType;
}
+ #region Properties
+
public ToplevelBlock Container {
get { return OriginalMethod.Block; }
}
get { return true; }
}
+ #endregion
+
+ public Method CreateFinallyHost (TryFinallyBlock block)
+ {
+ var method = new Method (storey, new TypeExpression (storey.Compiler.BuiltinTypes.Void, loc),
+ Modifiers.COMPILER_GENERATED, new MemberName (CompilerGeneratedContainer.MakeName (null, null, "Finally", finally_hosts_counter++), loc),
+ ParametersCompiled.EmptyReadOnlyParameters, null);
+
+ method.Block = new ToplevelBlock (method.Compiler, method.ParameterInfo, loc);
+ method.Block.IsCompilerGenerated = true;
+ method.Block.AddStatement (new TryFinallyBlockProxyStatement (this, block));
+
+ storey.AddMember (method);
+ return method;
+ }
+
public void EmitYieldBreak (EmitContext ec, bool unwind_protect)
{
ec.Emit (unwind_protect ? OpCodes.Leave : OpCodes.Br, move_next_error);
protected Statement stmt;
Label dispose_try_block;
bool prepared_for_dispose, emitted_dispose;
+ Method finally_host;
protected TryFinallyBlock (Statement stmt, Location loc)
: base (loc)
#endregion
protected abstract void EmitTryBody (EmitContext ec);
- protected abstract void EmitFinallyBody (EmitContext ec);
+ public abstract void EmitFinallyBody (EmitContext ec);
public override Label PrepareForDispose (EmitContext ec, Label end)
{
}
ec.MarkLabel (start_finally);
- EmitFinallyBody (ec);
+
+ if (finally_host != null) {
+ var ce = new CallEmitter ();
+ ce.InstanceExpression = new CompilerGeneratedThis (ec.CurrentType, loc);
+ ce.EmitPredefined (ec, finally_host.Spec, new Arguments (0));
+ } else {
+ EmitFinallyBody (ec);
+ }
ec.EndExceptionBlock ();
}
bool emit_dispatcher = j < labels.Length;
if (emit_dispatcher) {
- //SymbolWriter.StartIteratorDispatcher (ec.ig);
ec.Emit (OpCodes.Ldloc, pc);
ec.EmitInt (first_resume_pc);
ec.Emit (OpCodes.Sub);
ec.Emit (OpCodes.Switch, labels);
- //SymbolWriter.EndIteratorDispatcher (ec.ig);
}
foreach (ResumableStatement s in resume_points)
ec.BeginFinallyBlock ();
- EmitFinallyBody (ec);
+ if (finally_host != null) {
+ var ce = new CallEmitter ();
+ ce.InstanceExpression = new CompilerGeneratedThis (ec.CurrentType, loc);
+ ce.EmitPredefined (ec, finally_host.Spec, new Arguments (0));
+ } else {
+ EmitFinallyBody (ec);
+ }
ec.EndExceptionBlock ();
}
+
+ public override bool Resolve (BlockContext bc)
+ {
+ //
+ // Finally block inside iterator is called from MoveNext and
+ // Dispose methods that means we need to lift the block into
+ // newly created host method to emit the body only once. The
+ // original block then simply calls the newly generated method.
+ //
+ if (bc.CurrentIterator != null && !bc.IsInProbingMode) {
+ var iterator = bc.CurrentIterator;
+ finally_host = iterator.CreateFinallyHost (this);
+ }
+
+ return base.Resolve (bc);
+ }
}
//
Statement.Emit (ec);
}
- protected override void EmitFinallyBody (EmitContext ec)
+ public override void EmitFinallyBody (EmitContext ec)
{
//
// if (lock_taken) Monitor.Exit (expr_copy)
if (ok)
ec.CurrentBranching.CreateSibling (fini, FlowBranching.SiblingType.Finally);
+
using (ec.With (ResolveContext.Options.FinallyScope, true)) {
if (!fini.Resolve (ec))
ok = false;
stmt.Emit (ec);
}
- protected override void EmitFinallyBody (EmitContext ec)
+ public override void EmitFinallyBody (EmitContext ec)
{
fini.Emit (ec);
}
stmt.Emit (ec);
}
- protected override void EmitFinallyBody (EmitContext ec)
+ public override void EmitFinallyBody (EmitContext ec)
{
decl.EmitDispose (ec);
}
<size>52</size>
</method>
<method name="Boolean MoveNext()" attrs="486">
- <size>215</size>
+ <size>199</size>
</method>
<method name="Void Dispose()" attrs="486">
- <size>69</size>
+ <size>53</size>
</method>
<method name="Void Reset()" attrs="486">
<size>6</size>
<size>7</size>
</method>
</type>
+ <type name="MyTest+<Map>c__Iterator0`4[Aa,Af,Rf,Rr]">
+ <method name="Void <>__Finally0()" attrs="129">
+ <size>23</size>
+ </method>
+ </type>
</test>
<test name="gtest-218.cs">
<type name="Foo">
<size>26</size>
</method>
<method name="Boolean MoveNext()" attrs="486">
- <size>117</size>
+ <size>115</size>
</method>
<method name="Void Dispose()" attrs="486">
<size>53</size>
<size>26</size>
</method>
<method name="Boolean MoveNext()" attrs="486">
- <size>189</size>
+ <size>173</size>
</method>
<method name="Void Dispose()" attrs="486">
- <size>69</size>
+ <size>53</size>
</method>
<method name="Void Reset()" attrs="486">
<size>6</size>
<size>7</size>
</method>
</type>
+ <type name="TestGoto+<setX>c__Iterator0">
+ <method name="Void <>__Finally0()" attrs="129">
+ <size>9</size>
+ </method>
+ </type>
+ <type name="TestGoto+<test>c__Iterator1">
+ <method name="Void <>__Finally0()" attrs="129">
+ <size>23</size>
+ </method>
+ </type>
</test>
<test name="gtest-382.cs">
<type name="C">
<size>52</size>
</method>
<method name="Boolean MoveNext()" attrs="486">
- <size>211</size>
+ <size>181</size>
</method>
<method name="Void Dispose()" attrs="486">
- <size>83</size>
+ <size>53</size>
</method>
<method name="Void Reset()" attrs="486">
<size>6</size>
<size>7</size>
</method>
</type>
+ <type name="Test+<Select>c__Iterator0`1[T]">
+ <method name="Void <>__Finally0()" attrs="129">
+ <size>37</size>
+ </method>
+ </type>
</test>
<test name="gtest-autoproperty-01.cs">
<type name="Test">
<size>52</size>
</method>
<method name="Boolean MoveNext()" attrs="486">
- <size>303</size>
+ <size>287</size>
</method>
<method name="Void Dispose()" attrs="486">
- <size>69</size>
+ <size>53</size>
</method>
<method name="Void Reset()" attrs="486">
<size>6</size>
<method name="Void .ctor()" attrs="6278">
<size>7</size>
</method>
+ <method name="Void <>__Finally0()" attrs="129">
+ <size>23</size>
+ </method>
</type>
</test>
<test name="gtest-etree-15.cs">
<size>40</size>
</method>
<method name="Boolean MoveNext()" attrs="486">
- <size>204</size>
+ <size>188</size>
</method>
<method name="Void Dispose()" attrs="486">
- <size>69</size>
+ <size>53</size>
</method>
<method name="Void Reset()" attrs="486">
<size>6</size>
<size>52</size>
</method>
<method name="Boolean MoveNext()" attrs="486">
- <size>232</size>
+ <size>221</size>
</method>
<method name="Void Dispose()" attrs="486">
- <size>64</size>
+ <size>53</size>
</method>
<method name="Void Reset()" attrs="486">
<size>6</size>
<size>7</size>
</method>
</type>
+ <type name="Test+<Annotations>c__Iterator0`1[T]">
+ <method name="Void <>__Finally0()" attrs="129">
+ <size>23</size>
+ </method>
+ </type>
+ <type name="Test+<Annotations>c__Iterator1">
+ <method name="Void <>__Finally0()" attrs="129">
+ <size>18</size>
+ </method>
+ </type>
</test>
<test name="gtest-iter-04.cs">
<type name="TestClass">
<size>52</size>
</method>
<method name="Boolean MoveNext()" attrs="486">
- <size>197</size>
+ <size>181</size>
</method>
<method name="Void Dispose()" attrs="486">
- <size>69</size>
+ <size>53</size>
</method>
<method name="Void Reset()" attrs="486">
<size>6</size>
<method name="Void .ctor()" attrs="6278">
<size>7</size>
</method>
+ <method name="Void <>__Finally0()" attrs="129">
+ <size>23</size>
+ </method>
</type>
</test>
<test name="gtest-iter-06.cs">
<size>40</size>
</method>
<method name="Boolean MoveNext()" attrs="486">
- <size>197</size>
+ <size>186</size>
</method>
<method name="Void Dispose()" attrs="486">
- <size>64</size>
+ <size>53</size>
</method>
<method name="Void Reset()" attrs="486">
<size>6</size>
<method name="Void .ctor()" attrs="6278">
<size>7</size>
</method>
+ <method name="Void <>__Finally0()" attrs="129">
+ <size>18</size>
+ </method>
</type>
</test>
<test name="gtest-iter-08.cs">
<size>19</size>
</method>
<method name="Boolean MoveNext()" attrs="486">
- <size>184</size>
+ <size>173</size>
</method>
<method name="Void Dispose()" attrs="486">
- <size>64</size>
+ <size>53</size>
</method>
<method name="Void Reset()" attrs="486">
<size>6</size>
<method name="Void .ctor()" attrs="6278">
<size>7</size>
</method>
+ <method name="Void <>__Finally0()" attrs="129">
+ <size>18</size>
+ </method>
</type>
</test>
<test name="gtest-iter-12.cs">
<size>52</size>
</method>
<method name="Boolean MoveNext()" attrs="486">
- <size>225</size>
+ <size>195</size>
</method>
<method name="Void Dispose()" attrs="486">
- <size>83</size>
+ <size>53</size>
</method>
<method name="Void Reset()" attrs="486">
<size>6</size>
<method name="Void .ctor()" attrs="6278">
<size>7</size>
</method>
+ <method name="Void <>__Finally0()" attrs="129">
+ <size>37</size>
+ </method>
</type>
</test>
<test name="gtest-iter-14.cs">
<size>40</size>
</method>
<method name="Boolean MoveNext()" attrs="486">
- <size>189</size>
+ <size>173</size>
</method>
<method name="Void Dispose()" attrs="486">
- <size>69</size>
+ <size>53</size>
</method>
<method name="Void Reset()" attrs="486">
<size>6</size>
<method name="Void .ctor()" attrs="6278">
<size>7</size>
</method>
+ <method name="Void <>__Finally0()" attrs="129">
+ <size>23</size>
+ </method>
</type>
</test>
<test name="gtest-iter-16.cs">
<size>52</size>
</method>
<method name="Boolean MoveNext()" attrs="486">
- <size>195</size>
+ <size>179</size>
</method>
<method name="Void Dispose()" attrs="486">
- <size>69</size>
+ <size>53</size>
</method>
<method name="Void Reset()" attrs="486">
<size>6</size>
<size>52</size>
</method>
<method name="Boolean MoveNext()" attrs="486">
- <size>195</size>
+ <size>179</size>
</method>
<method name="Void Dispose()" attrs="486">
- <size>69</size>
+ <size>53</size>
</method>
<method name="Void Reset()" attrs="486">
<size>6</size>
<size>7</size>
</method>
</type>
+ <type name="Test.Derived+<GetStuff>c__Iterator1">
+ <method name="Void <>__Finally0()" attrs="129">
+ <size>23</size>
+ </method>
+ </type>
+ <type name="Test.SpecialDerived+<GetStuff>c__Iterator2">
+ <method name="Void <>__Finally0()" attrs="129">
+ <size>23</size>
+ </method>
+ </type>
</test>
<test name="gtest-iter-17.cs">
<type name="Test">
<size>52</size>
</method>
<method name="Boolean MoveNext()" attrs="486">
- <size>203</size>
+ <size>187</size>
</method>
<method name="Void Dispose()" attrs="486">
- <size>69</size>
+ <size>53</size>
</method>
<method name="Void Reset()" attrs="486">
<size>6</size>
<size>7</size>
</method>
</type>
+ <type name="IEnumerableTransform+<Transform>c__Iterator0`1[TOut]">
+ <method name="Void <>__Finally0()" attrs="129">
+ <size>23</size>
+ </method>
+ </type>
</test>
<test name="gtest-iter-20.cs">
<type name="X">
</method>
</type>
</test>
+ <test name="gtest-iter-21.cs">
+ <type name="C">
+ <method name="IEnumerable`1 Test()" attrs="129">
+ <size>23</size>
+ </method>
+ <method name="Int32 Main()" attrs="150">
+ <size>72</size>
+ </method>
+ <method name="Void .ctor()" attrs="6278">
+ <size>7</size>
+ </method>
+ </type>
+ <type name="C+<Test>c__Iterator0">
+ <method name="Int32 System.Collections.Generic.IEnumerator<int>.get_Current()" attrs="2529">
+ <size>14</size>
+ </method>
+ <method name="System.Object System.Collections.IEnumerator.get_Current()" attrs="2529">
+ <size>19</size>
+ </method>
+ <method name="IEnumerator System.Collections.IEnumerable.GetEnumerator()" attrs="481">
+ <size>14</size>
+ </method>
+ <method name="IEnumerator`1 System.Collections.Generic.IEnumerable<int>.GetEnumerator()" attrs="481">
+ <size>26</size>
+ </method>
+ <method name="Void <>__Finally0()" attrs="129">
+ <size>23</size>
+ </method>
+ <method name="Boolean MoveNext()" attrs="486">
+ <size>150</size>
+ </method>
+ <method name="Void Dispose()" attrs="486">
+ <size>57</size>
+ </method>
+ <method name="Void Reset()" attrs="486">
+ <size>6</size>
+ </method>
+ <method name="Void <>m__0()" attrs="131">
+ <size>12</size>
+ </method>
+ <method name="Void .ctor()" attrs="6278">
+ <size>7</size>
+ </method>
+ </type>
+ </test>
<test name="gtest-lambda-01.cs">
<type name="IntFunc">
<method name="Int32 Invoke(Int32)" attrs="454">
<size>40</size>
</method>
<method name="Boolean MoveNext()" attrs="486">
- <size>197</size>
+ <size>181</size>
</method>
<method name="Void Dispose()" attrs="486">
- <size>73</size>
+ <size>57</size>
</method>
<method name="Void Reset()" attrs="486">
<size>6</size>
<method name="Void .ctor()" attrs="6278">
<size>7</size>
</method>
+ <method name="Void <>__Finally0()" attrs="129">
+ <size>23</size>
+ </method>
</type>
</test>
<test name="test-anon-108.cs">
<size>14</size>
</method>
<method name="Boolean MoveNext()" attrs="486">
- <size>207</size>
+ <size>177</size>
</method>
<method name="Void Dispose()" attrs="486">
- <size>83</size>
+ <size>53</size>
</method>
<method name="Void Reset()" attrs="486">
<size>6</size>
<method name="Void .ctor()" attrs="6278">
<size>7</size>
</method>
+ <method name="Void <>__Finally0()" attrs="129">
+ <size>37</size>
+ </method>
</type>
</test>
<test name="test-anon-50.cs">
</method>
</type>
</test>
+ <test name="test-debug-21.cs">
+ <type name="C">
+ <method name="IEnumerable`1 Test()" attrs="129">
+ <size>23</size>
+ </method>
+ <method name="Void Main()" attrs="150">
+ <size>2</size>
+ </method>
+ <method name="Void .ctor()" attrs="6278">
+ <size>7</size>
+ </method>
+ </type>
+ <type name="C+<Test>c__Iterator0">
+ <method name="Int32 System.Collections.Generic.IEnumerator<int>.get_Current()" attrs="2529">
+ <size>14</size>
+ </method>
+ <method name="System.Object System.Collections.IEnumerator.get_Current()" attrs="2529">
+ <size>19</size>
+ </method>
+ <method name="IEnumerator System.Collections.IEnumerable.GetEnumerator()" attrs="481">
+ <size>14</size>
+ </method>
+ <method name="IEnumerator`1 System.Collections.Generic.IEnumerable<int>.GetEnumerator()" attrs="481">
+ <size>26</size>
+ </method>
+ <method name="Void <>__Finally0()" attrs="129">
+ <size>13</size>
+ </method>
+ <method name="Boolean MoveNext()" attrs="486">
+ <size>150</size>
+ </method>
+ <method name="Void Dispose()" attrs="486">
+ <size>57</size>
+ </method>
+ <method name="Void Reset()" attrs="486">
+ <size>6</size>
+ </method>
+ <method name="Void .ctor()" attrs="6278">
+ <size>7</size>
+ </method>
+ </type>
+ </test>
<test name="test-externalias-01.cs">
<type name="Test">
<method name="Int32 Main()" attrs="145">
<size>40</size>
</method>
<method name="Boolean MoveNext()" attrs="486">
- <size>282</size>
+ <size>264</size>
</method>
<method name="Void Dispose()" attrs="486">
- <size>119</size>
+ <size>107</size>
</method>
<method name="Void Reset()" attrs="486">
<size>6</size>
<method name="Void .ctor()" attrs="6278">
<size>7</size>
</method>
+ <method name="Void <>__Finally0()" attrs="129">
+ <size>13</size>
+ </method>
+ <method name="Void <>__Finally1()" attrs="129">
+ <size>13</size>
+ </method>
+ <method name="Void <>__Finally2()" attrs="129">
+ <size>13</size>
+ </method>
</type>
</test>
<test name="test-iter-08.cs">
<size>52</size>
</method>
<method name="Boolean MoveNext()" attrs="486">
- <size>393</size>
+ <size>361</size>
</method>
<method name="Void Dispose()" attrs="486">
- <size>109</size>
+ <size>77</size>
</method>
<method name="Void Reset()" attrs="486">
<size>6</size>
<method name="Void .ctor()" attrs="6278">
<size>7</size>
</method>
+ <method name="Void <>__Finally0()" attrs="129">
+ <size>23</size>
+ </method>
+ <method name="Void <>__Finally1()" attrs="129">
+ <size>23</size>
+ </method>
</type>
</test>
<test name="test-iter-09.cs">
<size>14</size>
</method>
<method name="Boolean MoveNext()" attrs="486">
- <size>693</size>
+ <size>663</size>
</method>
<method name="Void Dispose()" attrs="486">
- <size>103</size>
+ <size>73</size>
</method>
<method name="Void Reset()" attrs="486">
<size>6</size>
<method name="Void .ctor()" attrs="6278">
<size>7</size>
</method>
+ <method name="Void <>__Finally0()" attrs="129">
+ <size>37</size>
+ </method>
</type>
</test>
<test name="test-iter-10.cs">
<size>40</size>
</method>
<method name="Boolean MoveNext()" attrs="486">
- <size>203</size>
+ <size>190</size>
</method>
<method name="Void Dispose()" attrs="486">
- <size>70</size>
+ <size>57</size>
</method>
<method name="Void Reset()" attrs="486">
<size>6</size>
<method name="Void .ctor()" attrs="6278">
<size>7</size>
</method>
+ <method name="Void <>__Finally0()" attrs="129">
+ <size>20</size>
+ </method>
</type>
</test>
<test name="test-iter-13.cs">
<method name="Void .ctor()" attrs="6278">
<size>7</size>
</method>
+ <method name="Void <>__Finally0()" attrs="129">
+ <size>20</size>
+ </method>
</type>
</test>
<test name="test-iter-14.cs">
<size>26</size>
</method>
<method name="Boolean MoveNext()" attrs="486">
- <size>38</size>
+ <size>42</size>
</method>
<method name="Void Dispose()" attrs="486">
<size>15</size>
<method name="Void .ctor()" attrs="6278">
<size>7</size>
</method>
+ <method name="Void <>__Finally0()" attrs="129">
+ <size>3</size>
+ </method>
</type>
</test>
<test name="test-iter-17.cs">
<size>14</size>
</method>
<method name="Boolean MoveNext()" attrs="486">
- <size>207</size>
+ <size>177</size>
</method>
<method name="Void Dispose()" attrs="486">
- <size>83</size>
+ <size>53</size>
</method>
<method name="Void Reset()" attrs="486">
<size>6</size>
<method name="Void .ctor()" attrs="6278">
<size>7</size>
</method>
+ <method name="Void <>__Finally0()" attrs="129">
+ <size>37</size>
+ </method>
</type>
</test>
<test name="test-iter-23.cs">