OSDN Git Service

2009-07-07 Manuel López-Ibáñez <manu@gcc.gnu.org>
[pf3gnuchains/gcc-fork.git] / gcc / ada / s-finimp.adb
index 712bb12..9a5e534 100644 (file)
@@ -6,25 +6,23 @@
 --                                                                          --
 --                                 B o d y                                  --
 --                                                                          --
---          Copyright (C) 1992-2005 Free Software Foundation, Inc.          --
+--          Copyright (C) 1992-2009, 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- --
+-- ware  Foundation;  either version 3,  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,  51  Franklin  Street,  Fifth  Floor, --
--- Boston, MA 02110-1301, USA.                                              --
+-- or FITNESS FOR A PARTICULAR PURPOSE.                                     --
 --                                                                          --
--- As a special exception,  if other files  instantiate  generics from this --
--- unit, or you link  this unit with other files  to produce an executable, --
--- this  unit  does not  by itself cause  the resulting  executable  to  be --
--- covered  by the  GNU  General  Public  License.  This exception does not --
--- however invalidate  any other reasons why  the executable file  might be --
--- covered by the  GNU Public License.                                      --
+-- As a special exception under Section 7 of GPL version 3, you are granted --
+-- additional permissions described in the GCC Runtime Library Exception,   --
+-- version 3.1, as published by the Free Software Foundation.               --
+--                                                                          --
+-- You should have received a copy of the GNU General Public License and    --
+-- a copy of the GCC Runtime Library Exception along with this program;     --
+-- see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see    --
+-- <http://www.gnu.org/licenses/>.                                          --
 --                                                                          --
 -- GNAT was originally developed  by the GNAT team at  New York University. --
 -- Extensive contributions were provided by Ada Core Technologies Inc.      --
 with Ada.Exceptions;
 with Ada.Tags;
 
-with System.Storage_Elements;
 with System.Soft_Links;
 
-with Unchecked_Conversion;
 with System.Restrictions;
 
 package body System.Finalization_Implementation is
@@ -47,7 +43,6 @@ package body System.Finalization_Implementation is
 
    package SSL renames System.Soft_Links;
 
-   package SSE renames System.Storage_Elements;
    use type SSE.Storage_Offset;
 
    -----------------------
@@ -57,17 +52,17 @@ package body System.Finalization_Implementation is
    type RC_Ptr is access all Record_Controller;
 
    function To_RC_Ptr is
-     new Unchecked_Conversion (Address, RC_Ptr);
-
-   procedure Raise_Exception_No_Defer
-     (E       : in Exception_Id;
-      Message : in String := "");
-   pragma Import (Ada, Raise_Exception_No_Defer,
-     "ada__exceptions__raise_exception_no_defer");
-   pragma No_Return (Raise_Exception_No_Defer);
-   --  Raise an exception without deferring abort. Note that we have to
-   --  use this rather kludgy Ada Import interface, since this subprogram
-   --  is not available in the visible spec of Ada.Exceptions.
+     new Ada.Unchecked_Conversion (Address, RC_Ptr);
+
+   procedure Raise_From_Controlled_Operation (X : Exception_Occurrence);
+   pragma Import
+     (Ada, Raise_From_Controlled_Operation,
+      "ada__exceptions__raise_from_controlled_operation");
+   pragma No_Return (Raise_From_Controlled_Operation);
+   --  Raise Program_Error from an exception that occurred during an Adjust or
+   --  Finalize operation. We use this rather kludgy Ada Import interface
+   --  because this procedure is not available in the visible part of the
+   --  Ada.Exceptions spec.
 
    procedure Raise_From_Finalize
      (L          : Finalizable_Ptr;
@@ -93,17 +88,17 @@ package body System.Finalization_Implementation is
    -- Adjust --
    ------------
 
-   procedure Adjust (Object : in out Record_Controller) is
+   overriding procedure Adjust (Object : in out Record_Controller) is
 
       First_Comp : Finalizable_Ptr;
-      My_Offset : constant SSE.Storage_Offset :=
-                    Object.My_Address - Object'Address;
+      My_Offset  : constant SSE.Storage_Offset :=
+                     Object.My_Address - Object'Address;
 
       procedure Ptr_Adjust (Ptr : in out Finalizable_Ptr);
       --  Subtract the offset to the pointer
 
       procedure Reverse_Adjust (P : Finalizable_Ptr);
-      --  Ajust the components in the reverse order in which they are stored
+      --  Adjust the components in the reverse order in which they are stored
       --  on the finalization list. (Adjust and Finalization are not done in
       --  the same order)
 
@@ -128,7 +123,7 @@ package body System.Finalization_Implementation is
             Ptr_Adjust (P.Next);
             Reverse_Adjust (P.Next);
             Adjust (P.all);
-            Object.F := P;   --  Successfully adjusted, so place in list.
+            Object.F := P;   --  Successfully adjusted, so place in list
          end if;
       end Reverse_Adjust;
 
@@ -142,7 +137,7 @@ package body System.Finalization_Implementation is
 
       First_Comp := Object.F;
       Object.F := null;               --  nothing adjusted yet.
-      Ptr_Adjust (First_Comp);        --  set addresss of first component.
+      Ptr_Adjust (First_Comp);        --  set address of first component.
       Reverse_Adjust (First_Comp);
 
       --  Then Adjust the controller itself
@@ -170,7 +165,7 @@ package body System.Finalization_Implementation is
       Nb_Link : Short_Short_Integer)
    is
    begin
