1 | /* Stack allocation routines. This is intended for machines without support |
---|
2 | for the `alloca' function. |
---|
3 | |
---|
4 | Copyright 1996, 1997, 1999, 2000, 2001 Free Software Foundation, Inc. |
---|
5 | |
---|
6 | This file is part of the GNU MP Library. |
---|
7 | |
---|
8 | The GNU MP Library is free software; you can redistribute it and/or modify |
---|
9 | it under the terms of the GNU Lesser General Public License as published by |
---|
10 | the Free Software Foundation; either version 2.1 of the License, or (at your |
---|
11 | option) any later version. |
---|
12 | |
---|
13 | The GNU MP Library is distributed in the hope that it will be useful, but |
---|
14 | WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY |
---|
15 | or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public |
---|
16 | License for more details. |
---|
17 | |
---|
18 | You should have received a copy of the GNU Lesser General Public License |
---|
19 | along with the GNU MP Library; see the file COPYING.LIB. If not, write to |
---|
20 | the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, |
---|
21 | MA 02111-1307, USA. */ |
---|
22 | |
---|
23 | #include "gmp.h" |
---|
24 | #include "gmp-impl.h" |
---|
25 | |
---|
26 | |
---|
27 | struct tmp_stack |
---|
28 | { |
---|
29 | void *end; |
---|
30 | void *alloc_point; |
---|
31 | struct tmp_stack *prev; |
---|
32 | }; |
---|
33 | typedef struct tmp_stack tmp_stack; |
---|
34 | |
---|
35 | |
---|
36 | static unsigned long max_total_allocation = 0; |
---|
37 | static unsigned long current_total_allocation = 0; |
---|
38 | |
---|
39 | static tmp_stack xxx = {&xxx, &xxx, 0}; |
---|
40 | static tmp_stack *current = &xxx; |
---|
41 | |
---|
42 | /* The rounded size of the header of each allocation block. */ |
---|
43 | #define HSIZ ROUND_UP_MULTIPLE (sizeof (tmp_stack), __TMP_ALIGN) |
---|
44 | |
---|
45 | |
---|
46 | /* Allocate a block of exactly <size> bytes. This should only be called |
---|
47 | through the TMP_ALLOC macro, which takes care of rounding/alignment. */ |
---|
48 | void * |
---|
49 | __gmp_tmp_alloc (unsigned long size) |
---|
50 | { |
---|
51 | void *that; |
---|
52 | |
---|
53 | ASSERT ((size % __TMP_ALIGN) == 0); |
---|
54 | ASSERT (((unsigned) current->alloc_point % __TMP_ALIGN) == 0); |
---|
55 | |
---|
56 | if (size > (char *) current->end - (char *) current->alloc_point) |
---|
57 | { |
---|
58 | void *chunk; |
---|
59 | tmp_stack *header; |
---|
60 | unsigned long chunk_size; |
---|
61 | unsigned long now; |
---|
62 | |
---|
63 | /* Allocate a chunk that makes the total current allocation somewhat |
---|
64 | larger than the maximum allocation ever. If size is very large, we |
---|
65 | allocate that much. */ |
---|
66 | |
---|
67 | now = current_total_allocation + size; |
---|
68 | if (now > max_total_allocation) |
---|
69 | { |
---|
70 | /* We need more temporary memory than ever before. Increase |
---|
71 | for future needs. */ |
---|
72 | now = (now * 3 / 2 + __TMP_ALIGN - 1) & -__TMP_ALIGN; |
---|
73 | chunk_size = now - current_total_allocation + HSIZ; |
---|
74 | current_total_allocation = now; |
---|
75 | max_total_allocation = current_total_allocation; |
---|
76 | } |
---|
77 | else |
---|
78 | { |
---|
79 | chunk_size = max_total_allocation - current_total_allocation + HSIZ; |
---|
80 | current_total_allocation = max_total_allocation; |
---|
81 | } |
---|
82 | |
---|
83 | chunk = (*__gmp_allocate_func) (chunk_size); |
---|
84 | header = (tmp_stack *) chunk; |
---|
85 | header->end = (char *) chunk + chunk_size; |
---|
86 | header->alloc_point = (char *) chunk + HSIZ; |
---|
87 | header->prev = current; |
---|
88 | current = header; |
---|
89 | } |
---|
90 | |
---|
91 | that = current->alloc_point; |
---|
92 | current->alloc_point = (char *) that + size; |
---|
93 | ASSERT (((unsigned) that % __TMP_ALIGN) == 0); |
---|
94 | return that; |
---|
95 | } |
---|
96 | |
---|
97 | /* Typically called at function entry. <mark> is assigned so that |
---|
98 | __gmp_tmp_free can later be used to reclaim all subsequently allocated |
---|
99 | storage. */ |
---|
100 | void |
---|
101 | __gmp_tmp_mark (tmp_marker *mark) |
---|
102 | { |
---|
103 | mark->which_chunk = current; |
---|
104 | mark->alloc_point = current->alloc_point; |
---|
105 | } |
---|
106 | |
---|
107 | /* Free everything allocated since <mark> was assigned by __gmp_tmp_mark */ |
---|
108 | void |
---|
109 | __gmp_tmp_free (tmp_marker *mark) |
---|
110 | { |
---|
111 | while (mark->which_chunk != current) |
---|
112 | { |
---|
113 | tmp_stack *tmp; |
---|
114 | |
---|
115 | tmp = current; |
---|
116 | current = tmp->prev; |
---|
117 | current_total_allocation -= (((char *) (tmp->end) - (char *) tmp) - HSIZ); |
---|
118 | (*__gmp_free_func) (tmp, (char *) tmp->end - (char *) tmp); |
---|
119 | } |
---|
120 | current->alloc_point = mark->alloc_point; |
---|
121 | } |
---|