[multiple changes]
2011-08-04 Yannick Moy <moy@adacore.com> * sem_prag.adb, sem.ads: Code cleanup. 2011-08-04 Tristan Gingold <gingold@adacore.com> * s-tassta.adb (Task_Wrapper): Rewrite the dynamic stack usage part. * s-stausa.adb, s-stausa.ads: Major rewrite. Now provides accurate results if possible. * s-stusta.adb (Print): Adjust after changes in s-stausa. * gnat_ugn.texi: Update dynamic stack usage section. 2011-08-04 Steve Baird <baird@adacore.com> * bindgen.adb (Gen_CodePeer_Wrapper): new procedure. Generate (if CodePeer_Mode is set) a "wrapper" subprogram which contains only a call to the user-defined main subprogram. (Gen_Main_Ada) - If CodePeer_Mode is set, then call the "wrapper" subprogram instead of directly calling the user-defined main subprogram. 2011-08-04 Hristian Kirtchev <kirtchev@adacore.com> * exp_ch5.adb (Expand_N_Case_Statement): Check the statements of all alternatives of a case statement for controlled objects. Rename local variable A to Dead_Alt. (Expand_N_If_Statement): Check the then and else statements of an if statement for controlled objects. Check the then statements of all elsif parts of an if statement for controlled objects. (Expand_N_Loop_Statement): Check the statements of a loop for controlled objects. * exp_ch7.adb (Process_Transient_Objects): Rewrite the condition which detects a loop associated with the expansion of an array object. Augment the processing of the loop statements to account for a possible wrap done by Process_Statements_For_Controlled_Objects. * exp_ch9.adb (Expand_N_Asynchronous_Select): Check the triggering statements and abortable part of an asynchronous select for controlled objects. (Expand_N_Conditional_Entry_Call): Check the else statements of a conditional entry call for controlled objects. (Expand_N_Selective_Accept): Check the alternatives of a selective accept for controlled objects. (Expand_N_Timed_Entry_Call): Check the entry call and delay alternatives of a timed entry call for controlled objects. * exp_ch11.adb (Expand_Exception_Handlers): Check the statements of an exception handler for controlled objects. * exp_util.adb (Requires_Cleanup_Actions (List_Id, Boolean, Boolean)): Add formal parameter Nested_Constructs along with its associated comment. (Requires_Cleanup_Actions (Node_Id)): Update all calls to Requires_Cleanup_Actions. (Process_Statements_For_Controlled_Objects): New routine. * exp_util.ads (Process_Statements_For_Controlled_Objects): New routine. Inspect a node which contains a non-handled sequence of statements for controlled objects. If such an object is found, the statements are wrapped in a block. From-SVN: r177386
This commit is contained in:
parent
1bf773bb9f
commit
2ba7e31e7e
|
@ -1,3 +1,60 @@
|
|||
2011-08-04 Yannick Moy <moy@adacore.com>
|
||||
|
||||
* sem_prag.adb, sem.ads: Code cleanup.
|
||||
|
||||
2011-08-04 Tristan Gingold <gingold@adacore.com>
|
||||
|
||||
* s-tassta.adb (Task_Wrapper): Rewrite the dynamic stack usage part.
|
||||
* s-stausa.adb, s-stausa.ads: Major rewrite. Now provides accurate
|
||||
results if possible.
|
||||
* s-stusta.adb (Print): Adjust after changes in s-stausa.
|
||||
* gnat_ugn.texi: Update dynamic stack usage section.
|
||||
|
||||
2011-08-04 Steve Baird <baird@adacore.com>
|
||||
|
||||
* bindgen.adb (Gen_CodePeer_Wrapper): new procedure.
|
||||
Generate (if CodePeer_Mode is set) a "wrapper" subprogram which
|
||||
contains only a call to the user-defined main subprogram.
|
||||
(Gen_Main_Ada) - If CodePeer_Mode is set, then
|
||||
call the "wrapper" subprogram instead of directly
|
||||
calling the user-defined main subprogram.
|
||||
|
||||
2011-08-04 Hristian Kirtchev <kirtchev@adacore.com>
|
||||
|
||||
* exp_ch5.adb (Expand_N_Case_Statement): Check the statements of all
|
||||
alternatives of a case statement for controlled objects. Rename local
|
||||
variable A to Dead_Alt.
|
||||
(Expand_N_If_Statement): Check the then and else statements of an if
|
||||
statement for controlled objects. Check the then statements of all
|
||||
elsif parts of an if statement for controlled objects.
|
||||
(Expand_N_Loop_Statement): Check the statements of a loop for controlled
|
||||
objects.
|
||||
* exp_ch7.adb (Process_Transient_Objects): Rewrite the condition which
|
||||
detects a loop associated with the expansion of an array object.
|
||||
Augment the processing of the loop statements to account for a possible
|
||||
wrap done by Process_Statements_For_Controlled_Objects.
|
||||
* exp_ch9.adb (Expand_N_Asynchronous_Select): Check the triggering
|
||||
statements and abortable part of an asynchronous select for controlled
|
||||
objects.
|
||||
(Expand_N_Conditional_Entry_Call): Check the else statements of a
|
||||
conditional entry call for controlled objects.
|
||||
(Expand_N_Selective_Accept): Check the alternatives of a selective
|
||||
accept for controlled objects.
|
||||
(Expand_N_Timed_Entry_Call): Check the entry call and delay
|
||||
alternatives of a timed entry call for controlled objects.
|
||||
* exp_ch11.adb (Expand_Exception_Handlers): Check the statements of an
|
||||
exception handler for controlled objects.
|
||||
* exp_util.adb (Requires_Cleanup_Actions (List_Id, Boolean, Boolean)):
|
||||
Add formal parameter Nested_Constructs along with its associated
|
||||
comment.
|
||||
(Requires_Cleanup_Actions (Node_Id)): Update all calls to
|
||||
Requires_Cleanup_Actions.
|
||||
(Process_Statements_For_Controlled_Objects): New routine.
|
||||
* exp_util.ads (Process_Statements_For_Controlled_Objects): New
|
||||
routine. Inspect a node which contains a non-handled sequence of
|
||||
statements for controlled objects. If such an object is found, the
|
||||
statements are wrapped in a block.
|
||||
|
||||
2011-08-04 Bob Duff <duff@adacore.com>
|
||||
|
||||
* sem_type.adb (Covers): If T2 is a subtype of a class-wide type, we
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
------------------------------------------------------------------------------
|
||||
-----------------------------------------------------------------------------
|
||||
-- --
|
||||
-- GNAT COMPILER COMPONENTS --
|
||||
-- --
|
||||
|
@ -74,6 +74,10 @@ package body Bindgen is
|
|||
Lib_Final_Built : Boolean := False;
|
||||
-- Flag indicating whether the finalize_library rountine has been built
|
||||
|
||||
CodePeer_Wrapper_Name : constant String := "call_main_subprogram";
|
||||
-- For CodePeer, introduce a wrapper subprogram which calls the
|
||||
-- user-defined main subprogram.
|
||||
|
||||
----------------------------------
|
||||
-- Interface_State Pragma Table --
|
||||
----------------------------------
|
||||
|
@ -275,6 +279,9 @@ package body Bindgen is
|
|||
procedure Gen_Finalize_Library_Defs_C;
|
||||
-- Generate a sequence of defininitions for package finalizers (C case)
|
||||
|
||||
procedure Gen_CodePeer_Wrapper;
|
||||
-- For CodePeer, generate wrapper which calls user-defined main subprogram
|
||||
|
||||
procedure Gen_Main_Ada;
|
||||
-- Generate procedure main (Ada code case)
|
||||
|
||||
|
@ -2126,6 +2133,36 @@ package body Bindgen is
|
|||
WBI ("");
|
||||
end Gen_Finalize_Library_Defs_C;
|
||||
|
||||
--------------------------
|
||||
-- Gen_CodePeer_Wrapper --
|
||||
--------------------------
|
||||
|
||||
procedure Gen_CodePeer_Wrapper is
|
||||
begin
|
||||
Get_Name_String (Units.Table (First_Unit_Entry).Uname);
|
||||
|
||||
declare
|
||||
-- Bypass Ada_Main_Program; its Import pragma confuses CodePeer
|
||||
|
||||
Callee_Name : String renames Name_Buffer (1 .. Name_Len - 2);
|
||||
-- Strip trailing "%b"
|
||||
begin
|
||||
if ALIs.Table (ALIs.First).Main_Program = Proc then
|
||||
WBI (" procedure " & CodePeer_Wrapper_Name & " is ");
|
||||
WBI (" begin");
|
||||
WBI (" " & Callee_Name & ";");
|
||||
else
|
||||
WBI
|
||||
(" function " & CodePeer_Wrapper_Name & " return Integer is");
|
||||
WBI (" begin");
|
||||
WBI (" return " & Callee_Name & ";");
|
||||
end if;
|
||||
end;
|
||||
|
||||
WBI (" end " & CodePeer_Wrapper_Name & ";");
|
||||
WBI ("");
|
||||
end Gen_CodePeer_Wrapper;
|
||||
|
||||
------------------
|
||||
-- Gen_Main_Ada --
|
||||
------------------
|
||||
|
@ -2318,22 +2355,11 @@ package body Bindgen is
|
|||
if not No_Main_Subprogram then
|
||||
|
||||
if CodePeer_Mode then
|
||||
|
||||
-- Bypass Ada_Main_Program, its Import pragma confuses CodePeer
|
||||
|
||||
Get_Name_String (Units.Table (First_Unit_Entry).Uname);
|
||||
|
||||
declare
|
||||
Callee_Name : String renames Name_Buffer (1 .. Name_Len - 2);
|
||||
-- Strip trailing "%b"
|
||||
|
||||
begin
|
||||
if ALIs.Table (ALIs.First).Main_Program = Proc then
|
||||
WBI (" " & Callee_Name & ";");
|
||||
else
|
||||
WBI (" Result := " & Callee_Name & ";");
|
||||
end if;
|
||||
end;
|
||||
if ALIs.Table (ALIs.First).Main_Program = Proc then
|
||||
WBI (" " & CodePeer_Wrapper_Name & ";");
|
||||
else
|
||||
WBI (" Result := " & CodePeer_Wrapper_Name & ";");
|
||||
end if;
|
||||
|
||||
elsif ALIs.Table (ALIs.First).Main_Program = Proc then
|
||||
WBI (" Ada_Main_Program;");
|
||||
|
@ -3232,6 +3258,13 @@ package body Bindgen is
|
|||
Gen_Adainit_Ada;
|
||||
|
||||
if Bind_Main_Program and then VM_Target = No_VM then
|
||||
-- For CodePeer, declare a wrapper for the
|
||||
-- user-defined main program.
|
||||
|
||||
if CodePeer_Mode then
|
||||
Gen_CodePeer_Wrapper;
|
||||
end if;
|
||||
|
||||
Gen_Main_Ada;
|
||||
end if;
|
||||
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
-- --
|
||||
-- B o d y --
|
||||
-- --
|
||||
-- Copyright (C) 1992-2010, Free Software Foundation, Inc. --
|
||||
-- Copyright (C) 1992-2011, Free Software Foundation, Inc. --
|
||||
-- --
|
||||
-- GNAT is free software; you can redistribute it and/or modify it under --
|
||||
-- terms of the GNU General Public License as published by the Free Soft- --
|
||||
|
@ -968,6 +968,8 @@ package body Exp_Ch11 is
|
|||
|
||||
Handler := First_Non_Pragma (Handlrs);
|
||||
Handler_Loop : while Present (Handler) loop
|
||||
Process_Statements_For_Controlled_Objects (Handler);
|
||||
|
||||
Next_Handler := Next_Non_Pragma (Handler);
|
||||
|
||||
-- Remove source handler if gnat debug flag .x is set
|
||||
|
|
|
@ -2279,6 +2279,8 @@ package body Exp_Ch5 is
|
|||
if Compile_Time_Known_Value (Expr) then
|
||||
Alt := Find_Static_Alternative (N);
|
||||
|
||||
Process_Statements_For_Controlled_Objects (Alt);
|
||||
|
||||
-- Move statements from this alternative after the case statement.
|
||||
-- They are already analyzed, so will be skipped by the analyzer.
|
||||
|
||||
|
@ -2290,21 +2292,21 @@ package body Exp_Ch5 is
|
|||
Kill_Dead_Code (Expression (N));
|
||||
|
||||
declare
|
||||
A : Node_Id;
|
||||
Dead_Alt : Node_Id;
|
||||
|
||||
begin
|
||||
-- Loop through case alternatives, skipping pragmas, and skipping
|
||||
-- the one alternative that we select (and therefore retain).
|
||||
|
||||
A := First (Alternatives (N));
|
||||
while Present (A) loop
|
||||
if A /= Alt
|
||||
and then Nkind (A) = N_Case_Statement_Alternative
|
||||
Dead_Alt := First (Alternatives (N));
|
||||
while Present (Dead_Alt) loop
|
||||
if Dead_Alt /= Alt
|
||||
and then Nkind (Dead_Alt) = N_Case_Statement_Alternative
|
||||
then
|
||||
Kill_Dead_Code (Statements (A), Warn_On_Deleted_Code);
|
||||
Kill_Dead_Code (Statements (Dead_Alt), Warn_On_Deleted_Code);
|
||||
end if;
|
||||
|
||||
Next (A);
|
||||
Next (Dead_Alt);
|
||||
end loop;
|
||||
end;
|
||||
|
||||
|
@ -2351,12 +2353,16 @@ package body Exp_Ch5 is
|
|||
Len := List_Length (Alternatives (N));
|
||||
|
||||
if Len = 1 then
|
||||
-- We still need to evaluate the expression if it has any
|
||||
-- side effects.
|
||||
|
||||
-- We still need to evaluate the expression if it has any side
|
||||
-- effects.
|
||||
|
||||
Remove_Side_Effects (Expression (N));
|
||||
|
||||
Insert_List_After (N, Statements (First (Alternatives (N))));
|
||||
Alt := First (Alternatives (N));
|
||||
|
||||
Process_Statements_For_Controlled_Objects (Alt);
|
||||
Insert_List_After (N, Statements (Alt));
|
||||
|
||||
-- That leaves the case statement as a shell. The alternative that
|
||||
-- will be executed is reset to a null list. So now we can kill
|
||||
|
@ -2365,7 +2371,6 @@ package body Exp_Ch5 is
|
|||
Kill_Dead_Code (Expression (N));
|
||||
Rewrite (N, Make_Null_Statement (Loc));
|
||||
return;
|
||||
end if;
|
||||
|
||||
-- An optimization. If there are only two alternatives, and only
|
||||
-- a single choice, then rewrite the whole case statement as an
|
||||
|
@ -2374,7 +2379,7 @@ package body Exp_Ch5 is
|
|||
-- simple form, but also with generated code (discriminant check
|
||||
-- functions in particular)
|
||||
|
||||
if Len = 2 then
|
||||
elsif Len = 2 then
|
||||
Chlist := Discrete_Choices (First (Alternatives (N)));
|
||||
|
||||
if List_Length (Chlist) = 1 then
|
||||
|
@ -2451,6 +2456,15 @@ package body Exp_Ch5 is
|
|||
(Others_Node, Discrete_Choices (Last_Alt));
|
||||
Set_Discrete_Choices (Last_Alt, New_List (Others_Node));
|
||||
end if;
|
||||
|
||||
Alt := First (Alternatives (N));
|
||||
while Present (Alt)
|
||||
and then Nkind (Alt) = N_Case_Statement_Alternative
|
||||
loop
|
||||
Process_Statements_For_Controlled_Objects (Alt);
|
||||
|
||||
Next (Alt);
|
||||
end loop;
|
||||
end;
|
||||
end Expand_N_Case_Statement;
|
||||
|
||||
|
@ -2525,6 +2539,8 @@ package body Exp_Ch5 is
|
|||
-- these warnings for expander generated code.
|
||||
|
||||
begin
|
||||
Process_Statements_For_Controlled_Objects (N);
|
||||
|
||||
Adjust_Condition (Condition (N));
|
||||
|
||||
-- The following loop deals with constant conditions for the IF. We
|
||||
|
@ -2610,6 +2626,8 @@ package body Exp_Ch5 is
|
|||
if Present (Elsif_Parts (N)) then
|
||||
E := First (Elsif_Parts (N));
|
||||
while Present (E) loop
|
||||
Process_Statements_For_Controlled_Objects (E);
|
||||
|
||||
Adjust_Condition (Condition (E));
|
||||
|
||||
-- If there are condition actions, then rewrite the if statement
|
||||
|
@ -3065,6 +3083,8 @@ package body Exp_Ch5 is
|
|||
return;
|
||||
end if;
|
||||
|
||||
Process_Statements_For_Controlled_Objects (N);
|
||||
|
||||
-- Deal with condition for C/Fortran Boolean
|
||||
|
||||
if Present (Isc) then
|
||||
|
|
|
@ -4366,11 +4366,38 @@ package body Exp_Ch7 is
|
|||
-- sometimes generate a loop and create transient objects inside
|
||||
-- the loop.
|
||||
|
||||
elsif Nkind (Stmt) = N_Loop_Statement then
|
||||
Process_Transient_Objects
|
||||
(First_Object => First (Statements (Stmt)),
|
||||
Last_Object => Last (Statements (Stmt)),
|
||||
Related_Node => Related_Node);
|
||||
elsif Nkind (Related_Node) = N_Object_Declaration
|
||||
and then Is_Array_Type (Base_Type
|
||||
(Etype (Defining_Identifier (Related_Node))))
|
||||
and then Nkind (Stmt) = N_Loop_Statement
|
||||
then
|
||||
declare
|
||||
Block_HSS : Node_Id := First (Statements (Stmt));
|
||||
|
||||
begin
|
||||
-- The loop statements may have been wrapped in a block by
|
||||
-- Process_Statements_For_Controlled_Objects, inspect the
|
||||
-- handled sequence of statements.
|
||||
|
||||
if Nkind (Block_HSS) = N_Block_Statement
|
||||
and then No (Next (Block_HSS))
|
||||
then
|
||||
Block_HSS := Handled_Statement_Sequence (Block_HSS);
|
||||
|
||||
Process_Transient_Objects
|
||||
(First_Object => First (Statements (Block_HSS)),
|
||||
Last_Object => Last (Statements (Block_HSS)),
|
||||
Related_Node => Related_Node);
|
||||
|
||||
-- Inspect the statements of the loop
|
||||
|
||||
else
|
||||
Process_Transient_Objects
|
||||
(First_Object => First (Statements (Stmt)),
|
||||
Last_Object => Last (Statements (Stmt)),
|
||||
Related_Node => Related_Node);
|
||||
end if;
|
||||
end;
|
||||
|
||||
-- Terminate the scan after the last object has been processed
|
||||
|
||||
|
|
|
@ -5872,6 +5872,9 @@ package body Exp_Ch9 is
|
|||
T : Entity_Id; -- Additional status flag
|
||||
|
||||
begin
|
||||
Process_Statements_For_Controlled_Objects (Trig);
|
||||
Process_Statements_For_Controlled_Objects (Abrt);
|
||||
|
||||
Blk_Ent := Make_Temporary (Loc, 'A');
|
||||
Ecall := Triggering_Statement (Trig);
|
||||
|
||||
|
@ -6824,6 +6827,8 @@ package body Exp_Ch9 is
|
|||
S : Entity_Id; -- Primitive operation slot
|
||||
|
||||
begin
|
||||
Process_Statements_For_Controlled_Objects (N);
|
||||
|
||||
if Ada_Version >= Ada_2005
|
||||
and then Nkind (Blk) = N_Procedure_Call_Statement
|
||||
then
|
||||
|
@ -9660,6 +9665,8 @@ package body Exp_Ch9 is
|
|||
-- Start of processing for Expand_N_Selective_Accept
|
||||
|
||||
begin
|
||||
Process_Statements_For_Controlled_Objects (N);
|
||||
|
||||
-- First insert some declarations before the select. The first is:
|
||||
|
||||
-- Ann : Address
|
||||
|
@ -9679,6 +9686,7 @@ package body Exp_Ch9 is
|
|||
|
||||
Alt := First (Alts);
|
||||
while Present (Alt) loop
|
||||
Process_Statements_For_Controlled_Objects (Alt);
|
||||
|
||||
if Nkind (Alt) = N_Accept_Alternative then
|
||||
Add_Accept (Alt);
|
||||
|
@ -11035,6 +11043,9 @@ package body Exp_Ch9 is
|
|||
return;
|
||||
end if;
|
||||
|
||||
Process_Statements_For_Controlled_Objects (Entry_Call_Alternative (N));
|
||||
Process_Statements_For_Controlled_Objects (Delay_Alternative (N));
|
||||
|
||||
-- The arguments in the call may require dynamic allocation, and the
|
||||
-- call statement may have been transformed into a block. The block
|
||||
-- may contain additional declarations for internal entities, and the
|
||||
|
|
|
@ -148,15 +148,17 @@ package body Exp_Util is
|
|||
-- Create an implicit subtype of CW_Typ attached to node N
|
||||
|
||||
function Requires_Cleanup_Actions
|
||||
(L : List_Id;
|
||||
For_Package : Boolean) return Boolean;
|
||||
(L : List_Id;
|
||||
For_Package : Boolean;
|
||||
Nested_Constructs : Boolean) return Boolean;
|
||||
-- Given a list L, determine whether it contains one of the following:
|
||||
--
|
||||
-- 1) controlled objects
|
||||
-- 2) library-level tagged types
|
||||
--
|
||||
-- Flag For_Package should be set when the list comes from a package spec
|
||||
-- or body.
|
||||
-- or body. Flag Nested_Constructs should be set when any nested packages
|
||||
-- declared in L must be processed.
|
||||
|
||||
----------------------
|
||||
-- Adjust_Condition --
|
||||
|
@ -5446,6 +5448,107 @@ package body Exp_Util is
|
|||
end case;
|
||||
end Possible_Bit_Aligned_Component;
|
||||
|
||||
-----------------------------------------------
|
||||
-- Process_Statements_For_Controlled_Objects --
|
||||
-----------------------------------------------
|
||||
|
||||
procedure Process_Statements_For_Controlled_Objects (N : Node_Id) is
|
||||
Loc : constant Source_Ptr := Sloc (N);
|
||||
|
||||
function Are_Wrapped (L : List_Id) return Boolean;
|
||||
-- Determine whether list L contains only one statement which is a block
|
||||
|
||||
function Wrap_Statements_In_Block (L : List_Id) return Node_Id;
|
||||
-- Given a list of statements L, wrap it in a block statement and return
|
||||
-- the generated node.
|
||||
|
||||
-----------------
|
||||
-- Are_Wrapped --
|
||||
-----------------
|
||||
|
||||
function Are_Wrapped (L : List_Id) return Boolean is
|
||||
Stmt : constant Node_Id := First (L);
|
||||
|
||||
begin
|
||||
return
|
||||
Present (Stmt)
|
||||
and then No (Next (Stmt))
|
||||
and then Nkind (Stmt) = N_Block_Statement;
|
||||
end Are_Wrapped;
|
||||
|
||||
------------------------------
|
||||
-- Wrap_Statements_In_Block --
|
||||
------------------------------
|
||||
|
||||
function Wrap_Statements_In_Block (L : List_Id) return Node_Id is
|
||||
begin
|
||||
return
|
||||
Make_Block_Statement (Loc,
|
||||
Declarations => No_List,
|
||||
Handled_Statement_Sequence =>
|
||||
Make_Handled_Sequence_Of_Statements (Loc,
|
||||
Statements => L));
|
||||
end Wrap_Statements_In_Block;
|
||||
|
||||
-- Start of processing for Process_Statements_For_Controlled_Objects
|
||||
|
||||
begin
|
||||
case Nkind (N) is
|
||||
when N_Elsif_Part |
|
||||
N_If_Statement |
|
||||
N_Conditional_Entry_Call |
|
||||
N_Selective_Accept =>
|
||||
|
||||
-- Check the "then statements" for elsif parts and if statements
|
||||
|
||||
if Nkind_In (N, N_Elsif_Part,
|
||||
N_If_Statement)
|
||||
and then not Is_Empty_List (Then_Statements (N))
|
||||
and then not Are_Wrapped (Then_Statements (N))
|
||||
and then Requires_Cleanup_Actions
|
||||
(Then_Statements (N), False, False)
|
||||
then
|
||||
Set_Then_Statements (N, New_List (
|
||||
Wrap_Statements_In_Block (Then_Statements (N))));
|
||||
end if;
|
||||
|
||||
-- Check the "else statements" for conditional entry calls, if
|
||||
-- statements and selective accepts.
|
||||
|
||||
if Nkind_In (N, N_Conditional_Entry_Call,
|
||||
N_If_Statement,
|
||||
N_Selective_Accept)
|
||||
and then not Is_Empty_List (Else_Statements (N))
|
||||
and then not Are_Wrapped (Else_Statements (N))
|
||||
and then Requires_Cleanup_Actions
|
||||
(Else_Statements (N), False, False)
|
||||
then
|
||||
Set_Else_Statements (N, New_List (
|
||||
Wrap_Statements_In_Block (Else_Statements (N))));
|
||||
end if;
|
||||
|
||||
when N_Abortable_Part |
|
||||
N_Accept_Alternative |
|
||||
N_Case_Statement_Alternative |
|
||||
N_Delay_Alternative |
|
||||
N_Entry_Call_Alternative |
|
||||
N_Exception_Handler |
|
||||
N_Loop_Statement |
|
||||
N_Triggering_Alternative =>
|
||||
|
||||
if not Is_Empty_List (Statements (N))
|
||||
and then not Are_Wrapped (Statements (N))
|
||||
and then Requires_Cleanup_Actions (Statements (N), False, False)
|
||||
then
|
||||
Set_Statements (N, New_List (
|
||||
Wrap_Statements_In_Block (Statements (N))));
|
||||
end if;
|
||||
|
||||
when others =>
|
||||
null;
|
||||
end case;
|
||||
end Process_Statements_For_Controlled_Objects;
|
||||
|
||||
-------------------------
|
||||
-- Remove_Side_Effects --
|
||||
-------------------------
|
||||
|
@ -6148,18 +6251,20 @@ package body Exp_Util is
|
|||
N_Subprogram_Body |
|
||||
N_Task_Body =>
|
||||
return
|
||||
Requires_Cleanup_Actions (Declarations (N), For_Pkg)
|
||||
Requires_Cleanup_Actions (Declarations (N), For_Pkg, True)
|
||||
or else
|
||||
(Present (Handled_Statement_Sequence (N))
|
||||
and then
|
||||
Requires_Cleanup_Actions
|
||||
(Statements (Handled_Statement_Sequence (N)), For_Pkg));
|
||||
Requires_Cleanup_Actions (Statements
|
||||
(Handled_Statement_Sequence (N)), For_Pkg, True));
|
||||
|
||||
when N_Package_Specification =>
|
||||
return
|
||||
Requires_Cleanup_Actions (Visible_Declarations (N), For_Pkg)
|
||||
or else
|
||||
Requires_Cleanup_Actions (Private_Declarations (N), For_Pkg);
|
||||
Requires_Cleanup_Actions
|
||||
(Visible_Declarations (N), For_Pkg, True)
|
||||
or else
|
||||
Requires_Cleanup_Actions
|
||||
(Private_Declarations (N), For_Pkg, True);
|
||||
|
||||
when others =>
|
||||
return False;
|
||||
|
@ -6171,8 +6276,9 @@ package body Exp_Util is
|
|||
------------------------------
|
||||
|
||||
function Requires_Cleanup_Actions
|
||||
(L : List_Id;
|
||||
For_Package : Boolean) return Boolean
|
||||
(L : List_Id;
|
||||
For_Package : Boolean;
|
||||
Nested_Constructs : Boolean) return Boolean
|
||||
is
|
||||
Decl : Node_Id;
|
||||
Expr : Node_Id;
|
||||
|
@ -6345,7 +6451,9 @@ package body Exp_Util is
|
|||
|
||||
-- Nested package declarations
|
||||
|
||||
elsif Nkind (Decl) = N_Package_Declaration then
|
||||
elsif Nested_Constructs
|
||||
and then Nkind (Decl) = N_Package_Declaration
|
||||
then
|
||||
Pack_Id := Defining_Unit_Name (Specification (Decl));
|
||||
|
||||
if Nkind (Pack_Id) = N_Defining_Program_Unit_Name then
|
||||
|
@ -6360,7 +6468,9 @@ package body Exp_Util is
|
|||
|
||||
-- Nested package bodies
|
||||
|
||||
elsif Nkind (Decl) = N_Package_Body then
|
||||
elsif Nested_Constructs
|
||||
and then Nkind (Decl) = N_Package_Body
|
||||
then
|
||||
Pack_Id := Corresponding_Spec (Decl);
|
||||
|
||||
if Ekind (Pack_Id) /= E_Generic_Package
|
||||
|
|
|
@ -706,6 +706,11 @@ package Exp_Util is
|
|||
-- causes trouble for the back end (see Component_May_Be_Bit_Aligned for
|
||||
-- further details).
|
||||
|
||||
procedure Process_Statements_For_Controlled_Objects (N : Node_Id);
|
||||
-- N is a node which contains a non-handled statement list. Inspect the
|
||||
-- statements looking for declarations of controlled objects. If at least
|
||||
-- one such object is found, wrap the statement list in a block.
|
||||
|
||||
procedure Remove_Side_Effects
|
||||
(Exp : Node_Id;
|
||||
Name_Req : Boolean := False;
|
||||
|
|
|
@ -17259,7 +17259,7 @@ output this info at program termination. Results are displayed in four
|
|||
columns:
|
||||
|
||||
@noindent
|
||||
Index | Task Name | Stack Size | Stack Usage [Value +/- Variation]
|
||||
Index | Task Name | Stack Size | Stack Usage
|
||||
|
||||
@noindent
|
||||
where:
|
||||
|
@ -17277,8 +17277,7 @@ is the maximum size for the stack.
|
|||
@item Stack Usage
|
||||
is the measure done by the stack analyzer. In order to prevent overflow, the stack
|
||||
is not entirely analyzed, and it's not possible to know exactly how
|
||||
much has actually been used. The report thus contains the theoretical stack usage
|
||||
(Value) and the possible variation (Variation) around this value.
|
||||
much has actually been used.
|
||||
|
||||
@end table
|
||||
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
-- --
|
||||
-- B o d y --
|
||||
-- --
|
||||
-- Copyright (C) 2004-2010, Free Software Foundation, Inc. --
|
||||
-- Copyright (C) 2004-2011, Free Software Foundation, Inc. --
|
||||
-- --
|
||||
-- GNARL is free software; you can redistribute it and/or modify it under --
|
||||
-- terms of the GNU General Public License as published by the Free Soft- --
|
||||
|
@ -93,76 +93,6 @@ package body System.Stack_Usage is
|
|||
-- | entry frame | ... | leaf frame | |####|
|
||||
-- +------------------------------------------------------------------+
|
||||
|
||||
function Top_Slot_Index_In (Stack : Stack_Slots) return Integer;
|
||||
-- Index of the stack Top slot in the Slots array, denoting the latest
|
||||
-- possible slot available to call chain leaves.
|
||||
|
||||
function Bottom_Slot_Index_In (Stack : Stack_Slots) return Integer;
|
||||
-- Index of the stack Bottom slot in the Slots array, denoting the first
|
||||
-- possible slot available to call chain entry points.
|
||||
|
||||
function Push_Index_Step_For (Stack : Stack_Slots) return Integer;
|
||||
-- By how much do we need to update a Slots index to Push a single slot on
|
||||
-- the stack.
|
||||
|
||||
function Pop_Index_Step_For (Stack : Stack_Slots) return Integer;
|
||||
-- By how much do we need to update a Slots index to Pop a single slot off
|
||||
-- the stack.
|
||||
|
||||
pragma Inline_Always (Top_Slot_Index_In);
|
||||
pragma Inline_Always (Bottom_Slot_Index_In);
|
||||
pragma Inline_Always (Push_Index_Step_For);
|
||||
pragma Inline_Always (Pop_Index_Step_For);
|
||||
|
||||
-----------------------
|
||||
-- Top_Slot_Index_In --
|
||||
-----------------------
|
||||
|
||||
function Top_Slot_Index_In (Stack : Stack_Slots) return Integer is
|
||||
begin
|
||||
if System.Parameters.Stack_Grows_Down then
|
||||
return Stack'First;
|
||||
else
|
||||
return Stack'Last;
|
||||
end if;
|
||||
end Top_Slot_Index_In;
|
||||
|
||||
----------------------------
|
||||
-- Bottom_Slot_Index_In --
|
||||
----------------------------
|
||||
|
||||
function Bottom_Slot_Index_In (Stack : Stack_Slots) return Integer is
|
||||
begin
|
||||
if System.Parameters.Stack_Grows_Down then
|
||||
return Stack'Last;
|
||||
else
|
||||
return Stack'First;
|
||||
end if;
|
||||
end Bottom_Slot_Index_In;
|
||||
|
||||
-------------------------
|
||||
-- Push_Index_Step_For --
|
||||
-------------------------
|
||||
|
||||
function Push_Index_Step_For (Stack : Stack_Slots) return Integer is
|
||||
pragma Unreferenced (Stack);
|
||||
begin
|
||||
if System.Parameters.Stack_Grows_Down then
|
||||
return -1;
|
||||
else
|
||||
return +1;
|
||||
end if;
|
||||
end Push_Index_Step_For;
|
||||
|
||||
------------------------
|
||||
-- Pop_Index_Step_For --
|
||||
------------------------
|
||||
|
||||
function Pop_Index_Step_For (Stack : Stack_Slots) return Integer is
|
||||
begin
|
||||
return -Push_Index_Step_For (Stack);
|
||||
end Pop_Index_Step_For;
|
||||
|
||||
-------------------
|
||||
-- Unit Services --
|
||||
-------------------
|
||||
|
@ -175,9 +105,6 @@ package body System.Stack_Usage is
|
|||
Stack_Size_Str : constant String := "Stack Size";
|
||||
Actual_Size_Str : constant String := "Stack usage";
|
||||
|
||||
function Get_Usage_Range (Result : Task_Result) return String;
|
||||
-- Return string representing the range of possible result of stack usage
|
||||
|
||||
procedure Output_Result
|
||||
(Result_Id : Natural;
|
||||
Result : Task_Result;
|
||||
|
@ -194,7 +121,6 @@ package body System.Stack_Usage is
|
|||
----------------
|
||||
|
||||
procedure Initialize (Buffer_Size : Natural) is
|
||||
Bottom_Of_Stack : aliased Integer;
|
||||
Stack_Size_Chars : System.Address;
|
||||
|
||||
begin
|
||||
|
@ -204,9 +130,8 @@ package body System.Stack_Usage is
|
|||
Result_Array.all :=
|
||||
(others =>
|
||||
(Task_Name => (others => ASCII.NUL),
|
||||
Variation => 0,
|
||||
Value => 0,
|
||||
Max_Size => 0));
|
||||
Stack_Size => 0));
|
||||
|
||||
-- Set the Is_Enabled flag to true, so that the task wrapper knows that
|
||||
-- it has to handle dynamic stack analysis
|
||||
|
@ -231,9 +156,8 @@ package body System.Stack_Usage is
|
|||
(Environment_Task_Analyzer,
|
||||
"ENVIRONMENT TASK",
|
||||
My_Stack_Size,
|
||||
My_Stack_Size,
|
||||
System.Storage_Elements.To_Integer (Bottom_Of_Stack'Address),
|
||||
0);
|
||||
0,
|
||||
My_Stack_Size);
|
||||
|
||||
Fill_Stack (Environment_Task_Analyzer);
|
||||
|
||||
|
@ -257,99 +181,78 @@ package body System.Stack_Usage is
|
|||
-- big, the more an "instrumentation threshold at writing" error is
|
||||
-- likely to happen.
|
||||
|
||||
Stack_Used_When_Filling : Integer;
|
||||
Current_Stack_Level : aliased Integer;
|
||||
Current_Stack_Level : aliased Integer;
|
||||
|
||||
Guard : constant Integer := 256;
|
||||
Guard : constant := 256;
|
||||
-- Guard space between the Current_Stack_Level'Address and the last
|
||||
-- allocated byte on the stack.
|
||||
|
||||
begin
|
||||
-- Easiest and most accurate method: the top of the stack is known.
|
||||
|
||||
if Analyzer.Top_Pattern_Mark /= 0 then
|
||||
Analyzer.Pattern_Size :=
|
||||
Stack_Size (Analyzer.Top_Pattern_Mark,
|
||||
To_Stack_Address (Current_Stack_Level'Address))
|
||||
- Guard;
|
||||
|
||||
if System.Parameters.Stack_Grows_Down then
|
||||
Analyzer.Stack_Overlay_Address :=
|
||||
To_Address (Analyzer.Top_Pattern_Mark);
|
||||
else
|
||||
Analyzer.Stack_Overlay_Address :=
|
||||
To_Address (Analyzer.Top_Pattern_Mark
|
||||
- Stack_Address (Analyzer.Pattern_Size));
|
||||
end if;
|
||||
|
||||
declare
|
||||
Pattern : aliased Stack_Slots
|
||||
(1 .. Analyzer.Pattern_Size / Bytes_Per_Pattern);
|
||||
for Pattern'Address use Analyzer.Stack_Overlay_Address;
|
||||
|
||||
begin
|
||||
if System.Parameters.Stack_Grows_Down then
|
||||
for J in reverse Pattern'Range loop
|
||||
Pattern (J) := Analyzer.Pattern;
|
||||
end loop;
|
||||
|
||||
Analyzer.Bottom_Pattern_Mark :=
|
||||
To_Stack_Address (Pattern (Pattern'Last)'Address);
|
||||
|
||||
else
|
||||
for J in Pattern'Range loop
|
||||
Pattern (J) := Analyzer.Pattern;
|
||||
end loop;
|
||||
|
||||
Analyzer.Bottom_Pattern_Mark :=
|
||||
To_Stack_Address (Pattern (Pattern'First)'Address);
|
||||
end if;
|
||||
end;
|
||||
|
||||
else
|
||||
-- Readjust the pattern size. When we arrive in this function, there
|
||||
-- is already a given amount of stack used, that we won't analyze.
|
||||
|
||||
Stack_Used_When_Filling :=
|
||||
Stack_Size (Analyzer.Bottom_Of_Stack,
|
||||
To_Stack_Address (Current_Stack_Level'Address));
|
||||
|
||||
if Stack_Used_When_Filling > Analyzer.Pattern_Size then
|
||||
|
||||
-- In this case, the known size of the stack is too small, we've
|
||||
-- already taken more than expected, so there's no possible
|
||||
-- computation
|
||||
|
||||
if Parameters.Stack_Grows_Down then
|
||||
if Analyzer.Stack_Base - Stack_Address (Analyzer.Pattern_Size)
|
||||
> To_Stack_Address (Current_Stack_Level'Address) - Guard
|
||||
then
|
||||
-- No room for a pattern
|
||||
Analyzer.Pattern_Size := 0;
|
||||
else
|
||||
Analyzer.Pattern_Size :=
|
||||
Analyzer.Pattern_Size - Stack_Used_When_Filling;
|
||||
return;
|
||||
end if;
|
||||
|
||||
declare
|
||||
Stack : aliased Stack_Slots
|
||||
(1 .. Analyzer.Pattern_Size / Bytes_Per_Pattern);
|
||||
Analyzer.Pattern_Limit := Analyzer.Stack_Base
|
||||
- Stack_Address (Analyzer.Pattern_Size);
|
||||
|
||||
begin
|
||||
Stack := (others => Analyzer.Pattern);
|
||||
if Analyzer.Stack_Base >
|
||||
To_Stack_Address (Current_Stack_Level'Address) - Guard
|
||||
then
|
||||
-- Reduce pattern size to prevent local frame overwrite
|
||||
Analyzer.Pattern_Size :=
|
||||
Integer (To_Stack_Address (Current_Stack_Level'Address) - Guard
|
||||
- Analyzer.Pattern_Limit);
|
||||
end if;
|
||||
|
||||
Analyzer.Stack_Overlay_Address := Stack'Address;
|
||||
Analyzer.Pattern_Overlay_Address :=
|
||||
To_Address (Analyzer.Pattern_Limit);
|
||||
else
|
||||
if Analyzer.Stack_Base + Stack_Address (Analyzer.Pattern_Size)
|
||||
< To_Stack_Address (Current_Stack_Level'Address) + Guard
|
||||
then
|
||||
-- No room for a pattern
|
||||
Analyzer.Pattern_Size := 0;
|
||||
return;
|
||||
end if;
|
||||
|
||||
if Analyzer.Pattern_Size /= 0 then
|
||||
Analyzer.Bottom_Pattern_Mark :=
|
||||
To_Stack_Address
|
||||
(Stack (Bottom_Slot_Index_In (Stack))'Address);
|
||||
Analyzer.Top_Pattern_Mark :=
|
||||
To_Stack_Address
|
||||
(Stack (Top_Slot_Index_In (Stack))'Address);
|
||||
else
|
||||
Analyzer.Bottom_Pattern_Mark :=
|
||||
To_Stack_Address (Stack'Address);
|
||||
Analyzer.Top_Pattern_Mark :=
|
||||
To_Stack_Address (Stack'Address);
|
||||
end if;
|
||||
end;
|
||||
Analyzer.Pattern_Limit := Analyzer.Stack_Base
|
||||
+ Stack_Address (Analyzer.Pattern_Size);
|
||||
|
||||
if Analyzer.Stack_Base <
|
||||
To_Stack_Address (Current_Stack_Level'Address) + Guard
|
||||
then
|
||||
-- Reduce pattern size to prevent local frame overwrite
|
||||
Analyzer.Pattern_Size := Integer
|
||||
(Analyzer.Pattern_Limit
|
||||
- (To_Stack_Address (Current_Stack_Level'Address) + Guard));
|
||||
end if;
|
||||
|
||||
Analyzer.Pattern_Overlay_Address :=
|
||||
To_Address (Analyzer.Pattern_Limit
|
||||
- Stack_Address (Analyzer.Pattern_Size));
|
||||
end if;
|
||||
|
||||
-- Declare and fill the pattern buffer
|
||||
declare
|
||||
Pattern : aliased Stack_Slots
|
||||
(1 .. Analyzer.Pattern_Size / Bytes_Per_Pattern);
|
||||
for Pattern'Address use Analyzer.Pattern_Overlay_Address;
|
||||
|
||||
begin
|
||||
if System.Parameters.Stack_Grows_Down then
|
||||
for J in reverse Pattern'Range loop
|
||||
Pattern (J) := Analyzer.Pattern;
|
||||
end loop;
|
||||
else
|
||||
for J in Pattern'Range loop
|
||||
Pattern (J) := Analyzer.Pattern;
|
||||
end loop;
|
||||
end if;
|
||||
end;
|
||||
end Fill_Stack;
|
||||
|
||||
-------------------------
|
||||
|
@ -359,22 +262,20 @@ package body System.Stack_Usage is
|
|||
procedure Initialize_Analyzer
|
||||
(Analyzer : in out Stack_Analyzer;
|
||||
Task_Name : String;
|
||||
My_Stack_Size : Natural;
|
||||
Max_Pattern_Size : Natural;
|
||||
Bottom : Stack_Address;
|
||||
Top : Stack_Address;
|
||||
Pattern : Unsigned_32 := 16#DEAD_BEEF#)
|
||||
Stack_Size : Natural;
|
||||
Stack_Base : Stack_Address;
|
||||
Pattern_Size : Natural;
|
||||
Pattern : Interfaces.Unsigned_32 := 16#DEAD_BEEF#)
|
||||
is
|
||||
begin
|
||||
-- Initialize the analyzer fields
|
||||
|
||||
Analyzer.Bottom_Of_Stack := Bottom;
|
||||
Analyzer.Stack_Size := My_Stack_Size;
|
||||
Analyzer.Pattern_Size := Max_Pattern_Size;
|
||||
Analyzer.Pattern := Pattern;
|
||||
Analyzer.Result_Id := Next_Id;
|
||||
Analyzer.Task_Name := (others => ' ');
|
||||
Analyzer.Top_Pattern_Mark := Top;
|
||||
Analyzer.Stack_Base := Stack_Base;
|
||||
Analyzer.Stack_Size := Stack_Size;
|
||||
Analyzer.Pattern_Size := Pattern_Size;
|
||||
Analyzer.Pattern := Pattern;
|
||||
Analyzer.Result_Id := Next_Id;
|
||||
Analyzer.Task_Name := (others => ' ');
|
||||
|
||||
-- Compute the task name, and truncate if bigger than Task_Name_Length
|
||||
|
||||
|
@ -399,9 +300,9 @@ package body System.Stack_Usage is
|
|||
is
|
||||
begin
|
||||
if SP_Low > SP_High then
|
||||
return Natural (SP_Low - SP_High + 4);
|
||||
return Natural (SP_Low - SP_High);
|
||||
else
|
||||
return Natural (SP_High - SP_Low + 4);
|
||||
return Natural (SP_High - SP_Low);
|
||||
end if;
|
||||
end Stack_Size;
|
||||
|
||||
|
@ -417,10 +318,17 @@ package body System.Stack_Usage is
|
|||
-- likely to happen.
|
||||
|
||||
Stack : Stack_Slots (1 .. Analyzer.Pattern_Size / Bytes_Per_Pattern);
|
||||
for Stack'Address use Analyzer.Stack_Overlay_Address;
|
||||
for Stack'Address use Analyzer.Pattern_Overlay_Address;
|
||||
|
||||
begin
|
||||
Analyzer.Topmost_Touched_Mark := Analyzer.Bottom_Pattern_Mark;
|
||||
-- Value if the pattern was not modified
|
||||
if Parameters.Stack_Grows_Down then
|
||||
Analyzer.Topmost_Touched_Mark :=
|
||||
Analyzer.Pattern_Limit + Stack_Address (Analyzer.Pattern_Size);
|
||||
else
|
||||
Analyzer.Topmost_Touched_Mark :=
|
||||
Analyzer.Pattern_Limit - Stack_Address (Analyzer.Pattern_Size);
|
||||
end if;
|
||||
|
||||
if Analyzer.Pattern_Size = 0 then
|
||||
return;
|
||||
|
@ -430,40 +338,27 @@ package body System.Stack_Usage is
|
|||
-- the bottom of it. The first index not equals to the patterns marks
|
||||
-- the beginning of the used stack.
|
||||
|
||||
declare
|
||||
Top_Index : constant Integer := Top_Slot_Index_In (Stack);
|
||||
Bottom_Index : constant Integer := Bottom_Slot_Index_In (Stack);
|
||||
Step : constant Integer := Pop_Index_Step_For (Stack);
|
||||
J : Integer;
|
||||
|
||||
begin
|
||||
J := Top_Index;
|
||||
loop
|
||||
if System.Parameters.Stack_Grows_Down then
|
||||
for J in Stack'Range loop
|
||||
if Stack (J) /= Analyzer.Pattern then
|
||||
Analyzer.Topmost_Touched_Mark
|
||||
:= To_Stack_Address (Stack (J)'Address);
|
||||
exit;
|
||||
end if;
|
||||
|
||||
exit when J = Bottom_Index;
|
||||
J := J + Step;
|
||||
end loop;
|
||||
end;
|
||||
|
||||
else
|
||||
for J in reverse Stack'Range loop
|
||||
if Stack (J) /= Analyzer.Pattern then
|
||||
Analyzer.Topmost_Touched_Mark
|
||||
:= To_Stack_Address (Stack (J)'Address);
|
||||
exit;
|
||||
end if;
|
||||
end loop;
|
||||
|
||||
end if;
|
||||
end Compute_Result;
|
||||
|
||||
---------------------
|
||||
-- Get_Usage_Range --
|
||||
---------------------
|
||||
|
||||
function Get_Usage_Range (Result : Task_Result) return String is
|
||||
Variation_Used_Str : constant String :=
|
||||
Natural'Image (Result.Variation);
|
||||
Value_Used_Str : constant String :=
|
||||
Natural'Image (Result.Value);
|
||||
begin
|
||||
return Value_Used_Str & " +/- " & Variation_Used_Str;
|
||||
end Get_Usage_Range;
|
||||
|
||||
---------------------
|
||||
-- Output_Result --
|
||||
---------------------
|
||||
|
@ -474,16 +369,16 @@ package body System.Stack_Usage is
|
|||
Max_Stack_Size_Len : Natural;
|
||||
Max_Actual_Use_Len : Natural)
|
||||
is
|
||||
Result_Id_Str : constant String := Natural'Image (Result_Id);
|
||||
My_Stack_Size_Str : constant String := Natural'Image (Result.Max_Size);
|
||||
Actual_Use_Str : constant String := Get_Usage_Range (Result);
|
||||
Result_Id_Str : constant String := Natural'Image (Result_Id);
|
||||
Stack_Size_Str : constant String := Natural'Image (Result.Stack_Size);
|
||||
Actual_Use_Str : constant String := Natural'Image (Result.Value);
|
||||
|
||||
Result_Id_Blanks : constant
|
||||
String (1 .. Index_Str'Length - Result_Id_Str'Length) :=
|
||||
(others => ' ');
|
||||
|
||||
Stack_Size_Blanks : constant
|
||||
String (1 .. Max_Stack_Size_Len - My_Stack_Size_Str'Length) :=
|
||||
String (1 .. Max_Stack_Size_Len - Stack_Size_Str'Length) :=
|
||||
(others => ' ');
|
||||
|
||||
Actual_Use_Blanks : constant
|
||||
|
@ -496,7 +391,7 @@ package body System.Stack_Usage is
|
|||
Put (" | ");
|
||||
Put (Result.Task_Name);
|
||||
Put (" | ");
|
||||
Put (Stack_Size_Blanks & My_Stack_Size_Str);
|
||||
Put (Stack_Size_Blanks & Stack_Size_Str);
|
||||
Put (" | ");
|
||||
Put (Actual_Use_Blanks & Actual_Use_Str);
|
||||
New_Line;
|
||||
|
@ -508,7 +403,7 @@ package body System.Stack_Usage is
|
|||
|
||||
procedure Output_Results is
|
||||
Max_Stack_Size : Natural := 0;
|
||||
Max_Actual_Use_Result_Id : Natural := Result_Array'First;
|
||||
Max_Stack_Usage : Natural := 0;
|
||||
Max_Stack_Size_Len, Max_Actual_Use_Len : Natural := 0;
|
||||
|
||||
Task_Name_Blanks : constant
|
||||
|
@ -531,21 +426,18 @@ package body System.Stack_Usage is
|
|||
for J in Result_Array'Range loop
|
||||
exit when J >= Next_Id;
|
||||
|
||||
if Result_Array (J).Value >
|
||||
Result_Array (Max_Actual_Use_Result_Id).Value
|
||||
then
|
||||
Max_Actual_Use_Result_Id := J;
|
||||
if Result_Array (J).Value > Max_Stack_Usage then
|
||||
Max_Stack_Usage := Result_Array (J).Value;
|
||||
end if;
|
||||
|
||||
if Result_Array (J).Max_Size > Max_Stack_Size then
|
||||
Max_Stack_Size := Result_Array (J).Max_Size;
|
||||
if Result_Array (J).Stack_Size > Max_Stack_Size then
|
||||
Max_Stack_Size := Result_Array (J).Stack_Size;
|
||||
end if;
|
||||
end loop;
|
||||
|
||||
Max_Stack_Size_Len := Natural'Image (Max_Stack_Size)'Length;
|
||||
|
||||
Max_Actual_Use_Len :=
|
||||
Get_Usage_Range (Result_Array (Max_Actual_Use_Result_Id))'Length;
|
||||
Max_Actual_Use_Len := Natural'Image (Max_Stack_Usage)'Length;
|
||||
|
||||
-- Display the output header. Blanks will be added in front of the
|
||||
-- labels if needed.
|
||||
|
@ -599,37 +491,22 @@ package body System.Stack_Usage is
|
|||
-------------------
|
||||
|
||||
procedure Report_Result (Analyzer : Stack_Analyzer) is
|
||||
Result : Task_Result :=
|
||||
(Task_Name => Analyzer.Task_Name,
|
||||
Max_Size => Analyzer.Stack_Size,
|
||||
Variation => 0,
|
||||
Value => 0);
|
||||
|
||||
Overflow_Guard : constant Integer :=
|
||||
Analyzer.Stack_Size
|
||||
- Stack_Size (Analyzer.Top_Pattern_Mark, Analyzer.Bottom_Of_Stack);
|
||||
Max, Min : Positive;
|
||||
|
||||
Result : Task_Result := (Task_Name => Analyzer.Task_Name,
|
||||
Stack_Size => Analyzer.Stack_Size,
|
||||
Value => 0);
|
||||
begin
|
||||
if Analyzer.Pattern_Size = 0 then
|
||||
|
||||
-- If we have that result, it means that we didn't do any computation
|
||||
-- at all. In other words, we used at least everything (and possibly
|
||||
-- more).
|
||||
|
||||
Min := Analyzer.Stack_Size - Overflow_Guard;
|
||||
Max := Analyzer.Stack_Size;
|
||||
Result.Value := Analyzer.Stack_Size;
|
||||
|
||||
else
|
||||
Min :=
|
||||
Stack_Size
|
||||
(Analyzer.Topmost_Touched_Mark, Analyzer.Bottom_Of_Stack);
|
||||
Max := Min + Overflow_Guard;
|
||||
Result.Value := Stack_Size (Analyzer.Topmost_Touched_Mark,
|
||||
Analyzer.Stack_Base);
|
||||
end if;
|
||||
|
||||
Result.Value := (Max + Min) / 2;
|
||||
Result.Variation := (Max - Min) / 2;
|
||||
|
||||
if Analyzer.Result_Id in Result_Array'Range then
|
||||
|
||||
-- If the result can be stored, then store it in Result_Array
|
||||
|
@ -641,7 +518,7 @@ package body System.Stack_Usage is
|
|||
|
||||
declare
|
||||
Result_Str_Len : constant Natural :=
|
||||
Get_Usage_Range (Result)'Length;
|
||||
Natural'Image (Result.Value)'Length;
|
||||
Size_Str_Len : constant Natural :=
|
||||
Natural'Image (Analyzer.Stack_Size)'Length;
|
||||
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
-- --
|
||||
-- S p e c --
|
||||
-- --
|
||||
-- Copyright (C) 2004-2010, Free Software Foundation, Inc. --
|
||||
-- Copyright (C) 2004-2011, Free Software Foundation, Inc. --
|
||||
-- --
|
||||
-- GNARL is free software; you can redistribute it and/or modify it under --
|
||||
-- terms of the GNU General Public License as published by the Free Soft- --
|
||||
|
@ -57,11 +57,8 @@ package System.Stack_Usage is
|
|||
-- Amount of stack used. The value is calculated on the basis of the
|
||||
-- mechanism used by GNAT to allocate it, and it is NOT a precise value.
|
||||
|
||||
Variation : Natural;
|
||||
-- Possible variation in the amount of used stack. The real stack usage
|
||||
-- may vary in the range Value +/- Variation
|
||||
|
||||
Max_Size : Natural;
|
||||
Stack_Size : Natural;
|
||||
-- Size of the stack
|
||||
end record;
|
||||
|
||||
type Result_Array_Type is array (Positive range <>) of Task_Result;
|
||||
|
@ -91,8 +88,9 @@ package System.Stack_Usage is
|
|||
-- begin
|
||||
-- Initialize_Analyzer (A,
|
||||
-- "Task t",
|
||||
-- A_Storage_Size,
|
||||
-- 0,
|
||||
-- A_Storage_Size - A_Guard,
|
||||
-- A_Guard
|
||||
-- To_Stack_Address (Bottom_Of_Stack'Address));
|
||||
-- Fill_Stack (A);
|
||||
-- Some_User_Code;
|
||||
|
@ -115,7 +113,9 @@ package System.Stack_Usage is
|
|||
-- before the call to the instrumentation procedure.
|
||||
|
||||
-- Strategy: The user of this package should measure the bottom of stack
|
||||
-- before the call to Fill_Stack and pass it in parameter.
|
||||
-- before the call to Fill_Stack and pass it in parameter. The impact
|
||||
-- is very minor unless the stack used is very small, but in this case
|
||||
-- you aren't very interested by the figure.
|
||||
|
||||
-- Instrumentation threshold at writing:
|
||||
|
||||
|
@ -212,32 +212,29 @@ package System.Stack_Usage is
|
|||
-- the memory will look like that:
|
||||
--
|
||||
-- Stack growing
|
||||
-- ----------------------------------------------------------------------->
|
||||
-- |<---------------------->|<----------------------------------->|
|
||||
-- | Stack frame | Memory filled with Analyzer.Pattern |
|
||||
-- | of Fill_Stack | |
|
||||
-- | (deallocated at | |
|
||||
-- | the end of the call) | |
|
||||
-- ^ | ^
|
||||
-- Analyzer.Bottom_Of_Stack | Analyzer.Top_Pattern_Mark
|
||||
-- ^
|
||||
-- Analyzer.Bottom_Pattern_Mark
|
||||
-- ---------------------------------------------------------------------->
|
||||
-- |<--------------------->|<----------------------------------->|
|
||||
-- | Stack frames to | Memory filled with Analyzer.Pattern |
|
||||
-- | Fill_Stack | |
|
||||
-- ^ | ^
|
||||
-- Analyzer.Stack_Base | Analyzer.Pattern_Limit
|
||||
-- ^
|
||||
-- Analyzer.Pattern_Limit +/- Analyzer.Pattern_Size
|
||||
--
|
||||
|
||||
procedure Initialize_Analyzer
|
||||
(Analyzer : in out Stack_Analyzer;
|
||||
Task_Name : String;
|
||||
My_Stack_Size : Natural;
|
||||
Max_Pattern_Size : Natural;
|
||||
Bottom : Stack_Address;
|
||||
Top : Stack_Address;
|
||||
Stack_Size : Natural;
|
||||
Stack_Base : Stack_Address;
|
||||
Pattern_Size : Natural;
|
||||
Pattern : Interfaces.Unsigned_32 := 16#DEAD_BEEF#);
|
||||
-- Should be called before any use of a Stack_Analyzer, to initialize it.
|
||||
-- Max_Pattern_Size is the size of the pattern zone, might be smaller than
|
||||
-- the full stack size in order to take into account e.g. the secondary
|
||||
-- stack and a guard against overflow. The actual size taken will be
|
||||
-- readjusted with data already used at the time the stack is actually
|
||||
-- filled.
|
||||
-- the full stack size Stack_Size in order to take into account e.g. the
|
||||
-- secondary stack and a guard against overflow. The actual size taken
|
||||
-- will be readjusted with data already used at the time the stack is
|
||||
-- actually filled.
|
||||
|
||||
Is_Enabled : Boolean := False;
|
||||
-- When this flag is true, then stack analysis is enabled
|
||||
|
@ -253,16 +250,14 @@ package System.Stack_Usage is
|
|||
-- Stack growing
|
||||
-- ----------------------------------------------------------------------->
|
||||
-- |<---------------------->|<-------------->|<--------->|<--------->|
|
||||
-- | Stack frame | Array of | used | Memory |
|
||||
-- | of Compute_Result | Analyzer.Probe | during | filled |
|
||||
-- | (deallocated at | elements | the | with |
|
||||
-- | the end of the call) | | execution | pattern |
|
||||
-- | ^ | | |
|
||||
-- | Bottom_Pattern_Mark | | |
|
||||
-- | Stack frames | Array of | used | Memory |
|
||||
-- | to Compute_Result | Analyzer.Probe | during | filled |
|
||||
-- | | elements | the | with |
|
||||
-- | | | execution | pattern |
|
||||
-- | | |
|
||||
-- |<----------------------------------------------------> |
|
||||
-- Stack used ^
|
||||
-- Top_Pattern_Mark
|
||||
-- Pattern_Limit
|
||||
|
||||
procedure Report_Result (Analyzer : Stack_Analyzer);
|
||||
-- Store the results of the computation in memory, at the address
|
||||
|
@ -288,6 +283,10 @@ private
|
|||
Task_Name : String (1 .. Task_Name_Length);
|
||||
-- Name of the task
|
||||
|
||||
Stack_Base : Stack_Address;
|
||||
-- Address of the base of the stack, as given by the caller of
|
||||
-- Initialize_Analyzer.
|
||||
|
||||
Stack_Size : Natural;
|
||||
-- Entire size of the analyzed stack
|
||||
|
||||
|
@ -297,11 +296,8 @@ private
|
|||
Pattern : Pattern_Type;
|
||||
-- Pattern used to recognize untouched memory
|
||||
|
||||
Bottom_Pattern_Mark : Stack_Address;
|
||||
-- Bound of the pattern area on the stack closest to the bottom
|
||||
|
||||
Top_Pattern_Mark : Stack_Address;
|
||||
-- Topmost bound of the pattern area on the stack
|
||||
Pattern_Limit : Stack_Address;
|
||||
-- Bound of the pattern area farthest to the base
|
||||
|
||||
Topmost_Touched_Mark : Stack_Address;
|
||||
-- Topmost address of the pattern area whose value it is pointing
|
||||
|
@ -309,11 +305,7 @@ private
|
|||
-- compensated, it is the topmost value of the stack pointer during
|
||||
-- the execution.
|
||||
|
||||
Bottom_Of_Stack : Stack_Address;
|
||||
-- Address of the bottom of the stack, as given by the caller of
|
||||
-- Initialize_Analyzer.
|
||||
|
||||
Stack_Overlay_Address : System.Address;
|
||||
Pattern_Overlay_Address : System.Address;
|
||||
-- Address of the stack abstraction object we overlay over a
|
||||
-- task's real stack, typically a pattern-initialized array.
|
||||
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
-- --
|
||||
-- B o d y --
|
||||
-- --
|
||||
-- Copyright (C) 2009-2010, Free Software Foundation, Inc. --
|
||||
-- Copyright (C) 2009-2011, Free Software Foundation, Inc. --
|
||||
-- --
|
||||
-- GNAT is free software; you can redistribute it and/or modify it under --
|
||||
-- terms of the GNU General Public License as published by the Free Soft- --
|
||||
|
@ -250,9 +250,8 @@ package body System.Stack_Usage.Tasking is
|
|||
Obj.Task_Name (Obj.Task_Name'First .. Pos);
|
||||
begin
|
||||
Put_Line
|
||||
("| " & T_Name & " | " & Natural'Image (Obj.Max_Size) &
|
||||
Natural'Image (Obj.Value) & " +/- " &
|
||||
Natural'Image (Obj.Variation));
|
||||
("| " & T_Name & " | " & Natural'Image (Obj.Stack_Size) &
|
||||
Natural'Image (Obj.Value));
|
||||
end;
|
||||
end Print;
|
||||
|
||||
|
|
|
@ -1027,32 +1027,11 @@ package body System.Tasking.Stages is
|
|||
|
||||
Secondary_Stack : aliased SSE.Storage_Array (1 .. Secondary_Stack_Size);
|
||||
|
||||
pragma Warnings (Off);
|
||||
-- Why are warnings being turned off here???
|
||||
|
||||
Secondary_Stack_Address : System.Address := Secondary_Stack'Address;
|
||||
-- Address of secondary stack. In the fixed secondary stack case, this
|
||||
-- value is not modified, causing a warning, hence the bracketing with
|
||||
-- Warnings (Off/On). But why is so much *more* bracketed???
|
||||
|
||||
Small_Overflow_Guard : constant := 12 * 1024;
|
||||
-- Note: this used to be 4K, but was changed to 12K, since smaller
|
||||
-- values resulted in segmentation faults from dynamic stack analysis.
|
||||
|
||||
Big_Overflow_Guard : constant := 16 * 1024;
|
||||
Small_Stack_Limit : constant := 64 * 1024;
|
||||
-- ??? These three values are experimental, and seems to work on most
|
||||
-- platforms. They still need to be analyzed further. They also need
|
||||
-- documentation, what are they???
|
||||
|
||||
Size : Natural :=
|
||||
Natural (Self_ID.Common.Compiler_Data.Pri_Stack_Info.Size);
|
||||
|
||||
Overflow_Guard : Natural;
|
||||
-- Size of the overflow guard, used by dynamic stack usage analysis
|
||||
|
||||
pragma Warnings (On);
|
||||
|
||||
SEH_Table : aliased SSE.Storage_Array (1 .. 8);
|
||||
-- Structured Exception Registration table (2 words)
|
||||
|
||||
|
@ -1116,7 +1095,6 @@ package body System.Tasking.Stages is
|
|||
Self_ID.Common.Compiler_Data.Sec_Stack_Addr :=
|
||||
Secondary_Stack'Address;
|
||||
SST.SS_Init (Secondary_Stack_Address, Integer (Secondary_Stack'Last));
|
||||
Size := Size - Natural (Secondary_Stack_Size);
|
||||
end if;
|
||||
|
||||
if Use_Alternate_Stack then
|
||||
|
@ -1136,24 +1114,64 @@ package body System.Tasking.Stages is
|
|||
-- Initialize dynamic stack usage
|
||||
|
||||
if System.Stack_Usage.Is_Enabled then
|
||||
Overflow_Guard :=
|
||||
(if Size < Small_Stack_Limit
|
||||
then Small_Overflow_Guard
|
||||
else Big_Overflow_Guard);
|
||||
declare
|
||||
Guard_Page_Size : constant := 12 * 1024;
|
||||
-- Part of the stack used as a guard page. This is an OS dependent
|
||||
-- value, so we need to use the maximum. This value is only used
|
||||
-- when the stack address is known, that is currently Windows.
|
||||
|
||||
STPO.Lock_RTS;
|
||||
Initialize_Analyzer
|
||||
(Self_ID.Common.Analyzer,
|
||||
Self_ID.Common.Task_Image
|
||||
(1 .. Self_ID.Common.Task_Image_Len),
|
||||
Natural
|
||||
(Self_ID.Common.Compiler_Data.Pri_Stack_Info.Size),
|
||||
Size - Overflow_Guard,
|
||||
SSE.To_Integer (Bottom_Of_Stack'Address),
|
||||
SSE.To_Integer
|
||||
(Self_ID.Common.Compiler_Data.Pri_Stack_Info.Limit));
|
||||
STPO.Unlock_RTS;
|
||||
Fill_Stack (Self_ID.Common.Analyzer);
|
||||
Small_Overflow_Guard : constant := 12 * 1024;
|
||||
-- Note: this used to be 4K, but was changed to 12K, since
|
||||
-- smaller values resulted in segmentation faults from dynamic
|
||||
-- stack analysis.
|
||||
|
||||
Big_Overflow_Guard : constant := 16 * 1024;
|
||||
Small_Stack_Limit : constant := 64 * 1024;
|
||||
-- ??? These three values are experimental, and seems to work on
|
||||
-- most platforms. They still need to be analyzed further. They
|
||||
-- also need documentation, what are they???
|
||||
|
||||
Pattern_Size : Natural :=
|
||||
Natural (Self_ID.Common.Compiler_Data.Pri_Stack_Info.Size);
|
||||
-- Size of the pattern
|
||||
|
||||
Stack_Base : Address;
|
||||
-- Address of the base of the stack
|
||||
begin
|
||||
Stack_Base := Self_ID.Common.Compiler_Data.Pri_Stack_Info.Base;
|
||||
if Stack_Base = Null_Address then
|
||||
-- On many platforms, we don't know the real stack base
|
||||
-- address. Estimate it using an address in the frame.
|
||||
Stack_Base := Bottom_Of_Stack'Address;
|
||||
|
||||
-- Also reduce the size of the stack to take into account the
|
||||
-- secondary stack array declared in this frame. This is for
|
||||
-- sure very conservative.
|
||||
if not Parameters.Sec_Stack_Dynamic then
|
||||
Pattern_Size :=
|
||||
Pattern_Size - Natural (Secondary_Stack_Size);
|
||||
end if;
|
||||
|
||||
-- Adjustments for inner frames
|
||||
Pattern_Size := Pattern_Size -
|
||||
(if Pattern_Size < Small_Stack_Limit
|
||||
then Small_Overflow_Guard
|
||||
else Big_Overflow_Guard);
|
||||
else
|
||||
-- Reduce by the size of the final guard page
|
||||
Pattern_Size := Pattern_Size - Guard_Page_Size;
|
||||
end if;
|
||||
|
||||
STPO.Lock_RTS;
|
||||
Initialize_Analyzer
|
||||
(Self_ID.Common.Analyzer,
|
||||
Self_ID.Common.Task_Image (1 .. Self_ID.Common.Task_Image_Len),
|
||||
Natural (Self_ID.Common.Compiler_Data.Pri_Stack_Info.Size),
|
||||
SSE.To_Integer (Stack_Base),
|
||||
Pattern_Size);
|
||||
STPO.Unlock_RTS;
|
||||
Fill_Stack (Self_ID.Common.Analyzer);
|
||||
end;
|
||||
end if;
|
||||
|
||||
-- We setup the SEH (Structured Exception Handling) handler if supported
|
||||
|
|
|
@ -240,14 +240,6 @@ package Sem is
|
|||
-- then Full_Analysis above must be False. You should really regard this as
|
||||
-- a read only flag.
|
||||
|
||||
In_Pre_Post_Expression : Boolean := False;
|
||||
-- Switch to indicate that we are in a precondition or postcondition. The
|
||||
-- analysis is not expected to process a precondition or a postcondition as
|
||||
-- a sub-analysis for another precondition or postcondition, so this switch
|
||||
-- needs not be saved for recursive calls. When this switch is True then
|
||||
-- In_Spec_Expression above must be True also. You should really regard
|
||||
-- this as a read only flag.
|
||||
|
||||
In_Deleted_Code : Boolean := False;
|
||||
-- If the condition in an if-statement is statically known, the branch
|
||||
-- that is not taken is analyzed with expansion disabled, and the tree
|
||||
|
|
|
@ -258,11 +258,8 @@ package body Sem_Prag is
|
|||
-- Preanalyze the boolean expression, we treat this as a spec expression
|
||||
-- (i.e. similar to a default expression).
|
||||
|
||||
pragma Assert (In_Pre_Post_Expression = False);
|
||||
In_Pre_Post_Expression := True;
|
||||
Preanalyze_Spec_Expression
|
||||
(Get_Pragma_Arg (Arg1), Standard_Boolean);
|
||||
In_Pre_Post_Expression := False;
|
||||
|
||||
-- Remove the subprogram from the scope stack now that the pre-analysis
|
||||
-- of the precondition/postcondition is done.
|
||||
|
|
Loading…
Reference in New Issue