| ------------------------------------------------------------------------------ |
| -- -- |
| -- GNAT COMPILER COMPONENTS -- |
| -- -- |
| -- B I N D O -- |
| -- -- |
| -- B o d y -- |
| -- -- |
| -- Copyright (C) 2019-2022, 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- -- |
| -- ware Foundation; either version 3, or (at your option) any later ver- -- |
| -- sion. GNAT is distributed in the hope that it will be useful, but WITH- -- |
| -- OUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY -- |
| -- or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License -- |
| -- for more details. You should have received a copy of the GNU General -- |
| -- Public License distributed with GNAT; see file COPYING3. If not, go to -- |
| -- http://www.gnu.org/licenses for a complete copy of the license. -- |
| -- -- |
| -- GNAT was originally developed by the GNAT team at New York University. -- |
| -- Extensive contributions were provided by Ada Core Technologies Inc. -- |
| -- -- |
| ------------------------------------------------------------------------------ |
| |
| with Binde; |
| with Opt; use Opt; |
| |
| with Bindo.Elaborators; |
| use Bindo.Elaborators; |
| |
| package body Bindo is |
| |
| --------------------------------- |
| -- Elaboration-order mechanism -- |
| --------------------------------- |
| |
| -- The elaboration-order (EO) mechanism implemented in this unit and its |
| -- children has the following objectives: |
| -- |
| -- * Find an ordering of all library items (historically referred to as |
| -- "units") in the bind which require elaboration, taking into account: |
| -- |
| -- - The dependencies between units expressed in the form of with |
| -- clauses. |
| -- |
| -- - Pragmas Elaborate, Elaborate_All, Elaborate_Body, Preelaborable, |
| -- and Pure. |
| -- |
| -- - The flow of execution at elaboration time. |
| -- |
| -- - Additional dependencies between units supplied to the binder by |
| -- means of a forced-elaboration-order file. |
| -- |
| -- The high-level idea empoyed by the EO mechanism is to construct two |
| -- graphs and use the information they represent to find an ordering of |
| -- all units. |
| -- |
| -- The invocation graph represents the flow of execution at elaboration |
| -- time. |
| -- |
| -- The library graph captures the dependencies between units expressed |
| -- by with clause and elaboration-related pragmas. The library graph is |
| -- further augmented with additional information from the invocation |
| -- graph by exploring the execution paths from a unit with elaboration |
| -- code to other external units. |
| -- |
| -- The strongly connected components of the library graph are computed. |
| -- |
| -- The order is obtained using a topological sort-like algorithm which |
| -- traverses the library graph and its strongly connected components in |
| -- an attempt to order available units while enabling other units to be |
| -- ordered. |
| -- |
| -- * Diagnose elaboration circularities between units |
| -- |
| -- An elaboration circularity arises when either |
| -- |
| -- - At least one unit cannot be ordered, or |
| -- |
| -- - All units can be ordered, but an edge with an Elaborate_All |
| -- pragma links two vertices within the same component of the |
| -- library graph. |
| -- |
| -- The library graph is traversed to discover, collect, and sort all |
| -- cycles that hinder the elaboration order. |
| -- |
| -- The most important cycle is diagnosed by describing its effects on |
| -- the elaboration order and listing all units comprising the circuit. |
| -- Various suggestions on how to break the cycle are offered. |
| |
| ----------------- |
| -- Terminology -- |
| ----------------- |
| |
| -- * Component - A strongly connected component of a graph. |
| -- |
| -- * Elaborable component - A component that is not waiting on other |
| -- components to be elaborated. |
| -- |
| -- * Elaborable vertex - A vertex that is not waiting on strong and weak |
| -- predecessors, and whose component is elaborable. |
| -- |
| -- * Elaboration circularity - A cycle involving units from the bind. |
| -- |
| -- * Elaboration root - A special invocation construct which denotes the |
| -- elaboration procedure of a unit. |
| -- |
| -- * Invocation - The act of activating a task, calling a subprogram, or |
| -- instantiating a generic. |
| -- |
| -- * Invocation construct - An entry declaration, [single] protected type, |
| -- subprogram declaration, subprogram instantiation, or a [single] task |
| -- type declared in the visible, private, or body declarations of some |
| -- unit. The construct is encoded in the ALI file of the related unit. |
| -- |
| -- * Invocation graph - A directed graph which models the flow of execution |
| -- at elaboration time. |
| -- |
| -- - Vertices - Invocation constructs plus extra information. Certain |
| -- vertices act as elaboration roots. |
| -- |
| -- - Edges - Invocation relations plus extra information. |
| -- |
| -- * Invocation relation - A flow link between two invocation constructs. |
| -- This link is encoded in the ALI file of unit that houses the invoker. |
| -- |
| -- * Invocation signature - A set of attributes that uniquely identify an |
| -- invocation construct within the namespace of all ALI files. |
| -- |
| -- * Invoker - The source construct of an invocation relation (the caller, |
| -- instantiator, or task activator). |
| -- |
| -- * Library graph - A directed graph which captures with clause and pragma |
| -- dependencies between units. |
| -- |
| -- - Vertices - Units plus extra information. |
| -- |
| -- - Edges - With clause, pragma, and additional dependencies between |
| -- units. |
| -- |
| -- * Pending predecessor - A vertex that must be elaborated before another |
| -- vertex can be elaborated. |
| -- |
| -- * Strong edge - A non-invocation library graph edge. Strong edges |
| -- represent the language-defined relations between units. |
| -- |
| -- * Strong predecessor - A library graph vertex reachable via a strong |
| -- edge. |
| -- |
| -- * Target - The destination construct of an invocation relation (the |
| -- generic, subprogram, or task type). |
| -- |
| -- * Weak edge - An invocation library graph edge. Weak edges represent |
| -- the speculative flow of execution at elaboration time, which may or |
| -- may not take place. |
| -- |
| -- * Weak predecessor - A library graph vertex reachable via a weak edge. |
| -- |
| -- * Weakly elaborable vertex - A vertex that is waiting solely on weak |
| -- predecessors to be elaborated, and whose component is elaborable. |
| |
| ------------------ |
| -- Architecture -- |
| ------------------ |
| |
| -- Find_Elaboration_Order |
| -- | |
| -- +--> Collect_Elaborable_Units |
| -- +--> Write_ALI_Tables |
| -- +--> Elaborate_Units |
| -- | |
| -- +------ | -------------- Construction phase ------------------------+ |
| -- | | | |
| -- | +--> Build_Library_Graph | |
| -- | +--> Validate_Library_Graph | |
| -- | +--> Write_Library_Graph | |
| -- | | | |
| -- | +--> Build_Invocation_Graph | |
| -- | +--> Validate_Invocation_Graph | |
| -- | +--> Write_Invocation_Graph | |
| -- | | | |
| -- +------ | ----------------------------------------------------------+ |
| -- | |
| -- +------ | -------------- Augmentation phase ------------------------+ |
| -- | | | |
| -- | +--> Augment_Library_Graph | |
| -- | | | |
| -- +------ | ----------------------------------------------------------+ |
| -- | |
| -- +------ | -------------- Ordering phase ----------------------------+ |
| -- | | | |
| -- | +--> Find_Components | |
| -- | | | |
| -- | +--> Elaborate_Library_Graph | |
| -- | +--> Validate_Elaboration_Order | |
| -- | +--> Write_Elaboration_Order | |
| -- | | | |
| -- | +--> Write_Unit_Closure | |
| -- | | | |
| -- +------ | ----------------------------------------------------------+ |
| -- | |
| -- +------ | -------------- Diagnostics phase -------------------------+ |
| -- | | | |
| -- | +--> Find_Cycles | |
| -- | +--> Validate_Cycles | |
| -- | +--> Write_Cycles | |
| -- | | | |
| -- | +--> Diagnose_Cycle / Diagnose_All_Cycles | |
| -- | | |
| -- +-------------------------------------------------------------------+ |
| |
| ------------------------ |
| -- Construction phase -- |
| ------------------------ |
| |
| -- The Construction phase has the following objectives: |
| -- |
| -- * Build the library graph by inspecting the ALI file of each unit that |
| -- requires elaboration. |
| -- |
| -- * Validate the consistency of the library graph, only when switch -d_V |
| -- is in effect. |
| -- |
| -- * Write the contents of the invocation graph in human-readable form to |
| -- standard output when switch -d_L is in effect. |
| -- |
| -- * Build the invocation graph by inspecting invocation constructs and |
| -- relations in the ALI file of each unit that requires elaboration. |
| -- |
| -- * Validate the consistency of the invocation graph, only when switch |
| -- -d_V is in effect. |
| -- |
| -- * Write the contents of the invocation graph in human-readable form to |
| -- standard output when switch -d_I is in effect. |
| |
| ------------------------ |
| -- Augmentation phase -- |
| ------------------------ |
| |
| -- The Augmentation phase has the following objectives: |
| -- |
| -- * Discover transitions of the elaboration flow from a unit with an |
| -- elaboration root to other units. Augment the library graph with |
| -- extra edges for each such transition. |
| |
| -------------------- |
| -- Ordering phase -- |
| -------------------- |
| |
| -- The Ordering phase has the following objectives: |
| -- |
| -- * Discover all components of the library graph by treating specs and |
| -- bodies as single vertices. |
| -- |
| -- * Try to order as many vertices of the library graph as possible by |
| -- performing a topological sort based on the pending predecessors of |
| -- vertices across all components and within a single component. |
| -- |
| -- * Validate the consistency of the order, only when switch -d_V is in |
| -- effect. |
| -- |
| -- * Write the contents of the order in human-readable form to standard |
| -- output when switch -d_O is in effect. |
| -- |
| -- * Write the sources of the order closure when switch -R is in effect. |
| |
| ----------------------- |
| -- Diagnostics phase -- |
| ----------------------- |
| |
| -- The Diagnostics phase has the following objectives: |
| -- |
| -- * Discover, save, and sort all cycles in the library graph. The cycles |
| -- are sorted based on the following heuristics: |
| -- |
| -- - A cycle with higher precedence is preferred. |
| -- |
| -- - A cycle with fewer invocation edges is preferred. |
| -- |
| -- - A cycle with a shorter length is preferred. |
| -- |
| -- * Validate the consistency of cycles, only when switch -d_V is in |
| -- effect. |
| -- |
| -- * Write the contents of all cycles in human-readable form to standard |
| -- output when switch -d_O is in effect. |
| -- |
| -- * Diagnose the most important cycle, or all cycles when switch -d_C is |
| -- in effect. The diagnostic consists of: |
| -- |
| -- - The reason for the existence of the cycle, along with the unit |
| -- whose elaboration cannot be guaranteed. |
| -- |
| -- - A detailed traceback of the cycle, showcasing the transition |
| -- between units, along with any other elaboration-order-related |
| -- information. |
| -- |
| -- - A set of suggestions on how to break the cycle considering the |
| -- the edges comprising the circuit, the elaboration model used to |
| -- compile the units, the availability of invocation information, |
| -- and the state of various relevant switches. |
| |
| -------------- |
| -- Switches -- |
| -------------- |
| |
| -- -d_a Ignore the effects of pragma Elaborate_All |
| -- |
| -- GNATbind creates a regular with edge instead of an Elaborate_All |
| -- edge in the library graph, thus eliminating the effects of the |
| -- pragma. |
| -- |
| -- -d_b Ignore the effects of pragma Elaborate_Body |
| -- |
| -- GNATbind treats a spec and body pair as decoupled. |
| -- |
| -- -d_e Ignore the effects of pragma Elaborate |
| -- |
| -- GNATbind creates a regular with edge instead of an Elaborate edge |
| -- in the library graph, thus eliminating the effects of the pragma. |
| -- In addition, GNATbind does not create an edge to the body of the |
| -- pragma argument. |
| -- |
| -- -d_t Output cycle-detection trace information |
| -- |
| -- GNATbind outputs trace information on cycle-detection activities |
| -- to standard output. |
| -- |
| -- -d_A Output ALI invocation tables |
| -- |
| -- GNATbind outputs the contents of ALI table Invocation_Constructs |
| -- and Invocation_Edges in textual format to standard output. |
| -- |
| -- -d_C Diagnose all cycles |
| -- |
| -- GNATbind outputs diagnostics for all unique cycles in the bind, |
| -- rather than just the most important one. |
| -- |
| -- -d_I Output invocation graph |
| -- |
| -- GNATbind outputs the invocation graph in text format to standard |
| -- output. |
| -- |
| -- -d_L Output library graph |
| -- |
| -- GNATbind outputs the library graph in textual format to standard |
| -- output. |
| -- |
| -- -d_P Output cycle paths |
| -- |
| -- GNATbind outputs the cycle paths in text format to standard output |
| -- |
| -- -d_S Output elaboration-order status information |
| -- |
| -- GNATbind outputs trace information concerning the status of its |
| -- various phases to standard output. |
| -- |
| -- -d_T Output elaboration-order trace information |
| -- |
| -- GNATbind outputs trace information on elaboration-order detection |
| -- activities to standard output. |
| -- |
| -- -d_V Validate bindo cycles, graphs, and order |
| -- |
| -- GNATbind validates the invocation graph, library graph along with |
| -- its cycles, and elaboration order by detecting inconsistencies and |
| -- producing error reports. |
| -- |
| -- -e Output complete list of elaboration-order dependencies |
| -- |
| -- GNATbind outputs the dependencies between units to standard |
| -- output. |
| -- |
| -- -f Force elaboration order from given file |
| -- |
| -- GNATbind applies an additional set of edges to the library graph. |
| -- The edges are read from a file specified by the argument of the |
| -- flag. |
| -- |
| -- -H Legacy elaboration-order model enabled |
| -- |
| -- GNATbind uses the library-graph and heuristics-based elaboration- |
| -- order model. |
| -- |
| -- -l Output chosen elaboration order |
| -- |
| -- GNATbind outputs the elaboration order in text format to standard |
| -- output. |
| -- |
| -- -p Pessimistic (worst-case) elaboration order |
| -- |
| -- This switch is not used in Bindo and its children. |
| |
| ---------------------------------------- |
| -- Debugging elaboration-order issues -- |
| ---------------------------------------- |
| |
| -- Prior to debugging elaboration-order-related issues, enable all relevant |
| -- debug flags to collect as much information as possible. Depending on the |
| -- number of files in the bind, Bindo may emit anywhere between several MBs |
| -- to several hundred MBs of data to standard output. The switches are: |
| -- |
| -- -d_A -d_C -d_I -d_L -d_P -d_t -d_T -d_V |
| -- |
| -- Bindo offers several debugging routines that can be invoked from gdb. |
| -- Those are defined in the body of Bindo.Writers, in sections denoted by |
| -- header Debug. For quick reference, the routines are: |
| -- |
| -- palgc -- print all library-graph cycles |
| -- pau -- print all units |
| -- pc -- print component |
| -- pige -- print invocation-graph edge |
| -- pigv -- print invocation-graph vertex |
| -- plgc -- print library-graph cycle |
| -- plge -- print library-graph edge |
| -- plgv -- print library-graph vertex |
| -- pu -- print units |
| -- |
| -- * Apparent infinite loop |
| -- |
| -- The elaboration order mechanism appears to be stuck in an infinite |
| -- loop. Use switch -d_S to output the status of each elaboration phase. |
| -- |
| -- * Invalid elaboration order |
| -- |
| -- The elaboration order is invalid when: |
| -- |
| -- - A unit that requires elaboration is missing from the order |
| -- - A unit that does not require elaboration is present in the order |
| -- |
| -- Examine the output of the elaboration algorithm available via switch |
| -- -d_T to determine how the related units were included in or excluded |
| -- from the order. Determine whether the library graph contains all the |
| -- relevant edges for those units. |
| -- |
| -- Units and routines of interest: |
| -- Bindo.Elaborators |
| -- Elaborate_Library_Graph |
| -- Elaborate_Units |
| -- |
| -- * Invalid invocation graph |
| -- |
| -- The invocation graph is invalid when: |
| -- |
| -- - An edge lacks an attribute |
| -- - A vertex lacks an attribute |
| -- |
| -- Find the malformed edge or vertex and determine which attribute is |
| -- missing. Examine the contents of the invocation-related ALI tables |
| -- available via switch -d_A. If the invocation construct or relation |
| -- is missing, verify the ALI file. If the ALI lacks all the relevant |
| -- information, then Sem_Elab most likely failed to discover a valid |
| -- elaboration path. |
| -- |
| -- Units and routines of interest: |
| -- Bindo.Builders |
| -- Bindo.Graphs |
| -- Add_Edge |
| -- Add_Vertex |
| -- Build_Invocation_Graph |
| -- |
| -- * Invalid library graph |
| -- |
| -- The library graph is invalid when: |
| -- |
| -- - An edge lacks an attribute |
| -- - A vertex lacks an attribute |
| -- |
| -- Find the malformed edge or vertex and determine which attribute is |
| -- missing. |
| -- |
| -- Units and routines of interest: |
| -- Bindo.Builders |
| -- Bindo.Graphs |
| -- Add_Edge |
| -- Add_Vertex |
| -- Build_Library_Graph |
| -- |
| -- * Invalid library-graph cycle |
| -- |
| -- A library-graph cycle is invalid when: |
| -- |
| -- - It lacks enough edges to form a circuit |
| -- - At least one edge in the circuit is repeated |
| -- |
| -- Find the malformed cycle and determine which attribute is missing. |
| -- |
| -- Units and routines of interest: |
| -- Bindo.Graphs |
| -- Find_Cycles |
| |
| ---------------------------- |
| -- Find_Elaboration_Order -- |
| ---------------------------- |
| |
| procedure Find_Elaboration_Order |
| (Order : out Unit_Id_Table; |
| Main_Lib_File : File_Name_Type) |
| is |
| begin |
| -- Use the library graph and heuristic-based elaboration order when |
| -- switch -H (legacy elaboration-order mode enabled). |
| |
| if Legacy_Elaboration_Order then |
| Binde.Find_Elab_Order (Order, Main_Lib_File); |
| |
| -- Otherwise use the invocation and library-graph-based elaboration |
| -- order. |
| |
| else |
| Invocation_And_Library_Graph_Elaborators.Elaborate_Units |
| (Order => Order, |
| Main_Lib_File => Main_Lib_File); |
| end if; |
| end Find_Elaboration_Order; |
| |
| end Bindo; |