Release captured reference type stack variables
authorMarek Safar <marek.safar@gmail.com>
Fri, 16 Mar 2012 16:51:21 +0000 (16:51 +0000)
committerMarek Safar <marek.safar@gmail.com>
Fri, 16 Mar 2012 16:52:01 +0000 (16:52 +0000)
mcs/mcs/async.cs
mcs/mcs/codegen.cs
mcs/mcs/ecore.cs
mcs/mcs/statement.cs
mcs/tests/ver-il-net_4_5.xml

index 5fcc12827c8b8cccc6870b786ae4f5efb2f6fbb8..3fa90a545d553cff12a92f4f2adaa7bc48e57976 100644 (file)
@@ -911,7 +911,7 @@ namespace Mono.CSharp
                }
        }
 
-       class StackFieldExpr : FieldExpr
+       class StackFieldExpr : FieldExpr, IExpressionCleanup
        {
                public StackFieldExpr (Field field)
                        : base (field, Location.Null)
@@ -934,6 +934,19 @@ namespace Mono.CSharp
 
                        var field = (Field) spec.MemberDefinition;
                        field.IsAvailableForReuse = true;
+
+                       //
+                       // Release any captured reference type stack variables
+                       // to imitate real stack behavour and help GC stuff early
+                       //
+                       if (TypeSpec.IsReferenceType (type)) {
+                               ec.AddStatementEpilog (this);
+                       }
+               }
+
+               void IExpressionCleanup.EmitCleanup (EmitContext ec)
+               {
+                       EmitAssign (ec, new NullConstant (type, loc), false, false);
                }
        }
 }
index 342025b2b3d0131a0b993b5fba95d09f7327f403..fc8c82e31f6e0de14beb690c8428ab68a299ad9c 100644 (file)
@@ -83,6 +83,8 @@ namespace Mono.CSharp
 
                Label? return_label;
 
+               List<IExpressionCleanup> epilogue_expressions;
+
                public EmitContext (IMemberContext rc, ILGenerator ig, TypeSpec return_type, SourceMethodBuilder methodSymbols)
                {
                        this.member_context = rc;
@@ -190,8 +192,25 @@ namespace Mono.CSharp
                        }
                }
 
+               public List<IExpressionCleanup> StatementEpilogue {
+                       get {
+                               return epilogue_expressions;
+                       }
+               }
+
                #endregion
 
+               public void AddStatementEpilog (IExpressionCleanup cleanupExpression)
+               {
+                       if (epilogue_expressions == null) {
+                               epilogue_expressions = new List<IExpressionCleanup> ();
+                       } else if (epilogue_expressions.Contains (cleanupExpression)) {
+                               return;
+                       }
+
+                       epilogue_expressions.Add (cleanupExpression);
+               }
+
                public void AssertEmptyStack ()
                {
 #if STATIC
@@ -810,6 +829,17 @@ namespace Mono.CSharp
                        ig.Emit (OpCodes.Ldarg_0);
                }
 
+               public void EmitEpilogue ()
+               {
+                       if (epilogue_expressions == null)
+                               return;
+
+                       foreach (var e in epilogue_expressions)
+                               e.EmitCleanup (this);
+
+                       epilogue_expressions = null;
+               }
+
                /// <summary>
                ///   Returns a temporary storage for a variable of type t as 
                ///   a local variable in the current body.
index 0e3ebbe0fbd860a9f586979d189441a168134b56..b6ebc8f1c80b640ac686cb858dd104856d9c3b3a 100644 (file)
@@ -118,6 +118,11 @@ namespace Mono.CSharp {
                bool IsFixed { get; }
        }
 
+       public interface IExpressionCleanup
+       {
+               void EmitCleanup (EmitContext ec);
+       }
+
        /// <remarks>
        ///   Base class for expressions
        /// </remarks>
index 0c6f58f0a214889d2e53ebe67431e252d92da5ca..cc06e38f472bcb237794868fc74f854876a337dc 100644 (file)
@@ -68,6 +68,10 @@ namespace Mono.CSharp {
                {
                        ec.Mark (loc);
                        DoEmit (ec);
+
+                       if (ec.StatementEpilogue != null) {
+                               ec.EmitEpilogue ();
+                       }
                }
 
                //
@@ -947,12 +951,16 @@ namespace Mono.CSharp {
                                        if (async_return != null) {
                                                async_return.EmitAssign (ec);
 
+                                               ec.EmitEpilogue ();
+
                                                ec.Emit (unwind_protect ? OpCodes.Leave : OpCodes.Br, async_body.BodyEnd);
                                        }
 
                                        return;
                                }
 
+                               ec.EmitEpilogue ();
+
                                if (unwind_protect || ec.EmitAccurateDebugInfo)
                                        ec.Emit (OpCodes.Stloc, ec.TemporaryReturn ());
                        }
index 2a20ef843816f82b244c23b0a3c4a2639d146e3c..4cd01da83bd2652f992a2a929731ab2f54ffef07 100644 (file)
     </type>
     <type name="C+&lt;TestCompositionCall_2&gt;c__async1">
       <method name="Void MoveNext()" attrs="486">
