------------------------------------------------------------------------------ -- G N A T C O L L -- -- -- -- Copyright (C) 2015-2018, AdaCore -- -- -- -- This library is free software; you can redistribute it and/or modify it -- -- under terms of the GNU General Public License as published by the Free -- -- Software Foundation; either version 3, or (at your option) any later -- -- version. This library is distributed in the hope that it will be useful, -- -- but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHAN- -- -- TABILITY or FITNESS FOR A PARTICULAR PURPOSE. -- -- -- -- 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 -- -- . -- -- -- ------------------------------------------------------------------------------ with System.Memory; use System, System.Memory; with Ada.Unchecked_Conversion; package body GNATCOLL.Storage_Pools.Headers is Default_Align : constant Storage_Count := Standard'System_Allocator_Alignment; ------------------ -- Header_Pools -- ------------------ package body Header_Pools is type Header is record Extra : Extra_Header; end record; Extra_Bytes : constant Storage_Offset := (Header'Max_Size_In_Storage_Elements - Header'Object_Size / Storage_Unit); -- If the header is a controlled type, we need to allocate extra size -- for its Previous and Next pointers. This constant computes how -- much such extra size is needed. Header_Size_Bytes : constant Storage_Count := Header'Size / Storage_Unit; Extra_Allocation_Bytes : constant Storage_Count := ((Header_Size_Bytes + Extra_Bytes + Default_Align - 1) / Default_Align) * Default_Align; -- Allocate a multiple of Default_Align bytes, so that the -- alignment of the Element_Type is suitable. function Convert is new Ada.Unchecked_Conversion (System.Address, Header_Access); function Address_Header_Of (Addr : System.Address) return System.Address is (Addr - Extra_Allocation_Bytes); -- Compute the address of the header. -- Do not call with a null pointer. -------------- -- Allocate -- -------------- overriding procedure Allocate (Self : in out Header_Pool; Addr : out System.Address; Size : System.Storage_Elements.Storage_Count; Alignment : System.Storage_Elements.Storage_Count) is -- The compiler requests a size that include the object size -- plus any extra header like bounds or next/previous for -- controlled types. This size also includes a padding to -- ensure that the element will be properly aligned. -- The computation is done in s-stposu.adb, in -- Header_Size_With_Padding. pragma Unreferenced (Self, Alignment); Aligned_Size : constant Storage_Count := -- bytes Size + Extra_Allocation_Bytes; Allocated : constant System.Address := Alloc (size_t (Aligned_Size)); begin Addr := Allocated + Extra_Allocation_Bytes; end Allocate; ---------------- -- Deallocate -- ---------------- overriding procedure Deallocate (Self : in out Header_Pool; Addr : System.Address; Size : System.Storage_Elements.Storage_Count; Alignment : System.Storage_Elements.Storage_Count) is pragma Unreferenced (Self, Alignment, Size); Header : constant System.Address := Address_Header_Of (Addr); begin System.Memory.Free (Header); end Deallocate; ----------- -- Typed -- ----------- package body Typed is function Header_Of (Element : Element_Access) return Header_Access is Finalization_Size : Integer; -- If the element_type is a controlled type, this will -- be the number of extra bytes requested by the compiler in -- calls to Allocate and Deallocate (see the memory layout -- description in the specs). -- -- These extra bytes are automatically added and substracted by -- the compiler when calling Deallocate, but not when calling -- Header_Of so we need to take them into account when looking -- for the our own header. Descriptor_Size : Integer; -- Similarily, for bounds information if the element type is -- an unconstrained array (e.g. String). begin if Element = null then return null; end if; Finalization_Size := Element.all'Finalization_Size; Descriptor_Size := Element_Type'Descriptor_Size / Storage_Unit; return Convert (Address_Header_Of (Element.all'Address - Storage_Offset (Finalization_Size + Descriptor_Size))); end Header_Of; end Typed; end Header_Pools; end GNATCOLL.Storage_Pools.Headers;