altos/scheme: Use memory manager mark code to note recursive print
[fw/altos] / src / scheme / ao_scheme_frame.c
1 /*
2  * Copyright © 2016 Keith Packard <keithp@keithp.com>
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation, either version 2 of the License, or
7  * (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful, but
10  * WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * General Public License for more details.
13  */
14
15 #include "ao_scheme.h"
16
17 static inline int
18 frame_vals_num_size(int num)
19 {
20         return sizeof (struct ao_scheme_frame_vals) + num * sizeof (struct ao_scheme_val);
21 }
22
23 static int
24 frame_vals_size(void *addr)
25 {
26         struct ao_scheme_frame_vals     *vals = addr;
27         return frame_vals_num_size(vals->size);
28 }
29
30 static void
31 frame_vals_mark(void *addr)
32 {
33         struct ao_scheme_frame_vals     *vals = addr;
34         int                             f;
35
36         for (f = 0; f < vals->size; f++) {
37                 struct ao_scheme_val    *v = &vals->vals[f];
38
39                 ao_scheme_poly_mark(v->val, 0);
40                 MDBG_MOVE("frame mark atom %s %d val %d at %d    ",
41                           ao_scheme_poly_atom(v->atom)->name,
42                           MDBG_OFFSET(ao_scheme_ref(v->atom)),
43                           MDBG_OFFSET(ao_scheme_ref(v->val)), f);
44                 MDBG_DO(printf("\n"));
45         }
46 }
47
48 static void
49 frame_vals_move(void *addr)
50 {
51         struct ao_scheme_frame_vals     *vals = addr;
52         int                             f;
53
54         for (f = 0; f < vals->size; f++) {
55                 struct ao_scheme_val    *v = &vals->vals[f];
56
57                 ao_scheme_poly_move(&v->atom, 0);
58                 ao_scheme_poly_move(&v->val, 0);
59                 MDBG_MOVE("frame move atom %s %d val %d at %d\n",
60                           ao_scheme_poly_atom(v->atom)->name,
61                           MDBG_OFFSET(ao_scheme_ref(v->atom)),
62                           MDBG_OFFSET(ao_scheme_ref(v->val)), f);
63         }
64 }
65
66 const struct ao_scheme_type ao_scheme_frame_vals_type = {
67         .mark = frame_vals_mark,
68         .size = frame_vals_size,
69         .move = frame_vals_move,
70         .name = "frame_vals"
71 };
72
73 static int
74 frame_size(void *addr)
75 {
76         (void) addr;
77         return sizeof (struct ao_scheme_frame);
78 }
79
80 static void
81 frame_mark(void *addr)
82 {
83         struct ao_scheme_frame  *frame = addr;
84
85         for (;;) {
86                 struct ao_scheme_frame_vals     *vals = ao_scheme_poly_frame_vals(frame->vals);
87
88                 MDBG_MOVE("frame mark %d\n", MDBG_OFFSET(frame));
89                 if (!AO_SCHEME_IS_POOL(frame))
90                         break;
91                 if (!ao_scheme_mark_memory(&ao_scheme_frame_vals_type, vals))
92                         frame_vals_mark(vals);
93                 frame = ao_scheme_poly_frame(frame->prev);
94                 MDBG_MOVE("frame next %d\n", MDBG_OFFSET(frame));
95                 if (!frame)
96                         break;
97                 if (ao_scheme_mark_memory(&ao_scheme_frame_type, frame))
98                         break;
99         }
100 }
101
102 static void
103 frame_move(void *addr)
104 {
105         struct ao_scheme_frame  *frame = addr;
106
107         for (;;) {
108                 struct ao_scheme_frame          *prev;
109                 struct ao_scheme_frame_vals     *vals;
110                 int                             ret;
111
112                 MDBG_MOVE("frame move %d\n", MDBG_OFFSET(frame));
113                 if (!AO_SCHEME_IS_POOL(frame))
114                         break;
115
116                 vals = ao_scheme_poly_frame_vals(frame->vals);
117                 if (!ao_scheme_move_memory(&ao_scheme_frame_vals_type, (void **) &vals))
118                         frame_vals_move(vals);
119                 if (vals != ao_scheme_poly_frame_vals(frame->vals))
120                         frame->vals = ao_scheme_frame_vals_poly(vals);
121
122                 prev = ao_scheme_poly_frame(frame->prev);
123                 if (!prev)
124                         break;
125                 ret = ao_scheme_move_memory(&ao_scheme_frame_type, (void **) &prev);
126                 if (prev != ao_scheme_poly_frame(frame->prev)) {
127                         MDBG_MOVE("frame prev moved from %d to %d\n",
128                                   MDBG_OFFSET(ao_scheme_poly_frame(frame->prev)),
129                                   MDBG_OFFSET(prev));
130                         frame->prev = ao_scheme_frame_poly(prev);
131                 }
132                 if (ret)
133                         break;
134                 frame = prev;
135         }
136 }
137
138 const struct ao_scheme_type ao_scheme_frame_type = {
139         .mark = frame_mark,
140         .size = frame_size,
141         .move = frame_move,
142         .name = "frame",
143 };
144
145 void
146 ao_scheme_frame_write(ao_poly p)
147 {
148         struct ao_scheme_frame          *frame = ao_scheme_poly_frame(p);
149         struct ao_scheme_frame_vals     *vals = ao_scheme_poly_frame_vals(frame->vals);
150         int                             f;
151
152         printf ("{");
153         if (frame) {
154                 if (frame->type & AO_SCHEME_FRAME_PRINT)
155                         printf("recurse...");
156                 else {
157                         frame->type |= AO_SCHEME_FRAME_PRINT;
158                         for (f = 0; f < frame->num; f++) {
159                                 if (f != 0)
160                                         printf(", ");
161                                 ao_scheme_poly_write(vals->vals[f].atom);
162                                 printf(" = ");
163                                 ao_scheme_poly_write(vals->vals[f].val);
164                         }
165                         if (frame->prev)
166                                 ao_scheme_poly_write(frame->prev);
167                         frame->type &= ~AO_SCHEME_FRAME_PRINT;
168                 }
169         }
170         printf("}");
171 }
172
173 static int
174 ao_scheme_frame_find(struct ao_scheme_frame *frame, int top, ao_poly atom)
175 {
176         struct ao_scheme_frame_vals     *vals = ao_scheme_poly_frame_vals(frame->vals);
177         int                             l = 0;
178         int                             r = top - 1;
179
180         while (l <= r) {
181                 int m = (l + r) >> 1;
182                 if (vals->vals[m].atom < atom)
183                         l = m + 1;
184                 else
185                         r = m - 1;
186         }
187         return l;
188 }
189
190 ao_poly *
191 ao_scheme_frame_ref(struct ao_scheme_frame *frame, ao_poly atom)
192 {
193         struct ao_scheme_frame_vals     *vals = ao_scheme_poly_frame_vals(frame->vals);
194         int                             l = ao_scheme_frame_find(frame, frame->num, atom);
195
196         if (l >= frame->num)
197                 return NULL;
198
199         if (vals->vals[l].atom != atom)
200                 return NULL;
201         return &vals->vals[l].val;
202 }
203
204 struct ao_scheme_frame  *ao_scheme_frame_free_list[AO_SCHEME_FRAME_FREE];
205
206 static struct ao_scheme_frame_vals *
207 ao_scheme_frame_vals_new(int num)
208 {
209         struct ao_scheme_frame_vals     *vals;
210
211         vals = ao_scheme_alloc(frame_vals_num_size(num));
212         if (!vals)
213                 return NULL;
214         vals->type = AO_SCHEME_FRAME_VALS;
215         vals->size = num;
216         memset(vals->vals, '\0', num * sizeof (struct ao_scheme_val));
217         return vals;
218 }
219
220 struct ao_scheme_frame *
221 ao_scheme_frame_new(int num)
222 {
223         struct ao_scheme_frame          *frame;
224         struct ao_scheme_frame_vals     *vals;
225
226         if (num < AO_SCHEME_FRAME_FREE && (frame = ao_scheme_frame_free_list[num])) {
227                 ao_scheme_frame_free_list[num] = ao_scheme_poly_frame(frame->prev);
228                 vals = ao_scheme_poly_frame_vals(frame->vals);
229         } else {
230                 frame = ao_scheme_alloc(sizeof (struct ao_scheme_frame));
231                 if (!frame)
232                         return NULL;
233                 frame->type = AO_SCHEME_FRAME;
234                 frame->num = 0;
235                 frame->prev = AO_SCHEME_NIL;
236                 frame->vals = AO_SCHEME_NIL;
237                 ao_scheme_frame_stash(0, frame);
238                 vals = ao_scheme_frame_vals_new(num);
239                 frame = ao_scheme_frame_fetch(0);
240                 if (!vals)
241                         return NULL;
242                 frame->vals = ao_scheme_frame_vals_poly(vals);
243                 frame->num = num;
244         }
245         frame->prev = AO_SCHEME_NIL;
246         return frame;
247 }
248
249 ao_poly
250 ao_scheme_frame_mark(struct ao_scheme_frame *frame)
251 {
252         if (!frame)
253                 return AO_SCHEME_NIL;
254         frame->type |= AO_SCHEME_FRAME_MARK;
255         return ao_scheme_frame_poly(frame);
256 }
257
258 void
259 ao_scheme_frame_free(struct ao_scheme_frame *frame)
260 {
261         if (frame && !ao_scheme_frame_marked(frame)) {
262                 int     num = frame->num;
263                 if (num < AO_SCHEME_FRAME_FREE) {
264                         struct ao_scheme_frame_vals     *vals;
265
266                         vals = ao_scheme_poly_frame_vals(frame->vals);
267                         memset(vals->vals, '\0', vals->size * sizeof (struct ao_scheme_val));
268                         frame->prev = ao_scheme_frame_poly(ao_scheme_frame_free_list[num]);
269                         ao_scheme_frame_free_list[num] = frame;
270                 }
271         }
272 }
273
274 static struct ao_scheme_frame *
275 ao_scheme_frame_realloc(struct ao_scheme_frame *frame, int new_num)
276 {
277         struct ao_scheme_frame_vals     *vals;
278         struct ao_scheme_frame_vals     *new_vals;
279         int                             copy;
280
281         if (new_num == frame->num)
282                 return frame;
283         ao_scheme_frame_stash(0, frame);
284         new_vals = ao_scheme_frame_vals_new(new_num);
285         frame = ao_scheme_frame_fetch(0);
286         if (!new_vals)
287                 return NULL;
288         vals = ao_scheme_poly_frame_vals(frame->vals);
289         copy = new_num;
290         if (copy > frame->num)
291                 copy = frame->num;
292         memcpy(new_vals->vals, vals->vals, copy * sizeof (struct ao_scheme_val));
293         frame->vals = ao_scheme_frame_vals_poly(new_vals);
294         frame->num = new_num;
295         return frame;
296 }
297
298 void
299 ao_scheme_frame_bind(struct ao_scheme_frame *frame, int num, ao_poly atom, ao_poly val)
300 {
301         struct ao_scheme_frame_vals     *vals = ao_scheme_poly_frame_vals(frame->vals);
302         int                             l = ao_scheme_frame_find(frame, num, atom);
303
304         memmove(&vals->vals[l+1],
305                 &vals->vals[l],
306                 (num - l) * sizeof (struct ao_scheme_val));
307         vals->vals[l].atom = atom;
308         vals->vals[l].val = val;
309 }
310
311 ao_poly
312 ao_scheme_frame_add(struct ao_scheme_frame *frame, ao_poly atom, ao_poly val)
313 {
314         ao_poly *ref = frame ? ao_scheme_frame_ref(frame, atom) : NULL;
315
316         if (!ref) {
317                 int f = frame->num;
318                 ao_scheme_poly_stash(0, atom);
319                 ao_scheme_poly_stash(1, val);
320                 frame = ao_scheme_frame_realloc(frame, f + 1);
321                 val = ao_scheme_poly_fetch(1);
322                 atom = ao_scheme_poly_fetch(0);
323                 if (!frame)
324                         return AO_SCHEME_NIL;
325                 ao_scheme_frame_bind(frame, frame->num - 1, atom, val);
326         } else
327                 *ref = val;
328         return val;
329 }
330
331 struct ao_scheme_frame  *ao_scheme_frame_global;
332 struct ao_scheme_frame  *ao_scheme_frame_current;
333
334 void
335 ao_scheme_frame_init(void)
336 {
337         if (!ao_scheme_frame_global)
338                 ao_scheme_frame_global = ao_scheme_frame_new(0);
339 }