-        <size>244</size>
+        <size>251</size>
       </method>
       <method name="System.String &lt;&gt;m__3()" attrs="145">
         <size>13</size>
     </type>
     <type name="C+&lt;TestStack_1&gt;c__async1">
       <method name="Void MoveNext()" attrs="486">
-        <size>307</size>
+        <size>321</size>
       </method>
       <method name="Int32 &lt;&gt;m__1()" attrs="145">
         <size>9</size>
     </type>
     <type name="C+&lt;TestStack_2&gt;c__async2">
       <method name="Void MoveNext()" attrs="486">
-        <size>289</size>
+        <size>296</size>
       </method>
       <method name="Int32 &lt;&gt;m__2()" attrs="145">
         <size>9</size>
     </type>
     <type name="Tester+&lt;ArrayAccessTest_3&gt;c__async2">
       <method name="Void MoveNext()" attrs="486">
-        <size>1103</size>
+        <size>1117</size>
       </method>
       <method name="Int32 &lt;&gt;m__A()" attrs="145">
         <size>9</size>
     </type>
     <type name="Tester+&lt;ArrayAccessTest_4&gt;c__async3">
       <method name="Void MoveNext()" attrs="486">
-        <size>415</size>
+        <size>429</size>
       </method>
       <method name="Int32 &lt;&gt;m__F()" attrs="145">
         <size>9</size>
     </type>
     <type name="Tester+&lt;ArrayAccessTest_5&gt;c__async4">
       <method name="Void MoveNext()" attrs="486">
-        <size>399</size>
+        <size>413</size>
       </method>
       <method name="Int32 &lt;&gt;m__11()" attrs="145">
         <size>9</size>
     </type>
     <type name="Tester+&lt;ArrayAccessTest_9&gt;c__async8">
       <method name="Void MoveNext()" attrs="486">
-        <size>1205</size>
+        <size>1233</size>
       </method>
       <method name="Int32 &lt;&gt;m__17()" attrs="145">
         <size>9</size>
     </type>
     <type name="Tester+&lt;CallTest_4&gt;c__async14">
       <method name="Void MoveNext()" attrs="486">
-        <size>232</size>
+        <size>239</size>
       </method>
       <method name="Void SetStateMachine(IAsyncStateMachine)" attrs="486">
         <size>13</size>
     </type>
     <type name="Tester+&lt;CoalescingTest_1&gt;c__async18">
       <method name="Void MoveNext()" attrs="486">
-        <size>359</size>
+        <size>366</size>
       </method>
       <method name="Void SetStateMachine(IAsyncStateMachine)" attrs="486">
         <size>13</size>
     </type>
     <type name="Tester+&lt;IndexerTest_4&gt;c__async24">
       <method name="Void MoveNext()" attrs="486">
-        <size>400</size>
+        <size>407</size>
       </method>
       <method name="Void SetStateMachine(IAsyncStateMachine)" attrs="486">
         <size>13</size>
     </type>
     <type name="Tester+&lt;IndexerTest_5&gt;c__async25">
       <method name="Void MoveNext()" attrs="486">
-        <size>506</size>
+        <size>520</size>
       </method>
       <method name="Void SetStateMachine(IAsyncStateMachine)" attrs="486">
         <size>13</size>
     </type>
     <type name="Tester+&lt;IsTest_1&gt;c__async28">
       <method name="Void MoveNext()" attrs="486">
-        <size>229</size>
+        <size>236</size>
       </method>
       <method name="Void SetStateMachine(IAsyncStateMachine)" attrs="486">
         <size>13</size>
     </type>
     <type name="Tester+&lt;LogicalUserOperator_1&gt;c__async2A">
       <method name="Void MoveNext()" attrs="486">
-        <size>392</size>
+        <size>399</size>
       </method>
       <method name="Void SetStateMachine(IAsyncStateMachine)" attrs="486">
         <size>13</size>
     </type>
     <type name="Tester+&lt;LogicalUserOperator_2&gt;c__async2B">
       <method name="Void MoveNext()" attrs="486">
-        <size>297</size>
+        <size>304</size>
       </method>
       <method name="Void SetStateMachine(IAsyncStateMachine)" attrs="486">
         <size>13</size>
     </type>
     <type name="Tester+&lt;LogicalUserOperator_3&gt;c__async2C">
       <method name="Void MoveNext()" attrs="486">
-        <size>391</size>
+        <size>398</size>
       </method>
       <method name="Void SetStateMachine(IAsyncStateMachine)" attrs="486">
         <size>13</size>
     </type>
     <type name="Tester+&lt;NewTest_1&gt;c__async2D">
       <method name="Void MoveNext()" attrs="486">
-        <size>258</size>
+        <size>265</size>
       </method>
       <method name="Void SetStateMachine(IAsyncStateMachine)" attrs="486">
         <size>13</size>
     </type>
     <type name="Tester+&lt;NewInitTest_1&gt;c__async2F">
       <method name="Void MoveNext()" attrs="486">
