OSDN Git Service

0e3fc2379a4c551896bf5950f9c8f9613bcc40f4
[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-2008, 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 3,  or (at your option) any later ver- --
14 -- sion.  GNAT is distributed in the hope that it will be useful, but WITH- --
15 -- OUT ANY WARRANTY;  without even the  implied warranty of MERCHANTABILITY --
16 -- or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License --
17 -- for  more details.  You should have  received  a copy of the GNU General --
18 -- Public License  distributed with GNAT; see file COPYING3.  If not, go to --
19 -- http://www.gnu.org/licenses for a complete copy of the license.          --
20 --                                                                          --
21 -- GNAT was originally developed  by the GNAT team at  New York University. --
22 -- Extensive contributions were provided by Ada Core Technologies Inc.      --
23 --                                                                          --
24 ------------------------------------------------------------------------------
25
26 with Atree;    use Atree;
27 with Einfo;    use Einfo;
28 with Exp_Util; use Exp_Util;
29 with Nmake;    use Nmake;
30 with Namet;    use Namet;
31 with Nlists;   use Nlists;
32 with Rtsfind;  use Rtsfind;
33 with Sem;      use Sem;
34 with Sem_Util; use Sem_Util;
35 with Sinfo;    use Sinfo;
36 with Snames;   use Snames;
37 with Stand;    use Stand;
38 with Stringt;  use Stringt;
39 with Tbuild;   use Tbuild;
40
41 package body Exp_Smem is
42
43    Insert_Node : Node_Id;
44    --  Node after which a write call is to be inserted
45
46    -----------------------
47    -- Local Subprograms --
48    -----------------------
49
50    procedure Add_Read_Before (N : Node_Id);
51    --  Insert a Shared_Var_ROpen call for variable before node N
52
53    procedure Add_Write_After (N : Node_Id);
54    --  Insert a Shared_Var_WOpen call for variable after the node
55    --  Insert_Node, as recorded by On_Lhs_Of_Assignment (where it points
56    --  to the assignment statement) or Is_Out_Actual (where it points to
57    --  the procedure call statement).
58
59    procedure Build_Full_Name (E : Entity_Id; N : out String_Id);
60    --  Build the fully qualified string name of a shared variable
61
62    function On_Lhs_Of_Assignment (N : Node_Id) return Boolean;
63    --  Determines if N is on the left hand of the assignment. This means
64    --  that either it is a simple variable, or it is a record or array
65    --  variable with a corresponding selected or indexed component on
66    --  the left side of an assignment. If the result is True, then
67    --  Insert_Node is set to point to the assignment
68
69    function Is_Out_Actual (N : Node_Id) return Boolean;
70    --  In a similar manner, this function determines if N appears as an
71    --  OUT or IN OUT parameter to a procedure call. If the result is
72    --  True, then Insert_Node is set to point to the call.
73
74    function Build_Shared_Var_Proc_Call
75      (Loc : Source_Ptr;
76       E   : Node_Id;
77       N   : Name_Id) return Node_Id;
78    --  Build a call to support procedure N for shared object E (provided by
79    --  the instance of System.Shared_Storage.Shared_Var_Procs associated to E).
80
81    --------------------------------
82    -- Build_Shared_Var_Proc_Call --
83    --------------------------------
84
85    function Build_Shared_Var_Proc_Call
86      (Loc : Source_Ptr;
87       E   : Entity_Id;
88       N   : Name_Id) return Node_Id is
89    begin
90       return Make_Procedure_Call_Statement (Loc,
91         Name => Make_Selected_Component (Loc,
92           Prefix        =>
93             New_Occurrence_Of (Shared_Var_Procs_Instance (E), Loc),
94           Selector_Name => Make_Identifier (Loc, Chars => N)));
95    end Build_Shared_Var_Proc_Call;
96
97    ---------------------
98    -- Add_Read_Before --
99    ---------------------
100
101    procedure Add_Read_Before (N : Node_Id) is
102       Loc : constant Source_Ptr := Sloc (N);
103       Ent : constant Node_Id    := Entity (N);
104    begin
105       if Present (Shared_Var_Procs_Instance (Ent)) then
106          Insert_Action (N, Build_Shared_Var_Proc_Call (Loc, Ent, Name_Read));
107       end if;
108    end Add_Read_Before;
109
110    -------------------------------
111    -- Add_Shared_Var_Lock_Procs --
112    -------------------------------
113
114    procedure Add_Shared_Var_Lock_Procs (N : Node_Id) is
115       Loc   : constant Source_Ptr := Sloc (N);
116       Obj   : constant Entity_Id  := Entity (Expression (First_Actual (N)));
117       Inode : Node_Id;
118       Vnm   : String_Id;
119
120    begin
121       --  We have to add Shared_Var_Lock and Shared_Var_Unlock calls around
122       --  the procedure or function call node. First we locate the right
123       --  place to do the insertion, which is the call itself in the
124       --  procedure call case, or else the nearest non subexpression
125       --  node that contains the function call.
126
127       Inode := N;
128       while Nkind (Inode) /= N_Procedure_Call_Statement
129         and then Nkind (Inode) in N_Subexpr
130       loop
131          Inode := Parent (Inode);
132       end loop;
133
134       --  Now insert the Lock and Unlock calls and the read/write calls
135
136       --  Two concerns here. First we are not dealing with the exception
137       --  case, really we need some kind of cleanup routine to do the
138       --  Unlock. Second, these lock calls should be inside the protected
139       --  object processing, not outside, otherwise they can be done at
140       --  the wrong priority, resulting in dead lock situations ???
141
142       Build_Full_Name (Obj, Vnm);
143
144       --  First insert the Lock call before
145
146       Insert_Before_And_Analyze (Inode,
147         Make_Procedure_Call_Statement (Loc,
148           Name => New_Occurrence_Of (RTE (RE_Shared_Var_Lock), Loc),
149           Parameter_Associations => New_List (
150             Make_String_Literal (Loc, Vnm))));
151
152       --  Now, right after the Lock, insert a call to read the object
153
154       Insert_Before_And_Analyze (Inode,
155         Build_Shared_Var_Proc_Call (Loc, Obj, Name_Read));
156
157       --  Now insert the Unlock call after
158
159       Insert_After_And_Analyze (Inode,
160         Make_Procedure_Call_Statement (Loc,
161           Name => New_Occurrence_Of (RTE (RE_Shared_Var_Unlock), Loc),
162           Parameter_Associations => New_List (
163             Make_String_Literal (Loc, Vnm))));
164
165       --  Now for a procedure call, but not a function call, insert the
166       --  call to write the object just before the unlock.
167
168       if Nkind (N) = N_Procedure_Call_Statement then
169          Insert_After_And_Analyze (Inode,
170            Build_Shared_Var_Proc_Call (Loc, Obj, Name_Write));
171       end if;
172
173    end Add_Shared_Var_Lock_Procs;
174
175    ---------------------
176    -- Add_Write_After --
177    ---------------------
178
179    procedure Add_Write_After (N : Node_Id) is
180       Loc : constant Source_Ptr := Sloc (N);
181       Ent : constant Node_Id    := Entity (N);
182
183    begin
184       if Present (Shared_Var_Procs_Instance (Ent)) then
185          Insert_After_And_Analyze (Insert_Node,
186            Build_Shared_Var_Proc_Call (Loc, Ent, Name_Write));
187       end if;
188    end Add_Write_After;
189
190    ---------------------
191    -- Build_Full_Name --
192    ---------------------
193
194    procedure Build_Full_Name (E : Entity_Id; N : out String_Id) is
195
196       procedure Build_Name (E : Entity_Id);
197       --  This is a recursive routine used to construct the fully qualified
198       --  string name of the package corresponding to the shared variable.
199
200       ----------------
201       -- Build_Name --
202       ----------------
203
204       procedure Build_Name (E : Entity_Id) is
205       begin
206          if Scope (E) /= Standard_Standard then
207             Build_Name (Scope (E));
208             Store_String_Char ('.');
209          end if;
210
211          Get_Decoded_Name_String (Chars (E));
212          Store_String_Chars (Name_Buffer (1 .. Name_Len));
213       end Build_Name;
214
215    --  Start of processing for Build_Full_Name
216
217    begin
218       Start_String;
219       Build_Name (E);
220       N := End_String;
221    end Build_Full_Name;
222
223    ------------------------------------
224    -- Expand_Shared_Passive_Variable --
225    ------------------------------------
226
227    procedure Expand_Shared_Passive_Variable (N : Node_Id) is
228       Typ : constant Entity_Id := Etype (N);
229
230    begin
231       --  Nothing to do for protected or limited objects
232
233       if Is_Limited_Type (Typ) or else Is_Concurrent_Type (Typ) then
234          return;
235
236       --  If we are on the left hand side of an assignment, then we add
237       --  the write call after the assignment.
238
239       elsif On_Lhs_Of_Assignment (N) then
240          Add_Write_After (N);
241
242       --  If we are a parameter for an out or in out formal, then put
243       --  the read before and the write after.
244
245       elsif Is_Out_Actual (N) then
246          Add_Read_Before (N);
247          Add_Write_After (N);
248
249       --  All other cases are simple reads
250
251       else
252          Add_Read_Before (N);
253       end if;
254    end Expand_Shared_Passive_Variable;
255
256    -------------------
257    -- Is_Out_Actual --
258    -------------------
259
260    function Is_Out_Actual (N : Node_Id) return Boolean is
261       Formal : Entity_Id;
262       Call   : Node_Id;
263
264    begin
265       Find_Actual (N, Formal, Call);
266
267       if No (Formal) then
268          return False;
269
270       else
271          if Ekind (Formal) = E_Out_Parameter
272               or else
273             Ekind (Formal) = E_In_Out_Parameter
274          then
275             Insert_Node := Call;
276             return True;
277          else
278             return False;
279          end if;
280       end if;
281    end Is_Out_Actual;
282
283    ---------------------------
284    -- Make_Shared_Var_Procs --
285    ---------------------------
286
287    function Make_Shared_Var_Procs (N : Node_Id) return Node_Id is
288       Loc : constant Source_Ptr := Sloc (N);
289       Ent : constant Entity_Id  := Defining_Identifier (N);
290       Typ : constant Entity_Id  := Etype (Ent);
291       Vnm : String_Id;
292
293       After : constant Node_Id := Next (N);
294       --  Node located right after N originally (after insertion of the SV
295       --  procs this node is right after the last inserted node).
296
297       SVP_Instance : constant Entity_Id := Make_Defining_Identifier (Loc,
298                        Chars => New_External_Name (Chars (Ent), 'G'));
299       --  Instance of System.Shared_Storage.Shared_Var_Procs associated
300       --  with Ent.
301
302       Instantiation : Node_Id;
303       --  Package instanciation node for SVP_Instance
304
305    --  Start of processing for Make_Shared_Var_Procs
306
307    begin
308       Build_Full_Name (Ent, Vnm);
309
310       --  We turn off Shared_Passive during construction and analysis of
311       --  the generic package instantition, to avoid improper attempts to
312       --  process the variable references within these instantiation.
313
314       Set_Is_Shared_Passive (Ent, False);
315
316       --  Construct generic package instantiation
317
318       --  package varG is new Shared_Var_Procs (Typ, var, "pkg.var");
319
320       Instantiation :=
321         Make_Package_Instantiation (Loc,
322           Defining_Unit_Name   => SVP_Instance,
323           Name                 =>
324             New_Occurrence_Of (RTE (RE_Shared_Var_Procs), Loc),
325           Generic_Associations => New_List (
326             Make_Generic_Association (Loc, Explicit_Generic_Actual_Parameter =>
327               New_Occurrence_Of (Typ, Loc)),
328             Make_Generic_Association (Loc, Explicit_Generic_Actual_Parameter =>
329               New_Occurrence_Of (Ent, Loc)),
330             Make_Generic_Association (Loc, Explicit_Generic_Actual_Parameter =>
331               Make_String_Literal (Loc, Vnm))));
332
333       Insert_After_And_Analyze (N, Instantiation);
334
335       Set_Is_Shared_Passive (Ent, True);
336       Set_Shared_Var_Procs_Instance
337         (Ent, Defining_Entity (Instance_Spec (Instantiation)));
338
339       --  Return last node before After
340
341       declare
342          Nod : Node_Id := Next (N);
343
344       begin
345          while Next (Nod) /= After loop
346             Nod := Next (Nod);
347          end loop;
348
349          return Nod;
350       end;
351    end Make_Shared_Var_Procs;
352
353    --------------------------
354    -- On_Lhs_Of_Assignment --
355    --------------------------
356
357    function On_Lhs_Of_Assignment (N : Node_Id) return Boolean is
358       P : constant Node_Id := Parent (N);
359
360    begin
361       if Nkind (P) = N_Assignment_Statement then
362          if N = Name (P) then
363             Insert_Node := P;
364             return True;
365          else
366             return False;
367          end if;
368
369       elsif (Nkind (P) = N_Indexed_Component
370                or else
371              Nkind (P) = N_Selected_Component)
372         and then N = Prefix (P)
373       then
374          return On_Lhs_Of_Assignment (P);
375
376       else
377          return False;
378       end if;
379    end On_Lhs_Of_Assignment;
380
381 end Exp_Smem;