OSDN Git Service

2005-06-10 Arnaud Charlet <charlet@adacore.com>
[pf3gnuchains/gcc-fork.git] / gcc / ada / exp_smem.adb
1 ------------------------------------------------------------------------------
2 --                                                                          --
3 --                         GNAT COMPILER COMPONENTS                         --
4 --                                                                          --
5 --                             E X P _ S M E M                              --
6 --                                                                          --
7 --                                 B o d y                                  --
8 --                                                                          --
9 --          Copyright (C) 1998-2005 Free Software Foundation, Inc.          --
10 --                                                                          --
11 -- GNAT is free software;  you can  redistribute it  and/or modify it under --
12 -- terms of the  GNU General Public License as published  by the Free Soft- --
13 -- ware  Foundation;  either version 2,  or (at your option) any later ver- --
14 -- sion.  GNAT is distributed in the hope that it will be useful, but WITH- --
15 -- OUT ANY WARRANTY;  without even the  implied warranty of MERCHANTABILITY --
16 -- or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License --
17 -- for  more details.  You should have  received  a copy of the GNU General --
18 -- Public License  distributed with GNAT;  see file COPYING.  If not, write --
19 -- to  the Free Software Foundation,  59 Temple Place - Suite 330,  Boston, --
20 -- MA 02111-1307, USA.                                                      --
21 --                                                                          --
22 -- GNAT was originally developed  by the GNAT team at  New York University. --
23 -- Extensive contributions were provided by Ada Core Technologies Inc.      --
24 --                                                                          --
25 ------------------------------------------------------------------------------
26
27 with Atree;    use Atree;
28 with Einfo;    use Einfo;
29 with Exp_Util; use Exp_Util;
30 with Nmake;    use Nmake;
31 with Namet;    use Namet;
32 with Nlists;   use Nlists;
33 with Rtsfind;  use Rtsfind;
34 with Sem;      use Sem;
35 with Sem_Util; use Sem_Util;
36 with Sinfo;    use Sinfo;
37 with Snames;   use Snames;
38 with Stand;    use Stand;
39 with Stringt;  use Stringt;
40 with Tbuild;   use Tbuild;
41
42 package body Exp_Smem is
43
44    Insert_Node : Node_Id;
45    --  Node after which a write call is to be inserted
46
47    -----------------------
48    -- Local Subprograms --
49    -----------------------
50
51    procedure Add_Read_Before (N : Node_Id);
52    --  Insert a Shared_Var_ROpen call for variable before node N
53
54    procedure Add_Write_After (N : Node_Id);
55    --  Insert a Shared_Var_WOpen call for variable after the node
56    --  Insert_Node, as recorded by On_Lhs_Of_Assigment (where it points
57    --  to the assignment statement) or Is_Out_Actual (where it points to
58    --  the procedure call statement).
59
60    procedure Build_Full_Name
61      (E : in  Entity_Id;
62       N : out String_Id);
63    --  Build the fully qualified string name of a shared variable.
64
65    function On_Lhs_Of_Assignment (N : Node_Id) return Boolean;
66    --  Determines if N is on the left hand of the assignment. This means
67    --  that either it is a simple variable, or it is a record or array
68    --  variable with a corresponding selected or indexed component on
69    --  the left side of an assignment. If the result is True, then
70    --  Insert_Node is set to point to the assignment
71
72    function Is_Out_Actual (N : Node_Id) return Boolean;
73    --  In a similar manner, this function determines if N appears as an
74    --  OUT or IN OUT parameter to a procedure call. If the result is
75    --  True, then Insert_Node is set to point to the assignment.
76
77    ---------------------
78    -- Add_Read_Before --
79    ---------------------
80
81    procedure Add_Read_Before (N : Node_Id) is
82       Loc : constant Source_Ptr := Sloc (N);
83       Ent : constant Node_Id    := Entity (N);
84
85    begin
86       if Present (Shared_Var_Read_Proc (Ent)) then
87          Insert_Action (N,
88            Make_Procedure_Call_Statement (Loc,
89              Name =>
90                New_Occurrence_Of (Shared_Var_Read_Proc (Ent), Loc),
91              Parameter_Associations => Empty_List));
92       end if;
93    end Add_Read_Before;
94
95    -------------------------------
96    -- Add_Shared_Var_Lock_Procs --
97    -------------------------------
98
99    procedure Add_Shared_Var_Lock_Procs (N : Node_Id) is
100       Loc   : constant Source_Ptr := Sloc (N);
101       Obj   : constant Entity_Id  := Entity (Expression (First_Actual (N)));
102       Inode : Node_Id;
103       Vnm   : String_Id;
104
105    begin
106       --  We have to add Shared_Var_Lock and Shared_Var_Unlock calls around
107       --  the procedure or function call node. First we locate the right
108       --  place to do the insertion, which is the call itself in the
109       --  procedure call case, or else the nearest non subexpression
110       --  node that contains the function call.
111
112       Inode := N;
113       while Nkind (Inode) /= N_Procedure_Call_Statement
114         and then Nkind (Inode) in N_Subexpr
115       loop
116          Inode := Parent (Inode);
117       end loop;
118
119       --  Now insert the Lock and Unlock calls and the read/write calls
120
121       --  Two concerns here. First we are not dealing with the exception
122       --  case, really we need some kind of cleanup routine to do the
123       --  Unlock. Second, these lock calls should be inside the protected
124       --  object processing, not outside, otherwise they can be done at
125       --  the wrong priority, resulting in dead lock situations ???
126
127       Build_Full_Name (Obj, Vnm);
128
129       --  First insert the Lock call before
130
131       Insert_Before_And_Analyze (Inode,
132         Make_Procedure_Call_Statement (Loc,
133           Name => New_Occurrence_Of (RTE (RE_Shared_Var_Lock), Loc),
134           Parameter_Associations => New_List (
135             Make_String_Literal (Loc, Vnm))));
136
137       --  Now, right after the Lock, insert a call to read the object
138
139       Insert_Before_And_Analyze (Inode,
140         Make_Procedure_Call_Statement (Loc,
141           Name => New_Occurrence_Of (Shared_Var_Read_Proc (Obj), Loc)));
142
143       --  Now insert the Unlock call after
144
145       Insert_After_And_Analyze (Inode,
146         Make_Procedure_Call_Statement (Loc,
147           Name => New_Occurrence_Of (RTE (RE_Shared_Var_Unlock), Loc),
148           Parameter_Associations => New_List (
149             Make_String_Literal (Loc, Vnm))));
150
151       --  Now for a procedure call, but not a function call, insert the
152       --  call to write the object just before the unlock.
153
154       if Nkind (N) = N_Procedure_Call_Statement then
155          Insert_After_And_Analyze (Inode,
156            Make_Procedure_Call_Statement (Loc,
157              Name => New_Occurrence_Of (Shared_Var_Assign_Proc (Obj), Loc)));
158       end if;
159
160    end Add_Shared_Var_Lock_Procs;
161
162    ---------------------
163    -- Add_Write_After --
164    ---------------------
165
166    procedure Add_Write_After (N : Node_Id) is
167       Loc : constant Source_Ptr := Sloc (N);
168       Ent : constant Node_Id    := Entity (N);
169
170    begin
171       if Present (Shared_Var_Assign_Proc (Ent)) then
172          Insert_After_And_Analyze (Insert_Node,
173            Make_Procedure_Call_Statement (Loc,
174              Name =>
175                New_Occurrence_Of (Shared_Var_Assign_Proc (Ent), Loc),
176              Parameter_Associations => Empty_List));
177       end if;
178    end Add_Write_After;
179
180    ---------------------
181    -- Build_Full_Name --
182    ---------------------
183
184    procedure Build_Full_Name
185      (E : in  Entity_Id;
186       N : out String_Id)
187    is
188
189       procedure Build_Name (E : Entity_Id);
190       --  This is a recursive routine used to construct the fully
191       --  qualified string name of the package corresponding to the
192       --  shared variable.
193
194       procedure Build_Name (E : Entity_Id) is
195       begin
196          if Scope (E) /= Standard_Standard then
197             Build_Name (Scope (E));
198             Store_String_Char ('.');
199          end if;
200
201          Get_Decoded_Name_String (Chars (E));
202          Store_String_Chars (Name_Buffer (1 .. Name_Len));
203       end Build_Name;
204
205    begin
206       Start_String;
207       Build_Name (E);
208       N := End_String;
209    end Build_Full_Name;
210
211    ------------------------------------
212    -- Expand_Shared_Passive_Variable --
213    ------------------------------------
214
215    procedure Expand_Shared_Passive_Variable (N : Node_Id) is
216       Typ : constant Entity_Id := Etype (N);
217
218    begin
219       --  Nothing to do for protected or limited objects
220
221       if Is_Limited_Type (Typ) or else Is_Concurrent_Type (Typ) then
222          return;
223
224       --  If we are on the left hand side of an assignment, then we add
225       --  the write call after the assignment.
226
227       elsif On_Lhs_Of_Assignment (N) then
228          Add_Write_After (N);
229
230       --  If we are a parameter for an out or in out formal, then put
231       --  the read before and the write after.
232
233       elsif Is_Out_Actual (N) then
234          Add_Read_Before (N);
235          Add_Write_After (N);
236
237       --  All other cases are simple reads
238
239       else
240          Add_Read_Before (N);
241       end if;
242    end Expand_Shared_Passive_Variable;
243
244    -------------------
245    -- Is_Out_Actual --
246    -------------------
247
248    function Is_Out_Actual (N : Node_Id) return Boolean is
249       Parnt  : constant Node_Id := Parent (N);
250       Formal : Entity_Id;
251       Call   : Node_Id;
252       Actual : Node_Id;
253
254    begin
255       if (Nkind (Parnt) = N_Indexed_Component
256             or else
257           Nkind (Parnt) = N_Selected_Component)
258         and then N = Prefix (Parnt)
259       then
260          return Is_Out_Actual (Parnt);
261
262       elsif Nkind (Parnt) = N_Parameter_Association
263         and then N = Explicit_Actual_Parameter (Parnt)
264       then
265          Call := Parent (Parnt);
266
267       elsif Nkind (Parnt) = N_Procedure_Call_Statement then
268          Call := Parnt;
269
270       else
271          return False;
272       end if;
273
274       --  Fall here if we are definitely a parameter
275
276       Actual := First_Actual (Call);
277       Formal := First_Formal (Entity (Name (Call)));
278
279       loop
280          if Actual = N then
281             if Ekind (Formal) /= E_In_Parameter then
282                Insert_Node := Call;
283                return True;
284             else
285                return False;
286             end if;
287
288          else
289             Actual := Next_Actual (Actual);
290             Formal := Next_Formal (Formal);
291          end if;
292       end loop;
293    end Is_Out_Actual;
294
295    ---------------------------
296    -- Make_Shared_Var_Procs --
297    ---------------------------
298
299    procedure Make_Shared_Var_Procs (N : Node_Id) is
300       Loc : constant Source_Ptr := Sloc (N);
301       Ent : constant Entity_Id  := Defining_Identifier (N);
302       Typ : constant Entity_Id  := Etype (Ent);
303       Vnm : String_Id;
304       Atr : Node_Id;
305
306       Assign_Proc : constant Entity_Id :=
307                       Make_Defining_Identifier (Loc,
308                         Chars => New_External_Name (Chars (Ent), 'A'));
309
310       Read_Proc : constant Entity_Id :=
311                     Make_Defining_Identifier (Loc,
312                       Chars => New_External_Name (Chars (Ent), 'R'));
313
314       S : Entity_Id;
315
316    --  Start of processing for Make_Shared_Var_Procs
317
318    begin
319       Build_Full_Name (Ent, Vnm);
320
321       --  We turn off Shared_Passive during construction and analysis of
322       --  the assign and read routines, to avoid improper attempts to
323       --  process the variable references within these procedures.
324
325       Set_Is_Shared_Passive (Ent, False);
326
327       --  Construct assignment routine
328
329       --    procedure VarA is
330       --       S : Ada.Streams.Stream_IO.Stream_Access;
331       --    begin
332       --       S := Shared_Var_WOpen ("pkg.var");
333       --       typ'Write (S, var);
334       --       Shared_Var_Close (S);
335       --    end VarA;
336
337       S   := Make_Defining_Identifier (Loc, Name_uS);
338
339       Atr :=
340         Make_Attribute_Reference (Loc,
341           Prefix => New_Occurrence_Of (Typ, Loc),
342           Attribute_Name => Name_Write,
343           Expressions => New_List (
344             New_Reference_To (S, Loc),
345             New_Occurrence_Of (Ent, Loc)));
346
347       Insert_After_And_Analyze (N,
348         Make_Subprogram_Body (Loc,
349           Specification =>
350             Make_Procedure_Specification (Loc,
351               Defining_Unit_Name => Assign_Proc),
352
353          --  S : Ada.Streams.Stream_IO.Stream_Access;
354
355           Declarations => New_List (
356             Make_Object_Declaration (Loc,
357               Defining_Identifier => S,
358               Object_Definition =>
359                 New_Occurrence_Of (RTE (RE_Stream_Access), Loc))),
360
361           Handled_Statement_Sequence =>
362             Make_Handled_Sequence_Of_Statements (Loc,
363               Statements => New_List (
364
365                --  S := Shared_Var_WOpen ("pkg.var");
366
367                 Make_Assignment_Statement (Loc,
368                   Name => New_Reference_To (S, Loc),
369                   Expression =>
370                     Make_Function_Call (Loc,
371                       Name =>
372                         New_Occurrence_Of
373                           (RTE (RE_Shared_Var_WOpen), Loc),
374                       Parameter_Associations => New_List (
375                         Make_String_Literal (Loc, Vnm)))),
376
377                 Atr,
378
379                --  Shared_Var_Close (S);
380
381                 Make_Procedure_Call_Statement (Loc,
382                   Name =>
383                     New_Occurrence_Of (RTE (RE_Shared_Var_Close), Loc),
384                   Parameter_Associations =>
385                     New_List (New_Reference_To (S, Loc)))))));
386
387       --  Construct read routine
388
389       --    procedure varR is
390       --       S : Ada.Streams.Stream_IO.Stream_Access;
391       --    begin
392       --       S := Shared_Var_ROpen ("pkg.var");
393       --       if S /= null then
394       --          typ'Read (S, Var);
395       --          Shared_Var_Close (S);
396       --       end if;
397       --    end varR;
398
399       S   := Make_Defining_Identifier (Loc, Name_uS);
400
401       Atr :=
402         Make_Attribute_Reference (Loc,
403           Prefix => New_Occurrence_Of (Typ, Loc),
404           Attribute_Name => Name_Read,
405           Expressions => New_List (
406             New_Reference_To (S, Loc),
407             New_Occurrence_Of (Ent, Loc)));
408
409       Insert_After_And_Analyze (N,
410         Make_Subprogram_Body (Loc,
411           Specification =>
412             Make_Procedure_Specification (Loc,
413               Defining_Unit_Name => Read_Proc),
414
415          --  S : Ada.Streams.Stream_IO.Stream_Access;
416
417           Declarations => New_List (
418             Make_Object_Declaration (Loc,
419               Defining_Identifier => S,
420               Object_Definition =>
421                 New_Occurrence_Of (RTE (RE_Stream_Access), Loc))),
422
423           Handled_Statement_Sequence =>
424             Make_Handled_Sequence_Of_Statements (Loc,
425               Statements => New_List (
426
427                --  S := Shared_Var_ROpen ("pkg.var");
428
429                 Make_Assignment_Statement (Loc,
430                   Name => New_Reference_To (S, Loc),
431                   Expression =>
432                     Make_Function_Call (Loc,
433                       Name =>
434                         New_Occurrence_Of
435                           (RTE (RE_Shared_Var_ROpen), Loc),
436                       Parameter_Associations => New_List (
437                         Make_String_Literal (Loc, Vnm)))),
438
439                --  if S /= null then
440
441                 Make_Implicit_If_Statement (N,
442                   Condition =>
443                     Make_Op_Ne (Loc,
444                       Left_Opnd  => New_Reference_To (S, Loc),
445                       Right_Opnd => Make_Null (Loc)),
446
447                    Then_Statements => New_List (
448
449                      --  typ'Read (S, Var);
450
451                      Atr,
452
453                      --  Shared_Var_Close (S);
454
455                      Make_Procedure_Call_Statement (Loc,
456                        Name =>
457                          New_Occurrence_Of
458                            (RTE (RE_Shared_Var_Close), Loc),
459                        Parameter_Associations =>
460                          New_List (New_Reference_To (S, Loc)))))))));
461
462       Set_Is_Shared_Passive      (Ent, True);
463       Set_Shared_Var_Assign_Proc (Ent, Assign_Proc);
464       Set_Shared_Var_Read_Proc   (Ent, Read_Proc);
465    end Make_Shared_Var_Procs;
466
467    --------------------------
468    -- On_Lhs_Of_Assignment --
469    --------------------------
470
471    function On_Lhs_Of_Assignment (N : Node_Id) return Boolean is
472       P : constant Node_Id := Parent (N);
473
474    begin
475       if Nkind (P) = N_Assignment_Statement then
476          if N = Name (P) then
477             Insert_Node := P;
478             return True;
479          else
480             return False;
481          end if;
482
483       elsif (Nkind (P) = N_Indexed_Component
484                or else
485              Nkind (P) = N_Selected_Component)
486         and then N = Prefix (P)
487       then
488          return On_Lhs_Of_Assignment (P);
489
490       else
491          return False;
492       end if;
493    end On_Lhs_Of_Assignment;
494
495 end Exp_Smem;