-        <size>1025</size>
+        <size>1046</size>
       </method>
       <method name="Void SetStateMachine(IAsyncStateMachine)" attrs="486">
         <size>13</size>
     </type>
     <type name="Tester+&lt;NewArrayInitTest_1&gt;c__async31">
       <method name="Void MoveNext()" attrs="486">
-        <size>238</size>
+        <size>245</size>
       </method>
       <method name="Void SetStateMachine(IAsyncStateMachine)" attrs="486">
         <size>13</size>
     </type>
     <type name="Tester+&lt;NewArrayInitTest_2&gt;c__async32">
       <method name="Void MoveNext()" attrs="486">
-        <size>356</size>
+        <size>363</size>
       </method>
       <method name="Void SetStateMachine(IAsyncStateMachine)" attrs="486">
         <size>13</size>
     </type>
     <type name="Tester+&lt;NewArrayInitTest_3&gt;c__async33">
       <method name="Void MoveNext()" attrs="486">
-        <size>242</size>
+        <size>249</size>
       </method>
       <method name="Void SetStateMachine(IAsyncStateMachine)" attrs="486">
         <size>13</size>
     </type>
     <type name="Tester+&lt;NewArrayInitTest_4&gt;c__async34">
       <method name="Void MoveNext()" attrs="486">
-        <size>426</size>
+        <size>433</size>
       </method>
       <method name="Void SetStateMachine(IAsyncStateMachine)" attrs="486">
         <size>13</size>
     </type>
     <type name="Tester+&lt;NewArrayInitTest_5&gt;c__async35">
       <method name="Void MoveNext()" attrs="486">
-        <size>260</size>
+        <size>267</size>
       </method>
       <method name="Void SetStateMachine(IAsyncStateMachine)" attrs="486">
         <size>13</size>
     </type>
     <type name="Tester+&lt;NewArrayInitTest_6&gt;c__async36">
       <method name="Void MoveNext()" attrs="486">
-        <size>262</size>
+        <size>269</size>
       </method>
       <method name="Void SetStateMachine(IAsyncStateMachine)" attrs="486">
         <size>13</size>
     </type>
     <type name="Tester+&lt;PropertyTest_2&gt;c__async38">
       <method name="Void MoveNext()" attrs="486">
-        <size>293</size>
+        <size>300</size>
       </method>
       <method name="Void SetStateMachine(IAsyncStateMachine)" attrs="486">
         <size>13</size>
     </type>
     <type name="Tester+&lt;PropertyTest_3&gt;c__async39">
       <method name="Void MoveNext()" attrs="486">
-        <size>649</size>
+        <size>656</size>
       </method>
       <method name="Void SetStateMachine(IAsyncStateMachine)" attrs="486">
         <size>13</size>
     </type>
     <type name="Tester+&lt;StringConcatTest_1&gt;c__async3A">
       <method name="Void MoveNext()" attrs="486">
-        <size>459</size>
+        <size>466</size>
       </method>
       <method name="Void SetStateMachine(IAsyncStateMachine)" attrs="486">
         <size>13</size>
     </type>
     <type name="Tester+&lt;Add_1&gt;c__async0">
       <method name="Void MoveNext()" attrs="486">
-        <size>462</size>
+        <size>497</size>
       </method>
       <method name="Int32 &lt;&gt;m__4()" attrs="145">
         <size>9</size>
     </type>
     <type name="Tester+&lt;AssignCompound_1&gt;c__async1">
       <method name="Void MoveNext()" attrs="486">
-        <size>1188</size>
+        <size>1237</size>
       </method>
       <method name="Int32 &lt;&gt;m__5()" attrs="145">
         <size>9</size>
     </type>
     <type name="Tester+&lt;Convert_1&gt;c__async2">
       <method name="Void MoveNext()" attrs="486">
-        <size>328</size>
+        <size>349</size>
       </method>
       <method name="System.Object &lt;&gt;m__6()" attrs="145">
         <size>13</size>
     </type>
     <type name="Tester+&lt;Invocation_1&gt;c__async3">
       <method name="Void MoveNext()" attrs="486">
-        <size>580</size>
+        <size>601</size>
       </method>
       <method name="System.Object &lt;&gt;m__7()" attrs="145">
         <size>13</size>
     </type>
     <type name="A+&lt;Test1&gt;c__async0">
       <method name="Void MoveNext()" attrs="486">
-        <size>598</size>
+        <size>612</size>
       </method>
       <method name="Void SetStateMachine(IAsyncStateMachine)" attrs="486">
         <size>13</size>
     </type>
     <type name="C+&lt;Test&gt;c__async0">
       <method name="Void MoveNext()" attrs="486">
-        <size>271</size>
+        <size>285</size>
       </method>
       <method name="Int32 &lt;&gt;m__0(Int32)" attrs="145">
         <size>10</size>
     </type>
     <type name="C+&lt;Test_3&gt;c__async2">
       <method name="Void MoveNext()" attrs="486">
-        <size>1188</size>
+        <size>1237</size>
       </method>
       <method name="Int32 &lt;&gt;m__2()" attrs="145">
         <size>9</size>