1 ------------------------------------------------------------------------------
3 -- GNAT COMPILER COMPONENTS --
10 -- Copyright (C) 2000-2001 Free Software Foundation, Inc. --
12 -- GNAT is free software; you can redistribute it and/or modify it under --
13 -- terms of the GNU General Public License as published by the Free Soft- --
14 -- ware Foundation; either version 2, or (at your option) any later ver- --
15 -- sion. GNAT is distributed in the hope that it will be useful, but WITH- --
16 -- OUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY --
17 -- or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License --
18 -- for more details. You should have received a copy of the GNU General --
19 -- Public License distributed with GNAT; see file COPYING. If not, write --
20 -- to the Free Software Foundation, 59 Temple Place - Suite 330, Boston, --
21 -- MA 02111-1307, USA. --
23 -- GNAT was originally developed by the GNAT team at New York University. --
24 -- It is now maintained by Ada Core Technologies Inc (http://www.gnat.com). --
26 ------------------------------------------------------------------------------
28 with Atree
; use Atree
;
29 with Einfo
; use Einfo
;
31 with Nlists
; use Nlists
;
32 with Sem_Util
; use Sem_Util
;
33 with Sinfo
; use Sinfo
;
34 with Types
; use Types
;
40 -- The Name_Set type is used to store the temporary mark bits
41 -- used by the garbage collection of entities. Using a separate
42 -- array prevents using up any valuable per-node space and possibly
43 -- results in better locality and cache usage.
45 type Name_Set
is array (Node_Id
range <>) of Boolean;
46 pragma Pack
(Name_Set
);
48 function Marked
(Marks
: Name_Set
; Name
: Node_Id
) return Boolean;
49 pragma Inline
(Marked
);
52 (Marks
: in out Name_Set
;
54 Mark
: Boolean := True);
55 pragma Inline
(Set_Marked
);
59 -- The problem of finding live entities is solved in two steps:
61 procedure Mark
(Root
: Node_Id
; Marks
: out Name_Set
);
62 -- Mark all live entities in Root as Marked.
64 procedure Sweep
(Root
: Node_Id
; Marks
: Name_Set
);
65 -- For all unmarked entities in Root set Is_Eliminated to true
67 -- The Mark phase is split into two phases:
69 procedure Init_Marked
(Root
: Node_Id
; Marks
: out Name_Set
);
70 -- For all subprograms, reset Is_Public flag if a pragma Eliminate
71 -- applies to the entity, and set the Marked flag to Is_Public
73 procedure Trace_Marked
(Root
: Node_Id
; Marks
: in out Name_Set
);
74 -- Traverse the tree skipping any unmarked subprogram bodies.
75 -- All visited entities are marked, as well as entities denoted
76 -- by a visited identifier or operator. When an entity is first
77 -- marked it is traced as well.
81 function Body_Of
(E
: Entity_Id
) return Node_Id
;
82 -- Returns subprogram body corresponding to entity E
84 function Spec_Of
(N
: Node_Id
) return Entity_Id
;
85 -- Given a subprogram body N, return defining identifier of its declaration
87 -- ??? the body of this package contains no comments at all, this
94 function Body_Of
(E
: Entity_Id
) return Node_Id
is
95 Decl
: Node_Id
:= Unit_Declaration_Node
(E
);
97 Kind
: 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
);
141 function Process
(N
: Node_Id
) return Traverse_Result
is
144 when N_Entity
'Range =>
145 if Is_Eliminated
(N
) then
146 Set_Is_Public
(N
, False);
149 Set_Marked
(Marks
, N
, Is_Public
(N
));
151 when N_Subprogram_Body
=>
152 Traverse
(Spec_Of
(N
));
154 when N_Package_Body_Stub
=>
155 if Present
(Library_Unit
(N
)) then
156 Traverse
(Proper_Body
(Unit
(Library_Unit
(N
))));
159 when N_Package_Body
=>
161 Elmt
: Node_Id
:= First
(Declarations
(N
));
163 while Present
(Elmt
) loop
176 -- Start of processing for Init_Marked
179 Marks
:= (others => False);
187 procedure Mark
(Root
: Node_Id
; Marks
: out Name_Set
) is
189 Init_Marked
(Root
, Marks
);
190 Trace_Marked
(Root
, Marks
);
197 function Marked
(Marks
: Name_Set
; Name
: Node_Id
) return Boolean is
207 (Marks
: in out Name_Set
;
209 Mark
: Boolean := True)
212 Marks
(Name
) := Mark
;
219 function Spec_Of
(N
: Node_Id
) return Entity_Id
is
221 if Acts_As_Spec
(N
) then
222 return Defining_Entity
(N
);
224 return Corresponding_Spec
(N
);
232 procedure Sweep
(Root
: Node_Id
; Marks
: Name_Set
) is
234 function Process
(N
: Node_Id
) return Traverse_Result
;
235 procedure Traverse
is new Traverse_Proc
(Process
);
237 function Process
(N
: Node_Id
) return Traverse_Result
is
240 when N_Entity
'Range =>
241 Set_Is_Eliminated
(N
, not Marked
(Marks
, N
));
243 when N_Subprogram_Body
=>
244 Traverse
(Spec_Of
(N
));
246 when N_Package_Body_Stub
=>
247 if Present
(Library_Unit
(N
)) then
248 Traverse
(Proper_Body
(Unit
(Library_Unit
(N
))));
251 when N_Package_Body
=>
253 Elmt
: Node_Id
:= First
(Declarations
(N
));
255 while Present
(Elmt
) loop
275 procedure Trace_Marked
(Root
: Node_Id
; Marks
: in out Name_Set
) is
277 function Process
(N
: Node_Id
) return Traverse_Result
;
278 procedure Process
(N
: Node_Id
);
279 procedure Traverse
is new Traverse_Proc
(Process
);
281 procedure Process
(N
: Node_Id
) is
282 Result
: Traverse_Result
;
284 Result
:= Process
(N
);
287 function Process
(N
: Node_Id
) return Traverse_Result
is
288 Result
: Traverse_Result
:= OK
;
294 when N_Pragma | N_Generic_Declaration
'Range |
295 N_Subprogram_Declaration | N_Subprogram_Body_Stub
=>
298 when N_Subprogram_Body
=>
299 if not Marked
(Marks
, Spec_Of
(N
)) then
303 when N_Package_Body_Stub
=>
304 if Present
(Library_Unit
(N
)) then
305 Traverse
(Proper_Body
(Unit
(Library_Unit
(N
))));
308 when N_Identifier | N_Operator_Symbol | N_Expanded_Name
=>
311 if E
/= Empty
and then not Marked
(Marks
, E
) then
314 if Is_Subprogram
(E
) then
323 when N_Entity
'Range =>
324 if (Ekind
(N
) = E_Component
) and then not Marked
(Marks
, N
) then
325 if Present
(Discriminant_Checking_Func
(N
)) then
326 Process
(Discriminant_Checking_Func
(N
));
330 Set_Marked
(Marks
, N
);
339 -- Start of processing for Trace_Marked