1 ------------------------------------------------------------------------------
3 -- GNAT COMPILER COMPONENTS --
5 -- A D A . F I N A L I Z A T I O N . H E A P _ M A N A G E M E N T --
9 -- Copyright (C) 2008-2011, Free Software Foundation, Inc. --
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. --
18 -- As a special exception under Section 7 of GPL version 3, you are granted --
19 -- additional permissions described in the GCC Runtime Library Exception, --
20 -- version 3.1, as published by the Free Software Foundation. --
22 -- You should have received a copy of the GNU General Public License and --
23 -- a copy of the GCC Runtime Library Exception along with this program; --
24 -- see the files COPYING3 and COPYING.RUNTIME respectively. If not, see --
25 -- <http://www.gnu.org/licenses/>. --
27 -- GNAT was originally developed by the GNAT team at New York University. --
28 -- Extensive contributions were provided by Ada Core Technologies Inc. --
30 ------------------------------------------------------------------------------
32 with Ada.Exceptions; use Ada.Exceptions;
33 with Ada.Unchecked_Conversion;
34 with Ada.Unchecked_Deallocation;
36 with GNAT.IO; use GNAT.IO;
38 with System; use System;
39 with System.Address_Image;
40 with System.Soft_Links; use System.Soft_Links;
41 with System.Storage_Elements; use System.Storage_Elements;
42 with System.Storage_Pools; use System.Storage_Pools;
44 package body Ada.Finalization.Heap_Management is
46 Header_Size : constant Storage_Count := Node'Size / Storage_Unit;
47 Header_Offset : constant Storage_Offset := Header_Size;
50 function Address_To_Node_Ptr is
51 new Ada.Unchecked_Conversion (Address, Node_Ptr);
53 procedure Attach (N : Node_Ptr; L : Node_Ptr);
54 -- Prepend a node to a list
56 procedure Detach (N : Node_Ptr);
57 -- Unhook a node from an arbitrary list
59 procedure Free is new Ada.Unchecked_Deallocation (Node, Node_Ptr);
61 ---------------------------
62 -- Add_Offset_To_Address --
63 ---------------------------
65 function Add_Offset_To_Address
66 (Addr : System.Address;
67 Offset : System.Storage_Elements.Storage_Offset) return System.Address
70 return System.Storage_Elements."+" (Addr, Offset);
71 end Add_Offset_To_Address;
78 (Collection : in out Finalization_Collection;
79 Addr : out System.Address;
80 Storage_Size : System.Storage_Elements.Storage_Count;
81 Alignment : System.Storage_Elements.Storage_Count;
82 Needs_Header : Boolean := True)
85 -- Allocation of a controlled object
89 -- Do not allow the allocation of controlled objects while the
90 -- associated collection is being finalized.
92 if Collection.Finalization_Started then
93 raise Program_Error with "allocation after finalization started";
101 -- Use the underlying pool to allocate enough space for the object
102 -- and the list header. The returned address points to the list
106 (Collection.Base_Pool.all,
108 Storage_Size + Header_Size,
111 -- Map the allocated memory into a Node record. This converts the
112 -- top of the allocated bits into a list header.
114 N_Ptr := Address_To_Node_Ptr (N_Addr);
115 Attach (N_Ptr, Collection.Objects);
117 -- Move the address from Prev to the start of the object. This
118 -- operation effectively hides the list header.
120 Addr := N_Addr + Header_Offset;
123 -- Allocation of a non-controlled object
127 (Collection.Base_Pool.all,
138 procedure Attach (N : Node_Ptr; L : Node_Ptr) is
160 (Collection : Finalization_Collection) return Any_Storage_Pool_Ptr
163 return Collection.Base_Pool;
171 (Collection : in out Finalization_Collection;
172 Addr : System.Address;
173 Storage_Size : System.Storage_Elements.Storage_Count;
174 Alignment : System.Storage_Elements.Storage_Count;
175 Has_Header : Boolean := True)
178 -- Deallocation of a controlled object
186 -- Move the address from the object to the beginning of the list
189 N_Addr := Addr - Header_Offset;
191 -- Converts the bits preceding the object into a list header
193 N_Ptr := Address_To_Node_Ptr (N_Addr);
196 -- Use the underlying pool to destroy the object along with the
200 (Collection.Base_Pool.all,
202 Storage_Size + Header_Size,
206 -- Deallocation of a non-controlled object
210 (Collection.Base_Pool.all,
221 procedure Detach (N : Node_Ptr) is
226 and then N.Next /= null
228 N.Prev.Next := N.Next;
229 N.Next.Prev := N.Prev;
246 overriding procedure Finalize
247 (Collection : in out Finalization_Collection)
249 function Head (L : Node_Ptr) return Node_Ptr;
250 -- Return the node which comes after the dummy head
252 function Is_Dummy_Head (N : Node_Ptr) return Boolean;
253 -- Determine whether a node acts as a dummy head. Such nodes do not
254 -- have an actual "object" attached to them and point to themselves.
256 function Is_Empty_List (L : Node_Ptr) return Boolean;
257 -- Determine whether a list is empty
259 function Node_Ptr_To_Address (N : Node_Ptr) return Address;
260 -- Not the reverse of Address_To_Node_Ptr. Return the address of the
261 -- object following the list header.
267 function Head (L : Node_Ptr) return Node_Ptr is
276 function Is_Dummy_Head (N : Node_Ptr) return Boolean is
278 -- To be a dummy head, the node must point to itself in both
284 and then N.Prev /= null
292 function Is_Empty_List (L : Node_Ptr) return Boolean is
294 return L = null or else Is_Dummy_Head (L);
297 -------------------------
298 -- Node_Ptr_To_Address --
299 -------------------------
301 function Node_Ptr_To_Address (N : Node_Ptr) return Address is
303 return N.all'Address + Header_Offset;
304 end Node_Ptr_To_Address;
307 Ex_Occur : Exception_Occurrence;
309 Raised : Boolean := False;
311 -- Start of processing for Finalize
314 -- Lock the collection to prevent any allocations while the objects are
315 -- being finalized. The collection remains locked because the associated
316 -- access type is about to go out of scope.
318 Collection.Finalization_Started := True;
320 while not Is_Empty_List (Collection.Objects) loop
322 -- Find the real head of the collection, skipping the dummy head
324 Curr_Ptr := Head (Collection.Objects);
326 -- If the dummy head is the only remaining node, all real objects
327 -- have already been detached and finalized.
329 if Is_Dummy_Head (Curr_Ptr) then
333 -- Store the next node now since the detachment will destroy the
336 Next_Ptr := Curr_Ptr.Next;
338 -- Remove the current node from the list
342 -- ??? Kludge: Don't do anything until the proper place to set
343 -- primitive Finalize_Address has been determined.
345 if Collection.Finalize_Address /= null then
347 Collection.Finalize_Address (Node_Ptr_To_Address (Curr_Ptr));
350 when Fin_Except : others =>
353 Save_Occurrence (Ex_Occur, Fin_Except);
358 Curr_Ptr := Next_Ptr;
361 -- Deallocate the dummy head
363 Free (Collection.Objects);
365 -- If the finalization of a particular node raised an exception, reraise
366 -- it after the remainder of the list has been finalized.
369 Reraise_Occurrence (Ex_Occur);
377 overriding procedure Initialize
378 (Collection : in out Finalization_Collection)
381 Collection.Objects := new Node;
383 -- The dummy head must point to itself in both directions
385 Collection.Objects.Next := Collection.Objects;
386 Collection.Objects.Prev := Collection.Objects;
393 procedure pcol (Collection : Finalization_Collection) is
394 Head_Seen : Boolean := False;
398 -- Output the basic contents of the collection
400 -- Collection: 0x123456789
401 -- Base_Pool : null <or> 0x123456789
402 -- Fin_Addr : null <or> 0x123456789
403 -- Fin_Start : TRUE <or> FALSE
405 Put ("Collection: ");
406 Put_Line (Address_Image (Collection'Address));
408 Put ("Base_Pool : ");
409 if Collection.Base_Pool = null then
412 Put_Line (Address_Image (Collection.Base_Pool'Address));
416 if Collection.Finalize_Address = null then
419 Put_Line (Address_Image (Collection.Finalize_Address'Address));
422 Put ("Fin_Start : ");
423 Put_Line (Collection.Finalization_Started'Img);
425 -- Output all chained elements. The format is the following:
427 -- ^ <or> ? <or> null
428 -- |Header: 0x123456789 (dummy head)
429 -- | Prev: 0x123456789
430 -- | Next: 0x123456789
433 -- ^ - the current element points back to the correct element
434 -- ? - the current element points back to an erroneous element
435 -- n - the current element points back to null
437 -- Header - the address of the list header
438 -- Prev - the address of the list header which the current element
440 -- Next - the address of the list header which the current element
442 -- (dummy head) - present if dummy head
444 N_Ptr := Collection.Objects;
446 while N_Ptr /= null loop
449 -- The current node is the head. If we have already traversed the
450 -- chain, the head will be encountered again since the chain is
453 if N_Ptr = Collection.Objects then
461 -- The current element points back to null. This should never happen
462 -- since the list is circular.
464 if N_Ptr.Prev = null then
465 Put_Line ("null (ERROR)");
467 -- The current element points back to the correct element
469 elsif N_Ptr.Prev.Next = N_Ptr then
472 -- The current element points back to an erroneous element
475 Put_Line ("? (ERROR)");
478 -- Output the header and fields
481 Put (Address_Image (N_Ptr.all'Address));
483 -- Detect the dummy head
485 if N_Ptr = Collection.Objects then
486 Put_Line (" (dummy head)");
492 if N_Ptr.Prev = null then
495 Put_Line (Address_Image (N_Ptr.Prev.all'Address));
499 if N_Ptr.Next = null then
502 Put_Line (Address_Image (N_Ptr.Next.all'Address));
509 ------------------------------
510 -- Set_Finalize_Address_Ptr --
511 ------------------------------
513 procedure Set_Finalize_Address_Ptr
514 (Collection : in out Finalization_Collection;
515 Proc_Ptr : Finalize_Address_Ptr)
518 Collection.Finalize_Address := Proc_Ptr;
519 end Set_Finalize_Address_Ptr;
521 --------------------------
522 -- Set_Storage_Pool_Ptr --
523 --------------------------
525 procedure Set_Storage_Pool_Ptr
526 (Collection : in out Finalization_Collection;
527 Pool_Ptr : Any_Storage_Pool_Ptr)
530 Collection.Base_Pool := Pool_Ptr;
531 end Set_Storage_Pool_Ptr;
533 end Ada.Finalization.Heap_Management;