1 ------------------------------------------------------------------------------
3 -- GNAT COMPILER COMPONENTS --
5 -- S Y S T E M . S E C O N D A R Y _ S T A C K --
9 -- Copyright (C) 1992-2002 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 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. --
22 -- As a special exception, if other files instantiate generics from this --
23 -- unit, or you link this unit with other files to produce an executable, --
24 -- this unit does not by itself cause the resulting executable to be --
25 -- covered by the GNU General Public License. This exception does not --
26 -- however invalidate any other reasons why the executable file might be --
27 -- covered by the GNU Public License. --
29 -- GNAT was originally developed by the GNAT team at New York University. --
30 -- Extensive contributions were provided by Ada Core Technologies Inc. --
32 ------------------------------------------------------------------------------
34 with System
.Soft_Links
;
35 with System
.Parameters
;
36 with Unchecked_Conversion
;
37 with Unchecked_Deallocation
;
39 package body System
.Secondary_Stack
is
41 package SSL
renames System
.Soft_Links
;
43 use type SSE
.Storage_Offset
;
44 use type System
.Parameters
.Size_Type
;
46 SS_Ratio_Dynamic
: constant Boolean :=
47 Parameters
.Sec_Stack_Ratio
= Parameters
.Dynamic
;
49 -- +------------------+
51 -- +------------------+
59 -- +------------------+
61 -- | +----------+-------+
65 -- | +-------+----------+
67 -- | +------------------+
71 -- +-----------------+ | +-------->| U |
72 -- | Current_Chunk -|--+ | | N |
73 -- +-----------------+ | | K |
74 -- | Top -|-----+ | | First (1)
75 -- +-----------------+ +------------------+
76 -- | Default_Size | | Prev |
77 -- +-----------------+ +------------------+
80 type Memory
is array (Mark_Id
range <>) of SSE
.Storage_Element
;
82 type Chunk_Id
(First
, Last
: Mark_Id
);
83 type Chunk_Ptr
is access all Chunk_Id
;
85 type Chunk_Id
(First
, Last
: Mark_Id
) is record
86 Prev
, Next
: Chunk_Ptr
;
87 Mem
: Memory
(First
.. Last
);
90 type Stack_Id
is record
92 Default_Size
: SSE
.Storage_Count
;
93 Current_Chunk
: Chunk_Ptr
;
96 type Fixed_Stack_Id
is record
99 Mem
: Memory
(1 .. Mark_Id
'Last / 2 - 1);
100 -- This should really be 1 .. Mark_Id'Last, but there is a bug in gigi
101 -- with this type, introduced Sep 2001, that causes gigi to reject this
102 -- type because its size in bytes overflows ???
105 type Stack_Ptr
is access Stack_Id
;
106 type Fixed_Stack_Ptr
is access Fixed_Stack_Id
;
108 function From_Addr
is new Unchecked_Conversion
(Address
, Stack_Ptr
);
109 function To_Addr
is new Unchecked_Conversion
(Stack_Ptr
, System
.Address
);
110 function To_Fixed
is new Unchecked_Conversion
(Stack_Ptr
, Fixed_Stack_Ptr
);
112 procedure Free
is new Unchecked_Deallocation
(Chunk_Id
, Chunk_Ptr
);
118 procedure SS_Allocate
119 (Address
: out System
.Address
;
120 Storage_Size
: SSE
.Storage_Count
)
122 Stack
: constant Stack_Ptr
:=
123 From_Addr
(SSL
.Get_Sec_Stack_Addr
.all);
124 Fixed_Stack
: Fixed_Stack_Ptr
;
126 Max_Align
: constant Mark_Id
:= Mark_Id
(Standard
'Maximum_Alignment);
127 Max_Size
: constant Mark_Id
:=
128 ((Mark_Id
(Storage_Size
) + Max_Align
- 1) / Max_Align
)
131 To_Be_Released_Chunk
: Chunk_Ptr
;
134 -- If the secondary stack is fixed in the primary stack, then the
135 -- handling becomes simple
137 if not SS_Ratio_Dynamic
then
138 Fixed_Stack
:= To_Fixed
(Stack
);
140 if Fixed_Stack
.Top
+ Max_Size
> Fixed_Stack
.Last
then
144 Address
:= Fixed_Stack
.Mem
(Fixed_Stack
.Top
)'Address;
145 Fixed_Stack
.Top
:= Fixed_Stack
.Top
+ Mark_Id
(Max_Size
);
149 Chunk
:= Stack
.Current_Chunk
;
151 -- The Current_Chunk may not be the good one if a lot of release
152 -- operations have taken place. So go down the stack if necessary
154 while Chunk
.First
> Stack
.Top
loop
158 -- Find out if the available memory in the current chunk is sufficient.
159 -- if not, go to the next one and eventally create the necessary room
161 while Chunk
.Last
- Stack
.Top
+ 1 < Max_Size
loop
162 if Chunk
.Next
/= null then
164 -- Release unused non-first empty chunk
166 if Chunk
.Prev
/= null and then Chunk
.First
= Stack
.Top
then
167 To_Be_Released_Chunk
:= Chunk
;
169 Chunk
.Next
:= To_Be_Released_Chunk
.Next
;
170 To_Be_Released_Chunk
.Next
.Prev
:= Chunk
;
171 Free
(To_Be_Released_Chunk
);
174 -- Create new chunk of the default size unless it is not sufficient
176 elsif SSE
.Storage_Count
(Max_Size
) <= Stack
.Default_Size
then
177 Chunk
.Next
:= new Chunk_Id
(
178 First
=> Chunk
.Last
+ 1,
179 Last
=> Chunk
.Last
+ Mark_Id
(Stack
.Default_Size
));
181 Chunk
.Next
.Prev
:= Chunk
;
184 Chunk
.Next
:= new Chunk_Id
(
185 First
=> Chunk
.Last
+ 1,
186 Last
=> Chunk
.Last
+ Max_Size
);
188 Chunk
.Next
.Prev
:= Chunk
;
192 Stack
.Top
:= Chunk
.First
;
195 -- Resulting address is the address pointed by Stack.Top
197 Address
:= Chunk
.Mem
(Stack
.Top
)'Address;
198 Stack
.Top
:= Stack
.Top
+ Max_Size
;
199 Stack
.Current_Chunk
:= Chunk
;
206 procedure SS_Free
(Stk
: in out System
.Address
) is
210 procedure Free
is new Unchecked_Deallocation
(Stack_Id
, Stack_Ptr
);
213 if not SS_Ratio_Dynamic
then
217 Stack
:= From_Addr
(Stk
);
218 Chunk
:= Stack
.Current_Chunk
;
220 while Chunk
.Prev
/= null loop
224 while Chunk
.Next
/= null loop
239 Stack
: constant Stack_Ptr
:=
240 From_Addr
(SSL
.Get_Sec_Stack_Addr
.all);
241 Fixed_Stack
: Fixed_Stack_Ptr
;
242 Nb_Chunks
: Integer := 1;
243 Chunk
: Chunk_Ptr
:= Stack
.Current_Chunk
;
246 Put_Line
("Secondary Stack information:");
248 if not SS_Ratio_Dynamic
then
249 Fixed_Stack
:= To_Fixed
(Stack
);
252 & Mark_Id
'Image (Fixed_Stack
.Last
)
255 " Current allocated space : "
256 & Mark_Id
'Image (Fixed_Stack
.Top
- 1)
261 while Chunk
.Prev
/= null loop
265 while Chunk
.Next
/= null loop
266 Nb_Chunks
:= Nb_Chunks
+ 1;
270 -- Current Chunk information
274 & Mark_Id
'Image (Chunk
.Last
)
277 " Current allocated space : "
278 & Mark_Id
'Image (Stack
.Top
- 1)
282 " Number of Chunks : "
283 & Integer'Image (Nb_Chunks
));
286 " Default size of Chunks : "
287 & SSE
.Storage_Count
'Image (Stack
.Default_Size
));
295 (Stk
: in out System
.Address
;
296 Size
: Natural := Default_Secondary_Stack_Size
)
299 Fixed_Stack
: Fixed_Stack_Ptr
;
302 if not SS_Ratio_Dynamic
then
303 Fixed_Stack
:= To_Fixed
(From_Addr
(Stk
));
304 Fixed_Stack
.Top
:= Fixed_Stack
.Mem
'First;
306 if Size
< 2 * Mark_Id
'Max_Size_In_Storage_Elements then
307 Fixed_Stack
.Last
:= 0;
309 Fixed_Stack
.Last
:= Mark_Id
(Size
) -
310 2 * Mark_Id
'Max_Size_In_Storage_Elements;
316 Stack
:= new Stack_Id
;
317 Stack
.Current_Chunk
:= new Chunk_Id
(1, Mark_Id
(Size
));
319 Stack
.Default_Size
:= SSE
.Storage_Count
(Size
);
321 Stk
:= To_Addr
(Stack
);
328 function SS_Mark
return Mark_Id
is
330 return From_Addr
(SSL
.Get_Sec_Stack_Addr
.all).Top
;
337 procedure SS_Release
(M
: Mark_Id
) is
339 From_Addr
(SSL
.Get_Sec_Stack_Addr
.all).Top
:= M
;
342 -------------------------
343 -- Package Elaboration --
344 -------------------------
346 -- Allocate a secondary stack for the main program to use.
347 -- We make sure that the stack has maximum alignment. Some systems require
348 -- this (e.g. Sun), and in any case it is a good idea for efficiency.
350 Stack
: aliased Stack_Id
;
351 for Stack
'Alignment use Standard
'Maximum_Alignment;
353 Chunk
: aliased Chunk_Id
(1, Default_Secondary_Stack_Size
);
354 for Chunk
'Alignment use Standard
'Maximum_Alignment;
356 Chunk_Address
: System
.Address
;
359 if SS_Ratio_Dynamic
then
361 Stack
.Current_Chunk
:= Chunk
'Access;
362 Stack
.Default_Size
:= Default_Secondary_Stack_Size
;
363 System
.Soft_Links
.Set_Sec_Stack_Addr_NT
(Stack
'Address);
366 Chunk_Address
:= Chunk
'Address;
367 SS_Init
(Chunk_Address
, Default_Secondary_Stack_Size
);
368 System
.Soft_Links
.Set_Sec_Stack_Addr_NT
(Chunk_Address
);
370 end System
.Secondary_Stack
;