-      --  Simple case: attachement to a one way list
+      --  Simple case: attachment to a one way list
 
       if Nb_Link = 1 then
          Obj.Next := L;
@@ -178,11 +173,19 @@ package body System.Finalization_Implementation is
 
       --  Dynamically allocated objects: they are attached to a doubly linked
       --  list, so that an element can be finalized at any moment by means of
-      --  an unchecked deallocation. Attachement is protected against
+      --  an unchecked deallocation. Attachment is protected against
       --  multi-threaded access.
 
       elsif Nb_Link = 2 then
 
+         --  Raise Program_Error if we're trying to allocate an object in a
+         --  collection whose finalization has already started.
+
+         if L = Collection_Finalization_Started then
+            raise Program_Error with
+              "allocation after collection finalization started";
+         end if;
+
          Locked_Processing : begin
             SSL.Lock_Task.all;
             Obj.Next    := L.Next;
@@ -197,7 +200,7 @@ package body System.Finalization_Implementation is
                raise;
          end Locked_Processing;
 
-      --  Attachement of arrays to the final list (used only for objects
+      --  Attachment of arrays to the final list (used only for objects
       --  returned by function). Obj, in this case is the last element,
       --  but all other elements are already threaded after it. We just
       --  attach the rest of the final list at the end of the array list.
@@ -214,34 +217,15 @@ package body System.Finalization_Implementation is
             P.Next := L;
             L := Obj'Unchecked_Access;
          end;
-      end if;
-   end Attach_To_Final_List;
 
-   ---------------------
-   -- Deep_Tag_Adjust --
-   ---------------------
+      --  Make the object completely unattached (case of a library-level,
+      --  Finalize_Storage_Only object).
 
-   procedure Deep_Tag_Adjust
-     (L : in out SFR.Finalizable_Ptr;
-      A : System.Address;
-      B : Short_Short_Integer)
-   is
-      V          : constant SFR.Finalizable_Ptr := To_Finalizable_Ptr (A);
-      Controller : constant RC_Ptr := Get_Deep_Controller (A);
-
-   begin
-      if Controller /= null then
-         Adjust (Controller.all);
-         Attach_To_Final_List (L, Controller.all, B);
-      end if;
-
-      --  Is controlled
-
-      if V.all in Finalizable then
-         Adjust (V.all);
-         Attach_To_Final_List (L, Finalizable (V.all), 1);
+      elsif Nb_Link = 4 then
+         Obj.Prev := null;
+         Obj.Next := null;
       end if;
-   end Deep_Tag_Adjust;
+   end Attach_To_Final_List;
 
    ---------------------
    -- Deep_Tag_Attach --
@@ -267,85 +251,16 @@ package body System.Finalization_Implementation is
       end if;
    end Deep_Tag_Attach;
 
-   -----------------------
-   -- Deep_Tag_Finalize --
-   -----------------------
-
-   procedure Deep_Tag_Finalize
-     (L : in out SFR.Finalizable_Ptr;
-      A : System.Address;
-      B : Boolean)
-   is
-      pragma Warnings (Off, L);
-
-      V          : constant SFR.Finalizable_Ptr := To_Finalizable_Ptr (A);
-      Controller : constant RC_Ptr := Get_Deep_Controller (A);
-
-   begin
-      if Controller /= null then
-         if B then
-            Finalize_One (Controller.all);
-         else
-            Finalize (Controller.all);
-         end if;
-      end if;
-
-      --  Is controlled
-
-      if V.all in Finalizable then
-         if B then
-            Finalize_One (V.all);
-         else
-            Finalize (V.all);
-         end if;
-      end if;
-   end Deep_Tag_Finalize;
-
-   -------------------------
-   -- Deep_Tag_Initialize --
-   -------------------------
-
-   procedure Deep_Tag_Initialize
-     (L : in out SFR.Finalizable_Ptr;
-      A :        System.Address;
-      B :        Short_Short_Integer)
-   is
-      V          : constant SFR.Finalizable_Ptr := To_Finalizable_Ptr (A);
-      Controller : constant RC_Ptr := Get_Deep_Controller (A);
-
-   begin
-      --  This procedure should not be called if the object has no
-      --  controlled components
-
-      if Controller = null then
-         raise Program_Error;
-
-      --  Has controlled components
-
-      else
-         Initialize (Controller.all);
-         Attach_To_Final_List (L, Controller.all, B);
-      end if;
-
-      --  Is controlled
-
-      if V.all in Finalizable then
-         Initialize (V.all);
-         Attach_To_Final_List (Controller.F, Finalizable (Controller.all), 1);
-      end if;
-   end Deep_Tag_Initialize;
-
    -----------------------------
    -- Detach_From_Final_List --
    -----------------------------
 
    --  We know that the detach object is neither at the beginning nor at the
-   --  end of the list, thank's to the dummy First and Last Elements but the
+   --  end of the list, thanks to the dummy First and Last Elements, but the
    --  object may not be attached at all if it is Finalize_Storage_Only
 
    procedure Detach_From_Final_List (Obj : in out Finalizable) is
    begin
-
       --  When objects are not properly attached to a doubly linked list do
       --  not try to detach them. The only case where it can happen is when
       --  dealing with Finalize_Storage_Only objects which are not always
@@ -355,6 +270,13 @@ package body System.Finalization_Implementation is
          SSL.Lock_Task.all;
          Obj.Next.Prev := Obj.Prev;
          Obj.Prev.Next := Obj.Next;
+
+         --  Reset the pointers so that a new finalization of the same object
+         --  has no effect on the finalization list.
+
+         Obj.Next := null;
+         Obj.Prev := null;
+
          SSL.Unlock_Task.all;
       end if;
 
@@ -368,7 +290,7 @@ package body System.Finalization_Implementation is
    -- Finalize --
    --------------
 
-   procedure Finalize   (Object : in out Limited_Record_Controller) is
+   overriding procedure Finalize (Object : in out Limited_Record_Controller) is
    begin
       Finalize_List (Object.F);
    end Finalize;
@@ -416,7 +338,7 @@ package body System.Finalization_Implementation is
       type Ptr is access all Fake_Exception_Occurence;
 
       function To_Ptr is new
-        Unchecked_Conversion (Exception_Occurrence_Access, Ptr);
+        Ada.Unchecked_Conversion (Exception_Occurrence_Access, Ptr);
 
       X :  Exception_Id := Null_Id;
 
@@ -428,7 +350,7 @@ package body System.Finalization_Implementation is
       --  programs using controlled types heavily.
 
       if System.Restrictions.Abort_Allowed then
-         X := To_Ptr (System.Soft_Links.Get_Current_Excep.all).Id;
+         X := To_Ptr (SSL.Get_Current_Excep.all).Id;
       end if;
 
       while P /= null loop
@@ -467,7 +389,7 @@ package body System.Finalization_Implementation is
 
    begin
       --  Fetch the controller from the Parent or above if necessary
-      --  when there are no controller at this level
+      --  when there are no controller at this level.
 
       while Offset = -2 loop
          The_Tag := Ada.Tags.Parent_Tag (The_Tag);
@@ -487,7 +409,7 @@ package body System.Finalization_Implementation is
       --  At this stage, we know that the controller is part of the
       --  ancestor corresponding to the tag "The_Tag" and that its parent
       --  is variable sized. We assume that the _controller is the first
-      --  compoment right after the parent.
+      --  component right after the parent.
 
       --  ??? note that it may not be true if there are new discriminants
 
@@ -518,7 +440,7 @@ package body System.Finalization_Implementation is
 
             type Obj_Ptr is access all Faked_Type_Of_Obj;
             function To_Obj_Ptr is
-              new Unchecked_Conversion (Address, Obj_Ptr);
+              new Ada.Unchecked_Conversion (Address, Obj_Ptr);
 
          begin
             return To_RC_Ptr (To_Obj_Ptr (Obj).Controller'Address);
@@ -530,17 +452,47 @@ package body System.Finalization_Implementation is
    -- Initialize --
    ----------------
 
-   procedure Initialize (Object : in out Limited_Record_Controller) is
+   overriding procedure Initialize
+     (Object : in out Limited_Record_Controller)
+   is
       pragma Warnings (Off, Object);
    begin
       null;
    end Initialize;
 
-   procedure Initialize (Object : in out Record_Controller) is
+   overriding procedure Initialize (Object : in out Record_Controller) is
    begin
       Object.My_Address := Object'Address;
    end Initialize;
 
+   ---------------------
+   -- Move_Final_List --
+   ---------------------
+
+   procedure Move_Final_List
+     (From : in out SFR.Finalizable_Ptr;
+      To   : Finalizable_Ptr_Ptr)
+   is
+   begin
+      --  This is currently called at the end of the return statement, and the
+      --  caller does NOT defer aborts. We need to defer aborts to prevent
+      --  mangling the finalization lists.
+
+      SSL.Abort_Defer.all;
+
+      --  Put the return statement's finalization list onto the caller's one,
+      --  thus transferring responsibility for finalization of the return
+      --  object to the caller.
+
+      Attach_To_Final_List (To.all, From.all, Nb_Link => 3);
+
+      --  Empty the return statement's finalization list, so that when the
+      --  cleanup code executes, there will be nothing to finalize.
+      From := null;
+
+      SSL.Abort_Undefer.all;
+   end Move_Final_List;
+
    -------------------------
    -- Raise_From_Finalize --
    -------------------------
@@ -550,9 +502,8 @@ package body System.Finalization_Implementation is
       From_Abort : Boolean;
       E_Occ      : Exception_Occurrence)
    is
-      Msg : constant String := Exception_Message (E_Occ);
-      P   : Finalizable_Ptr := L;
-      Q   : Finalizable_Ptr;
+      P : Finalizable_Ptr := L;
+      Q : Finalizable_Ptr;
 
    begin
       --  We already got an exception. We now finalize the remainder of
@@ -570,24 +521,15 @@ package body System.Finalization_Implementation is
          P := Q;
       end loop;
 
-      --  If finalization from an Abort, then nothing to do
-
       if From_Abort then
-         null;
+         --  If finalization from an Abort, then nothing to do
 
-      --  If no message, then add our own message saying what happened
-
-      elsif Msg = "" then
-         Raise_Exception_No_Defer
-           (E       => Program_Error'Identity,
-            Message => "exception " &
-                       Exception_Name (E_Occ) &
-                       " raised during finalization");
-
-      --  If there was a message, pass it on
+         null;
 
       else
-         Raise_Exception_No_Defer (Program_Error'Identity, Msg);
+         --  Else raise Program_Error with an appropriate message
+
+         Raise_From_Controlled_Operation (E_Occ);
       end if;
    end Raise_From_Finalize;
 
@@ -595,5 +537,4 @@ package body System.Finalization_Implementation is
 
 begin
    SSL.Finalize_Global_List := Finalize_Global_List'Access;
-
 end System.Finalization_Implementation;