1 ------------------------------------------------------------------------------
3 -- GNAT COMPILER COMPONENTS --
11 -- Copyright (C) 1998-2000 Free Software Foundation, Inc. --
13 -- GNAT is free software; you can redistribute it and/or modify it under --
14 -- terms of the GNU General Public License as published by the Free Soft- --
15 -- ware Foundation; either version 2, or (at your option) any later ver- --
16 -- sion. GNAT is distributed in the hope that it will be useful, but WITH- --
17 -- OUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY --
18 -- or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License --
19 -- for more details. You should have received a copy of the GNU General --
20 -- Public License distributed with GNAT; see file COPYING. If not, write --
21 -- to the Free Software Foundation, 59 Temple Place - Suite 330, Boston, --
22 -- MA 02111-1307, USA. --
24 -- GNAT was originally developed by the GNAT team at New York University. --
25 -- Extensive contributions were provided by Ada Core Technologies Inc. --
27 ------------------------------------------------------------------------------
29 with Atree
; use Atree
;
30 with Einfo
; use Einfo
;
31 with Exp_Util
; use Exp_Util
;
32 with Nmake
; use Nmake
;
33 with Namet
; use Namet
;
34 with Nlists
; use Nlists
;
35 with Rtsfind
; use Rtsfind
;
37 with Sem_Util
; use Sem_Util
;
38 with Sinfo
; use Sinfo
;
39 with Snames
; use Snames
;
40 with Stand
; use Stand
;
41 with Stringt
; use Stringt
;
42 with Tbuild
; use Tbuild
;
44 package body Exp_Smem
is
46 Insert_Node
: Node_Id
;
47 -- Node after which a write call is to be inserted
49 -----------------------
50 -- Local Subprograms --
51 -----------------------
53 procedure Add_Read_Before
(N
: Node_Id
);
54 -- Insert a Shared_Var_ROpen call for variable before node N
56 procedure Add_Write_After
(N
: Node_Id
);
57 -- Insert a Shared_Var_WOpen call for variable after the node
58 -- Insert_Node, as recorded by On_Lhs_Of_Assigment (where it points
59 -- to the assignment statement) or Is_Out_Actual (where it points to
60 -- the procedure call statement).
62 procedure Build_Full_Name
65 -- Build the fully qualified string name of a shared variable.
67 function On_Lhs_Of_Assignment
(N
: Node_Id
) return Boolean;
68 -- Determines if N is on the left hand of the assignment. This means
69 -- that either it is a simple variable, or it is a record or array
70 -- variable with a corresponding selected or indexed component on
71 -- the left side of an assignment. If the result is True, then
72 -- Insert_Node is set to point to the assignment
74 function Is_Out_Actual
(N
: Node_Id
) return Boolean;
75 -- In a similar manner, this function determines if N appears as an
76 -- OUT or IN OUT parameter to a procedure call. If the result is
77 -- True, then Insert_Node is set to point to the assignment.
83 procedure Add_Read_Before
(N
: Node_Id
) is
84 Loc
: constant Source_Ptr
:= Sloc
(N
);
85 Ent
: constant Node_Id
:= Entity
(N
);
88 if Present
(Shared_Var_Read_Proc
(Ent
)) then
90 Make_Procedure_Call_Statement
(Loc
,
92 New_Occurrence_Of
(Shared_Var_Read_Proc
(Ent
), Loc
),
93 Parameter_Associations
=> Empty_List
));
97 -------------------------------
98 -- Add_Shared_Var_Lock_Procs --
99 -------------------------------
101 procedure Add_Shared_Var_Lock_Procs
(N
: Node_Id
) is
102 Loc
: constant Source_Ptr
:= Sloc
(N
);
103 Obj
: constant Entity_Id
:= Entity
(Expression
(First_Actual
(N
)));
108 -- We have to add Shared_Var_Lock and Shared_Var_Unlock calls around
109 -- the procedure or function call node. First we locate the right
110 -- place to do the insertion, which is the call itself in the
111 -- procedure call case, or else the nearest non subexpression
112 -- node that contains the function call.
115 while Nkind
(Inode
) /= N_Procedure_Call_Statement
116 and then Nkind
(Inode
) in N_Subexpr
118 Inode
:= Parent
(Inode
);
121 -- Now insert the Lock and Unlock calls and the read/write calls
123 -- Two concerns here. First we are not dealing with the exception
124 -- case, really we need some kind of cleanup routine to do the
125 -- Unlock. Second, these lock calls should be inside the protected
126 -- object processing, not outside, otherwise they can be done at
127 -- the wrong priority, resulting in dead lock situations ???
129 Build_Full_Name
(Obj
, Vnm
);
131 -- First insert the Lock call before
133 Insert_Before_And_Analyze
(Inode
,
134 Make_Procedure_Call_Statement
(Loc
,
135 Name
=> New_Occurrence_Of
(RTE
(RE_Shared_Var_Lock
), Loc
),
136 Parameter_Associations
=> New_List
(
137 Make_String_Literal
(Loc
, Vnm
))));
139 -- Now, right after the Lock, insert a call to read the object
141 Insert_Before_And_Analyze
(Inode
,
142 Make_Procedure_Call_Statement
(Loc
,
143 Name
=> New_Occurrence_Of
(Shared_Var_Read_Proc
(Obj
), Loc
)));
145 -- Now insert the Unlock call after
147 Insert_After_And_Analyze
(Inode
,
148 Make_Procedure_Call_Statement
(Loc
,
149 Name
=> New_Occurrence_Of
(RTE
(RE_Shared_Var_Unlock
), Loc
),
150 Parameter_Associations
=> New_List
(
151 Make_String_Literal
(Loc
, Vnm
))));
153 -- Now for a procedure call, but not a function call, insert the
154 -- call to write the object just before the unlock.
156 if Nkind
(N
) = N_Procedure_Call_Statement
then
157 Insert_After_And_Analyze
(Inode
,
158 Make_Procedure_Call_Statement
(Loc
,
159 Name
=> New_Occurrence_Of
(Shared_Var_Assign_Proc
(Obj
), Loc
)));
162 end Add_Shared_Var_Lock_Procs
;
164 ---------------------
165 -- Add_Write_After --
166 ---------------------
168 procedure Add_Write_After
(N
: Node_Id
) is
169 Loc
: constant Source_Ptr
:= Sloc
(N
);
170 Ent
: constant Node_Id
:= Entity
(N
);
173 if Present
(Shared_Var_Assign_Proc
(Ent
)) then
174 Insert_After_And_Analyze
(Insert_Node
,
175 Make_Procedure_Call_Statement
(Loc
,
177 New_Occurrence_Of
(Shared_Var_Assign_Proc
(Ent
), Loc
),
178 Parameter_Associations
=> Empty_List
));
182 ---------------------
183 -- Build_Full_Name --
184 ---------------------
186 procedure Build_Full_Name
191 procedure Build_Name
(E
: Entity_Id
);
192 -- This is a recursive routine used to construct the fully
193 -- qualified string name of the package corresponding to the
196 procedure Build_Name
(E
: Entity_Id
) is
198 if Scope
(E
) /= Standard_Standard
then
199 Build_Name
(Scope
(E
));
200 Store_String_Char
('.');
203 Get_Decoded_Name_String
(Chars
(E
));
204 Store_String_Chars
(Name_Buffer
(1 .. Name_Len
));
213 ------------------------------------
214 -- Expand_Shared_Passive_Variable --
215 ------------------------------------
217 procedure Expand_Shared_Passive_Variable
(N
: Node_Id
) is
218 Typ
: constant Entity_Id
:= Etype
(N
);
221 -- Nothing to do for protected or limited objects
223 if Is_Limited_Type
(Typ
) or else Is_Concurrent_Type
(Typ
) then
226 -- If we are on the left hand side of an assignment, then we add
227 -- the write call after the assignment.
229 elsif On_Lhs_Of_Assignment
(N
) then
232 -- If we are a parameter for an out or in out formal, then put
233 -- the read before and the write after.
235 elsif Is_Out_Actual
(N
) then
239 -- All other cases are simple reads
244 end Expand_Shared_Passive_Variable
;
250 function Is_Out_Actual
(N
: Node_Id
) return Boolean is
251 Parnt
: constant Node_Id
:= Parent
(N
);
257 if (Nkind
(Parnt
) = N_Indexed_Component
259 Nkind
(Parnt
) = N_Selected_Component
)
260 and then N
= Prefix
(Parnt
)
262 return Is_Out_Actual
(Parnt
);
264 elsif Nkind
(Parnt
) = N_Parameter_Association
265 and then N
= Explicit_Actual_Parameter
(Parnt
)
267 Call
:= Parent
(Parnt
);
269 elsif Nkind
(Parnt
) = N_Procedure_Call_Statement
then
276 -- Fall here if we are definitely a parameter
278 Actual
:= First_Actual
(Call
);
279 Formal
:= First_Formal
(Entity
(Name
(Call
)));
283 if Ekind
(Formal
) /= E_In_Parameter
then
291 Actual
:= Next_Actual
(Actual
);
292 Formal
:= Next_Formal
(Formal
);
297 ---------------------------
298 -- Make_Shared_Var_Procs --
299 ---------------------------
301 procedure Make_Shared_Var_Procs
(N
: Node_Id
) is
302 Loc
: constant Source_Ptr
:= Sloc
(N
);
303 Ent
: constant Entity_Id
:= Defining_Identifier
(N
);
304 Typ
: constant Entity_Id
:= Etype
(Ent
);
308 Assign_Proc
: constant Entity_Id
:=
309 Make_Defining_Identifier
(Loc
,
310 Chars
=> New_External_Name
(Chars
(Ent
), 'A'));
312 Read_Proc
: constant Entity_Id
:=
313 Make_Defining_Identifier
(Loc
,
314 Chars
=> New_External_Name
(Chars
(Ent
), 'R'));
318 -- Start of processing for Make_Shared_Var_Procs
321 Build_Full_Name
(Ent
, Vnm
);
323 -- We turn off Shared_Passive during construction and analysis of
324 -- the assign and read routines, to avoid improper attempts to
325 -- process the variable references within these procedures.
327 Set_Is_Shared_Passive
(Ent
, False);
329 -- Construct assignment routine
332 -- S : Ada.Streams.Stream_IO.Stream_Access;
334 -- S := Shared_Var_WOpen ("pkg.var");
335 -- typ'Write (S, var);
336 -- Shared_Var_Close (S);
339 S
:= Make_Defining_Identifier
(Loc
, Name_uS
);
342 Make_Attribute_Reference
(Loc
,
343 Prefix
=> New_Occurrence_Of
(Typ
, Loc
),
344 Attribute_Name
=> Name_Write
,
345 Expressions
=> New_List
(
346 New_Reference_To
(S
, Loc
),
347 New_Occurrence_Of
(Ent
, Loc
)));
349 Set_OK_For_Stream
(Atr
, True);
351 Insert_After_And_Analyze
(N
,
352 Make_Subprogram_Body
(Loc
,
354 Make_Procedure_Specification
(Loc
,
355 Defining_Unit_Name
=> Assign_Proc
),
357 -- S : Ada.Streams.Stream_IO.Stream_Access;
359 Declarations
=> New_List
(
360 Make_Object_Declaration
(Loc
,
361 Defining_Identifier
=> S
,
363 New_Occurrence_Of
(RTE
(RE_Stream_Access
), Loc
))),
365 Handled_Statement_Sequence
=>
366 Make_Handled_Sequence_Of_Statements
(Loc
,
367 Statements
=> New_List
(
369 -- S := Shared_Var_WOpen ("pkg.var");
371 Make_Assignment_Statement
(Loc
,
372 Name
=> New_Reference_To
(S
, Loc
),
374 Make_Function_Call
(Loc
,
377 (RTE
(RE_Shared_Var_WOpen
), Loc
),
378 Parameter_Associations
=> New_List
(
379 Make_String_Literal
(Loc
, Vnm
)))),
383 -- Shared_Var_Close (S);
385 Make_Procedure_Call_Statement
(Loc
,
387 New_Occurrence_Of
(RTE
(RE_Shared_Var_Close
), Loc
),
388 Parameter_Associations
=>
389 New_List
(New_Reference_To
(S
, Loc
)))))));
391 -- Construct read routine
394 -- S : Ada.Streams.Stream_IO.Stream_Access;
396 -- S := Shared_Var_ROpen ("pkg.var");
398 -- typ'Read (S, Var);
399 -- Shared_Var_Close (S);
403 S
:= Make_Defining_Identifier
(Loc
, Name_uS
);
406 Make_Attribute_Reference
(Loc
,
407 Prefix
=> New_Occurrence_Of
(Typ
, Loc
),
408 Attribute_Name
=> Name_Read
,
409 Expressions
=> New_List
(
410 New_Reference_To
(S
, Loc
),
411 New_Occurrence_Of
(Ent
, Loc
)));
413 Set_OK_For_Stream
(Atr
, True);
415 Insert_After_And_Analyze
(N
,
416 Make_Subprogram_Body
(Loc
,
418 Make_Procedure_Specification
(Loc
,
419 Defining_Unit_Name
=> Read_Proc
),
421 -- S : Ada.Streams.Stream_IO.Stream_Access;
423 Declarations
=> New_List
(
424 Make_Object_Declaration
(Loc
,
425 Defining_Identifier
=> S
,
427 New_Occurrence_Of
(RTE
(RE_Stream_Access
), Loc
))),
429 Handled_Statement_Sequence
=>
430 Make_Handled_Sequence_Of_Statements
(Loc
,
431 Statements
=> New_List
(
433 -- S := Shared_Var_ROpen ("pkg.var");
435 Make_Assignment_Statement
(Loc
,
436 Name
=> New_Reference_To
(S
, Loc
),
438 Make_Function_Call
(Loc
,
441 (RTE
(RE_Shared_Var_ROpen
), Loc
),
442 Parameter_Associations
=> New_List
(
443 Make_String_Literal
(Loc
, Vnm
)))),
447 Make_Implicit_If_Statement
(N
,
450 Left_Opnd
=> New_Reference_To
(S
, Loc
),
451 Right_Opnd
=> Make_Null
(Loc
)),
453 Then_Statements
=> New_List
(
455 -- typ'Read (S, Var);
459 -- Shared_Var_Close (S);
461 Make_Procedure_Call_Statement
(Loc
,
464 (RTE
(RE_Shared_Var_Close
), Loc
),
465 Parameter_Associations
=>
466 New_List
(New_Reference_To
(S
, Loc
)))))))));
468 Set_Is_Shared_Passive
(Ent
, True);
469 Set_Shared_Var_Assign_Proc
(Ent
, Assign_Proc
);
470 Set_Shared_Var_Read_Proc
(Ent
, Read_Proc
);
471 end Make_Shared_Var_Procs
;
473 --------------------------
474 -- On_Lhs_Of_Assignment --
475 --------------------------
477 function On_Lhs_Of_Assignment
(N
: Node_Id
) return Boolean is
478 P
: constant Node_Id
:= Parent
(N
);
481 if Nkind
(P
) = N_Assignment_Statement
then
489 elsif (Nkind
(P
) = N_Indexed_Component
491 Nkind
(P
) = N_Selected_Component
)
492 and then N
= Prefix
(P
)
494 return On_Lhs_Of_Assignment
(P
);
499 end On_Lhs_Of_Assignment
;