altos/lisp: Change GC move API
[fw/altos] / src / lisp / ao_lisp_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_lisp.h"
16
17 #if 0
18 #define DBG(...)        printf(__VA_ARGS__)
19 #else
20 #define DBG(...)
21 #endif
22
23 static inline int
24 frame_num_size(int num)
25 {
26         return sizeof (struct ao_lisp_frame) + num * sizeof (struct ao_lisp_val);
27 }
28
29 static int
30 frame_size(void *addr)
31 {
32         struct ao_lisp_frame    *frame = addr;
33         return frame_num_size(frame->num);
34 }
35
36 #define OFFSET(a)       ((int) ((uint8_t *) (ao_lisp_ref(a)) - ao_lisp_const))
37
38 static void
39 frame_mark(void *addr)
40 {
41         struct ao_lisp_frame    *frame = addr;
42         int                     f;
43
44         for (;;) {
45                 DBG("frame mark %p\n", frame);
46                 if (!AO_LISP_IS_POOL(frame))
47                         break;
48                 for (f = 0; f < frame->num; f++) {
49                         struct ao_lisp_val      *v = &frame->vals[f];
50
51                         ao_lisp_poly_mark(v->val);
52                         DBG ("\tframe mark atom %s %d val %d at %d\n",
53                              ao_lisp_poly_atom(v->atom)->name,
54                              OFFSET(v->atom), OFFSET(v->val), f);
55                 }
56                 frame = ao_lisp_poly_frame(frame->next);
57                 DBG("frame next %p\n", frame);
58                 if (!frame)
59                         break;
60                 if (ao_lisp_mark_memory(frame, frame_size(frame)))
61                         break;
62         }
63 }
64
65 static void
66 frame_move(void *addr)
67 {
68         struct ao_lisp_frame    *frame = addr;
69         int                     f;
70
71         for (;;) {
72                 DBG("frame move %p\n", frame);
73                 if (!AO_LISP_IS_POOL(frame))
74                         break;
75                 for (f = 0; f < frame->num; f++) {
76                         struct ao_lisp_val      *v = &frame->vals[f];
77
78                         ao_lisp_poly_move(&v->atom);
79                         DBG("moved atom %s\n", ao_lisp_poly_atom(v->atom)->name);
80                         ao_lisp_poly_move(&v->val);
81                 }
82                 if (ao_lisp_poly_move(&frame->next))
83                         break;
84                 frame = ao_lisp_poly_frame(frame->next);
85         }
86 }
87
88 const struct ao_lisp_type ao_lisp_frame_type = {
89         .mark = frame_mark,
90         .size = frame_size,
91         .move = frame_move
92 };
93
94 ao_poly *
95 ao_lisp_frame_ref(struct ao_lisp_frame *frame, ao_poly atom)
96 {
97         int f;
98         for (f = 0; f < frame->num; f++)
99                 if (frame->vals[f].atom == atom)
100                         return &frame->vals[f].val;
101         return NULL;
102 }
103
104 int
105 ao_lisp_frame_set(struct ao_lisp_frame *frame, ao_poly atom, ao_poly val)
106 {
107         while (frame) {
108                 if (!AO_LISP_IS_CONST(frame)) {
109                         ao_poly *ref = ao_lisp_frame_ref(frame, atom);
110                         if (ref) {
111                                 *ref = val;
112                                 return 1;
113                         }
114                 }
115                 frame = ao_lisp_poly_frame(frame->next);
116         }
117         return 0;
118 }
119
120 ao_poly
121 ao_lisp_frame_get(struct ao_lisp_frame *frame, ao_poly atom)
122 {
123         while (frame) {
124                 ao_poly *ref = ao_lisp_frame_ref(frame, atom);
125                 if (ref)
126                         return *ref;
127                 frame = ao_lisp_poly_frame(frame->next);
128         }
129         return AO_LISP_NIL;
130 }
131
132 struct ao_lisp_frame *
133 ao_lisp_frame_new(int num)
134 {
135         struct ao_lisp_frame *frame = ao_lisp_alloc(frame_num_size(num));
136
137         if (!frame)
138                 return NULL;
139         frame->type = AO_LISP_FRAME;
140         frame->num = num;
141         frame->next = AO_LISP_NIL;
142         memset(frame->vals, '\0', num * sizeof (struct ao_lisp_val));
143         return frame;
144 }
145
146 static struct ao_lisp_frame *
147 ao_lisp_frame_realloc(struct ao_lisp_frame *frame, int new_num)
148 {
149         struct ao_lisp_frame    *new;
150         int                     copy;
151
152         if (new_num == frame->num)
153                 return frame;
154         new = ao_lisp_frame_new(new_num);
155         if (!new)
156                 return NULL;
157         copy = new_num;
158         if (copy > frame->num)
159                 copy = frame->num;
160         memcpy(new->vals, frame->vals, copy * sizeof (struct ao_lisp_val));
161         if (frame)
162                 new->next = frame->next;
163         return new;
164 }
165
166 struct ao_lisp_frame *
167 ao_lisp_frame_add(struct ao_lisp_frame *frame, ao_poly atom, ao_poly val)
168 {
169         ao_poly *ref = frame ? ao_lisp_frame_ref(frame, atom) : NULL;
170         if (!ref) {
171                 int f;
172                 if (frame) {
173                         f = frame->num;
174                         frame = ao_lisp_frame_realloc(frame, f + 1);
175                 } else {
176                         f = 0;
177                         frame = ao_lisp_frame_new(1);
178                 }
179                 if (!frame)
180                         return NULL;
181                 DBG ("add atom %s %d, val %d at %d\n", ao_lisp_poly_atom(atom)->name, OFFSET(atom), OFFSET(val), f);
182                 frame->vals[f].atom = atom;
183                 ref = &frame->vals[f].val;
184         }
185         *ref = val;
186         return frame;
187 }