This patch modifies the management of secondary stack within transient blocks by allowing "relaxed management" to be the default. In this mode a block will not manage the secondary stack if there exists an enclosing scope which already does that. "Strict management" can be enforced by means of switch -gnatd.s. No need for a test as Q111-032 already performs all necessary checks.
Tested on x86_64-pc-linux-gnu, committed on trunk 2017-04-27 Hristian Kirtchev <kirtc...@adacore.com> * debug.adb Change the documentation of switch -gnatd.s. * exp_ch7.adb (Make_Transient_Block): Transient blocks do not need to manage the secondary stack when an enclosing scope already performs this functionality (aka relaxed management). Switch -gnatd.s may be used to force strict management in which case the block will manage the secondary stack unconditionally. Add a guard to stop the traversal when encountering a package or a subprogram scope.
Index: exp_ch7.adb =================================================================== --- exp_ch7.adb (revision 247295) +++ exp_ch7.adb (working copy) @@ -8275,31 +8275,27 @@ function Manages_Sec_Stack (Id : Entity_Id) return Boolean is begin - -- An exception handler with a choice parameter utilizes a dummy - -- block to provide a declarative region. Such a block should not be - -- considered because it never manifests in the tree and can never - -- release the secondary stack. + case Ekind (Id) is - if Ekind (Id) = E_Block - and then Uses_Sec_Stack (Id) - and then not Is_Exception_Handler (Id) - then - return True; + -- An exception handler with a choice parameter utilizes a dummy + -- block to provide a declarative region. Such a block should not + -- be considered because it never manifests in the tree and can + -- never release the secondary stack. - -- Loops are intentionally excluded because they undergo special - -- treatment, see Establish_Transient_Scope. + when E_Block => + return + Uses_Sec_Stack (Id) and then not Is_Exception_Handler (Id); - elsif Ekind_In (Id, E_Entry, - E_Entry_Family, - E_Function, - E_Procedure) - and then Uses_Sec_Stack (Id) - then - return True; + when E_Entry + | E_Entry_Family + | E_Function + | E_Procedure + => + return Uses_Sec_Stack (Id); - else - return False; - end if; + when others => + return False; + end case; end Manages_Sec_Stack; -- Local variables @@ -8326,14 +8322,11 @@ Scop := Scope (Trans_Id); while Present (Scop) loop - if Scop = Standard_Standard then - exit; - -- The transient block must manage the secondary stack when the - -- block appears within a loop in order to reclaim the memory at - -- each iteration. + -- It should not be possible to reach Standard without hitting one + -- of the other cases first unless Standard was manually pushed. - elsif Ekind (Scop) = E_Loop then + if Scop = Standard_Standard then exit; -- The transient block is within a function which returns on the @@ -8351,15 +8344,36 @@ Set_Uses_Sec_Stack (Trans_Id, False); exit; - -- When requested, the transient block does not need to manage the - -- secondary stack when there exists an enclosing block, entry, - -- entry family, function, or a procedure which already does that. + -- The transient block must manage the secondary stack when the + -- block appears within a loop in order to reclaim the memory at + -- each iteration. + + elsif Ekind (Scop) = E_Loop then + exit; + + -- The transient block does not need to manage the secondary stack + -- when there is an enclosing construct which already does that. -- This optimization saves on SS_Mark and SS_Release calls but may -- allow objects to live a little longer than required. - elsif Debug_Flag_Dot_S and then Manages_Sec_Stack (Scop) then + -- The transient block must manage the secondary stack when switch + -- -gnatd.s (strict management) is in effect. + + elsif Manages_Sec_Stack (Scop) and then not Debug_Flag_Dot_S then Set_Uses_Sec_Stack (Trans_Id, False); exit; + + -- Prevent the search from going too far because transient blocks + -- are bounded by packages and subprogram scopes. + + elsif Ekind_In (Scop, E_Entry, + E_Entry_Family, + E_Function, + E_Package, + E_Procedure, + E_Subprogram_Body) + then + exit; end if; Scop := Scope (Scop); Index: debug.adb =================================================================== --- debug.adb (revision 247295) +++ debug.adb (working copy) @@ -109,7 +109,7 @@ -- d.p Use original Ada 95 semantics for Bit_Order (disable AI95-0133) -- d.q Suppress optimizations on imported 'in' -- d.r Enable OK_To_Reorder_Components in non-variant records - -- d.s Minimize secondary stack Mark and Release calls + -- d.s Strict secondary stack management -- d.t Disable static allocation of library level dispatch tables -- d.u Enable Modify_Tree_For_C (update tree for c) -- d.v Enable OK_To_Reorder_Components in variant records @@ -572,6 +572,11 @@ -- d.r Forces the flag OK_To_Reorder_Components to be set in all record -- base types that have no discriminants. + -- d.s The compiler no longer attempts to optimize the calls to secondary + -- stack management routines SS_Mark and SS_Release. As a result, each + -- transient block tasked with secondary stack management will fulfill + -- its role unconditionally. + -- d.s The compiler does not generate calls to secondary stack management -- routines SS_Mark and SS_Release for a transient block when there is -- an enclosing scoping construct which already manages the secondary