PR rtl-optimization/79386
[official-gcc.git] / gcc / ada / s-poosiz.adb
blobda3a0c5594cc94d4c326c4ea7666dee7f685ab3d
1 ------------------------------------------------------------------------------
2 -- --
3 -- GNAT RUN-TIME COMPONENTS --
4 -- --
5 -- S Y S T E M . P O O L _ S I Z E --
6 -- --
7 -- B o d y --
8 -- --
9 -- Copyright (C) 1992-2016, 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. --
17 -- --
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. --
21 -- --
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/>. --
26 -- --
27 -- GNAT was originally developed by the GNAT team at New York University. --
28 -- Extensive contributions were provided by Ada Core Technologies Inc. --
29 -- --
30 ------------------------------------------------------------------------------
32 with System.Soft_Links;
34 with Ada.Unchecked_Conversion;
36 package body System.Pool_Size is
38 package SSE renames System.Storage_Elements;
39 use type SSE.Storage_Offset;
41 -- Even though these storage pools are typically only used by a single
42 -- task, if multiple tasks are declared at the same or a more nested scope
43 -- as the storage pool, there still may be concurrent access. The current
44 -- implementation of Stack_Bounded_Pool always uses a global lock for
45 -- protecting access. This should eventually be replaced by an atomic
46 -- linked list implementation for efficiency reasons.
48 package SSL renames System.Soft_Links;
50 type Storage_Count_Access is access SSE.Storage_Count;
51 function To_Storage_Count_Access is
52 new Ada.Unchecked_Conversion (Address, Storage_Count_Access);
54 SC_Size : constant := SSE.Storage_Count'Object_Size / System.Storage_Unit;
56 package Variable_Size_Management is
58 -- Embedded pool that manages allocation of variable-size data
60 -- This pool is used as soon as the Elmt_Size of the pool object is 0
62 -- Allocation is done on the first chunk long enough for the request.
63 -- Deallocation just puts the freed chunk at the beginning of the list.
65 procedure Initialize (Pool : in out Stack_Bounded_Pool);
66 procedure Allocate
67 (Pool : in out Stack_Bounded_Pool;
68 Address : out System.Address;
69 Storage_Size : SSE.Storage_Count;
70 Alignment : SSE.Storage_Count);
72 procedure Deallocate
73 (Pool : in out Stack_Bounded_Pool;
74 Address : System.Address;
75 Storage_Size : SSE.Storage_Count;
76 Alignment : SSE.Storage_Count);
77 end Variable_Size_Management;
79 package Vsize renames Variable_Size_Management;
81 --------------
82 -- Allocate --
83 --------------
85 procedure Allocate
86 (Pool : in out Stack_Bounded_Pool;
87 Address : out System.Address;
88 Storage_Size : SSE.Storage_Count;
89 Alignment : SSE.Storage_Count)
91 begin
92 SSL.Lock_Task.all;
94 if Pool.Elmt_Size = 0 then
95 Vsize.Allocate (Pool, Address, Storage_Size, Alignment);
97 elsif Pool.First_Free /= 0 then
98 Address := Pool.The_Pool (Pool.First_Free)'Address;
99 Pool.First_Free := To_Storage_Count_Access (Address).all;
101 elsif
102 Pool.First_Empty <= (Pool.Pool_Size - Pool.Aligned_Elmt_Size + 1)
103 then
104 Address := Pool.The_Pool (Pool.First_Empty)'Address;
105 Pool.First_Empty := Pool.First_Empty + Pool.Aligned_Elmt_Size;
107 else
108 raise Storage_Error;
109 end if;
111 SSL.Unlock_Task.all;
113 exception
114 when others =>
115 SSL.Unlock_Task.all;
116 raise;
117 end Allocate;
119 ----------------
120 -- Deallocate --
121 ----------------
123 procedure Deallocate
124 (Pool : in out Stack_Bounded_Pool;
125 Address : System.Address;
126 Storage_Size : SSE.Storage_Count;
127 Alignment : SSE.Storage_Count)
129 begin
130 SSL.Lock_Task.all;
132 if Pool.Elmt_Size = 0 then
133 Vsize.Deallocate (Pool, Address, Storage_Size, Alignment);
135 else
136 To_Storage_Count_Access (Address).all := Pool.First_Free;
137 Pool.First_Free := Address - Pool.The_Pool'Address + 1;
138 end if;
140 SSL.Unlock_Task.all;
141 exception
142 when others =>
143 SSL.Unlock_Task.all;
144 raise;
145 end Deallocate;
147 ----------------
148 -- Initialize --
149 ----------------
151 procedure Initialize (Pool : in out Stack_Bounded_Pool) is
153 -- Define the appropriate alignment for allocations. This is the
154 -- maximum of the requested alignment, and the alignment required
155 -- for Storage_Count values. The latter test is to ensure that we
156 -- can properly reference the linked list pointers for free lists.
158 Align : constant SSE.Storage_Count :=
159 SSE.Storage_Count'Max
160 (SSE.Storage_Count'Alignment, Pool.Alignment);
162 begin
163 if Pool.Elmt_Size = 0 then
164 Vsize.Initialize (Pool);
166 else
167 Pool.First_Free := 0;
168 Pool.First_Empty := 1;
170 -- Compute the size to allocate given the size of the element and
171 -- the possible alignment requirement as defined above.
173 Pool.Aligned_Elmt_Size :=
174 SSE.Storage_Count'Max (SC_Size,
175 ((Pool.Elmt_Size + Align - 1) / Align) * Align);
176 end if;
177 end Initialize;
179 ------------------
180 -- Storage_Size --
181 ------------------
183 function Storage_Size
184 (Pool : Stack_Bounded_Pool) return SSE.Storage_Count
186 begin
187 return Pool.Pool_Size;
188 end Storage_Size;
190 ------------------------------
191 -- Variable_Size_Management --
192 ------------------------------
194 package body Variable_Size_Management is
196 Minimum_Size : constant := 2 * SC_Size;
198 procedure Set_Size
199 (Pool : Stack_Bounded_Pool;
200 Chunk, Size : SSE.Storage_Count);
201 -- Update the field 'size' of a chunk of available storage
203 procedure Set_Next
204 (Pool : Stack_Bounded_Pool;
205 Chunk, Next : SSE.Storage_Count);
206 -- Update the field 'next' of a chunk of available storage
208 function Size
209 (Pool : Stack_Bounded_Pool;
210 Chunk : SSE.Storage_Count) return SSE.Storage_Count;
211 -- Fetch the field 'size' of a chunk of available storage
213 function Next
214 (Pool : Stack_Bounded_Pool;
215 Chunk : SSE.Storage_Count) return SSE.Storage_Count;
216 -- Fetch the field 'next' of a chunk of available storage
218 function Chunk_Of
219 (Pool : Stack_Bounded_Pool;
220 Addr : System.Address) return SSE.Storage_Count;
221 -- Give the chunk number in the pool from its Address
223 --------------
224 -- Allocate --
225 --------------
227 procedure Allocate
228 (Pool : in out Stack_Bounded_Pool;
229 Address : out System.Address;
230 Storage_Size : SSE.Storage_Count;
231 Alignment : SSE.Storage_Count)
233 Chunk : SSE.Storage_Count;
234 New_Chunk : SSE.Storage_Count;
235 Prev_Chunk : SSE.Storage_Count;
236 Our_Align : constant SSE.Storage_Count :=
237 SSE.Storage_Count'Max (SSE.Storage_Count'Alignment,
238 Alignment);
239 Align_Size : constant SSE.Storage_Count :=
240 SSE.Storage_Count'Max (
241 Minimum_Size,
242 ((Storage_Size + Our_Align - 1) / Our_Align) *
243 Our_Align);
245 begin
246 -- Look for the first big enough chunk
248 Prev_Chunk := Pool.First_Free;
249 Chunk := Next (Pool, Prev_Chunk);
251 while Chunk /= 0 and then Size (Pool, Chunk) < Align_Size loop
252 Prev_Chunk := Chunk;
253 Chunk := Next (Pool, Chunk);
254 end loop;
256 -- Raise storage_error if no big enough chunk available
258 if Chunk = 0 then
259 raise Storage_Error;
260 end if;
262 -- When the chunk is bigger than what is needed, take appropriate
263 -- amount and build a new shrinked chunk with the remainder.
265 if Size (Pool, Chunk) - Align_Size > Minimum_Size then
266 New_Chunk := Chunk + Align_Size;
267 Set_Size (Pool, New_Chunk, Size (Pool, Chunk) - Align_Size);
268 Set_Next (Pool, New_Chunk, Next (Pool, Chunk));
269 Set_Next (Pool, Prev_Chunk, New_Chunk);
271 -- If the chunk is the right size, just delete it from the chain
273 else
274 Set_Next (Pool, Prev_Chunk, Next (Pool, Chunk));
275 end if;
277 Address := Pool.The_Pool (Chunk)'Address;
278 end Allocate;
280 --------------
281 -- Chunk_Of --
282 --------------
284 function Chunk_Of
285 (Pool : Stack_Bounded_Pool;
286 Addr : System.Address) return SSE.Storage_Count
288 begin
289 return 1 + abs (Addr - Pool.The_Pool (1)'Address);
290 end Chunk_Of;
292 ----------------
293 -- Deallocate --
294 ----------------
296 procedure Deallocate
297 (Pool : in out Stack_Bounded_Pool;
298 Address : System.Address;
299 Storage_Size : SSE.Storage_Count;
300 Alignment : SSE.Storage_Count)
302 pragma Warnings (Off, Pool);
304 Align_Size : constant SSE.Storage_Count :=
305 ((Storage_Size + Alignment - 1) / Alignment) *
306 Alignment;
307 Chunk : constant SSE.Storage_Count := Chunk_Of (Pool, Address);
309 begin
310 -- Attach the freed chunk to the chain
312 Set_Size (Pool, Chunk,
313 SSE.Storage_Count'Max (Align_Size, Minimum_Size));
314 Set_Next (Pool, Chunk, Next (Pool, Pool.First_Free));
315 Set_Next (Pool, Pool.First_Free, Chunk);
317 end Deallocate;
319 ----------------
320 -- Initialize --
321 ----------------
323 procedure Initialize (Pool : in out Stack_Bounded_Pool) is
324 begin
325 Pool.First_Free := 1;
327 if Pool.Pool_Size > Minimum_Size then
328 Set_Next (Pool, Pool.First_Free, Pool.First_Free + Minimum_Size);
329 Set_Size (Pool, Pool.First_Free, 0);
330 Set_Size (Pool, Pool.First_Free + Minimum_Size,
331 Pool.Pool_Size - Minimum_Size);
332 Set_Next (Pool, Pool.First_Free + Minimum_Size, 0);
333 end if;
334 end Initialize;
336 ----------
337 -- Next --
338 ----------
340 function Next
341 (Pool : Stack_Bounded_Pool;
342 Chunk : SSE.Storage_Count) return SSE.Storage_Count
344 begin
345 pragma Warnings (Off);
346 -- Kill alignment warnings, we are careful to make sure
347 -- that the alignment is correct.
349 return To_Storage_Count_Access
350 (Pool.The_Pool (Chunk + SC_Size)'Address).all;
352 pragma Warnings (On);
353 end Next;
355 --------------
356 -- Set_Next --
357 --------------
359 procedure Set_Next
360 (Pool : Stack_Bounded_Pool;
361 Chunk, Next : SSE.Storage_Count)
363 begin
364 pragma Warnings (Off);
365 -- Kill alignment warnings, we are careful to make sure
366 -- that the alignment is correct.
368 To_Storage_Count_Access
369 (Pool.The_Pool (Chunk + SC_Size)'Address).all := Next;
371 pragma Warnings (On);
372 end Set_Next;
374 --------------
375 -- Set_Size --
376 --------------
378 procedure Set_Size
379 (Pool : Stack_Bounded_Pool;
380 Chunk, Size : SSE.Storage_Count)
382 begin
383 pragma Warnings (Off);
384 -- Kill alignment warnings, we are careful to make sure
385 -- that the alignment is correct.
387 To_Storage_Count_Access
388 (Pool.The_Pool (Chunk)'Address).all := Size;
390 pragma Warnings (On);
391 end Set_Size;
393 ----------
394 -- Size --
395 ----------
397 function Size
398 (Pool : Stack_Bounded_Pool;
399 Chunk : SSE.Storage_Count) return SSE.Storage_Count
401 begin
402 pragma Warnings (Off);
403 -- Kill alignment warnings, we are careful to make sure
404 -- that the alignment is correct.
406 return To_Storage_Count_Access (Pool.The_Pool (Chunk)'Address).all;
408 pragma Warnings (On);
409 end Size;
411 end Variable_Size_Management;
412 end System.Pool_Size;