Import Debian changes 20180207-1
[hcoop/debian/mlton.git] / runtime / gc / stack.c
CommitLineData
7f918cf1
CE
1/* Copyright (C) 2012,2016 Matthew Fluet.
2 * Copyright (C) 1999-2007 Henry Cejtin, Matthew Fluet, Suresh
3 * Jagannathan, and Stephen Weeks.
4 * Copyright (C) 1997-2000 NEC Research Institute.
5 *
6 * MLton is released under a BSD-style license.
7 * See the file MLton-LICENSE for details.
8 */
9
10void displayStack (__attribute__ ((unused)) GC_state s,
11 GC_stack stack,
12 FILE *stream) {
13 fprintf(stream,
14 "\t\treserved = %"PRIuMAX"\n"
15 "\t\tused = %"PRIuMAX"\n",
16 (uintmax_t)stack->reserved,
17 (uintmax_t)stack->used);
18}
19
20
21#if ASSERT
22bool isStackEmpty (GC_stack stack) {
23 return 0 == stack->used;
24}
25
26bool isStackReservedAligned (GC_state s, size_t reserved) {
27 return isAligned (GC_STACK_METADATA_SIZE + sizeof (struct GC_stack) + reserved,
28 s->alignment);
29}
30#endif
31
32/* sizeofStackSlop returns the amount of "slop" space needed between
33 * the top of the stack and the end of the stack space.
34 */
35size_t sizeofStackSlop (GC_state s) {
36 return (size_t)(2 * s->maxFrameSize);
37}
38
39
40/* Pointer to the bottommost word in use on the stack. */
41pointer getStackBottom (ARG_USED_FOR_ASSERT GC_state s, GC_stack stack) {
42 pointer res;
43
44 res = ((pointer)stack) + sizeof (struct GC_stack);
45 assert (isAligned ((size_t)res, s->alignment));
46 return res;
47}
48
49/* Pointer to the topmost word in use on the stack. */
50pointer getStackTop (GC_state s, GC_stack stack) {
51 pointer res;
52
53 res = getStackBottom (s, stack) + stack->used;
54 assert (isAligned ((size_t)res, s->alignment));
55 return res;
56}
57
58/* Pointer to the end of stack. */
59pointer getStackLimitPlusSlop (GC_state s, GC_stack stack) {
60 pointer res;
61
62 res = getStackBottom (s, stack) + stack->reserved;
63 // assert (isAligned ((size_t)res, s->alignment));
64 return res;
65}
66
67/* The maximum value which is valid for stackTop. */
68pointer getStackLimit (GC_state s, GC_stack stack) {
69 pointer res;
70
71 res = getStackLimitPlusSlop (s, stack) - sizeofStackSlop (s);
72 // assert (isAligned ((size_t)res, s->alignment));
73 return res;
74}
75
76GC_frameIndex getCachedStackTopFrameIndex (GC_state s) {
77 GC_frameIndex res;
78
79 res =
80 getFrameIndexFromReturnAddress
81 (s, *((GC_returnAddress*)(s->stackTop - GC_RETURNADDRESS_SIZE)));
82 return res;
83}
84
85GC_frameIndex getStackTopFrameIndex (GC_state s, GC_stack stack) {
86 GC_frameIndex res;
87
88 res =
89 getFrameIndexFromReturnAddress
90 (s, *((GC_returnAddress*)(getStackTop (s, stack) - GC_RETURNADDRESS_SIZE)));
91 return res;
92}
93
94GC_frameLayout getStackTopFrameLayout (GC_state s, GC_stack stack) {
95 GC_frameLayout layout;
96
97 layout = getFrameLayoutFromFrameIndex (s, getStackTopFrameIndex (s, stack));
98 return layout;
99}
100
101uint16_t getStackTopFrameSize (GC_state s, GC_stack stack) {
102 GC_frameLayout layout;
103
104 assert (not (isStackEmpty (stack)));
105 layout = getStackTopFrameLayout (s, stack);
106 return layout->size;
107}
108
109
110size_t alignStackReserved (GC_state s, size_t reserved) {
111 size_t res;
112
113 res = alignWithExtra (s, reserved, GC_STACK_METADATA_SIZE + sizeof (struct GC_stack));
114 if (DEBUG_STACKS)
115 fprintf (stderr, "%"PRIuMAX" = alignStackReserved (%"PRIuMAX")\n",
116 (uintmax_t)res, (uintmax_t)reserved);
117 assert (isStackReservedAligned (s, res));
118 return res;
119}
120
121size_t sizeofStackWithMetaData (ARG_USED_FOR_ASSERT GC_state s, size_t reserved) {
122 size_t res;
123
124 assert (isStackReservedAligned (s, reserved));
125 res = GC_STACK_METADATA_SIZE + sizeof (struct GC_stack) + reserved;
126 if (DEBUG_STACKS)
127 fprintf (stderr, "%"PRIuMAX" = sizeofStackWithMetaData (%"PRIuMAX")\n",
128 (uintmax_t)res, (uintmax_t)reserved);
129 assert (isAligned (res, s->alignment));
130 return res;
131}
132
133size_t sizeofStackInitialReserved (GC_state s) {
134 size_t res;
135
136 res = alignStackReserved(s, sizeofStackSlop (s));
137 return res;
138}
139
140size_t sizeofStackMinimumReserved (GC_state s, GC_stack stack) {
141 size_t res;
142
143 res = alignStackReserved (s,
144 stack->used
145 + sizeofStackSlop (s)
146 - getStackTopFrameSize (s, stack));
147 return res;
148}
149
150size_t sizeofStackGrowReserved (GC_state s, GC_stack stack) {
151 double reservedD;
152 size_t reservedGrow, reservedMin, reservedNew;
153 const size_t RESERVED_MAX = (SIZE_MAX >> 2);
154
155 assert (isStackReservedAligned (s, stack->reserved));
156 reservedD = (double)(stack->reserved);
157 double reservedGrowD =
158 (double)s->controls.ratios.stackCurrentGrow * reservedD;
159 reservedGrow =
160 reservedGrowD > (double)RESERVED_MAX
161 ? RESERVED_MAX
162 : (size_t)reservedGrowD;
163 reservedMin = sizeofStackMinimumReserved (s, stack);
164 reservedNew =
165 alignStackReserved
166 (s, max (reservedGrow, reservedMin));
167 assert (isStackReservedAligned (s, reservedNew));
168 return reservedNew;
169}
170
171size_t sizeofStackShrinkReserved (GC_state s, GC_stack stack, bool current) {
172 double usedD, reservedD;
173 size_t reservedMax, reservedShrink, reservedMin, reservedNew;
174 const size_t RESERVED_MAX = (SIZE_MAX >> 2);
175
176 assert (isStackReservedAligned (s, stack->reserved));
177 usedD = (double)(stack->used);
178 reservedD = (double)(stack->reserved);
179 if (current) {
180 /* Shrink current stacks. */
181 double reservedMaxD =
182 (double)(s->controls.ratios.stackCurrentMaxReserved) * usedD;
183 reservedMax =
184 reservedMaxD > (double)RESERVED_MAX
185 ? RESERVED_MAX
186 : (size_t)reservedMaxD;
187 double reservedPermitD =
188 (double)(s->controls.ratios.stackCurrentPermitReserved) * usedD;
189 size_t reservedPermit =
190 reservedPermitD > (double)RESERVED_MAX
191 ? RESERVED_MAX
192 : (size_t)reservedPermitD;
193 reservedShrink =
194 (stack->reserved <= reservedPermit)
195 ? stack->reserved
196 : (size_t)((double)(s->controls.ratios.stackCurrentShrink) * reservedD);
197 reservedMin = sizeofStackMinimumReserved (s, stack);
198 } else {
199 /* Shrink paused stacks. */
200 double reservedMaxD =
201 (double)(s->controls.ratios.stackMaxReserved) * usedD;
202 reservedMax =
203 reservedMaxD > (double)RESERVED_MAX
204 ? RESERVED_MAX
205 : (size_t)reservedMaxD;
206 reservedShrink =
207 (size_t)((double)s->controls.ratios.stackShrink * reservedD);
208 reservedMin = stack->used;
209 }
210 reservedNew =
211 alignStackReserved
212 (s, max(min(reservedMax,reservedShrink),reservedMin));
213 /* It's possible that reservedNew > stack->reserved for the current
214 * stack if the stack invariant is violated. In that case, we want
215 * to leave the stack alone, because some other part of the gc will
216 * grow the stack. We cannot do any growing here because we may run
217 * out of to space.
218 */
219 assert (current or reservedNew <= stack->reserved);
220 reservedNew = min (stack->reserved, reservedNew);
221 assert (isStackReservedAligned (s, reservedNew));
222 return reservedNew;
223}
224
225void copyStack (GC_state s, GC_stack from, GC_stack to) {
226 pointer fromBottom, toBottom;
227
228 fromBottom = getStackBottom (s, from);
229 toBottom = getStackBottom (s, to);
230 assert (from->used <= to->reserved);
231 to->used = from->used;
232 if (DEBUG_STACKS)
233 fprintf (stderr, "stackCopy from "FMTPTR" to "FMTPTR" of length %"PRIuMAX"\n",
234 (uintptr_t)fromBottom,
235 (uintptr_t)toBottom,
236 (uintmax_t)from->used);
237 GC_memcpy (fromBottom, toBottom, from->used);
238}