diff options
Diffstat (limited to 'gcc/ada/exp_dist.adb')
-rw-r--r-- | gcc/ada/exp_dist.adb | 3760 |
1 files changed, 3760 insertions, 0 deletions
diff --git a/gcc/ada/exp_dist.adb b/gcc/ada/exp_dist.adb new file mode 100644 index 00000000000..c0d79d12d22 --- /dev/null +++ b/gcc/ada/exp_dist.adb @@ -0,0 +1,3760 @@ +------------------------------------------------------------------------------ +-- -- +-- GNAT COMPILER COMPONENTS -- +-- -- +-- E X P_ D I S T -- +-- -- +-- B o d y -- +-- -- +-- $Revision: 1.125 $ +-- -- +-- Copyright (C) 1992-2001 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 2, 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 COPYING. If not, write -- +-- to the Free Software Foundation, 59 Temple Place - Suite 330, Boston, -- +-- MA 02111-1307, USA. -- +-- -- +-- GNAT was originally developed by the GNAT team at New York University. -- +-- It is now maintained by Ada Core Technologies Inc (http://www.gnat.com). -- +-- -- +------------------------------------------------------------------------------ + +with Atree; use Atree; +with Einfo; use Einfo; +with Elists; use Elists; +with Exp_Tss; use Exp_Tss; +with Exp_Util; use Exp_Util; +with GNAT.HTable; use GNAT.HTable; +with Lib; use Lib; +with Namet; use Namet; +with Nlists; use Nlists; +with Nmake; use Nmake; +with Opt; use Opt; +with Rtsfind; use Rtsfind; +with Sem; use Sem; +with Sem_Ch3; use Sem_Ch3; +with Sem_Ch8; use Sem_Ch8; +with Sem_Dist; use Sem_Dist; +with Sem_Util; use Sem_Util; +with Sinfo; use Sinfo; +with Snames; use Snames; +with Stand; use Stand; +with Stringt; use Stringt; +with Tbuild; use Tbuild; +with Uintp; use Uintp; +with Uname; use Uname; + +package body Exp_Dist is + + -- The following model has been used to implement distributed objects: + -- given a designated type D and a RACW type R, then a record of the + -- form: + -- type Stub is tagged record + -- [...declaration similar to s-parint.ads RACW_Stub_Type...] + -- end Stub; + -- is built. This type has two properties: + -- + -- 1) Since it has the same structure than RACW_Stub_Type, it can be + -- converted to and from this type to make it suitable for + -- System.Partition_Interface.Get_Unique_Remote_Pointer in order + -- to avoid memory leaks when the same remote object arrive on the + -- same partition by following different pathes + -- + -- 2) It also has the same dispatching table as the designated type D, + -- and thus can be used as an object designated by a value of type + -- R on any partition other than the one on which the object has + -- been created, since only dispatching calls will be performed and + -- the fields themselves will not be used. We call Derive_Subprograms + -- to fake half a derivation to ensure that the subprograms do have + -- the same dispatching table. + + ----------------------- + -- Local subprograms -- + ----------------------- + + procedure Build_General_Calling_Stubs + (Decls : in List_Id; + Statements : in List_Id; + Target_Partition : in Entity_Id; + RPC_Receiver : in Node_Id; + Subprogram_Id : in Node_Id; + Asynchronous : in Node_Id := Empty; + Is_Known_Asynchronous : in Boolean := False; + Is_Known_Non_Asynchronous : in Boolean := False; + Is_Function : in Boolean; + Spec : in Node_Id; + Object_Type : in Entity_Id := Empty; + Nod : in Node_Id); + -- Build calling stubs for general purpose. The parameters are: + -- Decls : a place to put declarations + -- Statements : a place to put statements + -- Target_Partition : a node containing the target partition that must + -- be a N_Defining_Identifier + -- RPC_Receiver : a node containing the RPC receiver + -- Subprogram_Id : a node containing the subprogram ID + -- Asynchronous : True if an APC must be made instead of an RPC. + -- The value needs not be supplied if one of the + -- Is_Known_... is True. + -- Is_Known_Async... : True if we know that this is asynchronous + -- Is_Known_Non_A... : True if we know that this is not asynchronous + -- Spec : a node with a Parameter_Specifications and + -- a Subtype_Mark if applicable + -- Object_Type : in case of a RACW, parameters of type access to + -- Object_Type will be marshalled using the + -- address of this object (the addr field) rather + -- than using the 'Write on the object itself + -- Nod : used to provide sloc for generated code + + function Build_Subprogram_Calling_Stubs + (Vis_Decl : Node_Id; + Subp_Id : Int; + Asynchronous : Boolean; + Dynamically_Asynchronous : Boolean := False; + Stub_Type : Entity_Id := Empty; + Locator : Entity_Id := Empty; + New_Name : Name_Id := No_Name) + return Node_Id; + -- Build the calling stub for a given subprogram with the subprogram ID + -- being Subp_Id. If Stub_Type is given, then the "addr" field of + -- parameters of this type will be marshalled instead of the object + -- itself. It will then be converted into Stub_Type before performing + -- the real call. If Dynamically_Asynchronous is True, then it will be + -- computed at run time whether the call is asynchronous or not. + -- Otherwise, the value of the formal Asynchronous will be used. + -- If Locator is not Empty, it will be used instead of RCI_Cache. If + -- New_Name is given, then it will be used instead of the original name. + + function Build_Subprogram_Receiving_Stubs + (Vis_Decl : Node_Id; + Asynchronous : Boolean; + Dynamically_Asynchronous : Boolean := False; + Stub_Type : Entity_Id := Empty; + RACW_Type : Entity_Id := Empty; + Parent_Primitive : Entity_Id := Empty) + return Node_Id; + -- Build the receiving stub for a given subprogram. The subprogram + -- declaration is also built by this procedure, and the value returned + -- is a N_Subprogram_Body. If a parameter of type access to Stub_Type is + -- found in the specification, then its address is read from the stream + -- instead of the object itself and converted into an access to + -- class-wide type before doing the real call using any of the RACW type + -- pointing on the designated type. + + function Build_Ordered_Parameters_List (Spec : Node_Id) return List_Id; + -- Return an ordered parameter list: unconstrained parameters are put + -- at the beginning of the list and constrained ones are put after. If + -- there are no parameters, an empty list is returned. + + procedure Add_Calling_Stubs_To_Declarations + (Pkg_Spec : in Node_Id; + Decls : in List_Id); + -- Add calling stubs to the declarative part + + procedure Add_Receiving_Stubs_To_Declarations + (Pkg_Spec : in Node_Id; + Decls : in List_Id); + -- Add receiving stubs to the declarative part + + procedure Add_RAS_Dereference_Attribute (N : in Node_Id); + -- Add a subprogram body for RAS dereference + + procedure Add_RAS_Access_Attribute (N : in Node_Id); + -- Add a subprogram body for RAS Access attribute + + function Could_Be_Asynchronous (Spec : Node_Id) return Boolean; + -- Return True if nothing prevents the program whose specification is + -- given to be asynchronous (i.e. no out parameter). + + function Get_Pkg_Name_String_Id (Decl_Node : Node_Id) return String_Id; + function Get_String_Id (Val : String) return String_Id; + -- Ugly functions used to retrieve a package name. Inherited from the + -- old exp_dist.adb and not rewritten yet ??? + + function Pack_Entity_Into_Stream_Access + (Loc : Source_Ptr; + Stream : Entity_Id; + Object : Entity_Id; + Etyp : Entity_Id := Empty) + return Node_Id; + -- Pack Object (of type Etyp) into Stream. If Etyp is not given, + -- then Etype (Object) will be used if present. If the type is + -- constrained, then 'Write will be used to output the object, + -- If the type is unconstrained, 'Output will be used. + + function Pack_Node_Into_Stream + (Loc : Source_Ptr; + Stream : Entity_Id; + Object : Node_Id; + Etyp : Entity_Id) + return Node_Id; + -- Similar to above, with an arbitrary node instead of an entity + + function Pack_Node_Into_Stream_Access + (Loc : Source_Ptr; + Stream : Entity_Id; + Object : Node_Id; + Etyp : Entity_Id) + return Node_Id; + -- Similar to above, with Stream instead of Stream'Access + + function Copy_Specification + (Loc : Source_Ptr; + Spec : Node_Id; + Object_Type : Entity_Id := Empty; + Stub_Type : Entity_Id := Empty; + New_Name : Name_Id := No_Name) + return Node_Id; + -- Build a specification from another one. If Object_Type is not Empty + -- and any access to Object_Type is found, then it is replaced by an + -- access to Stub_Type. If New_Name is given, then it will be used as + -- the name for the newly created spec. + + function Scope_Of_Spec (Spec : Node_Id) return Entity_Id; + -- Return the scope represented by a given spec + + function Need_Extra_Constrained (Parameter : Node_Id) return Boolean; + -- Return True if the current parameter needs an extra formal to reflect + -- its constrained status. + + function Is_RACW_Controlling_Formal + (Parameter : Node_Id; Stub_Type : Entity_Id) + return Boolean; + -- Return True if the current parameter is a controlling formal argument + -- of type Stub_Type or access to Stub_Type. + + type Stub_Structure is record + Stub_Type : Entity_Id; + Stub_Type_Access : Entity_Id; + Object_RPC_Receiver : Entity_Id; + RPC_Receiver_Stream : Entity_Id; + RPC_Receiver_Result : Entity_Id; + RACW_Type : Entity_Id; + end record; + -- This structure is necessary because of the two phases analysis of + -- a RACW declaration occurring in the same Remote_Types package as the + -- designated type. RACW_Type is any of the RACW types pointing on this + -- designated type, it is used here to save an anonymous type creation + -- for each primitive operation. + + Empty_Stub_Structure : constant Stub_Structure := + (Empty, Empty, Empty, Empty, Empty, Empty); + + type Hash_Index is range 0 .. 50; + function Hash (F : Entity_Id) return Hash_Index; + + package Stubs_Table is + new Simple_HTable (Header_Num => Hash_Index, + Element => Stub_Structure, + No_Element => Empty_Stub_Structure, + Key => Entity_Id, + Hash => Hash, + Equal => "="); + -- Mapping between a RACW designated type and its stub type + + package Asynchronous_Flags_Table is + new Simple_HTable (Header_Num => Hash_Index, + Element => Node_Id, + No_Element => Empty, + Key => Entity_Id, + Hash => Hash, + Equal => "="); + -- Mapping between a RACW type and the node holding the value True if + -- the RACW is asynchronous and False otherwise. + + package RCI_Locator_Table is + new Simple_HTable (Header_Num => Hash_Index, + Element => Entity_Id, + No_Element => Empty, + Key => Entity_Id, + Hash => Hash, + Equal => "="); + -- Mapping between a RCI package on which All_Calls_Remote applies and + -- the generic instantiation of RCI_Info for this package. + + package RCI_Calling_Stubs_Table is + new Simple_HTable (Header_Num => Hash_Index, + Element => Entity_Id, + No_Element => Empty, + Key => Entity_Id, + Hash => Hash, + Equal => "="); + -- Mapping between a RCI subprogram and the corresponding calling stubs + + procedure Add_Stub_Type + (Designated_Type : in Entity_Id; + RACW_Type : in Entity_Id; + Decls : in List_Id; + Stub_Type : out Entity_Id; + Stub_Type_Access : out Entity_Id; + Object_RPC_Receiver : out Entity_Id; + Existing : out Boolean); + -- Add the declaration of the stub type, the access to stub type and the + -- object RPC receiver at the end of Decls. If these already exist, + -- then nothing is added in the tree but the right values are returned + -- anyhow and Existing is set to True. + + procedure Add_RACW_Read_Attribute + (RACW_Type : in Entity_Id; + Stub_Type : in Entity_Id; + Stub_Type_Access : in Entity_Id; + Declarations : in List_Id); + -- Add Read attribute in Decls for the RACW type. The Read attribute + -- is added right after the RACW_Type declaration while the body is + -- inserted after Declarations. + + procedure Add_RACW_Write_Attribute + (RACW_Type : in Entity_Id; + Stub_Type : in Entity_Id; + Stub_Type_Access : in Entity_Id; + Object_RPC_Receiver : in Entity_Id; + Declarations : in List_Id); + -- Same thing for the Write attribute + + procedure Add_RACW_Read_Write_Attributes + (RACW_Type : in Entity_Id; + Stub_Type : in Entity_Id; + Stub_Type_Access : in Entity_Id; + Object_RPC_Receiver : in Entity_Id; + Declarations : in List_Id); + -- Add Read and Write attributes declarations and bodies for a given + -- RACW type. The declarations are added just after the declaration + -- of the RACW type itself, while the bodies are inserted at the end + -- of Decls. + + function RCI_Package_Locator + (Loc : Source_Ptr; + Package_Spec : Node_Id) + return Node_Id; + -- Instantiate the generic package RCI_Info in order to locate the + -- RCI package whose spec is given as argument. + + function Make_Tag_Check (Loc : Source_Ptr; N : Node_Id) return Node_Id; + -- Surround a node N by a tag check, as in: + -- begin + -- <N>; + -- exception + -- when E : Ada.Tags.Tag_Error => + -- Raise_Exception (Program_Error'Identity, + -- Exception_Message (E)); + -- end; + + function Input_With_Tag_Check + (Loc : Source_Ptr; + Var_Type : Entity_Id; + Stream : Entity_Id) + return Node_Id; + -- Return a function with the following form: + -- function R return Var_Type is + -- begin + -- return Var_Type'Input (S); + -- exception + -- when E : Ada.Tags.Tag_Error => + -- Raise_Exception (Program_Error'Identity, + -- Exception_Message (E)); + -- end R; + + ------------------------------------ + -- Local variables and structures -- + ------------------------------------ + + RCI_Cache : Node_Id; + + Output_From_Constrained : constant array (Boolean) of Name_Id := + (False => Name_Output, + True => Name_Write); + -- The attribute to choose depending on the fact that the parameter + -- is constrained or not. There is no such thing as Input_From_Constrained + -- since this require separate mechanisms ('Input is a function while + -- 'Read is a procedure). + + --------------------------------------- + -- Add_Calling_Stubs_To_Declarations -- + --------------------------------------- + + procedure Add_Calling_Stubs_To_Declarations + (Pkg_Spec : in Node_Id; + Decls : in List_Id) + is + Current_Subprogram_Number : Int := 0; + Current_Declaration : Node_Id; + + Loc : constant Source_Ptr := Sloc (Pkg_Spec); + + RCI_Instantiation : Node_Id; + + Subp_Stubs : Node_Id; + + begin + -- The first thing added is an instantiation of the generic package + -- System.Partition_interface.RCI_Info with the name of the (current) + -- remote package. This will act as an interface with the name server + -- to determine the Partition_ID and the RPC_Receiver for the + -- receiver of this package. + + RCI_Instantiation := RCI_Package_Locator (Loc, Pkg_Spec); + RCI_Cache := Defining_Unit_Name (RCI_Instantiation); + + Append_To (Decls, RCI_Instantiation); + Analyze (RCI_Instantiation); + + -- For each subprogram declaration visible in the spec, we do + -- build a body. We also increment a counter to assign a different + -- Subprogram_Id to each subprograms. The receiving stubs processing + -- do use the same mechanism and will thus assign the same Id and + -- do the correct dispatching. + + Current_Declaration := First (Visible_Declarations (Pkg_Spec)); + + while Current_Declaration /= Empty loop + + if Nkind (Current_Declaration) = N_Subprogram_Declaration + and then Comes_From_Source (Current_Declaration) + then + pragma Assert (Current_Subprogram_Number = + Get_Subprogram_Id (Defining_Unit_Name (Specification ( + Current_Declaration)))); + + Subp_Stubs := + Build_Subprogram_Calling_Stubs ( + Vis_Decl => Current_Declaration, + Subp_Id => Current_Subprogram_Number, + Asynchronous => + Nkind (Specification (Current_Declaration)) = + N_Procedure_Specification + and then + Is_Asynchronous (Defining_Unit_Name (Specification + (Current_Declaration)))); + + Append_To (Decls, Subp_Stubs); + Analyze (Subp_Stubs); + + Current_Subprogram_Number := Current_Subprogram_Number + 1; + end if; + + Next (Current_Declaration); + end loop; + + end Add_Calling_Stubs_To_Declarations; + + ----------------------- + -- Add_RACW_Features -- + ----------------------- + + procedure Add_RACW_Features (RACW_Type : in Entity_Id) + is + Desig : constant Entity_Id := + Etype (Designated_Type (RACW_Type)); + Decls : List_Id := + List_Containing (Declaration_Node (RACW_Type)); + + Same_Scope : constant Boolean := + Scope (Desig) = Scope (RACW_Type); + + Stub_Type : Entity_Id; + Stub_Type_Access : Entity_Id; + Object_RPC_Receiver : Entity_Id; + Existing : Boolean; + + begin + if not Expander_Active then + return; + end if; + + if Same_Scope then + + -- We are declaring a RACW in the same package than its designated + -- type, so the list to use for late declarations must be the + -- private part of the package. We do know that this private part + -- exists since the designated type has to be a private one. + + Decls := Private_Declarations + (Package_Specification_Of_Scope (Current_Scope)); + + elsif Nkind (Parent (Decls)) = N_Package_Specification + and then Present (Private_Declarations (Parent (Decls))) + then + Decls := Private_Declarations (Parent (Decls)); + end if; + + -- If we were unable to find the declarations, that means that the + -- completion of the type was missing. We can safely return and let + -- the error be caught by the semantic analysis. + + if No (Decls) then + return; + end if; + + Add_Stub_Type + (Designated_Type => Desig, + RACW_Type => RACW_Type, + Decls => Decls, + Stub_Type => Stub_Type, + Stub_Type_Access => Stub_Type_Access, + Object_RPC_Receiver => Object_RPC_Receiver, + Existing => Existing); + + Add_RACW_Read_Write_Attributes + (RACW_Type => RACW_Type, + Stub_Type => Stub_Type, + Stub_Type_Access => Stub_Type_Access, + Object_RPC_Receiver => Object_RPC_Receiver, + Declarations => Decls); + + if not Same_Scope and then not Existing then + + -- The RACW has been declared in another scope than the designated + -- type and has not been handled by another RACW in the same + -- package as the first one, so add primitive for the stub type + -- here. + + Add_RACW_Primitive_Declarations_And_Bodies + (Designated_Type => Desig, + Insertion_Node => + Parent (Declaration_Node (Object_RPC_Receiver)), + Decls => Decls); + + else + Add_Access_Type_To_Process (E => Desig, A => RACW_Type); + end if; + end Add_RACW_Features; + + ------------------------------------------------- + -- Add_RACW_Primitive_Declarations_And_Bodies -- + ------------------------------------------------- + + procedure Add_RACW_Primitive_Declarations_And_Bodies + (Designated_Type : in Entity_Id; + Insertion_Node : in Node_Id; + Decls : in List_Id) + is + -- Set sloc of generated declaration to be that of the + -- insertion node, so the declarations are recognized as + -- belonging to the current package. + + Loc : constant Source_Ptr := Sloc (Insertion_Node); + + Stub_Elements : constant Stub_Structure := + Stubs_Table.Get (Designated_Type); + + pragma Assert (Stub_Elements /= Empty_Stub_Structure); + + Current_Insertion_Node : Node_Id := Insertion_Node; + + RPC_Receiver_Declarations : List_Id; + RPC_Receiver_Statements : List_Id; + RPC_Receiver_Case_Alternatives : constant List_Id := New_List; + RPC_Receiver_Subp_Id : Entity_Id; + + Current_Primitive_Elmt : Elmt_Id; + Current_Primitive : Entity_Id; + Current_Primitive_Body : Node_Id; + Current_Primitive_Spec : Node_Id; + Current_Primitive_Decl : Node_Id; + Current_Primitive_Number : Int := 0; + + Current_Primitive_Alias : Node_Id; + + Current_Receiver : Entity_Id; + Current_Receiver_Body : Node_Id; + + RPC_Receiver_Decl : Node_Id; + + Possibly_Asynchronous : Boolean; + + begin + + if not Expander_Active then + return; + end if; + + -- Build callers, receivers for every primitive operations and a RPC + -- receiver for this type. + + if Present (Primitive_Operations (Designated_Type)) then + + Current_Primitive_Elmt := + First_Elmt (Primitive_Operations (Designated_Type)); + + while Current_Primitive_Elmt /= No_Elmt loop + + Current_Primitive := Node (Current_Primitive_Elmt); + + -- Copy the primitive of all the parents, except predefined + -- ones that are not remotely dispatching. + + if Chars (Current_Primitive) /= Name_uSize + and then Chars (Current_Primitive) /= Name_uDeep_Finalize + then + -- The first thing to do is build an up-to-date copy of + -- the spec with all the formals referencing Designated_Type + -- transformed into formals referencing Stub_Type. Since this + -- primitive may have been inherited, go back the alias chain + -- until the real primitive has been found. + + Current_Primitive_Alias := Current_Primitive; + while Present (Alias (Current_Primitive_Alias)) loop + pragma Assert + (Current_Primitive_Alias + /= Alias (Current_Primitive_Alias)); + Current_Primitive_Alias := Alias (Current_Primitive_Alias); + end loop; + + Current_Primitive_Spec := + Copy_Specification (Loc, + Spec => Parent (Current_Primitive_Alias), + Object_Type => Designated_Type, + Stub_Type => Stub_Elements.Stub_Type); + + Current_Primitive_Decl := + Make_Subprogram_Declaration (Loc, + Specification => Current_Primitive_Spec); + + Insert_After (Current_Insertion_Node, Current_Primitive_Decl); + Analyze (Current_Primitive_Decl); + Current_Insertion_Node := Current_Primitive_Decl; + + Possibly_Asynchronous := + Nkind (Current_Primitive_Spec) = N_Procedure_Specification + and then Could_Be_Asynchronous (Current_Primitive_Spec); + + Current_Primitive_Body := + Build_Subprogram_Calling_Stubs + (Vis_Decl => Current_Primitive_Decl, + Subp_Id => Current_Primitive_Number, + Asynchronous => Possibly_Asynchronous, + Dynamically_Asynchronous => Possibly_Asynchronous, + Stub_Type => Stub_Elements.Stub_Type); + Append_To (Decls, Current_Primitive_Body); + + -- Analyzing the body here would cause the Stub type to be + -- frozen, thus preventing subsequent primitive declarations. + -- For this reason, it will be analyzed later in the + -- regular flow. + + -- Build the receiver stubs + + Current_Receiver_Body := + Build_Subprogram_Receiving_Stubs + (Vis_Decl => Current_Primitive_Decl, + Asynchronous => Possibly_Asynchronous, + Dynamically_Asynchronous => Possibly_Asynchronous, + Stub_Type => Stub_Elements.Stub_Type, + RACW_Type => Stub_Elements.RACW_Type, + Parent_Primitive => Current_Primitive); + + Current_Receiver := + Defining_Unit_Name (Specification (Current_Receiver_Body)); + + Append_To (Decls, Current_Receiver_Body); + + -- Add a case alternative to the receiver + + Append_To (RPC_Receiver_Case_Alternatives, + Make_Case_Statement_Alternative (Loc, + Discrete_Choices => New_List ( + Make_Integer_Literal (Loc, Current_Primitive_Number)), + + Statements => New_List ( + Make_Procedure_Call_Statement (Loc, + Name => + New_Occurrence_Of (Current_Receiver, Loc), + Parameter_Associations => New_List ( + New_Occurrence_Of + (Stub_Elements.RPC_Receiver_Stream, Loc), + New_Occurrence_Of + (Stub_Elements.RPC_Receiver_Result, Loc)))))); + + -- Increment the index of current primitive + + Current_Primitive_Number := Current_Primitive_Number + 1; + end if; + + Next_Elmt (Current_Primitive_Elmt); + end loop; + end if; + + -- Build the case statement and the heart of the subprogram + + Append_To (RPC_Receiver_Case_Alternatives, + Make_Case_Statement_Alternative (Loc, + Discrete_Choices => New_List (Make_Others_Choice (Loc)), + Statements => New_List (Make_Null_Statement (Loc)))); + + RPC_Receiver_Subp_Id := + Make_Defining_Identifier (Loc, New_Internal_Name ('S')); + + RPC_Receiver_Declarations := New_List ( + Make_Object_Declaration (Loc, + Defining_Identifier => RPC_Receiver_Subp_Id, + Object_Definition => + New_Occurrence_Of (RTE (RE_Subprogram_Id), Loc))); + + RPC_Receiver_Statements := New_List ( + Make_Attribute_Reference (Loc, + Prefix => + New_Occurrence_Of (RTE (RE_Subprogram_Id), Loc), + Attribute_Name => + Name_Read, + Expressions => New_List ( + New_Occurrence_Of (Stub_Elements.RPC_Receiver_Stream, Loc), + New_Occurrence_Of (RPC_Receiver_Subp_Id, Loc)))); + + Append_To (RPC_Receiver_Statements, + Make_Case_Statement (Loc, + Expression => + New_Occurrence_Of (RPC_Receiver_Subp_Id, Loc), + Alternatives => RPC_Receiver_Case_Alternatives)); + + RPC_Receiver_Decl := + Make_Subprogram_Body (Loc, + Specification => + Copy_Specification (Loc, + Parent (Stub_Elements.Object_RPC_Receiver)), + Declarations => RPC_Receiver_Declarations, + Handled_Statement_Sequence => + Make_Handled_Sequence_Of_Statements (Loc, + Statements => RPC_Receiver_Statements)); + + Append_To (Decls, RPC_Receiver_Decl); + + -- Do not analyze RPC receiver at this stage since it will otherwise + -- reference subprograms that have not been analyzed yet. It will + -- be analyzed in the regular flow. + + end Add_RACW_Primitive_Declarations_And_Bodies; + + ----------------------------- + -- Add_RACW_Read_Attribute -- + ----------------------------- + + procedure Add_RACW_Read_Attribute + (RACW_Type : in Entity_Id; + Stub_Type : in Entity_Id; + Stub_Type_Access : in Entity_Id; + Declarations : in List_Id) + is + Loc : constant Source_Ptr := Sloc (RACW_Type); + + Proc_Spec : Node_Id; + -- Specification and body of the currently built procedure + + Proc_Body_Spec : Node_Id; + + Proc_Decl : Node_Id; + Attr_Decl : Node_Id; + + Body_Node : Node_Id; + + Decls : List_Id; + Statements : List_Id; + Local_Statements : List_Id; + Remote_Statements : List_Id; + -- Various parts of the procedure + + Procedure_Name : constant Name_Id := + New_Internal_Name ('R'); + Source_Partition : constant Entity_Id := + Make_Defining_Identifier + (Loc, New_Internal_Name ('P')); + Source_Receiver : constant Entity_Id := + Make_Defining_Identifier + (Loc, New_Internal_Name ('S')); + Source_Address : constant Entity_Id := + Make_Defining_Identifier + (Loc, New_Internal_Name ('P')); + Stream_Parameter : constant Entity_Id := + Make_Defining_Identifier + (Loc, New_Internal_Name ('S')); + Result : constant Entity_Id := + Make_Defining_Identifier + (Loc, New_Internal_Name ('P')); + Stubbed_Result : constant Entity_Id := + Make_Defining_Identifier + (Loc, New_Internal_Name ('S')); + Asynchronous_Flag : constant Entity_Id := + Make_Defining_Identifier + (Loc, New_Internal_Name ('S')); + Asynchronous_Node : constant Node_Id := + New_Occurrence_Of (Standard_False, Loc); + + begin + -- Declare the asynchronous flag. This flag will be changed to True + -- whenever it is known that the RACW type is asynchronous. Also, the + -- node gets stored since it may be rewritten when we process the + -- asynchronous pragma. + + Append_To (Declarations, + Make_Object_Declaration (Loc, + Defining_Identifier => Asynchronous_Flag, + Constant_Present => True, + Object_Definition => New_Occurrence_Of (Standard_Boolean, Loc), + Expression => Asynchronous_Node)); + + Asynchronous_Flags_Table.Set (RACW_Type, Asynchronous_Node); + + -- Object declarations + + Decls := New_List ( + Make_Object_Declaration (Loc, + Defining_Identifier => Source_Partition, + Object_Definition => + New_Occurrence_Of (RTE (RE_Partition_ID), Loc)), + + Make_Object_Declaration (Loc, + Defining_Identifier => Source_Receiver, + Object_Definition => + New_Occurrence_Of (RTE (RE_Unsigned_64), Loc)), + + Make_Object_Declaration (Loc, + Defining_Identifier => Source_Address, + Object_Definition => + New_Occurrence_Of (RTE (RE_Unsigned_64), Loc)), + + Make_Object_Declaration (Loc, + Defining_Identifier => Stubbed_Result, + Object_Definition => + New_Occurrence_Of (Stub_Type_Access, Loc))); + + -- Read the source Partition_ID and RPC_Receiver from incoming stream + + Statements := New_List ( + Make_Attribute_Reference (Loc, + Prefix => + New_Occurrence_Of (RTE (RE_Partition_ID), Loc), + Attribute_Name => Name_Read, + Expressions => New_List ( + New_Occurrence_Of (Stream_Parameter, Loc), + New_Occurrence_Of (Source_Partition, Loc))), + + Make_Attribute_Reference (Loc, + Prefix => + New_Occurrence_Of (RTE (RE_Unsigned_64), Loc), + Attribute_Name => + Name_Read, + Expressions => New_List ( + New_Occurrence_Of (Stream_Parameter, Loc), + New_Occurrence_Of (Source_Receiver, Loc))), + + Make_Attribute_Reference (Loc, + Prefix => + New_Occurrence_Of (RTE (RE_Unsigned_64), Loc), + Attribute_Name => + Name_Read, + Expressions => New_List ( + New_Occurrence_Of (Stream_Parameter, Loc), + New_Occurrence_Of (Source_Address, Loc)))); + + -- If the Address is Null_Address, then return a null object + + Append_To (Statements, + Make_Implicit_If_Statement (RACW_Type, + Condition => + Make_Op_Eq (Loc, + Left_Opnd => New_Occurrence_Of (Source_Address, Loc), + Right_Opnd => Make_Integer_Literal (Loc, Uint_0)), + Then_Statements => New_List ( + Make_Assignment_Statement (Loc, + Name => New_Occurrence_Of (Result, Loc), + Expression => Make_Null (Loc)), + Make_Return_Statement (Loc)))); + + -- If the RACW denotes an object created on the current partition, then + -- Local_Statements will be executed. The real object will be used. + + Local_Statements := New_List ( + Make_Assignment_Statement (Loc, + Name => New_Occurrence_Of (Result, Loc), + Expression => + Unchecked_Convert_To (RACW_Type, + OK_Convert_To (RTE (RE_Address), + New_Occurrence_Of (Source_Address, Loc))))); + + -- If the object is located on another partition, then a stub object + -- will be created with all the information needed to rebuild the + -- real object at the other end. + + Remote_Statements := New_List ( + + Make_Assignment_Statement (Loc, + Name => New_Occurrence_Of (Stubbed_Result, Loc), + Expression => + Make_Allocator (Loc, + New_Occurrence_Of (Stub_Type, Loc))), + + Make_Assignment_Statement (Loc, + Name => Make_Selected_Component (Loc, + Prefix => New_Occurrence_Of (Stubbed_Result, Loc), + Selector_Name => Make_Identifier (Loc, Name_Origin)), + Expression => + New_Occurrence_Of (Source_Partition, Loc)), + + Make_Assignment_Statement (Loc, + Name => Make_Selected_Component (Loc, + Prefix => New_Occurrence_Of (Stubbed_Result, Loc), + Selector_Name => Make_Identifier (Loc, Name_Receiver)), + Expression => + New_Occurrence_Of (Source_Receiver, Loc)), + + Make_Assignment_Statement (Loc, + Name => Make_Selected_Component (Loc, + Prefix => New_Occurrence_Of (Stubbed_Result, Loc), + Selector_Name => Make_Identifier (Loc, Name_Addr)), + Expression => + New_Occurrence_Of (Source_Address, Loc))); + + Append_To (Remote_Statements, + Make_Assignment_Statement (Loc, + Name => Make_Selected_Component (Loc, + Prefix => New_Occurrence_Of (Stubbed_Result, Loc), + Selector_Name => Make_Identifier (Loc, Name_Asynchronous)), + Expression => + New_Occurrence_Of (Asynchronous_Flag, Loc))); + + Append_To (Remote_Statements, + Make_Procedure_Call_Statement (Loc, + Name => + New_Occurrence_Of (RTE (RE_Get_Unique_Remote_Pointer), Loc), + Parameter_Associations => New_List ( + Unchecked_Convert_To (RTE (RE_RACW_Stub_Type_Access), + New_Occurrence_Of (Stubbed_Result, Loc))))); + + Append_To (Remote_Statements, + Make_Assignment_Statement (Loc, + Name => New_Occurrence_Of (Result, Loc), + Expression => Unchecked_Convert_To (RACW_Type, + New_Occurrence_Of (Stubbed_Result, Loc)))); + + -- Distinguish between the local and remote cases, and execute the + -- appropriate piece of code. + + Append_To (Statements, + Make_Implicit_If_Statement (RACW_Type, + Condition => + Make_Op_Eq (Loc, + Left_Opnd => + Make_Function_Call (Loc, + Name => + New_Occurrence_Of (RTE (RE_Get_Local_Partition_Id), Loc)), + Right_Opnd => New_Occurrence_Of (Source_Partition, Loc)), + Then_Statements => Local_Statements, + Else_Statements => Remote_Statements)); + + Proc_Spec := + Make_Procedure_Specification (Loc, + Defining_Unit_Name => + Make_Defining_Identifier (Loc, Procedure_Name), + + Parameter_Specifications => New_List ( + Make_Parameter_Specification (Loc, + Defining_Identifier => Stream_Parameter, + Parameter_Type => + Make_Access_Definition (Loc, + Subtype_Mark => + Make_Attribute_Reference (Loc, + Prefix => + New_Occurrence_Of (RTE (RE_Root_Stream_Type), Loc), + Attribute_Name => + Name_Class))), + + Make_Parameter_Specification (Loc, + Defining_Identifier => Result, + Out_Present => True, + Parameter_Type => + New_Occurrence_Of (RACW_Type, Loc)))); + + Proc_Body_Spec := + Make_Procedure_Specification (Loc, + Defining_Unit_Name => + Make_Defining_Identifier (Loc, Procedure_Name), + + Parameter_Specifications => New_List ( + Make_Parameter_Specification (Loc, + Defining_Identifier => + Make_Defining_Identifier (Loc, Chars (Stream_Parameter)), + Parameter_Type => + Make_Access_Definition (Loc, + Subtype_Mark => + Make_Attribute_Reference (Loc, + Prefix => + New_Occurrence_Of (RTE (RE_Root_Stream_Type), Loc), + Attribute_Name => + Name_Class))), + + Make_Parameter_Specification (Loc, + Defining_Identifier => + Make_Defining_Identifier (Loc, Chars (Result)), + Out_Present => True, + Parameter_Type => + New_Occurrence_Of (RACW_Type, Loc)))); + + Body_Node := + Make_Subprogram_Body (Loc, + Specification => Proc_Body_Spec, + Declarations => Decls, + Handled_Statement_Sequence => + Make_Handled_Sequence_Of_Statements (Loc, + Statements => Statements)); + + Proc_Decl := + Make_Subprogram_Declaration (Loc, Specification => Proc_Spec); + + Attr_Decl := + Make_Attribute_Definition_Clause (Loc, + Name => New_Occurrence_Of (RACW_Type, Loc), + Chars => Name_Read, + Expression => + New_Occurrence_Of (Defining_Unit_Name (Proc_Spec), Loc)); + + Insert_After (Declaration_Node (RACW_Type), Proc_Decl); + Insert_After (Proc_Decl, Attr_Decl); + Append_To (Declarations, Body_Node); + end Add_RACW_Read_Attribute; + + ------------------------------------ + -- Add_RACW_Read_Write_Attributes -- + ------------------------------------ + + procedure Add_RACW_Read_Write_Attributes + (RACW_Type : in Entity_Id; + Stub_Type : in Entity_Id; + Stub_Type_Access : in Entity_Id; + Object_RPC_Receiver : in Entity_Id; + Declarations : in List_Id) + is + begin + Add_RACW_Write_Attribute + (RACW_Type => RACW_Type, + Stub_Type => Stub_Type, + Stub_Type_Access => Stub_Type_Access, + Object_RPC_Receiver => Object_RPC_Receiver, + Declarations => Declarations); + + Add_RACW_Read_Attribute + (RACW_Type => RACW_Type, + Stub_Type => Stub_Type, + Stub_Type_Access => Stub_Type_Access, + Declarations => Declarations); + end Add_RACW_Read_Write_Attributes; + + ------------------------------ + -- Add_RACW_Write_Attribute -- + ------------------------------ + + procedure Add_RACW_Write_Attribute + (RACW_Type : in Entity_Id; + Stub_Type : in Entity_Id; + Stub_Type_Access : in Entity_Id; + Object_RPC_Receiver : in Entity_Id; + Declarations : in List_Id) + is + Loc : constant Source_Ptr := Sloc (RACW_Type); + + Proc_Spec : Node_Id; + + Proc_Body_Spec : Node_Id; + + Body_Node : Node_Id; + + Proc_Decl : Node_Id; + Attr_Decl : Node_Id; + + Statements : List_Id; + Local_Statements : List_Id; + Remote_Statements : List_Id; + Null_Statements : List_Id; + + Procedure_Name : constant Name_Id := New_Internal_Name ('R'); + + Stream_Parameter : constant Entity_Id := + Make_Defining_Identifier + (Loc, New_Internal_Name ('S')); + + Object : constant Entity_Id := + Make_Defining_Identifier (Loc, New_Internal_Name ('P')); + + begin + -- Build the code fragment corresponding to the marshalling of a + -- local object. + + Local_Statements := New_List ( + + Pack_Entity_Into_Stream_Access (Loc, + Stream => Stream_Parameter, + Object => RTE (RE_Get_Local_Partition_Id)), + + Pack_Node_Into_Stream_Access (Loc, + Stream => Stream_Parameter, + Object => OK_Convert_To (RTE (RE_Unsigned_64), + Make_Attribute_Reference (Loc, + Prefix => New_Occurrence_Of (Object_RPC_Receiver, Loc), + Attribute_Name => Name_Address)), + Etyp => RTE (RE_Unsigned_64)), + + Pack_Node_Into_Stream_Access (Loc, + Stream => Stream_Parameter, + Object => OK_Convert_To (RTE (RE_Unsigned_64), + Make_Attribute_Reference (Loc, + Prefix => + Make_Explicit_Dereference (Loc, + Prefix => New_Occurrence_Of (Object, Loc)), + Attribute_Name => Name_Address)), + Etyp => RTE (RE_Unsigned_64))); + + -- Build the code fragment corresponding to the marshalling of + -- a remote object. + + Remote_Statements := New_List ( + + Pack_Node_Into_Stream_Access (Loc, + Stream => Stream_Parameter, + Object => + Make_Selected_Component (Loc, + Prefix => Unchecked_Convert_To (Stub_Type_Access, + New_Occurrence_Of (Object, Loc)), + Selector_Name => + Make_Identifier (Loc, Name_Origin)), + Etyp => RTE (RE_Partition_ID)), + + Pack_Node_Into_Stream_Access (Loc, + Stream => Stream_Parameter, + Object => + Make_Selected_Component (Loc, + Prefix => Unchecked_Convert_To (Stub_Type_Access, + New_Occurrence_Of (Object, Loc)), + Selector_Name => + Make_Identifier (Loc, Name_Receiver)), + Etyp => RTE (RE_Unsigned_64)), + + Pack_Node_Into_Stream_Access (Loc, + Stream => Stream_Parameter, + Object => + Make_Selected_Component (Loc, + Prefix => Unchecked_Convert_To (Stub_Type_Access, + New_Occurrence_Of (Object, Loc)), + Selector_Name => + Make_Identifier (Loc, Name_Addr)), + Etyp => RTE (RE_Unsigned_64))); + + -- Build the code fragment corresponding to the marshalling of a null + -- object. + + Null_Statements := New_List ( + + Pack_Entity_Into_Stream_Access (Loc, + Stream => Stream_Parameter, + Object => RTE (RE_Get_Local_Partition_Id)), + + Pack_Node_Into_Stream_Access (Loc, + Stream => Stream_Parameter, + Object => OK_Convert_To (RTE (RE_Unsigned_64), + Make_Attribute_Reference (Loc, + Prefix => New_Occurrence_Of (Object_RPC_Receiver, Loc), + Attribute_Name => Name_Address)), + Etyp => RTE (RE_Unsigned_64)), + + Pack_Node_Into_Stream_Access (Loc, + Stream => Stream_Parameter, + Object => Make_Integer_Literal (Loc, Uint_0), + Etyp => RTE (RE_Unsigned_64))); + + Statements := New_List ( + Make_Implicit_If_Statement (RACW_Type, + Condition => + Make_Op_Eq (Loc, + Left_Opnd => New_Occurrence_Of (Object, Loc), + Right_Opnd => Make_Null (Loc)), + Then_Statements => Null_Statements, + Elsif_Parts => New_List ( + Make_Elsif_Part (Loc, + Condition => + Make_Op_Eq (Loc, + Left_Opnd => + Make_Attribute_Reference (Loc, + Prefix => New_Occurrence_Of (Object, Loc), + Attribute_Name => Name_Tag), + Right_Opnd => + Make_Attribute_Reference (Loc, + Prefix => New_Occurrence_Of (Stub_Type, Loc), + Attribute_Name => Name_Tag)), + Then_Statements => Remote_Statements)), + Else_Statements => Local_Statements)); + + Proc_Spec := + Make_Procedure_Specification (Loc, + Defining_Unit_Name => + Make_Defining_Identifier (Loc, Procedure_Name), + + Parameter_Specifications => New_List ( + Make_Parameter_Specification (Loc, + Defining_Identifier => Stream_Parameter, + Parameter_Type => + Make_Access_Definition (Loc, + Subtype_Mark => + Make_Attribute_Reference (Loc, + Prefix => + New_Occurrence_Of (RTE (RE_Root_Stream_Type), Loc), + Attribute_Name => + Name_Class))), + + Make_Parameter_Specification (Loc, + Defining_Identifier => Object, + In_Present => True, + Parameter_Type => + New_Occurrence_Of (RACW_Type, Loc)))); + + Proc_Decl := + Make_Subprogram_Declaration (Loc, Specification => Proc_Spec); + + Attr_Decl := + Make_Attribute_Definition_Clause (Loc, + Name => New_Occurrence_Of (RACW_Type, Loc), + Chars => Name_Write, + Expression => + New_Occurrence_Of (Defining_Unit_Name (Proc_Spec), Loc)); + + Proc_Body_Spec := + Make_Procedure_Specification (Loc, + Defining_Unit_Name => + Make_Defining_Identifier (Loc, Procedure_Name), + + Parameter_Specifications => New_List ( + Make_Parameter_Specification (Loc, + Defining_Identifier => + Make_Defining_Identifier (Loc, Chars (Stream_Parameter)), + Parameter_Type => + Make_Access_Definition (Loc, + Subtype_Mark => + Make_Attribute_Reference (Loc, + Prefix => + New_Occurrence_Of (RTE (RE_Root_Stream_Type), Loc), + Attribute_Name => + Name_Class))), + + Make_Parameter_Specification (Loc, + Defining_Identifier => + Make_Defining_Identifier (Loc, Chars (Object)), + In_Present => True, + Parameter_Type => + New_Occurrence_Of (RACW_Type, Loc)))); + + Body_Node := + Make_Subprogram_Body (Loc, + Specification => Proc_Body_Spec, + Declarations => No_List, + Handled_Statement_Sequence => + Make_Handled_Sequence_Of_Statements (Loc, + Statements => Statements)); + + Insert_After (Declaration_Node (RACW_Type), Proc_Decl); + Insert_After (Proc_Decl, Attr_Decl); + Append_To (Declarations, Body_Node); + end Add_RACW_Write_Attribute; + + ------------------------------ + -- Add_RAS_Access_Attribute -- + ------------------------------ + + procedure Add_RAS_Access_Attribute (N : in Node_Id) is + Ras_Type : constant Entity_Id := Defining_Identifier (N); + Fat_Type : constant Entity_Id := Equivalent_Type (Ras_Type); + -- Ras_Type is the access to subprogram type while Fat_Type points to + -- the record type corresponding to a remote access to subprogram type. + + Proc_Decls : constant List_Id := New_List; + Proc_Statements : constant List_Id := New_List; + + Proc_Spec : Node_Id; + Proc_Body : Node_Id; + + Proc : Node_Id; + + Param : Node_Id; + Package_Name : Node_Id; + Subp_Id : Node_Id; + Asynchronous : Node_Id; + Return_Value : Node_Id; + + Loc : constant Source_Ptr := Sloc (N); + + procedure Set_Field (Field_Name : in Name_Id; Value : in Node_Id); + -- Set a field name for the return value + + procedure Set_Field (Field_Name : in Name_Id; Value : in Node_Id) + is + begin + Append_To (Proc_Statements, + Make_Assignment_Statement (Loc, + Name => + Make_Selected_Component (Loc, + Prefix => New_Occurrence_Of (Return_Value, Loc), + Selector_Name => Make_Identifier (Loc, Field_Name)), + Expression => Value)); + end Set_Field; + + -- Start of processing for Add_RAS_Access_Attribute + + begin + Param := Make_Defining_Identifier (Loc, New_Internal_Name ('P')); + Package_Name := Make_Defining_Identifier (Loc, New_Internal_Name ('S')); + Subp_Id := Make_Defining_Identifier (Loc, New_Internal_Name ('N')); + Asynchronous := Make_Defining_Identifier (Loc, New_Internal_Name ('B')); + Return_Value := Make_Defining_Identifier (Loc, New_Internal_Name ('P')); + + -- Create the object which will be returned of type Fat_Type + + Append_To (Proc_Decls, + Make_Object_Declaration (Loc, + Defining_Identifier => Return_Value, + Object_Definition => + New_Occurrence_Of (Fat_Type, Loc))); + + -- Initialize the fields of the record type with the appropriate data + + Set_Field (Name_Ras, + OK_Convert_To (RTE (RE_Unsigned_64), New_Occurrence_Of (Param, Loc))); + + Set_Field (Name_Origin, + Unchecked_Convert_To (Standard_Integer, + Make_Function_Call (Loc, + Name => + New_Occurrence_Of (RTE (RE_Get_Active_Partition_Id), Loc), + Parameter_Associations => New_List ( + New_Occurrence_Of (Package_Name, Loc))))); + + Set_Field (Name_Receiver, + Make_Function_Call (Loc, + Name => + New_Occurrence_Of (RTE (RE_Get_RCI_Package_Receiver), Loc), + Parameter_Associations => New_List ( + New_Occurrence_Of (Package_Name, Loc)))); + + Set_Field (Name_Subp_Id, + New_Occurrence_Of (Subp_Id, Loc)); + + Set_Field (Name_Async, + New_Occurrence_Of (Asynchronous, Loc)); + + -- Return the newly created value + + Append_To (Proc_Statements, + Make_Return_Statement (Loc, + Expression => + New_Occurrence_Of (Return_Value, Loc))); + + Proc := Make_Defining_Identifier (Loc, Name_uRAS_Access); + + Proc_Spec := + Make_Function_Specification (Loc, + Defining_Unit_Name => Proc, + Parameter_Specifications => New_List ( + Make_Parameter_Specification (Loc, + Defining_Identifier => Param, + Parameter_Type => + New_Occurrence_Of (RTE (RE_Address), Loc)), + + Make_Parameter_Specification (Loc, + Defining_Identifier => Package_Name, + Parameter_Type => + New_Occurrence_Of (Standard_String, Loc)), + + Make_Parameter_Specification (Loc, + Defining_Identifier => Subp_Id, + Parameter_Type => + New_Occurrence_Of (Standard_Natural, Loc)), + + Make_Parameter_Specification (Loc, + Defining_Identifier => Asynchronous, + Parameter_Type => + New_Occurrence_Of (Standard_Boolean, Loc))), + + Subtype_Mark => + New_Occurrence_Of (Fat_Type, Loc)); + + -- Set the kind and return type of the function to prevent ambiguities + -- between Ras_Type and Fat_Type in subsequent analysis. + + Set_Ekind (Proc, E_Function); + Set_Etype (Proc, New_Occurrence_Of (Fat_Type, Loc)); + + Proc_Body := + Make_Subprogram_Body (Loc, + Specification => Proc_Spec, + Declarations => Proc_Decls, + Handled_Statement_Sequence => + Make_Handled_Sequence_Of_Statements (Loc, + Statements => Proc_Statements)); + + Set_TSS (Fat_Type, Proc); + + end Add_RAS_Access_Attribute; + + ----------------------------------- + -- Add_RAS_Dereference_Attribute -- + ----------------------------------- + + procedure Add_RAS_Dereference_Attribute (N : in Node_Id) is + Loc : constant Source_Ptr := Sloc (N); + + Type_Def : constant Node_Id := Type_Definition (N); + + Ras_Type : constant Entity_Id := Defining_Identifier (N); + + Fat_Type : constant Entity_Id := Equivalent_Type (Ras_Type); + + Proc_Decls : constant List_Id := New_List; + Proc_Statements : constant List_Id := New_List; + + Inner_Decls : constant List_Id := New_List; + Inner_Statements : constant List_Id := New_List; + + Direct_Statements : constant List_Id := New_List; + + Proc : Node_Id; + + Proc_Spec : Node_Id; + Proc_Body : Node_Id; + + Param_Specs : constant List_Id := New_List; + Param_Assoc : constant List_Id := New_List; + + Pointer : Node_Id; + + Converted_Ras : Node_Id; + Target_Partition : Node_Id; + RPC_Receiver : Node_Id; + Subprogram_Id : Node_Id; + Asynchronous : Node_Id; + + Is_Function : constant Boolean := + Nkind (Type_Def) = N_Access_Function_Definition; + + Spec : constant Node_Id := Type_Def; + + Current_Parameter : Node_Id; + + begin + -- The way to do it is test if the Ras field is non-null and then if + -- the Origin field is equal to the current partition ID (which is in + -- fact Current_Package'Partition_ID). If this is the case, then it + -- is safe to dereference the Ras field directly rather than + -- performing a remote call. + + Pointer := + Make_Defining_Identifier (Loc, New_Internal_Name ('P')); + + Target_Partition := + Make_Defining_Identifier (Loc, New_Internal_Name ('P')); + + Append_To (Proc_Decls, + Make_Object_Declaration (Loc, + Defining_Identifier => Target_Partition, + Constant_Present => True, + Object_Definition => + New_Occurrence_Of (RTE (RE_Partition_ID), Loc), + Expression => + Unchecked_Convert_To (RTE (RE_Partition_ID), + Make_Selected_Component (Loc, + Prefix => + New_Occurrence_Of (Pointer, Loc), + Selector_Name => + Make_Identifier (Loc, Name_Origin))))); + + RPC_Receiver := + Make_Selected_Component (Loc, + Prefix => + New_Occurrence_Of (Pointer, Loc), + Selector_Name => + Make_Identifier (Loc, Name_Receiver)); + + Subprogram_Id := + Unchecked_Convert_To (RTE (RE_Subprogram_Id), + Make_Selected_Component (Loc, + Prefix => + New_Occurrence_Of (Pointer, Loc), + Selector_Name => + Make_Identifier (Loc, Name_Subp_Id))); + + -- A function is never asynchronous. A procedure may or may not be + -- asynchronous depending on whether a pragma Asynchronous applies + -- on it. Since a RAST may point onto various subprograms, this is + -- only known at runtime so both versions (synchronous and asynchronous) + -- must be built every times it is not a function. + + if Is_Function then + Asynchronous := Empty; + + else + Asynchronous := + Make_Selected_Component (Loc, + Prefix => + New_Occurrence_Of (Pointer, Loc), + Selector_Name => + Make_Identifier (Loc, Name_Async)); + + end if; + + if Present (Parameter_Specifications (Type_Def)) then + Current_Parameter := First (Parameter_Specifications (Type_Def)); + + while Current_Parameter /= Empty loop + Append_To (Param_Specs, + Make_Parameter_Specification (Loc, + Defining_Identifier => + Make_Defining_Identifier (Loc, + Chars => Chars (Defining_Identifier (Current_Parameter))), + In_Present => In_Present (Current_Parameter), + Out_Present => Out_Present (Current_Parameter), + Parameter_Type => + New_Occurrence_Of + (Etype (Parameter_Type (Current_Parameter)), Loc), + Expression => + New_Copy_Tree (Expression (Current_Parameter)))); + + Append_To (Param_Assoc, + Make_Identifier (Loc, + Chars => Chars (Defining_Identifier (Current_Parameter)))); + + Next (Current_Parameter); + end loop; + end if; + + Proc := Make_Defining_Identifier (Loc, Name_uRAS_Dereference); + + if Is_Function then + Proc_Spec := + Make_Function_Specification (Loc, + Defining_Unit_Name => Proc, + Parameter_Specifications => Param_Specs, + Subtype_Mark => + New_Occurrence_Of ( + Entity (Subtype_Mark (Spec)), Loc)); + + Set_Ekind (Proc, E_Function); + + Set_Etype (Proc, + New_Occurrence_Of (Entity (Subtype_Mark (Spec)), Loc)); + + else + Proc_Spec := + Make_Procedure_Specification (Loc, + Defining_Unit_Name => Proc, + Parameter_Specifications => Param_Specs); + + Set_Ekind (Proc, E_Procedure); + Set_Etype (Proc, Standard_Void_Type); + end if; + + -- Build the calling stubs for the dereference of the RAS + + Build_General_Calling_Stubs + (Decls => Inner_Decls, + Statements => Inner_Statements, + Target_Partition => Target_Partition, + RPC_Receiver => RPC_Receiver, + Subprogram_Id => Subprogram_Id, + Asynchronous => Asynchronous, + Is_Known_Non_Asynchronous => Is_Function, + Is_Function => Is_Function, + Spec => Proc_Spec, + Nod => N); + + Converted_Ras := + Unchecked_Convert_To (Ras_Type, + OK_Convert_To (RTE (RE_Address), + Make_Selected_Component (Loc, + Prefix => New_Occurrence_Of (Pointer, Loc), + Selector_Name => Make_Identifier (Loc, Name_Ras)))); + + if Is_Function then + Append_To (Direct_Statements, + Make_Return_Statement (Loc, + Expression => + Make_Function_Call (Loc, + Name => + Make_Explicit_Dereference (Loc, + Prefix => Converted_Ras), + Parameter_Associations => Param_Assoc))); + + else + Append_To (Direct_Statements, + Make_Procedure_Call_Statement (Loc, + Name => + Make_Explicit_Dereference (Loc, + Prefix => Converted_Ras), + Parameter_Associations => Param_Assoc)); + end if; + + Prepend_To (Param_Specs, + Make_Parameter_Specification (Loc, + Defining_Identifier => Pointer, + In_Present => True, + Parameter_Type => + New_Occurrence_Of (Fat_Type, Loc))); + + Append_To (Proc_Statements, + Make_Implicit_If_Statement (N, + Condition => + Make_And_Then (Loc, + Left_Opnd => + Make_Op_Ne (Loc, + Left_Opnd => + Make_Selected_Component (Loc, + Prefix => New_Occurrence_Of (Pointer, Loc), + Selector_Name => Make_Identifier (Loc, Name_Ras)), + Right_Opnd => + Make_Integer_Literal (Loc, Uint_0)), + + Right_Opnd => + Make_Op_Eq (Loc, + Left_Opnd => + New_Occurrence_Of (Target_Partition, Loc), + Right_Opnd => + Make_Function_Call (Loc, + New_Occurrence_Of ( + RTE (RE_Get_Local_Partition_Id), Loc)))), + + Then_Statements => + Direct_Statements, + + Else_Statements => New_List ( + Make_Block_Statement (Loc, + Declarations => Inner_Decls, + Handled_Statement_Sequence => + Make_Handled_Sequence_Of_Statements (Loc, + Statements => Inner_Statements))))); + + Proc_Body := + Make_Subprogram_Body (Loc, + Specification => Proc_Spec, + Declarations => Proc_Decls, + Handled_Statement_Sequence => + Make_Handled_Sequence_Of_Statements (Loc, + Statements => Proc_Statements)); + + Set_TSS (Fat_Type, Defining_Unit_Name (Proc_Spec)); + + end Add_RAS_Dereference_Attribute; + + ----------------------- + -- Add_RAST_Features -- + ----------------------- + + procedure Add_RAST_Features (Vis_Decl : Node_Id) is + begin + -- Do not add attributes more than once in any case. This should + -- be replaced by an assert or this comment removed if we decide + -- that this is normal to be called several times ??? + + if Present (TSS (Equivalent_Type (Defining_Identifier + (Vis_Decl)), Name_uRAS_Access)) + then + return; + end if; + + Add_RAS_Dereference_Attribute (Vis_Decl); + Add_RAS_Access_Attribute (Vis_Decl); + end Add_RAST_Features; + + ----------------------------------------- + -- Add_Receiving_Stubs_To_Declarations -- + ----------------------------------------- + + procedure Add_Receiving_Stubs_To_Declarations + (Pkg_Spec : in Node_Id; + Decls : in List_Id) + is + Loc : constant Source_Ptr := Sloc (Pkg_Spec); + + Stream_Parameter : Node_Id; + Result_Parameter : Node_Id; + + Pkg_RPC_Receiver : Node_Id; + Pkg_RPC_Receiver_Spec : Node_Id; + Pkg_RPC_Receiver_Formals : List_Id; + Pkg_RPC_Receiver_Decls : List_Id; + Pkg_RPC_Receiver_Statements : List_Id; + Pkg_RPC_Receiver_Cases : List_Id := New_List; + Pkg_RPC_Receiver_Body : Node_Id; + -- A Pkg_RPC_Receiver is built to decode the request + + Subp_Id : Node_Id; + -- Subprogram_Id as read from the incoming stream + + Current_Declaration : Node_Id; + Current_Subprogram_Number : Int := 0; + Current_Stubs : Node_Id; + + Actuals : List_Id; + + Dummy_Register_Name : Name_Id; + Dummy_Register_Spec : Node_Id; + Dummy_Register_Decl : Node_Id; + Dummy_Register_Body : Node_Id; + + begin + -- Building receiving stubs consist in several operations: + + -- - a package RPC receiver must be built. This subprogram + -- will get a Subprogram_Id from the incoming stream + -- and will dispatch the call to the right subprogram + + -- - a receiving stub for any subprogram visible in the package + -- spec. This stub will read all the parameters from the stream, + -- and put the result as well as the exception occurrence in the + -- output stream + + -- - a dummy package with an empty spec and a body made of an + -- elaboration part, whose job is to register the receiving + -- part of this RCI package on the name server. This is done + -- by calling System.Partition_Interface.Register_Receiving_Stub + + Stream_Parameter := + Make_Defining_Identifier (Loc, New_Internal_Name ('S')); + Result_Parameter := + Make_Defining_Identifier (Loc, New_Internal_Name ('R')); + Subp_Id := + Make_Defining_Identifier (Loc, New_Internal_Name ('P')); + + Pkg_RPC_Receiver := + Make_Defining_Identifier (Loc, New_Internal_Name ('P')); + + -- The parameters of the package RPC receiver are made of two + -- streams, an input one and an output one. + + Pkg_RPC_Receiver_Formals := New_List ( + Make_Parameter_Specification (Loc, + Defining_Identifier => Stream_Parameter, + Parameter_Type => + Make_Access_Definition (Loc, + Subtype_Mark => + New_Occurrence_Of (RTE (RE_Params_Stream_Type), Loc))), + Make_Parameter_Specification (Loc, + Defining_Identifier => Result_Parameter, + Parameter_Type => + Make_Access_Definition (Loc, + Subtype_Mark => + New_Occurrence_Of (RTE (RE_Params_Stream_Type), Loc)))); + + Pkg_RPC_Receiver_Spec := + Make_Procedure_Specification (Loc, + Defining_Unit_Name => Pkg_RPC_Receiver, + Parameter_Specifications => Pkg_RPC_Receiver_Formals); + + Pkg_RPC_Receiver_Decls := New_List ( + Make_Object_Declaration (Loc, + Defining_Identifier => Subp_Id, + Object_Definition => + New_Occurrence_Of (RTE (RE_Subprogram_Id), Loc))); + + Pkg_RPC_Receiver_Statements := New_List ( + Make_Attribute_Reference (Loc, + Prefix => + New_Occurrence_Of (RTE (RE_Subprogram_Id), Loc), + Attribute_Name => + Name_Read, + Expressions => New_List ( + New_Occurrence_Of (Stream_Parameter, Loc), + New_Occurrence_Of (Subp_Id, Loc)))); + + -- For each subprogram, the receiving stub will be built and a + -- case statement will be made on the Subprogram_Id to dispatch + -- to the right subprogram. + + Current_Declaration := First (Visible_Declarations (Pkg_Spec)); + + while Current_Declaration /= Empty loop + + if Nkind (Current_Declaration) = N_Subprogram_Declaration + and then Comes_From_Source (Current_Declaration) + then + pragma Assert (Current_Subprogram_Number = + Get_Subprogram_Id (Defining_Unit_Name (Specification ( + Current_Declaration)))); + + Current_Stubs := + Build_Subprogram_Receiving_Stubs + (Vis_Decl => Current_Declaration, + Asynchronous => + Nkind (Specification (Current_Declaration)) = + N_Procedure_Specification + and then Is_Asynchronous + (Defining_Unit_Name (Specification + (Current_Declaration)))); + + Append_To (Decls, Current_Stubs); + + Analyze (Current_Stubs); + + Actuals := New_List (New_Occurrence_Of (Stream_Parameter, Loc)); + + if Nkind (Specification (Current_Declaration)) + = N_Function_Specification + or else + not Is_Asynchronous ( + Defining_Entity (Specification (Current_Declaration))) + then + -- An asynchronous procedure does not want an output parameter + -- since no result and no exception will ever be returned. + + Append_To (Actuals, + New_Occurrence_Of (Result_Parameter, Loc)); + + end if; + + Append_To (Pkg_RPC_Receiver_Cases, + Make_Case_Statement_Alternative (Loc, + Discrete_Choices => + New_List ( + Make_Integer_Literal (Loc, Current_Subprogram_Number)), + + Statements => + New_List ( + Make_Procedure_Call_Statement (Loc, + Name => + New_Occurrence_Of ( + Defining_Entity (Current_Stubs), Loc), + Parameter_Associations => + Actuals)))); + + Current_Subprogram_Number := Current_Subprogram_Number + 1; + end if; + + Next (Current_Declaration); + end loop; + + -- If we receive an invalid Subprogram_Id, it is best to do nothing + -- rather than raising an exception since we do not want someone + -- to crash a remote partition by sending invalid subprogram ids. + -- This is consistent with the other parts of the case statement + -- since even in presence of incorrect parameters in the stream, + -- every exception will be caught and (if the subprogram is not an + -- APC) put into the result stream and sent away. + + Append_To (Pkg_RPC_Receiver_Cases, + Make_Case_Statement_Alternative (Loc, + Discrete_Choices => + New_List (Make_Others_Choice (Loc)), + Statements => + New_List (Make_Null_Statement (Loc)))); + + Append_To (Pkg_RPC_Receiver_Statements, + Make_Case_Statement (Loc, + Expression => + New_Occurrence_Of (Subp_Id, Loc), + Alternatives => Pkg_RPC_Receiver_Cases)); + + Pkg_RPC_Receiver_Body := + Make_Subprogram_Body (Loc, + Specification => Pkg_RPC_Receiver_Spec, + Declarations => Pkg_RPC_Receiver_Decls, + Handled_Statement_Sequence => + Make_Handled_Sequence_Of_Statements (Loc, + Statements => Pkg_RPC_Receiver_Statements)); + + Append_To (Decls, Pkg_RPC_Receiver_Body); + Analyze (Pkg_RPC_Receiver_Body); + + -- Construction of the dummy package used to register the package + -- receiving stubs on the nameserver. + + Dummy_Register_Name := New_Internal_Name ('P'); + + Dummy_Register_Spec := + Make_Package_Specification (Loc, + Defining_Unit_Name => + Make_Defining_Identifier (Loc, Dummy_Register_Name), + Visible_Declarations => No_List, + End_Label => Empty); + + Dummy_Register_Decl := + Make_Package_Declaration (Loc, + Specification => Dummy_Register_Spec); + + Append_To (Decls, + Dummy_Register_Decl); + Analyze (Dummy_Register_Decl); + + Dummy_Register_Body := + Make_Package_Body (Loc, + Defining_Unit_Name => + Make_Defining_Identifier (Loc, Dummy_Register_Name), + Declarations => No_List, + + Handled_Statement_Sequence => + Make_Handled_Sequence_Of_Statements (Loc, + Statements => New_List ( + Make_Procedure_Call_Statement (Loc, + Name => + New_Occurrence_Of (RTE (RE_Register_Receiving_Stub), Loc), + + Parameter_Associations => New_List ( + Make_String_Literal (Loc, + Strval => Get_Pkg_Name_String_Id (Pkg_Spec)), + Make_Attribute_Reference (Loc, + Prefix => + New_Occurrence_Of (Pkg_RPC_Receiver, Loc), + Attribute_Name => + Name_Unrestricted_Access), + Make_Attribute_Reference (Loc, + Prefix => + New_Occurrence_Of (Defining_Entity (Pkg_Spec), Loc), + Attribute_Name => + Name_Version)))))); + + Append_To (Decls, Dummy_Register_Body); + Analyze (Dummy_Register_Body); + end Add_Receiving_Stubs_To_Declarations; + + ------------------- + -- Add_Stub_Type -- + ------------------- + + procedure Add_Stub_Type + (Designated_Type : in Entity_Id; + RACW_Type : in Entity_Id; + Decls : in List_Id; + Stub_Type : out Entity_Id; + Stub_Type_Access : out Entity_Id; + Object_RPC_Receiver : out Entity_Id; + Existing : out Boolean) + is + Loc : constant Source_Ptr := Sloc (RACW_Type); + + Stub_Elements : constant Stub_Structure := + Stubs_Table.Get (Designated_Type); + + Stub_Type_Declaration : Node_Id; + Stub_Type_Access_Declaration : Node_Id; + Object_RPC_Receiver_Declaration : Node_Id; + + RPC_Receiver_Stream : Entity_Id; + RPC_Receiver_Result : Entity_Id; + + begin + if Stub_Elements /= Empty_Stub_Structure then + Stub_Type := Stub_Elements.Stub_Type; + Stub_Type_Access := Stub_Elements.Stub_Type_Access; + Object_RPC_Receiver := Stub_Elements.Object_RPC_Receiver; + Existing := True; + return; + end if; + + Existing := False; + Stub_Type := + Make_Defining_Identifier (Loc, New_Internal_Name ('S')); + Stub_Type_Access := + Make_Defining_Identifier (Loc, New_Internal_Name ('S')); + Object_RPC_Receiver := + Make_Defining_Identifier (Loc, New_Internal_Name ('P')); + RPC_Receiver_Stream := + Make_Defining_Identifier (Loc, New_Internal_Name ('S')); + RPC_Receiver_Result := + Make_Defining_Identifier (Loc, New_Internal_Name ('S')); + Stubs_Table.Set (Designated_Type, + (Stub_Type => Stub_Type, + Stub_Type_Access => Stub_Type_Access, + Object_RPC_Receiver => Object_RPC_Receiver, + RPC_Receiver_Stream => RPC_Receiver_Stream, + RPC_Receiver_Result => RPC_Receiver_Result, + RACW_Type => RACW_Type)); + + -- The stub type definition below must match exactly the one in + -- s-parint.ads, since unchecked conversions will be used in + -- s-parint.adb to modify pointers passed to Get_Unique_Remote_Pointer. + + Stub_Type_Declaration := + Make_Full_Type_Declaration (Loc, + Defining_Identifier => Stub_Type, + Type_Definition => + Make_Record_Definition (Loc, + Tagged_Present => True, + Limited_Present => True, + Component_List => + Make_Component_List (Loc, + Component_Items => New_List ( + + Make_Component_Declaration (Loc, + Defining_Identifier => + Make_Defining_Identifier (Loc, Name_Origin), + Subtype_Indication => + New_Occurrence_Of (RTE (RE_Partition_ID), Loc)), + + Make_Component_Declaration (Loc, + Defining_Identifier => + Make_Defining_Identifier (Loc, Name_Receiver), + Subtype_Indication => + New_Occurrence_Of (RTE (RE_Unsigned_64), Loc)), + + Make_Component_Declaration (Loc, + Defining_Identifier => + Make_Defining_Identifier (Loc, Name_Addr), + Subtype_Indication => + New_Occurrence_Of (RTE (RE_Unsigned_64), Loc)), + + Make_Component_Declaration (Loc, + Defining_Identifier => + Make_Defining_Identifier (Loc, Name_Asynchronous), + Subtype_Indication => + New_Occurrence_Of (Standard_Boolean, Loc)))))); + + Append_To (Decls, Stub_Type_Declaration); + Analyze (Stub_Type_Declaration); + + -- This is in no way a type derivation, but we fake it to make + -- sure that the dispatching table gets built with the corresponding + -- primitive operations at the right place. + + Derive_Subprograms (Parent_Type => Designated_Type, + Derived_Type => Stub_Type); + + Stub_Type_Access_Declaration := + Make_Full_Type_Declaration (Loc, + Defining_Identifier => Stub_Type_Access, + Type_Definition => + Make_Access_To_Object_Definition (Loc, + Subtype_Indication => New_Occurrence_Of (Stub_Type, Loc))); + + Append_To (Decls, Stub_Type_Access_Declaration); + Analyze (Stub_Type_Access_Declaration); + + Object_RPC_Receiver_Declaration := + Make_Subprogram_Declaration (Loc, + Make_Procedure_Specification (Loc, + Defining_Unit_Name => Object_RPC_Receiver, + Parameter_Specifications => New_List ( + Make_Parameter_Specification (Loc, + Defining_Identifier => RPC_Receiver_Stream, + Parameter_Type => + Make_Access_Definition (Loc, + Subtype_Mark => + New_Occurrence_Of (RTE (RE_Params_Stream_Type), Loc))), + + Make_Parameter_Specification (Loc, + Defining_Identifier => RPC_Receiver_Result, + Parameter_Type => + Make_Access_Definition (Loc, + Subtype_Mark => + New_Occurrence_Of + (RTE (RE_Params_Stream_Type), Loc)))))); + + Append_To (Decls, Object_RPC_Receiver_Declaration); + end Add_Stub_Type; + + --------------------------------- + -- Build_General_Calling_Stubs -- + --------------------------------- + + procedure Build_General_Calling_Stubs + (Decls : List_Id; + Statements : List_Id; + Target_Partition : Entity_Id; + RPC_Receiver : Node_Id; + Subprogram_Id : Node_Id; + Asynchronous : Node_Id := Empty; + Is_Known_Asynchronous : Boolean := False; + Is_Known_Non_Asynchronous : Boolean := False; + Is_Function : Boolean; + Spec : Node_Id; + Object_Type : Entity_Id := Empty; + Nod : Node_Id) + is + Loc : constant Source_Ptr := Sloc (Nod); + + Stream_Parameter : Node_Id; + -- Name of the stream used to transmit parameters to the remote package + + Result_Parameter : Node_Id; + -- Name of the result parameter (in non-APC cases) which get the + -- result of the remote subprogram. + + Exception_Return_Parameter : Node_Id; + -- Name of the parameter which will hold the exception sent by the + -- remote subprogram. + + Current_Parameter : Node_Id; + -- Current parameter being handled + + Ordered_Parameters_List : constant List_Id := + Build_Ordered_Parameters_List (Spec); + + Asynchronous_Statements : List_Id := No_List; + Non_Asynchronous_Statements : List_Id := No_List; + -- Statements specifics to the Asynchronous/Non-Asynchronous cases. + + Extra_Formal_Statements : constant List_Id := New_List; + -- List of statements for extra formal parameters. It will appear after + -- the regular statements for writing out parameters. + + begin + -- The general form of a calling stub for a given subprogram is: + + -- procedure X (...) is + -- P : constant Partition_ID := RCI_Cache.Get_Active_Partition_ID; + -- Stream, Result : aliased System.RPC.Params_Stream_Type (0); + -- begin + -- Put_Package_RPC_Receiver_In_Stream; (the package RPC receiver + -- comes from RCI_Cache.Get_RCI_Package_Receiver) + -- Put_Subprogram_Id_In_Stream; + -- Put_Parameters_In_Stream; + -- Do_RPC (Stream, Result); + -- Read_Exception_Occurrence_From_Result; Raise_It; + -- Read_Out_Parameters_And_Function_Return_From_Stream; + -- end X; + + -- There are some variations: Do_APC is called for an asynchronous + -- procedure and the part after the call is completely ommitted + -- as well as the declaration of Result. For a function call, + -- 'Input is always used to read the result even if it is constrained. + + Stream_Parameter := + Make_Defining_Identifier (Loc, New_Internal_Name ('S')); + + Append_To (Decls, + Make_Object_Declaration (Loc, + Defining_Identifier => Stream_Parameter, + Aliased_Present => True, + Object_Definition => + Make_Subtype_Indication (Loc, + Subtype_Mark => + New_Occurrence_Of (RTE (RE_Params_Stream_Type), Loc), + Constraint => + Make_Index_Or_Discriminant_Constraint (Loc, + Constraints => + New_List (Make_Integer_Literal (Loc, 0)))))); + + if not Is_Known_Asynchronous then + Result_Parameter := + Make_Defining_Identifier (Loc, New_Internal_Name ('R')); + + Append_To (Decls, + Make_Object_Declaration (Loc, + Defining_Identifier => Result_Parameter, + Aliased_Present => True, + Object_Definition => + Make_Subtype_Indication (Loc, + Subtype_Mark => + New_Occurrence_Of (RTE (RE_Params_Stream_Type), Loc), + Constraint => + Make_Index_Or_Discriminant_Constraint (Loc, + Constraints => + New_List (Make_Integer_Literal (Loc, 0)))))); + + Exception_Return_Parameter := + Make_Defining_Identifier (Loc, New_Internal_Name ('E')); + + Append_To (Decls, + Make_Object_Declaration (Loc, + Defining_Identifier => Exception_Return_Parameter, + Object_Definition => + New_Occurrence_Of (RTE (RE_Exception_Occurrence), Loc))); + + else + Result_Parameter := Empty; + Exception_Return_Parameter := Empty; + end if; + + -- Put first the RPC receiver corresponding to the remote package + + Append_To (Statements, + Make_Attribute_Reference (Loc, + Prefix => + New_Occurrence_Of (RTE (RE_Unsigned_64), Loc), + Attribute_Name => Name_Write, + Expressions => New_List ( + Make_Attribute_Reference (Loc, + Prefix => + New_Occurrence_Of (Stream_Parameter, Loc), + Attribute_Name => + Name_Access), + RPC_Receiver))); + + -- Then put the Subprogram_Id of the subprogram we want to call in + -- the stream. + + Append_To (Statements, + Make_Attribute_Reference (Loc, + Prefix => + New_Occurrence_Of (RTE (RE_Subprogram_Id), Loc), + Attribute_Name => + Name_Write, + Expressions => New_List ( + Make_Attribute_Reference (Loc, + Prefix => + New_Occurrence_Of (Stream_Parameter, Loc), + Attribute_Name => Name_Access), + Subprogram_Id))); + + Current_Parameter := First (Ordered_Parameters_List); + + while Current_Parameter /= Empty loop + + if Is_RACW_Controlling_Formal (Current_Parameter, Object_Type) then + + -- In the case of a controlling formal argument, we marshall + -- its addr field rather than the local stub. + + Append_To (Statements, + Pack_Node_Into_Stream (Loc, + Stream => Stream_Parameter, + Object => + Make_Selected_Component (Loc, + Prefix => + New_Occurrence_Of ( + Defining_Identifier (Current_Parameter), Loc), + Selector_Name => + Make_Identifier (Loc, Name_Addr)), + Etyp => RTE (RE_Unsigned_64))); + + else + declare + Etyp : constant Entity_Id := + Etype (Parameter_Type (Current_Parameter)); + + Constrained : constant Boolean := + Is_Constrained (Etyp) + or else Is_Elementary_Type (Etyp); + + begin + if In_Present (Current_Parameter) + or else not Out_Present (Current_Parameter) + or else not Constrained + then + Append_To (Statements, + Make_Attribute_Reference (Loc, + Prefix => + New_Occurrence_Of (Etyp, Loc), + Attribute_Name => Output_From_Constrained (Constrained), + Expressions => New_List ( + Make_Attribute_Reference (Loc, + Prefix => + New_Occurrence_Of (Stream_Parameter, Loc), + Attribute_Name => Name_Access), + New_Occurrence_Of ( + Defining_Identifier (Current_Parameter), Loc)))); + end if; + end; + end if; + + -- If the current parameter has a dynamic constrained status, + -- then this status is transmitted as well. + -- This should be done for accessibility as well ??? + + if Nkind (Parameter_Type (Current_Parameter)) /= N_Access_Definition + and then Need_Extra_Constrained (Current_Parameter) + then + -- In this block, we do not use the extra formal that has been + -- created because it does not exist at the time of expansion + -- when building calling stubs for remote access to subprogram + -- types. We create an extra variable of this type and push it + -- in the stream after the regular parameters. + + declare + Extra_Parameter : constant Entity_Id := + Make_Defining_Identifier + (Loc, New_Internal_Name ('P')); + + begin + Append_To (Decls, + Make_Object_Declaration (Loc, + Defining_Identifier => Extra_Parameter, + Constant_Present => True, + Object_Definition => + New_Occurrence_Of (Standard_Boolean, Loc), + Expression => + Make_Attribute_Reference (Loc, + Prefix => + New_Occurrence_Of ( + Defining_Identifier (Current_Parameter), Loc), + Attribute_Name => Name_Constrained))); + + Append_To (Extra_Formal_Statements, + Make_Attribute_Reference (Loc, + Prefix => + New_Occurrence_Of (Standard_Boolean, Loc), + Attribute_Name => + Name_Write, + Expressions => New_List ( + Make_Attribute_Reference (Loc, + Prefix => + New_Occurrence_Of (Stream_Parameter, Loc), + Attribute_Name => + Name_Access), + New_Occurrence_Of (Extra_Parameter, Loc)))); + end; + end if; + + Next (Current_Parameter); + end loop; + + -- Append the formal statements list to the statements + + Append_List_To (Statements, Extra_Formal_Statements); + + if not Is_Known_Non_Asynchronous then + + -- Build the call to System.RPC.Do_APC + + Asynchronous_Statements := New_List ( + Make_Procedure_Call_Statement (Loc, + Name => + New_Occurrence_Of (RTE (RE_Do_Apc), Loc), + Parameter_Associations => New_List ( + New_Occurrence_Of (Target_Partition, Loc), + Make_Attribute_Reference (Loc, + Prefix => + New_Occurrence_Of (Stream_Parameter, Loc), + Attribute_Name => + Name_Access)))); + else + Asynchronous_Statements := No_List; + end if; + + if not Is_Known_Asynchronous then + + -- Build the call to System.RPC.Do_RPC + + Non_Asynchronous_Statements := New_List ( + Make_Procedure_Call_Statement (Loc, + Name => + New_Occurrence_Of (RTE (RE_Do_Rpc), Loc), + Parameter_Associations => New_List ( + New_Occurrence_Of (Target_Partition, Loc), + + Make_Attribute_Reference (Loc, + Prefix => + New_Occurrence_Of (Stream_Parameter, Loc), + Attribute_Name => + Name_Access), + + Make_Attribute_Reference (Loc, + Prefix => + New_Occurrence_Of (Result_Parameter, Loc), + Attribute_Name => + Name_Access)))); + + -- Read the exception occurrence from the result stream and + -- reraise it. It does no harm if this is a Null_Occurrence since + -- this does nothing. + + Append_To (Non_Asynchronous_Statements, + Make_Attribute_Reference (Loc, + Prefix => + New_Occurrence_Of (RTE (RE_Exception_Occurrence), Loc), + + Attribute_Name => + Name_Read, + + Expressions => New_List ( + Make_Attribute_Reference (Loc, + Prefix => + New_Occurrence_Of (Result_Parameter, Loc), + Attribute_Name => + Name_Access), + New_Occurrence_Of (Exception_Return_Parameter, Loc)))); + + Append_To (Non_Asynchronous_Statements, + Make_Procedure_Call_Statement (Loc, + Name => + New_Occurrence_Of (RTE (RE_Reraise_Occurrence), Loc), + Parameter_Associations => New_List ( + New_Occurrence_Of (Exception_Return_Parameter, Loc)))); + + if Is_Function then + + -- If this is a function call, then read the value and return + -- it. The return value is written/read using 'Output/'Input. + + Append_To (Non_Asynchronous_Statements, + Make_Tag_Check (Loc, + Make_Return_Statement (Loc, + Expression => + Make_Attribute_Reference (Loc, + Prefix => + New_Occurrence_Of ( + Etype (Subtype_Mark (Spec)), Loc), + + Attribute_Name => Name_Input, + + Expressions => New_List ( + Make_Attribute_Reference (Loc, + Prefix => + New_Occurrence_Of (Result_Parameter, Loc), + Attribute_Name => Name_Access)))))); + + else + -- Loop around parameters and assign out (or in out) parameters. + -- In the case of RACW, controlling arguments cannot possibly + -- have changed since they are remote, so we do not read them + -- from the stream. + + Current_Parameter := + First (Ordered_Parameters_List); + + while Current_Parameter /= Empty loop + + if Out_Present (Current_Parameter) + and then + Etype (Parameter_Type (Current_Parameter)) /= Object_Type + then + Append_To (Non_Asynchronous_Statements, + Make_Attribute_Reference (Loc, + Prefix => + New_Occurrence_Of ( + Etype (Parameter_Type (Current_Parameter)), Loc), + + Attribute_Name => Name_Read, + + Expressions => New_List ( + Make_Attribute_Reference (Loc, + Prefix => + New_Occurrence_Of (Result_Parameter, Loc), + Attribute_Name => + Name_Access), + New_Occurrence_Of ( + Defining_Identifier (Current_Parameter), Loc)))); + end if; + + Next (Current_Parameter); + end loop; + end if; + end if; + + if Is_Known_Asynchronous then + Append_List_To (Statements, Asynchronous_Statements); + + elsif Is_Known_Non_Asynchronous then + Append_List_To (Statements, Non_Asynchronous_Statements); + + else + pragma Assert (Asynchronous /= Empty); + Prepend_To (Asynchronous_Statements, + Make_Attribute_Reference (Loc, + Prefix => New_Occurrence_Of (Standard_Boolean, Loc), + Attribute_Name => Name_Write, + Expressions => New_List ( + Make_Attribute_Reference (Loc, + Prefix => New_Occurrence_Of (Stream_Parameter, Loc), + Attribute_Name => Name_Access), + New_Occurrence_Of (Standard_True, Loc)))); + Prepend_To (Non_Asynchronous_Statements, + Make_Attribute_Reference (Loc, + Prefix => New_Occurrence_Of (Standard_Boolean, Loc), + Attribute_Name => Name_Write, + Expressions => New_List ( + Make_Attribute_Reference (Loc, + Prefix => New_Occurrence_Of (Stream_Parameter, Loc), + Attribute_Name => Name_Access), + New_Occurrence_Of (Standard_False, Loc)))); + Append_To (Statements, + Make_Implicit_If_Statement (Nod, + Condition => Asynchronous, + Then_Statements => Asynchronous_Statements, + Else_Statements => Non_Asynchronous_Statements)); + end if; + end Build_General_Calling_Stubs; + + ----------------------------------- + -- Build_Ordered_Parameters_List -- + ----------------------------------- + + function Build_Ordered_Parameters_List (Spec : Node_Id) return List_Id is + Constrained_List : List_Id; + Unconstrained_List : List_Id; + Current_Parameter : Node_Id; + + begin + if not Present (Parameter_Specifications (Spec)) then + return New_List; + end if; + + Constrained_List := New_List; + Unconstrained_List := New_List; + + -- Loop through the parameters and add them to the right list + + Current_Parameter := First (Parameter_Specifications (Spec)); + while Current_Parameter /= Empty loop + + if Nkind (Parameter_Type (Current_Parameter)) = N_Access_Definition + or else + Is_Constrained (Etype (Parameter_Type (Current_Parameter))) + or else + Is_Elementary_Type (Etype (Parameter_Type (Current_Parameter))) + then + Append_To (Constrained_List, New_Copy (Current_Parameter)); + else + Append_To (Unconstrained_List, New_Copy (Current_Parameter)); + end if; + + Next (Current_Parameter); + end loop; + + -- Unconstrained parameters are returned first + + Append_List_To (Unconstrained_List, Constrained_List); + + return Unconstrained_List; + + end Build_Ordered_Parameters_List; + + ---------------------------------- + -- Build_Passive_Partition_Stub -- + ---------------------------------- + + procedure Build_Passive_Partition_Stub (U : Node_Id) is + Pkg_Spec : Node_Id; + L : List_Id; + Reg : Node_Id; + Loc : constant Source_Ptr := Sloc (U); + Dist_OK : Entity_Id; + + begin + -- Verify that the implementation supports distribution, by accessing + -- a type defined in the proper version of system.rpc + + Dist_OK := RTE (RE_Params_Stream_Type); + + -- Use body if present, spec otherwise + + if Nkind (U) = N_Package_Declaration then + Pkg_Spec := Specification (U); + L := Visible_Declarations (Pkg_Spec); + else + Pkg_Spec := Parent (Corresponding_Spec (U)); + L := Declarations (U); + end if; + + Reg := + Make_Procedure_Call_Statement (Loc, + Name => + New_Occurrence_Of (RTE (RE_Register_Passive_Package), Loc), + Parameter_Associations => New_List ( + Make_String_Literal (Loc, Get_Pkg_Name_String_Id (Pkg_Spec)), + Make_Attribute_Reference (Loc, + Prefix => + New_Occurrence_Of (Defining_Entity (Pkg_Spec), Loc), + Attribute_Name => + Name_Version))); + Append_To (L, Reg); + Analyze (Reg); + end Build_Passive_Partition_Stub; + + ------------------------------------ + -- Build_Subprogram_Calling_Stubs -- + ------------------------------------ + + function Build_Subprogram_Calling_Stubs + (Vis_Decl : Node_Id; + Subp_Id : Int; + Asynchronous : Boolean; + Dynamically_Asynchronous : Boolean := False; + Stub_Type : Entity_Id := Empty; + Locator : Entity_Id := Empty; + New_Name : Name_Id := No_Name) + return Node_Id + is + Loc : constant Source_Ptr := Sloc (Vis_Decl); + + Target_Partition : Node_Id; + -- Contains the name of the target partition + + Decls : constant List_Id := New_List; + Statements : constant List_Id := New_List; + + Subp_Spec : Node_Id; + -- The specification of the body + + Controlling_Parameter : Entity_Id := Empty; + RPC_Receiver : Node_Id; + + Asynchronous_Expr : Node_Id := Empty; + + RCI_Locator : Entity_Id; + + Spec_To_Use : Node_Id; + + procedure Insert_Partition_Check (Parameter : in Node_Id); + -- Check that the parameter has been elaborated on the same partition + -- than the controlling parameter (E.4(19)). + + ---------------------------- + -- Insert_Partition_Check -- + ---------------------------- + + procedure Insert_Partition_Check (Parameter : in Node_Id) is + Parameter_Entity : constant Entity_Id := + Defining_Identifier (Parameter); + Designated_Object : Node_Id; + Condition : Node_Id; + + begin + -- The expression that will be built is of the form: + -- if not (Parameter in Stub_Type and then + -- Parameter.Origin = Controlling.Origin) + -- then + -- raise Constraint_Error; + -- end if; + -- + -- Condition contains the reversed condition. Also, Parameter is + -- dereferenced if it is an access type. We do not check that + -- Parameter is in Stub_Type since such a check has been inserted + -- at the point of call already (a tag check since we have multiple + -- controlling operands). + + if Nkind (Parameter_Type (Parameter)) = N_Access_Definition then + Designated_Object := + Make_Explicit_Dereference (Loc, + Prefix => New_Occurrence_Of (Parameter_Entity, Loc)); + else + Designated_Object := New_Occurrence_Of (Parameter_Entity, Loc); + end if; + + Condition := + Make_Op_Eq (Loc, + Left_Opnd => + Make_Selected_Component (Loc, + Prefix => + New_Occurrence_Of (Parameter_Entity, Loc), + Selector_Name => + Make_Identifier (Loc, Name_Origin)), + + Right_Opnd => + Make_Selected_Component (Loc, + Prefix => + New_Occurrence_Of (Controlling_Parameter, Loc), + Selector_Name => + Make_Identifier (Loc, Name_Origin))); + + Append_To (Decls, + Make_Raise_Constraint_Error (Loc, + Condition => + Make_Op_Not (Loc, Right_Opnd => Condition))); + end Insert_Partition_Check; + + -- Start of processing for Build_Subprogram_Calling_Stubs + + begin + Target_Partition := + Make_Defining_Identifier (Loc, New_Internal_Name ('P')); + + Subp_Spec := Copy_Specification (Loc, + Spec => Specification (Vis_Decl), + New_Name => New_Name); + + if Locator = Empty then + RCI_Locator := RCI_Cache; + Spec_To_Use := Specification (Vis_Decl); + else + RCI_Locator := Locator; + Spec_To_Use := Subp_Spec; + end if; + + -- Find a controlling argument if we have a stub type. Also check + -- if this subprogram can be made asynchronous. + + if Stub_Type /= Empty + and then Present (Parameter_Specifications (Spec_To_Use)) + then + declare + Current_Parameter : Node_Id := + First (Parameter_Specifications + (Spec_To_Use)); + begin + while Current_Parameter /= Empty loop + + if + Is_RACW_Controlling_Formal (Current_Parameter, Stub_Type) + then + if Controlling_Parameter = Empty then + Controlling_Parameter := + Defining_Identifier (Current_Parameter); + else + Insert_Partition_Check (Current_Parameter); + end if; + end if; + + Next (Current_Parameter); + end loop; + end; + end if; + + if Stub_Type /= Empty then + pragma Assert (Controlling_Parameter /= Empty); + + Append_To (Decls, + Make_Object_Declaration (Loc, + Defining_Identifier => Target_Partition, + Constant_Present => True, + Object_Definition => + New_Occurrence_Of (RTE (RE_Partition_ID), Loc), + + Expression => + Make_Selected_Component (Loc, + Prefix => + New_Occurrence_Of (Controlling_Parameter, Loc), + Selector_Name => + Make_Identifier (Loc, Name_Origin)))); + + RPC_Receiver := + Make_Selected_Component (Loc, + Prefix => + New_Occurrence_Of (Controlling_Parameter, Loc), + Selector_Name => + Make_Identifier (Loc, Name_Receiver)); + + else + Append_To (Decls, + Make_Object_Declaration (Loc, + Defining_Identifier => Target_Partition, + Constant_Present => True, + Object_Definition => + New_Occurrence_Of (RTE (RE_Partition_ID), Loc), + + Expression => + Make_Function_Call (Loc, + Name => Make_Selected_Component (Loc, + Prefix => + Make_Identifier (Loc, Chars (RCI_Locator)), + Selector_Name => + Make_Identifier (Loc, Name_Get_Active_Partition_ID))))); + + RPC_Receiver := + Make_Selected_Component (Loc, + Prefix => + Make_Identifier (Loc, Chars (RCI_Locator)), + Selector_Name => + Make_Identifier (Loc, Name_Get_RCI_Package_Receiver)); + end if; + + if Dynamically_Asynchronous then + Asynchronous_Expr := + Make_Selected_Component (Loc, + Prefix => + New_Occurrence_Of (Controlling_Parameter, Loc), + Selector_Name => + Make_Identifier (Loc, Name_Asynchronous)); + end if; + + Build_General_Calling_Stubs + (Decls => Decls, + Statements => Statements, + Target_Partition => Target_Partition, + RPC_Receiver => RPC_Receiver, + Subprogram_Id => Make_Integer_Literal (Loc, Subp_Id), + Asynchronous => Asynchronous_Expr, + Is_Known_Asynchronous => Asynchronous + and then not Dynamically_Asynchronous, + Is_Known_Non_Asynchronous + => not Asynchronous + and then not Dynamically_Asynchronous, + Is_Function => Nkind (Spec_To_Use) = + N_Function_Specification, + Spec => Spec_To_Use, + Object_Type => Stub_Type, + Nod => Vis_Decl); + + RCI_Calling_Stubs_Table.Set + (Defining_Unit_Name (Specification (Vis_Decl)), + Defining_Unit_Name (Spec_To_Use)); + + return + Make_Subprogram_Body (Loc, + Specification => Subp_Spec, + Declarations => Decls, + Handled_Statement_Sequence => + Make_Handled_Sequence_Of_Statements (Loc, Statements)); + end Build_Subprogram_Calling_Stubs; + + -------------------------------------- + -- Build_Subprogram_Receiving_Stubs -- + -------------------------------------- + + function Build_Subprogram_Receiving_Stubs + (Vis_Decl : Node_Id; + Asynchronous : Boolean; + Dynamically_Asynchronous : Boolean := False; + Stub_Type : Entity_Id := Empty; + RACW_Type : Entity_Id := Empty; + Parent_Primitive : Entity_Id := Empty) + return Node_Id + is + Loc : constant Source_Ptr := Sloc (Vis_Decl); + + Stream_Parameter : Node_Id; + Result_Parameter : Node_Id; + -- See explanations of those in Build_Subprogram_Calling_Stubs + + Decls : List_Id := New_List; + -- All the parameters will get declared before calling the real + -- subprograms. Also the out parameters will be declared. + + Statements : List_Id := New_List; + + Extra_Formal_Statements : List_Id := New_List; + -- Statements concerning extra formal parameters + + After_Statements : List_Id := New_List; + -- Statements to be executed after the subprogram call + + Inner_Decls : List_Id := No_List; + -- In case of a function, the inner declarations are needed since + -- the result may be unconstrained. + + Excep_Handler : Node_Id; + Excep_Choice : Entity_Id; + Excep_Code : List_Id; + + Parameter_List : List_Id := New_List; + -- List of parameters to be passed to the subprogram. + + Current_Parameter : Node_Id; + + Ordered_Parameters_List : constant List_Id := + Build_Ordered_Parameters_List (Specification (Vis_Decl)); + + Subp_Spec : Node_Id; + -- Subprogram specification + + Called_Subprogram : Node_Id; + -- The subprogram to call + + Null_Raise_Statement : Node_Id; + + Dynamic_Async : Entity_Id; + + begin + if RACW_Type /= Empty then + Called_Subprogram := + New_Occurrence_Of (Parent_Primitive, Loc); + else + Called_Subprogram := + New_Occurrence_Of ( + Defining_Unit_Name (Specification (Vis_Decl)), Loc); + end if; + + Stream_Parameter := + Make_Defining_Identifier (Loc, New_Internal_Name ('S')); + + if Dynamically_Asynchronous then + Dynamic_Async := + Make_Defining_Identifier (Loc, New_Internal_Name ('S')); + else + Dynamic_Async := Empty; + end if; + + if not Asynchronous or else Dynamically_Asynchronous then + Result_Parameter := + Make_Defining_Identifier (Loc, New_Internal_Name ('S')); + + -- The first statement after the subprogram call is a statement to + -- writes a Null_Occurrence into the result stream. + + Null_Raise_Statement := + Make_Attribute_Reference (Loc, + Prefix => + New_Occurrence_Of (RTE (RE_Exception_Occurrence), Loc), + Attribute_Name => Name_Write, + Expressions => New_List ( + New_Occurrence_Of (Result_Parameter, Loc), + New_Occurrence_Of (RTE (RE_Null_Occurrence), Loc))); + + if Dynamically_Asynchronous then + Null_Raise_Statement := + Make_Implicit_If_Statement (Vis_Decl, + Condition => + Make_Op_Not (Loc, New_Occurrence_Of (Dynamic_Async, Loc)), + Then_Statements => New_List (Null_Raise_Statement)); + end if; + + Append_To (After_Statements, Null_Raise_Statement); + + else + Result_Parameter := Empty; + end if; + + -- Loop through every parameter and get its value from the stream. If + -- the parameter is unconstrained, then the parameter is read using + -- 'Input at the point of declaration. + + Current_Parameter := First (Ordered_Parameters_List); + + while Current_Parameter /= Empty loop + + declare + Etyp : Entity_Id; + Constrained : Boolean; + Object : Entity_Id; + Expr : Node_Id := Empty; + + begin + Object := Make_Defining_Identifier (Loc, New_Internal_Name ('P')); + Set_Ekind (Object, E_Variable); + + if + Is_RACW_Controlling_Formal (Current_Parameter, Stub_Type) + then + -- We have a controlling formal parameter. Read its address + -- rather than a real object. The address is in Unsigned_64 + -- form. + + Etyp := RTE (RE_Unsigned_64); + else + Etyp := Etype (Parameter_Type (Current_Parameter)); + end if; + + Constrained := + Is_Constrained (Etyp) or else Is_Elementary_Type (Etyp); + + if In_Present (Current_Parameter) + or else not Out_Present (Current_Parameter) + or else not Constrained + then + -- If an input parameter is contrained, then its reading is + -- deferred until the beginning of the subprogram body. If + -- it is unconstrained, then an expression is built for + -- the object declaration and the variable is set using + -- 'Input instead of 'Read. + + if Constrained then + Append_To (Statements, + Make_Attribute_Reference (Loc, + Prefix => New_Occurrence_Of (Etyp, Loc), + Attribute_Name => Name_Read, + Expressions => New_List ( + New_Occurrence_Of (Stream_Parameter, Loc), + New_Occurrence_Of (Object, Loc)))); + + else + Expr := Input_With_Tag_Check (Loc, + Var_Type => Etyp, + Stream => Stream_Parameter); + Append_To (Decls, Expr); + Expr := Make_Function_Call (Loc, + New_Occurrence_Of (Defining_Unit_Name + (Specification (Expr)), Loc)); + end if; + end if; + + -- If we do not have to output the current parameter, then + -- it can well be flagged as constant. This may allow further + -- optimizations done by the back end. + + Append_To (Decls, + Make_Object_Declaration (Loc, + Defining_Identifier => Object, + Constant_Present => + not Constrained and then not Out_Present (Current_Parameter), + Object_Definition => + New_Occurrence_Of (Etyp, Loc), + Expression => Expr)); + + -- An out parameter may be written back using a 'Write + -- attribute instead of a 'Output because it has been + -- constrained by the parameter given to the caller. Note that + -- out controlling arguments in the case of a RACW are not put + -- back in the stream because the pointer on them has not + -- changed. + + if Out_Present (Current_Parameter) + and then + Etype (Parameter_Type (Current_Parameter)) /= Stub_Type + then + Append_To (After_Statements, + Make_Attribute_Reference (Loc, + Prefix => New_Occurrence_Of (Etyp, Loc), + Attribute_Name => Name_Write, + Expressions => New_List ( + New_Occurrence_Of (Result_Parameter, Loc), + New_Occurrence_Of (Object, Loc)))); + end if; + + if + Is_RACW_Controlling_Formal (Current_Parameter, Stub_Type) + then + + if Nkind (Parameter_Type (Current_Parameter)) /= + N_Access_Definition + then + Append_To (Parameter_List, + Make_Parameter_Association (Loc, + Selector_Name => + New_Occurrence_Of ( + Defining_Identifier (Current_Parameter), Loc), + Explicit_Actual_Parameter => + Make_Explicit_Dereference (Loc, + Unchecked_Convert_To (RACW_Type, + OK_Convert_To (RTE (RE_Address), + New_Occurrence_Of (Object, Loc)))))); + else + Append_To (Parameter_List, + Make_Parameter_Association (Loc, + Selector_Name => + New_Occurrence_Of ( + Defining_Identifier (Current_Parameter), Loc), + Explicit_Actual_Parameter => + Unchecked_Convert_To (RACW_Type, + OK_Convert_To (RTE (RE_Address), + New_Occurrence_Of (Object, Loc))))); + end if; + else + Append_To (Parameter_List, + Make_Parameter_Association (Loc, + Selector_Name => + New_Occurrence_Of ( + Defining_Identifier (Current_Parameter), Loc), + Explicit_Actual_Parameter => + New_Occurrence_Of (Object, Loc))); + end if; + + -- If the current parameter needs an extra formal, then read it + -- from the stream and set the corresponding semantic field in + -- the variable. If the kind of the parameter identifier is + -- E_Void, then this is a compiler generated parameter that + -- doesn't need an extra constrained status. + + -- The case of Extra_Accessibility should also be handled ??? + + if Nkind (Parameter_Type (Current_Parameter)) /= + N_Access_Definition + and then + Ekind (Defining_Identifier (Current_Parameter)) /= E_Void + and then + Present (Extra_Constrained + (Defining_Identifier (Current_Parameter))) + then + declare + Extra_Parameter : constant Entity_Id := + Extra_Constrained + (Defining_Identifier + (Current_Parameter)); + + Formal_Entity : constant Entity_Id := + Make_Defining_Identifier + (Loc, Chars (Extra_Parameter)); + + Formal_Type : constant Entity_Id := + Etype (Extra_Parameter); + + begin + Append_To (Decls, + Make_Object_Declaration (Loc, + Defining_Identifier => Formal_Entity, + Object_Definition => + New_Occurrence_Of (Formal_Type, Loc))); + + Append_To (Extra_Formal_Statements, + Make_Attribute_Reference (Loc, + Prefix => New_Occurrence_Of (Formal_Type, Loc), + Attribute_Name => Name_Read, + Expressions => New_List ( + New_Occurrence_Of (Stream_Parameter, Loc), + New_Occurrence_Of (Formal_Entity, Loc)))); + Set_Extra_Constrained (Object, Formal_Entity); + end; + end if; + end; + + Next (Current_Parameter); + end loop; + + -- Append the formal statements list at the end of regular statements + + Append_List_To (Statements, Extra_Formal_Statements); + + if Nkind (Specification (Vis_Decl)) = N_Function_Specification then + + -- The remote subprogram is a function. We build an inner block to + -- be able to hold a potentially unconstrained result in a variable. + + declare + Etyp : constant Entity_Id := + Etype (Subtype_Mark (Specification (Vis_Decl))); + Result : constant Node_Id := + Make_Defining_Identifier (Loc, New_Internal_Name ('R')); + + begin + Inner_Decls := New_List ( + Make_Object_Declaration (Loc, + Defining_Identifier => Result, + Constant_Present => True, + Object_Definition => New_Occurrence_Of (Etyp, Loc), + Expression => + Make_Function_Call (Loc, + Name => Called_Subprogram, + Parameter_Associations => Parameter_List))); + + Append_To (After_Statements, + Make_Attribute_Reference (Loc, + Prefix => New_Occurrence_Of (Etyp, Loc), + Attribute_Name => Name_Output, + Expressions => New_List ( + New_Occurrence_Of (Result_Parameter, Loc), + New_Occurrence_Of (Result, Loc)))); + end; + + Append_To (Statements, + Make_Block_Statement (Loc, + Declarations => Inner_Decls, + Handled_Statement_Sequence => + Make_Handled_Sequence_Of_Statements (Loc, + Statements => After_Statements))); + + else + -- The remote subprogram is a procedure. We do not need any inner + -- block in this case. + + if Dynamically_Asynchronous then + Append_To (Decls, + Make_Object_Declaration (Loc, + Defining_Identifier => Dynamic_Async, + Object_Definition => + New_Occurrence_Of (Standard_Boolean, Loc))); + + Append_To (Statements, + Make_Attribute_Reference (Loc, + Prefix => New_Occurrence_Of (Standard_Boolean, Loc), + Attribute_Name => Name_Read, + Expressions => New_List ( + New_Occurrence_Of (Stream_Parameter, Loc), + New_Occurrence_Of (Dynamic_Async, Loc)))); + end if; + + Append_To (Statements, + Make_Procedure_Call_Statement (Loc, + Name => Called_Subprogram, + Parameter_Associations => Parameter_List)); + + Append_List_To (Statements, After_Statements); + + end if; + + if Asynchronous and then not Dynamically_Asynchronous then + + -- An asynchronous procedure does not want a Result + -- parameter. Also, we put an exception handler with an others + -- clause that does nothing. + + Subp_Spec := + Make_Procedure_Specification (Loc, + Defining_Unit_Name => + Make_Defining_Identifier (Loc, New_Internal_Name ('F')), + Parameter_Specifications => New_List ( + Make_Parameter_Specification (Loc, + Defining_Identifier => Stream_Parameter, + Parameter_Type => + Make_Access_Definition (Loc, + Subtype_Mark => + New_Occurrence_Of (RTE (RE_Params_Stream_Type), Loc))))); + + Excep_Handler := + Make_Exception_Handler (Loc, + Exception_Choices => + New_List (Make_Others_Choice (Loc)), + Statements => New_List ( + Make_Null_Statement (Loc))); + + else + -- In the other cases, if an exception is raised, then the + -- exception occurrence is copied into the output stream and + -- no other output parameter is written. + + Excep_Choice := + Make_Defining_Identifier (Loc, New_Internal_Name ('E')); + + Excep_Code := New_List ( + Make_Attribute_Reference (Loc, + Prefix => + New_Occurrence_Of (RTE (RE_Exception_Occurrence), Loc), + Attribute_Name => Name_Write, + Expressions => New_List ( + New_Occurrence_Of (Result_Parameter, Loc), + New_Occurrence_Of (Excep_Choice, Loc)))); + + if Dynamically_Asynchronous then + Excep_Code := New_List ( + Make_Implicit_If_Statement (Vis_Decl, + Condition => Make_Op_Not (Loc, + New_Occurrence_Of (Dynamic_Async, Loc)), + Then_Statements => Excep_Code)); + end if; + + Excep_Handler := + Make_Exception_Handler (Loc, + Choice_Parameter => Excep_Choice, + Exception_Choices => New_List (Make_Others_Choice (Loc)), + Statements => Excep_Code); + + Subp_Spec := + Make_Procedure_Specification (Loc, + Defining_Unit_Name => + Make_Defining_Identifier (Loc, New_Internal_Name ('F')), + + Parameter_Specifications => New_List ( + Make_Parameter_Specification (Loc, + Defining_Identifier => Stream_Parameter, + Parameter_Type => + Make_Access_Definition (Loc, + Subtype_Mark => + New_Occurrence_Of (RTE (RE_Params_Stream_Type), Loc))), + + Make_Parameter_Specification (Loc, + Defining_Identifier => Result_Parameter, + Parameter_Type => + Make_Access_Definition (Loc, + Subtype_Mark => + New_Occurrence_Of (RTE (RE_Params_Stream_Type), Loc))))); + end if; + + return + Make_Subprogram_Body (Loc, + Specification => Subp_Spec, + Declarations => Decls, + Handled_Statement_Sequence => + Make_Handled_Sequence_Of_Statements (Loc, + Statements => Statements, + Exception_Handlers => New_List (Excep_Handler))); + + end Build_Subprogram_Receiving_Stubs; + + ------------------------ + -- Copy_Specification -- + ------------------------ + + function Copy_Specification + (Loc : Source_Ptr; + Spec : Node_Id; + Object_Type : Entity_Id := Empty; + Stub_Type : Entity_Id := Empty; + New_Name : Name_Id := No_Name) + return Node_Id + is + Parameters : List_Id := No_List; + + Current_Parameter : Node_Id; + Current_Type : Node_Id; + + Name_For_New_Spec : Name_Id; + + New_Identifier : Entity_Id; + + begin + if New_Name = No_Name then + Name_For_New_Spec := Chars (Defining_Unit_Name (Spec)); + else + Name_For_New_Spec := New_Name; + end if; + + if Present (Parameter_Specifications (Spec)) then + + Parameters := New_List; + Current_Parameter := First (Parameter_Specifications (Spec)); + + while Current_Parameter /= Empty loop + + Current_Type := Parameter_Type (Current_Parameter); + + if Nkind (Current_Type) = N_Access_Definition then + if Object_Type = Empty then + Current_Type := + Make_Access_Definition (Loc, + Subtype_Mark => + New_Occurrence_Of (Etype ( + Subtype_Mark (Current_Type)), Loc)); + else + pragma Assert + (Root_Type (Etype (Subtype_Mark (Current_Type))) + = Root_Type (Object_Type)); + Current_Type := + Make_Access_Definition (Loc, + Subtype_Mark => New_Occurrence_Of (Stub_Type, Loc)); + end if; + + elsif Object_Type /= Empty + and then Etype (Current_Type) = Object_Type + then + Current_Type := New_Occurrence_Of (Stub_Type, Loc); + + else + Current_Type := New_Occurrence_Of (Etype (Current_Type), Loc); + end if; + + New_Identifier := Make_Defining_Identifier (Loc, + Chars (Defining_Identifier (Current_Parameter))); + + Append_To (Parameters, + Make_Parameter_Specification (Loc, + Defining_Identifier => New_Identifier, + Parameter_Type => Current_Type, + In_Present => In_Present (Current_Parameter), + Out_Present => Out_Present (Current_Parameter), + Expression => + New_Copy_Tree (Expression (Current_Parameter)))); + + Next (Current_Parameter); + end loop; + end if; + + if Nkind (Spec) = N_Function_Specification then + return + Make_Function_Specification (Loc, + Defining_Unit_Name => + Make_Defining_Identifier (Loc, + Chars => Name_For_New_Spec), + Parameter_Specifications => Parameters, + Subtype_Mark => + New_Occurrence_Of (Etype (Subtype_Mark (Spec)), Loc)); + + else + return + Make_Procedure_Specification (Loc, + Defining_Unit_Name => + Make_Defining_Identifier (Loc, + Chars => Name_For_New_Spec), + Parameter_Specifications => Parameters); + end if; + + end Copy_Specification; + + --------------------------- + -- Could_Be_Asynchronous -- + --------------------------- + + function Could_Be_Asynchronous (Spec : Node_Id) return Boolean is + Current_Parameter : Node_Id; + + begin + if Present (Parameter_Specifications (Spec)) then + Current_Parameter := First (Parameter_Specifications (Spec)); + while Current_Parameter /= Empty loop + if Out_Present (Current_Parameter) then + return False; + end if; + + Next (Current_Parameter); + end loop; + end if; + + return True; + end Could_Be_Asynchronous; + + --------------------------------------------- + -- Expand_All_Calls_Remote_Subprogram_Call -- + --------------------------------------------- + + procedure Expand_All_Calls_Remote_Subprogram_Call (N : in Node_Id) is + Called_Subprogram : constant Entity_Id := Entity (Name (N)); + RCI_Package : constant Entity_Id := Scope (Called_Subprogram); + Loc : constant Source_Ptr := Sloc (N); + RCI_Locator : Node_Id; + RCI_Cache : Entity_Id; + Calling_Stubs : Node_Id; + E_Calling_Stubs : Entity_Id; + + begin + E_Calling_Stubs := RCI_Calling_Stubs_Table.Get (Called_Subprogram); + + if E_Calling_Stubs = Empty then + RCI_Cache := RCI_Locator_Table.Get (RCI_Package); + + if RCI_Cache = Empty then + RCI_Locator := + RCI_Package_Locator + (Loc, Specification (Unit_Declaration_Node (RCI_Package))); + Prepend_To (Current_Sem_Unit_Declarations, RCI_Locator); + + -- The RCI_Locator package is inserted at the top level in the + -- current unit, and must appear in the proper scope, so that it + -- is not prematurely removed by the GCC back-end. + + declare + Scop : Entity_Id := Cunit_Entity (Current_Sem_Unit); + + begin + if Ekind (Scop) = E_Package_Body then + New_Scope (Spec_Entity (Scop)); + + elsif Ekind (Scop) = E_Subprogram_Body then + New_Scope + (Corresponding_Spec (Unit_Declaration_Node (Scop))); + + else + New_Scope (Scop); + end if; + + Analyze (RCI_Locator); + Pop_Scope; + end; + + RCI_Cache := Defining_Unit_Name (RCI_Locator); + + else + RCI_Locator := Parent (RCI_Cache); + end if; + + Calling_Stubs := Build_Subprogram_Calling_Stubs + (Vis_Decl => Parent (Parent (Called_Subprogram)), + Subp_Id => Get_Subprogram_Id (Called_Subprogram), + Asynchronous => Nkind (N) = N_Procedure_Call_Statement + and then + Is_Asynchronous (Called_Subprogram), + Locator => RCI_Cache, + New_Name => New_Internal_Name ('S')); + Insert_After (RCI_Locator, Calling_Stubs); + Analyze (Calling_Stubs); + E_Calling_Stubs := Defining_Unit_Name (Specification (Calling_Stubs)); + end if; + + Rewrite (Name (N), New_Occurrence_Of (E_Calling_Stubs, Loc)); + end Expand_All_Calls_Remote_Subprogram_Call; + + --------------------------------- + -- Expand_Calling_Stubs_Bodies -- + --------------------------------- + + procedure Expand_Calling_Stubs_Bodies (Unit_Node : in Node_Id) is + Spec : constant Node_Id := Specification (Unit_Node); + Decls : constant List_Id := Visible_Declarations (Spec); + + begin + New_Scope (Scope_Of_Spec (Spec)); + Add_Calling_Stubs_To_Declarations (Specification (Unit_Node), + Decls); + Pop_Scope; + end Expand_Calling_Stubs_Bodies; + + ----------------------------------- + -- Expand_Receiving_Stubs_Bodies -- + ----------------------------------- + + procedure Expand_Receiving_Stubs_Bodies (Unit_Node : in Node_Id) is + Spec : Node_Id; + Decls : List_Id; + Temp : List_Id; + + begin + if Nkind (Unit_Node) = N_Package_Declaration then + Spec := Specification (Unit_Node); + Decls := Visible_Declarations (Spec); + New_Scope (Scope_Of_Spec (Spec)); + Add_Receiving_Stubs_To_Declarations (Spec, Decls); + + else + Spec := + Package_Specification_Of_Scope (Corresponding_Spec (Unit_Node)); + Decls := Declarations (Unit_Node); + New_Scope (Scope_Of_Spec (Unit_Node)); + Temp := New_List; + Add_Receiving_Stubs_To_Declarations (Spec, Temp); + Insert_List_Before (First (Decls), Temp); + end if; + + Pop_Scope; + end Expand_Receiving_Stubs_Bodies; + + ---------------------------- + -- Get_Pkg_Name_string_Id -- + ---------------------------- + + function Get_Pkg_Name_String_Id (Decl_Node : Node_Id) return String_Id is + Unit_Name_Id : Unit_Name_Type := Get_Unit_Name (Decl_Node); + + begin + Get_Unit_Name_String (Unit_Name_Id); + + -- Remove seven last character (" (spec)" or " (body)"). + + Name_Len := Name_Len - 7; + pragma Assert (Name_Buffer (Name_Len + 1) = ' '); + + return Get_String_Id (Name_Buffer (1 .. Name_Len)); + end Get_Pkg_Name_String_Id; + + ------------------- + -- Get_String_Id -- + ------------------- + + function Get_String_Id (Val : String) return String_Id is + begin + Start_String; + Store_String_Chars (Val); + return End_String; + end Get_String_Id; + + ---------- + -- Hash -- + ---------- + + function Hash (F : Entity_Id) return Hash_Index is + begin + return Hash_Index (Natural (F) mod Positive (Hash_Index'Last + 1)); + end Hash; + + -------------------------- + -- Input_With_Tag_Check -- + -------------------------- + + function Input_With_Tag_Check + (Loc : Source_Ptr; + Var_Type : Entity_Id; + Stream : Entity_Id) + return Node_Id + is + begin + return + Make_Subprogram_Body (Loc, + Specification => Make_Function_Specification (Loc, + Defining_Unit_Name => + Make_Defining_Identifier (Loc, New_Internal_Name ('S')), + Subtype_Mark => New_Occurrence_Of (Var_Type, Loc)), + Declarations => No_List, + Handled_Statement_Sequence => + Make_Handled_Sequence_Of_Statements (Loc, New_List ( + Make_Tag_Check (Loc, + Make_Return_Statement (Loc, + Make_Attribute_Reference (Loc, + Prefix => New_Occurrence_Of (Var_Type, Loc), + Attribute_Name => Name_Input, + Expressions => + New_List (New_Occurrence_Of (Stream, Loc)))))))); + end Input_With_Tag_Check; + + -------------------------------- + -- Is_RACW_Controlling_Formal -- + -------------------------------- + + function Is_RACW_Controlling_Formal + (Parameter : Node_Id; + Stub_Type : Entity_Id) + return Boolean + is + Typ : Entity_Id; + + begin + -- If the kind of the parameter is E_Void, then it is not a + -- controlling formal (this can happen in the context of RAS). + + if Ekind (Defining_Identifier (Parameter)) = E_Void then + return False; + end if; + + -- If the parameter is not a controlling formal, then it cannot + -- be possibly a RACW_Controlling_Formal. + + if not Is_Controlling_Formal (Defining_Identifier (Parameter)) then + return False; + end if; + + Typ := Parameter_Type (Parameter); + return (Nkind (Typ) = N_Access_Definition + and then Etype (Subtype_Mark (Typ)) = Stub_Type) + or else Etype (Typ) = Stub_Type; + end Is_RACW_Controlling_Formal; + + -------------------- + -- Make_Tag_Check -- + -------------------- + + function Make_Tag_Check (Loc : Source_Ptr; N : Node_Id) return Node_Id is + Occ : constant Entity_Id := + Make_Defining_Identifier (Loc, New_Internal_Name ('E')); + + begin + return Make_Block_Statement (Loc, + Handled_Statement_Sequence => + Make_Handled_Sequence_Of_Statements (Loc, + Statements => New_List (N), + + Exception_Handlers => New_List ( + Make_Exception_Handler (Loc, + Choice_Parameter => Occ, + + Exception_Choices => + New_List (New_Occurrence_Of (RTE (RE_Tag_Error), Loc)), + + Statements => + New_List (Make_Procedure_Call_Statement (Loc, + New_Occurrence_Of + (RTE (RE_Raise_Program_Error_Unknown_Tag), Loc), + New_List (New_Occurrence_Of (Occ, Loc)))))))); + end Make_Tag_Check; + + ---------------------------- + -- Need_Extra_Constrained -- + ---------------------------- + + function Need_Extra_Constrained (Parameter : Node_Id) return Boolean is + Etyp : constant Entity_Id := Etype (Parameter_Type (Parameter)); + + begin + return Out_Present (Parameter) + and then Has_Discriminants (Etyp) + and then not Is_Constrained (Etyp) + and then not Is_Indefinite_Subtype (Etyp); + end Need_Extra_Constrained; + + ------------------------------------ + -- Pack_Entity_Into_Stream_Access -- + ------------------------------------ + + function Pack_Entity_Into_Stream_Access + (Loc : Source_Ptr; + Stream : Entity_Id; + Object : Entity_Id; + Etyp : Entity_Id := Empty) + return Node_Id + is + Typ : Entity_Id; + + begin + if Etyp /= Empty then + Typ := Etyp; + else + Typ := Etype (Object); + end if; + + return + Pack_Node_Into_Stream_Access (Loc, + Stream => Stream, + Object => New_Occurrence_Of (Object, Loc), + Etyp => Typ); + end Pack_Entity_Into_Stream_Access; + + --------------------------- + -- Pack_Node_Into_Stream -- + --------------------------- + + function Pack_Node_Into_Stream + (Loc : Source_Ptr; + Stream : Entity_Id; + Object : Node_Id; + Etyp : Entity_Id) + return Node_Id + is + Write_Attribute : Name_Id := Name_Write; + + begin + if not Is_Constrained (Etyp) then + Write_Attribute := Name_Output; + end if; + + return + Make_Attribute_Reference (Loc, + Prefix => New_Occurrence_Of (Etyp, Loc), + Attribute_Name => Write_Attribute, + Expressions => New_List ( + Make_Attribute_Reference (Loc, + Prefix => New_Occurrence_Of (Stream, Loc), + Attribute_Name => Name_Access), + Object)); + end Pack_Node_Into_Stream; + + ---------------------------------- + -- Pack_Node_Into_Stream_Access -- + ---------------------------------- + + function Pack_Node_Into_Stream_Access + (Loc : Source_Ptr; + Stream : Entity_Id; + Object : Node_Id; + Etyp : Entity_Id) + return Node_Id + is + Write_Attribute : Name_Id := Name_Write; + + begin + if not Is_Constrained (Etyp) then + Write_Attribute := Name_Output; + end if; + + return + Make_Attribute_Reference (Loc, + Prefix => New_Occurrence_Of (Etyp, Loc), + Attribute_Name => Write_Attribute, + Expressions => New_List ( + New_Occurrence_Of (Stream, Loc), + Object)); + end Pack_Node_Into_Stream_Access; + + ------------------------------- + -- RACW_Type_Is_Asynchronous -- + ------------------------------- + + procedure RACW_Type_Is_Asynchronous (RACW_Type : in Entity_Id) is + N : constant Node_Id := Asynchronous_Flags_Table.Get (RACW_Type); + pragma Assert (N /= Empty); + + begin + Replace (N, New_Occurrence_Of (Standard_True, Sloc (N))); + end RACW_Type_Is_Asynchronous; + + ------------------------- + -- RCI_Package_Locator -- + ------------------------- + + function RCI_Package_Locator + (Loc : Source_Ptr; + Package_Spec : Node_Id) + return Node_Id + is + Inst : constant Node_Id := + Make_Package_Instantiation (Loc, + Defining_Unit_Name => + Make_Defining_Identifier (Loc, New_Internal_Name ('R')), + Name => + New_Occurrence_Of (RTE (RE_RCI_Info), Loc), + Generic_Associations => New_List ( + Make_Generic_Association (Loc, + Selector_Name => + Make_Identifier (Loc, Name_RCI_Name), + Explicit_Generic_Actual_Parameter => + Make_String_Literal (Loc, + Strval => Get_Pkg_Name_String_Id (Package_Spec))))); + + begin + RCI_Locator_Table.Set (Defining_Unit_Name (Package_Spec), + Defining_Unit_Name (Inst)); + return Inst; + end RCI_Package_Locator; + + ----------------------------------------------- + -- Remote_Types_Tagged_Full_View_Encountered -- + ----------------------------------------------- + + procedure Remote_Types_Tagged_Full_View_Encountered + (Full_View : in Entity_Id) + is + Stub_Elements : constant Stub_Structure := + Stubs_Table.Get (Full_View); + + begin + if Stub_Elements /= Empty_Stub_Structure then + Add_RACW_Primitive_Declarations_And_Bodies + (Full_View, + Parent (Declaration_Node (Stub_Elements.Object_RPC_Receiver)), + List_Containing (Declaration_Node (Full_View))); + end if; + end Remote_Types_Tagged_Full_View_Encountered; + + ------------------- + -- Scope_Of_Spec -- + ------------------- + + function Scope_Of_Spec (Spec : Node_Id) return Entity_Id is + Unit_Name : Node_Id := Defining_Unit_Name (Spec); + + begin + while Nkind (Unit_Name) /= N_Defining_Identifier loop + Unit_Name := Defining_Identifier (Unit_Name); + end loop; + + return Unit_Name; + end Scope_Of_Spec; + +end Exp_Dist; |