1 ------------------------------------------------------------------------------
3 -- GNAT COMPILER COMPONENTS --
9 -- Copyright (C) 2000-2023, Free Software Foundation, Inc. --
11 -- GNAT is free software; you can redistribute it and/or modify it under --
12 -- terms of the GNU General Public License as published by the Free Soft- --
13 -- ware Foundation; either version 3, or (at your option) any later ver- --
14 -- sion. GNAT is distributed in the hope that it will be useful, but WITH- --
15 -- OUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY --
16 -- or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License --
17 -- for more details. You should have received a copy of the GNU General --
18 -- Public License distributed with GNAT; see file COPYING3. If not, go to --
19 -- http://www.gnu.org/licenses for a complete copy of the license. --
21 -- GNAT was originally developed by the GNAT team at New York University. --
22 -- Extensive contributions were provided by Ada Core Technologies Inc. --
24 ------------------------------------------------------------------------------
26 with Atree
; use Atree
;
27 with Einfo
; use Einfo
;
28 with Einfo
.Entities
; use Einfo
.Entities
;
29 with Einfo
.Utils
; use Einfo
.Utils
;
31 with Nlists
; use Nlists
;
32 with Sem_Aux
; use Sem_Aux
;
33 with Sem_Util
; use Sem_Util
;
34 with Sinfo
; use Sinfo
;
35 with Sinfo
.Nodes
; use Sinfo
.Nodes
;
36 with Sinfo
.Utils
; use Sinfo
.Utils
;
37 with Types
; use Types
;
43 -- The Name_Set type is used to store the temporary mark bits used by the
44 -- garbage collection of entities. Using a separate array prevents using up
45 -- any valuable per-node space and possibly results in better locality and
48 type Name_Set
is array (Node_Id
'Base range <>) of Boolean;
49 -- We use 'Base here, in case we want to add a predicate to Node_Id
50 pragma Pack
(Name_Set
);
52 function Marked
(Marks
: Name_Set
; Name
: Node_Id
) return Boolean;
53 pragma Inline
(Marked
);
56 (Marks
: in out Name_Set
;
58 Mark
: Boolean := True);
59 pragma Inline
(Set_Marked
);
63 -- The problem of finding live entities is solved in two steps:
65 procedure Mark
(Root
: Node_Id
; Marks
: out Name_Set
);
66 -- Mark all live entities in Root as Marked
68 procedure Sweep
(Root
: Node_Id
; Marks
: Name_Set
);
69 -- For all unmarked entities in Root set Is_Eliminated to true
71 -- The Mark phase is split into two phases:
73 procedure Init_Marked
(Root
: Node_Id
; Marks
: out Name_Set
);
74 -- For all subprograms, reset Is_Public flag if a pragma Eliminate applies
75 -- to the entity, and set the Marked flag to Is_Public.
77 procedure Trace_Marked
(Root
: Node_Id
; Marks
: in out Name_Set
);
78 -- Traverse the tree skipping any unmarked subprogram bodies. All visited
79 -- entities are marked, as well as entities denoted by a visited identifier
80 -- or operator. When an entity is first marked it is traced as well.
84 function Body_Of
(E
: Entity_Id
) return Node_Id
;
85 -- Returns subprogram body corresponding to entity E
87 function Spec_Of
(N
: Node_Id
) return Entity_Id
;
88 -- Given a subprogram body N, return defining identifier of its declaration
94 function Body_Of
(E
: Entity_Id
) return Node_Id
is
95 Decl
: constant Node_Id
:= Unit_Declaration_Node
(E
);
96 Kind
: constant Node_Kind
:= Nkind
(Decl
);
100 if Kind
= N_Subprogram_Body
then
103 elsif Kind
/= N_Subprogram_Declaration
104 and Kind
/= N_Subprogram_Body_Stub
109 Result
:= Corresponding_Body
(Decl
);
111 if Result
/= Empty
then
112 Result
:= Unit_Declaration_Node
(Result
);
119 ------------------------------
120 -- Collect_Garbage_Entities --
121 ------------------------------
123 procedure Collect_Garbage_Entities
is
124 Root
: constant Node_Id
:= Cunit
(Main_Unit
);
125 Marks
: Name_Set
(0 .. Last_Node_Id
);
130 end Collect_Garbage_Entities
;
136 procedure Init_Marked
(Root
: Node_Id
; Marks
: out Name_Set
) is
138 function Process
(N
: Node_Id
) return Traverse_Result
;
139 procedure Traverse
is new Traverse_Proc
(Process
);
145 function Process
(N
: Node_Id
) return Traverse_Result
is
148 when N_Entity
'Range =>
149 if Is_Eliminated
(N
) then
150 Set_Is_Public
(N
, False);
153 Set_Marked
(Marks
, N
, Is_Public
(N
));
155 when N_Subprogram_Body
=>
156 Traverse
(Spec_Of
(N
));
158 when N_Package_Body_Stub
=>
159 if Present
(Library_Unit
(N
)) then
160 Traverse
(Proper_Body
(Unit
(Library_Unit
(N
))));
163 when N_Package_Body
=>
165 Elmt
: Node_Id
:= First
(Declarations
(N
));
167 while Present
(Elmt
) loop
180 -- Start of processing for Init_Marked
183 Marks
:= (others => False);
191 procedure Mark
(Root
: Node_Id
; Marks
: out Name_Set
) is
193 Init_Marked
(Root
, Marks
);
194 Trace_Marked
(Root
, Marks
);
201 function Marked
(Marks
: Name_Set
; Name
: Node_Id
) return Boolean is
211 (Marks
: in out Name_Set
;
213 Mark
: Boolean := True)
216 Marks
(Name
) := Mark
;
223 function Spec_Of
(N
: Node_Id
) return Entity_Id
is
225 if Acts_As_Spec
(N
) then
226 return Defining_Entity
(N
);
228 return Corresponding_Spec
(N
);
236 procedure Sweep
(Root
: Node_Id
; Marks
: Name_Set
) is
238 function Process
(N
: Node_Id
) return Traverse_Result
;
239 procedure Traverse
is new Traverse_Proc
(Process
);
245 function Process
(N
: Node_Id
) return Traverse_Result
is
248 when N_Entity
'Range =>
249 Set_Is_Eliminated
(N
, not Marked
(Marks
, N
));
251 when N_Subprogram_Body
=>
252 Traverse
(Spec_Of
(N
));
254 when N_Package_Body_Stub
=>
255 if Present
(Library_Unit
(N
)) then
256 Traverse
(Proper_Body
(Unit
(Library_Unit
(N
))));
259 when N_Package_Body
=>
261 Elmt
: Node_Id
:= First
(Declarations
(N
));
263 while Present
(Elmt
) loop
276 -- Start of processing for Sweep
286 procedure Trace_Marked
(Root
: Node_Id
; Marks
: in out Name_Set
) is
288 function Process
(N
: Node_Id
) return Traverse_Result
;
289 procedure Process
(N
: Node_Id
);
290 procedure Traverse
is new Traverse_Proc
(Process
);
296 procedure Process
(N
: Node_Id
) is
297 Result
: Traverse_Result
;
298 pragma Warnings
(Off
, Result
);
301 Result
:= Process
(N
);
304 function Process
(N
: Node_Id
) return Traverse_Result
is
305 Result
: Traverse_Result
:= OK
;
311 when N_Generic_Declaration
'Range
313 | N_Subprogram_Body_Stub
314 | N_Subprogram_Declaration
318 when N_Subprogram_Body
=>
319 if not Marked
(Marks
, Spec_Of
(N
)) then
323 when N_Package_Body_Stub
=>
324 if Present
(Library_Unit
(N
)) then
325 Traverse
(Proper_Body
(Unit
(Library_Unit
(N
))));
334 if E
/= Empty
and then not Marked
(Marks
, E
) then
337 if Is_Subprogram
(E
) then
346 when N_Entity
'Range =>
347 if Ekind
(N
) = E_Component
and then not Marked
(Marks
, N
) then
348 if Present
(Discriminant_Checking_Func
(N
)) then
349 Process
(Discriminant_Checking_Func
(N
));
353 Set_Marked
(Marks
, N
);
362 -- Start of processing for Trace_Marked