1 ------------------------------------------------------------------------------
3 -- GNAT COMPILER COMPONENTS --
9 -- Copyright (C) 2010-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
;
30 with Elists
; use Elists
;
31 with Exp_Dbug
; use Exp_Dbug
;
32 with Exp_Tss
; use Exp_Tss
;
34 with Namet
; use Namet
;
36 with Output
; use Output
;
37 with Sem_Aux
; use Sem_Aux
;
38 with Sem_Disp
; use Sem_Disp
;
39 with Sem_Type
; use Sem_Type
;
40 with Sem_Util
; use Sem_Util
;
41 with Sinfo
; use Sinfo
;
42 with Sinfo
.Nodes
; use Sinfo
.Nodes
;
43 with Sinfo
.Utils
; use Sinfo
.Utils
;
44 with Sinput
; use Sinput
;
45 with Snames
; use Snames
;
46 with System
; use System
;
48 with Uintp
; use Uintp
;
50 package body Exp_CG
is
52 -- We duplicate here some declarations from packages Interfaces.C and
53 -- Interfaces.C_Streams because adding their dependence to the frontend
54 -- causes bootstrapping problems with old versions of the compiler.
56 subtype FILEs
is System
.Address
;
57 -- Corresponds to the C type FILE*
59 subtype C_chars
is System
.Address
;
60 -- Pointer to null-terminated array of characters
62 function fputs
(Strng
: C_chars
; Stream
: FILEs
) return Integer;
63 pragma Import
(C
, fputs
, "fputs");
65 -- Import the file stream associated with the "ci" output file. Done to
66 -- generate the output in the file created and left opened by routine
67 -- toplev.c before calling gnat1drv.
69 Callgraph_Info_File
: FILEs
;
70 pragma Import
(C
, Callgraph_Info_File
);
72 package Call_Graph_Nodes
is new Table
.Table
(
73 Table_Component_Type
=> Node_Id
,
74 Table_Index_Type
=> Natural,
77 Table_Increment
=> 100,
78 Table_Name
=> "Call_Graph_Nodes");
79 -- This table records nodes associated with dispatching calls and tagged
80 -- type declarations found in the main compilation unit. Used as an
81 -- auxiliary storage because the call-graph output requires fully qualified
82 -- names and they are not available until the backend is called.
84 function Is_Predefined_Dispatching_Operation
(E
: Entity_Id
) return Boolean;
85 -- Determines if E is a predefined primitive operation.
86 -- Note: This routine should replace the routine with the same name that is
87 -- currently available in exp_disp because it extends its functionality to
88 -- handle fully qualified names. It's actually in Sem_Util. ???
90 function Slot_Number
(Prim
: Entity_Id
) return Uint
;
91 -- Returns the slot number associated with Prim. For predefined primitives
92 -- the slot is returned as a negative number.
94 procedure Write_Output
(Str
: String);
95 -- Used to print a line in the output file (this is used as the
96 -- argument for a call to Set_Special_Output in package Output).
98 procedure Write_Call_Info
(Call
: Node_Id
);
99 -- Subsidiary of Generate_CG_Output that generates the output associated
100 -- with a dispatching call.
102 procedure Write_Type_Info
(Typ
: Entity_Id
);
103 -- Subsidiary of Generate_CG_Output that generates the output associated
104 -- with a tagged type declaration.
106 ------------------------
107 -- Generate_CG_Output --
108 ------------------------
110 procedure Generate_CG_Output
is
114 -- No output if the "ci" output file has not been previously opened
117 if Callgraph_Info_File
= Null_Address
then
121 -- Setup write routine, create the output file and generate the output
123 Set_Special_Output
(Write_Output
'Access);
125 for J
in Call_Graph_Nodes
.First
.. Call_Graph_Nodes
.Last
loop
126 N
:= Call_Graph_Nodes
.Table
(J
);
128 -- No action needed for subprogram calls removed by the expander
129 -- (for example, calls to ignored ghost entities).
131 if Nkind
(N
) = N_Null_Statement
then
132 pragma Assert
(Nkind
(Original_Node
(N
)) in N_Subprogram_Call
);
135 elsif Nkind
(N
) in N_Subprogram_Call
then
138 else pragma Assert
(Nkind
(N
) = N_Defining_Identifier
);
140 -- The type may be a private untagged type whose completion is
141 -- tagged, in which case we must use the full tagged view.
143 if not Is_Tagged_Type
(N
) and then Is_Private_Type
(N
) then
147 pragma Assert
(Is_Tagged_Type
(N
));
153 Cancel_Special_Output
;
154 end Generate_CG_Output
;
160 procedure Initialize
is
162 Call_Graph_Nodes
.Init
;
165 -----------------------------------------
166 -- Is_Predefined_Dispatching_Operation --
167 -----------------------------------------
169 function Is_Predefined_Dispatching_Operation
170 (E
: Entity_Id
) return Boolean
172 function Homonym_Suffix_Length
(E
: Entity_Id
) return Natural;
173 -- Returns the length of the homonym suffix corresponding to E.
174 -- Note: This routine relies on the functionality provided by routines
175 -- of Exp_Dbug. Further work needed here to decide if it should be
176 -- located in that package???
178 ---------------------------
179 -- Homonym_Suffix_Length --
180 ---------------------------
182 function Homonym_Suffix_Length
(E
: Entity_Id
) return Natural is
183 Prefix_Length
: constant := 2;
184 -- Length of prefix "__"
190 if not Has_Homonym
(E
) then
195 while Present
(H
) loop
196 if Scope
(H
) = Scope
(E
) then
206 -- Prefix "__" followed by number
210 Result
: Natural := Prefix_Length
+ 1;
214 Result
:= Result
+ 1;
222 end Homonym_Suffix_Length
;
226 Full_Name
: constant String := Get_Name_String
(Chars
(E
));
227 Suffix_Length
: Natural;
228 TSS_Name
: TSS_Name_Type
;
230 -- Start of processing for Is_Predefined_Dispatching_Operation
233 if not Is_Dispatching_Operation
(E
) then
237 -- Search for and strip suffix for body-nested package entities
239 Suffix_Length
:= Homonym_Suffix_Length
(E
);
240 for J
in reverse Full_Name
'First + 2 .. Full_Name
'Last loop
241 if Full_Name
(J
) = 'X' then
243 -- Include the "X", "Xb", "Xn", ... in the part of the
244 -- suffix to be removed.
246 Suffix_Length
:= Suffix_Length
+ Full_Name
'Last - J
+ 1;
250 exit when Full_Name
(J
) /= 'b' and then Full_Name
(J
) /= 'n';
253 -- Most predefined primitives have internally generated names. Equality
254 -- must be treated differently; the predefined operation is recognized
255 -- as a homogeneous binary operator that returns Boolean.
257 if Full_Name
'Length > TSS_Name_Type
'Length then
261 (Full_Name
'Last - TSS_Name
'Length - Suffix_Length
+ 1
262 .. Full_Name
'Last - Suffix_Length
));
264 if TSS_Name
= TSS_Stream_Read
265 or else TSS_Name
= TSS_Stream_Write
266 or else TSS_Name
= TSS_Stream_Input
267 or else TSS_Name
= TSS_Stream_Output
268 or else TSS_Name
= TSS_Put_Image
269 or else TSS_Name
= TSS_Deep_Adjust
270 or else TSS_Name
= TSS_Deep_Finalize
274 elsif not Has_Fully_Qualified_Name
(E
) then
275 if Chars
(E
) in Name_uSize | Name_uAlignment | Name_uAssign
277 (Chars
(E
) = Name_Op_Eq
278 and then Etype
(First_Formal
(E
)) = Etype
(Last_Formal
(E
)))
279 or else Is_Predefined_Interface_Primitive
(E
)
284 -- Handle fully qualified names
288 type Names_Table
is array (Positive range <>) of Name_Id
;
290 Predef_Names_95
: constant Names_Table
:=
296 Predef_Names_05
: constant Names_Table
:=
297 (Name_uDisp_Asynchronous_Select
,
298 Name_uDisp_Conditional_Select
,
299 Name_uDisp_Get_Prim_Op_Kind
,
300 Name_uDisp_Get_Task_Id
,
302 Name_uDisp_Timed_Select
);
305 for J
in Predef_Names_95
'Range loop
306 Get_Name_String
(Predef_Names_95
(J
));
308 -- The predefined primitive operations are identified by the
309 -- names "_size", "_alignment", etc. If we try a pattern
310 -- matching against this string, we can wrongly match other
311 -- primitive operations like "get_size". To avoid this, we
312 -- add the "__" scope separator, which can only prepend
313 -- predefined primitive operations because other primitive
314 -- operations can neither start with an underline nor
315 -- contain two consecutive underlines in its name.
317 if Full_Name
'Last - Suffix_Length
> Name_Len
+ 2
320 (Full_Name
'Last - Name_Len
- 2 - Suffix_Length
+ 1
321 .. Full_Name
'Last - Suffix_Length
) =
322 "__" & Name_Buffer
(1 .. Name_Len
)
324 -- For the equality operator the type of the two operands
327 return Predef_Names_95
(J
) /= Name_Op_Eq
329 Etype
(First_Formal
(E
)) = Etype
(Last_Formal
(E
));
333 if Ada_Version
>= Ada_2005
then
334 for J
in Predef_Names_05
'Range loop
335 Get_Name_String
(Predef_Names_05
(J
));
337 if Full_Name
'Last - Suffix_Length
> Name_Len
+ 2
340 (Full_Name
'Last - Name_Len
- 2 - Suffix_Length
+ 1
341 .. Full_Name
'Last - Suffix_Length
) =
342 "__" & Name_Buffer
(1 .. Name_Len
)
353 end Is_Predefined_Dispatching_Operation
;
355 ----------------------
356 -- Register_CG_Node --
357 ----------------------
359 procedure Register_CG_Node
(N
: Node_Id
) is
361 if Nkind
(N
) in N_Subprogram_Call
then
362 if Current_Scope
= Main_Unit_Entity
363 or else Entity_Is_In_Main_Unit
(Current_Scope
)
365 -- Register a copy of the dispatching call node. Needed since the
366 -- node containing a dispatching call is rewritten by the
370 Copy
: constant Node_Id
:= New_Copy
(N
);
374 -- Determine the enclosing scope to use when generating the
375 -- call graph. This must be done now to avoid problems with
376 -- control structures that may be rewritten during expansion.
379 while Nkind
(Par
) /= N_Subprogram_Body
380 and then Nkind
(Parent
(Par
)) /= N_Compilation_Unit
384 -- Par can legitimately be empty inside a class-wide
385 -- precondition; the "real" call will be found inside the
393 Set_Parent
(Copy
, Par
);
394 Call_Graph_Nodes
.Append
(Copy
);
398 else pragma Assert
(Nkind
(N
) = N_Defining_Identifier
);
399 if Entity_Is_In_Main_Unit
(N
) then
400 Call_Graph_Nodes
.Append
(N
);
403 end Register_CG_Node
;
409 function Slot_Number
(Prim
: Entity_Id
) return Uint
is
410 E
: constant Entity_Id
:= Ultimate_Alias
(Prim
);
412 if Is_Predefined_Dispatching_Operation
(E
) then
413 return -DT_Position
(E
);
415 return DT_Position
(E
);
423 procedure Write_Output
(Str
: String) is
424 Nul
: constant Character := Character'First;
425 Line
: String (Str
'First .. Str
'Last + 1);
429 -- Add the null character to the string as required by fputs
432 Errno
:= fputs
(Line
'Address, Callgraph_Info_File
);
433 pragma Assert
(Errno
>= 0);
436 ---------------------
437 -- Write_Call_Info --
438 ---------------------
440 procedure Write_Call_Info
(Call
: Node_Id
) is
441 Ctrl_Arg
: constant Node_Id
:= Controlling_Argument
(Call
);
442 Ctrl_Typ
: constant Entity_Id
:= Base_Type
(Etype
(Ctrl_Arg
));
443 Prim
: constant Entity_Id
:= Entity
(Sinfo
.Nodes
.Name
(Call
));
444 P
: constant Node_Id
:= Parent
(Call
);
447 Write_Str
("edge: { sourcename: ");
450 -- The parent node is the construct that contains the call: subprogram
451 -- body or library-level package. Display the qualified name of the
452 -- entity of the construct. For a subprogram, it is the entity of the
453 -- spec, which carries a homonym counter when it is overloaded.
455 if Nkind
(P
) = N_Subprogram_Body
456 and then not Acts_As_Spec
(P
)
458 Get_External_Name
(Corresponding_Spec
(P
));
461 Get_External_Name
(Defining_Entity
(P
));
464 Write_Str
(Name_Buffer
(1 .. Name_Len
));
466 if Nkind
(P
) = N_Package_Declaration
then
467 Write_Str
("___elabs");
469 elsif Nkind
(P
) = N_Package_Body
then
470 Write_Str
("___elabb");
476 -- The targetname is a triple:
477 -- N: the index in a vtable used for dispatch
478 -- V: the type who's vtable is used
479 -- S: the static type of the expression
481 Write_Str
(" targetname: ");
484 pragma Assert
(No
(Interface_Alias
(Prim
)));
486 -- The check on Is_Ancestor is done here to avoid problems with
487 -- renamings of primitives. For example:
489 -- type Root is tagged ...
490 -- procedure Base (Obj : Root);
491 -- procedure Base2 (Obj : Root) renames Base;
493 if Present
(Alias
(Prim
))
496 (Find_Dispatching_Type
(Ultimate_Alias
(Prim
)),
497 Root_Type
(Ctrl_Typ
),
498 Use_Full_View
=> True)
500 -- This is a special case in which we generate in the ci file the
501 -- slot number of the renaming primitive (i.e. Base2) but instead of
502 -- generating the name of this renaming entity we reference directly
503 -- the renamed entity (i.e. Base).
505 Write_Int
(UI_To_Int
(Slot_Number
(Prim
)));
508 (Chars
(Find_Dispatching_Type
(Ultimate_Alias
(Prim
))));
510 Write_Int
(UI_To_Int
(Slot_Number
(Prim
)));
512 Write_Name
(Chars
(Root_Type
(Ctrl_Typ
)));
516 Write_Name
(Chars
(Root_Type
(Ctrl_Typ
)));
521 Write_Str
(" label: ");
523 Write_Location
(Sloc
(Call
));
531 ---------------------
532 -- Write_Type_Info --
533 ---------------------
535 procedure Write_Type_Info
(Typ
: Entity_Id
) is
539 Parent_Typ
: Entity_Id
;
540 Separator_Needed
: Boolean := False;
543 -- Initialize Parent_Typ handling private types
545 Parent_Typ
:= Etype
(Typ
);
547 if Present
(Full_View
(Parent_Typ
)) then
548 Parent_Typ
:= Full_View
(Parent_Typ
);
551 Write_Str
("class {");
554 Write_Str
(" classname: ");
556 Write_Name
(Chars
(Typ
));
560 Write_Str
(" label: ");
562 Write_Name
(Chars
(Typ
));
564 Write_Location
(Sloc
(Typ
));
568 if Parent_Typ
/= Typ
then
569 Write_Str
(" parent: ");
571 Write_Name
(Chars
(Parent_Typ
));
573 -- Note: Einfo.Entities prefix not needed if this routine is moved to
576 if Present
(Einfo
.Entities
.Interfaces
(Typ
))
577 and then not Is_Empty_Elmt_List
(Einfo
.Entities
.Interfaces
(Typ
))
579 Elmt
:= First_Elmt
(Einfo
.Entities
.Interfaces
(Typ
));
580 while Present
(Elmt
) loop
582 Write_Name
(Chars
(Node
(Elmt
)));
591 Write_Str
(" virtuals: ");
594 Elmt
:= First_Elmt
(Primitive_Operations
(Typ
));
595 while Present
(Elmt
) loop
598 -- Skip internal entities associated with overridden interface
599 -- primitives, and also inherited primitives.
601 if Present
(Interface_Alias
(Prim
))
603 (Present
(Alias
(Prim
))
604 and then Find_Dispatching_Type
(Prim
) /=
605 Find_Dispatching_Type
(Alias
(Prim
)))
610 -- Do not generate separator for output of first primitive
612 if Separator_Needed
then
617 Separator_Needed
:= True;
620 Write_Int
(UI_To_Int
(Slot_Number
(Prim
)));
623 -- Handle renamed primitives
625 if Present
(Alias
(Prim
)) then
626 Write_Name
(Chars
(Ultimate_Alias
(Prim
)));
628 Write_Name
(Chars
(Prim
));
631 -- Display overriding of parent primitives
633 if Present
(Overridden_Operation
(Prim
))
636 (Find_Dispatching_Type
(Overridden_Operation
(Prim
)), Typ
,
637 Use_Full_View
=> True)
641 (UI_To_Int
(Slot_Number
(Overridden_Operation
(Prim
))));
644 (Chars
(Find_Dispatching_Type
(Overridden_Operation
(Prim
))));
647 -- Display overriding of interface primitives
649 if Has_Interfaces
(Typ
) then
653 Int_Alias
: Entity_Id
;
656 Prim_Elmt
:= First_Elmt
(Primitive_Operations
(Typ
));
657 while Present
(Prim_Elmt
) loop
658 Prim_Op
:= Node
(Prim_Elmt
);
659 Int_Alias
:= Interface_Alias
(Prim_Op
);
661 if Present
(Int_Alias
)
663 not Is_Ancestor
(Find_Dispatching_Type
(Int_Alias
), Typ
,
664 Use_Full_View
=> True)
665 and then (Alias
(Prim_Op
)) = Prim
668 Write_Int
(UI_To_Int
(Slot_Number
(Int_Alias
)));
670 Write_Name
(Chars
(Find_Dispatching_Type
(Int_Alias
)));
673 Next_Elmt
(Prim_Elmt
);