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-2000 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 27with Atree; use Atree; 28with Einfo; use Einfo; 29with Exp_Util; use Exp_Util; 30with Nmake; use Nmake; 31with Namet; use Namet; 32with Nlists; use Nlists; 33with Rtsfind; use Rtsfind; 34with Sem; use Sem; 35with Sem_Util; use Sem_Util; 36with Sinfo; use Sinfo; 37with Snames; use Snames; 38with Stand; use Stand; 39with Stringt; use Stringt; 40with Tbuild; use Tbuild; 41 42package 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 Set_OK_For_Stream (Atr, True); 348 349 Insert_After_And_Analyze (N, 350 Make_Subprogram_Body (Loc, 351 Specification => 352 Make_Procedure_Specification (Loc, 353 Defining_Unit_Name => Assign_Proc), 354 355 -- S : Ada.Streams.Stream_IO.Stream_Access; 356 357 Declarations => New_List ( 358 Make_Object_Declaration (Loc, 359 Defining_Identifier => S, 360 Object_Definition => 361 New_Occurrence_Of (RTE (RE_Stream_Access), Loc))), 362 363 Handled_Statement_Sequence => 364 Make_Handled_Sequence_Of_Statements (Loc, 365 Statements => New_List ( 366 367 -- S := Shared_Var_WOpen ("pkg.var"); 368 369 Make_Assignment_Statement (Loc, 370 Name => New_Reference_To (S, Loc), 371 Expression => 372 Make_Function_Call (Loc, 373 Name => 374 New_Occurrence_Of 375 (RTE (RE_Shared_Var_WOpen), Loc), 376 Parameter_Associations => New_List ( 377 Make_String_Literal (Loc, Vnm)))), 378 379 Atr, 380 381 -- Shared_Var_Close (S); 382 383 Make_Procedure_Call_Statement (Loc, 384 Name => 385 New_Occurrence_Of (RTE (RE_Shared_Var_Close), Loc), 386 Parameter_Associations => 387 New_List (New_Reference_To (S, Loc))))))); 388 389 -- Construct read routine 390 391 -- procedure varR is 392 -- S : Ada.Streams.Stream_IO.Stream_Access; 393 -- begin 394 -- S := Shared_Var_ROpen ("pkg.var"); 395 -- if S /= null then 396 -- typ'Read (S, Var); 397 -- Shared_Var_Close (S); 398 -- end if; 399 -- end varR; 400 401 S := Make_Defining_Identifier (Loc, Name_uS); 402 403 Atr := 404 Make_Attribute_Reference (Loc, 405 Prefix => New_Occurrence_Of (Typ, Loc), 406 Attribute_Name => Name_Read, 407 Expressions => New_List ( 408 New_Reference_To (S, Loc), 409 New_Occurrence_Of (Ent, Loc))); 410 411 Set_OK_For_Stream (Atr, True); 412 413 Insert_After_And_Analyze (N, 414 Make_Subprogram_Body (Loc, 415 Specification => 416 Make_Procedure_Specification (Loc, 417 Defining_Unit_Name => Read_Proc), 418 419 -- S : Ada.Streams.Stream_IO.Stream_Access; 420 421 Declarations => New_List ( 422 Make_Object_Declaration (Loc, 423 Defining_Identifier => S, 424 Object_Definition => 425 New_Occurrence_Of (RTE (RE_Stream_Access), Loc))), 426 427 Handled_Statement_Sequence => 428 Make_Handled_Sequence_Of_Statements (Loc, 429 Statements => New_List ( 430 431 -- S := Shared_Var_ROpen ("pkg.var"); 432 433 Make_Assignment_Statement (Loc, 434 Name => New_Reference_To (S, Loc), 435 Expression => 436 Make_Function_Call (Loc, 437 Name => 438 New_Occurrence_Of 439 (RTE (RE_Shared_Var_ROpen), Loc), 440 Parameter_Associations => New_List ( 441 Make_String_Literal (Loc, Vnm)))), 442 443 -- if S /= null then 444 445 Make_Implicit_If_Statement (N, 446 Condition => 447 Make_Op_Ne (Loc, 448 Left_Opnd => New_Reference_To (S, Loc), 449 Right_Opnd => Make_Null (Loc)), 450 451 Then_Statements => New_List ( 452 453 -- typ'Read (S, Var); 454 455 Atr, 456 457 -- Shared_Var_Close (S); 458 459 Make_Procedure_Call_Statement (Loc, 460 Name => 461 New_Occurrence_Of 462 (RTE (RE_Shared_Var_Close), Loc), 463 Parameter_Associations => 464 New_List (New_Reference_To (S, Loc))))))))); 465 466 Set_Is_Shared_Passive (Ent, True); 467 Set_Shared_Var_Assign_Proc (Ent, Assign_Proc); 468 Set_Shared_Var_Read_Proc (Ent, Read_Proc); 469 end Make_Shared_Var_Procs; 470 471 -------------------------- 472 -- On_Lhs_Of_Assignment -- 473 -------------------------- 474 475 function On_Lhs_Of_Assignment (N : Node_Id) return Boolean is 476 P : constant Node_Id := Parent (N); 477 478 begin 479 if Nkind (P) = N_Assignment_Statement then 480 if N = Name (P) then 481 Insert_Node := P; 482 return True; 483 else 484 return False; 485 end if; 486 487 elsif (Nkind (P) = N_Indexed_Component 488 or else 489 Nkind (P) = N_Selected_Component) 490 and then N = Prefix (P) 491 then 492 return On_Lhs_Of_Assignment (P); 493 494 else 495 return False; 496 end if; 497 end On_Lhs_Of_Assignment; 498 499 500end Exp_Smem; 501