2 * Copyright © 2016 Keith Packard <keithp@keithp.com>
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.
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.
15 #define AO_LISP_CONST_BITS
20 uint8_t ao_lisp_pool[AO_LISP_POOL] __attribute__((aligned(4)));
22 #ifdef AO_LISP_MAKE_CONST
24 uint8_t ao_lisp_const[AO_LISP_POOL_CONST] __attribute__((aligned(4)));
27 uint8_t ao_lisp_exception;
31 const struct ao_lisp_type *type;
34 #define AO_LISP_ROOT 16
36 static struct ao_lisp_root ao_lisp_root[AO_LISP_ROOT];
38 static uint8_t ao_lisp_busy[AO_LISP_POOL / 32];
40 static uint8_t ao_lisp_moving[AO_LISP_POOL / 32];
44 static inline void mark(uint8_t *tag, int offset) {
45 int byte = offset >> 5;
46 int bit = (offset >> 2) & 7;
47 tag[byte] |= (1 << bit);
50 static inline void clear(uint8_t *tag, int offset) {
51 int byte = offset >> 5;
52 int bit = (offset >> 2) & 7;
53 tag[byte] &= ~(1 << bit);
56 static inline int busy(uint8_t *tag, int offset) {
57 int byte = offset >> 5;
58 int bit = (offset >> 2) & 7;
59 return (tag[byte] >> bit) & 1;
62 static inline int min(int a, int b) { return a < b ? a : b; }
63 static inline int max(int a, int b) { return a > b ? a : b; }
65 static inline int limit(int offset) {
66 return min(AO_LISP_POOL, max(offset, 0));
70 mark_object(uint8_t *tag, void *addr, int size) {
77 if ((uint8_t *) addr < ao_lisp_pool || ao_lisp_pool + AO_LISP_POOL <= (uint8_t*) addr)
80 base = (uint8_t *) addr - ao_lisp_pool;
87 while (base < bound) {
95 clear_object(uint8_t *tag, void *addr, int size) {
101 base = (uint8_t *) addr - ao_lisp_pool;
105 bound = limit(bound);
106 if (!busy(tag, base))
108 while (base < bound) {
115 static void *move_old, *move_new;
116 static int move_size;
123 memset(ao_lisp_moving, '\0', sizeof (ao_lisp_moving));
124 for (i = 0; i < AO_LISP_ROOT; i++)
125 if (ao_lisp_root[i].addr) {
127 new = ao_lisp_move(ao_lisp_root[i].type, *ao_lisp_root[i].addr);
129 *ao_lisp_root[i].addr = new;
139 memset(ao_lisp_busy, '\0', sizeof (ao_lisp_busy));
140 for (i = 0; i < AO_LISP_ROOT; i++)
141 if (ao_lisp_root[i].addr)
142 ao_lisp_mark(ao_lisp_root[i].type, *ao_lisp_root[i].addr);
146 for (i = 0; i < AO_LISP_POOL; i += 4) {
147 if (!busy(ao_lisp_busy, i))
151 while(i < AO_LISP_POOL) {
152 if (busy(ao_lisp_busy, i)) {
153 move_old = &ao_lisp_pool[i];
154 move_new = &ao_lisp_pool[ao_lisp_top];
157 clear_object(ao_lisp_busy, move_old, move_size);
159 ao_lisp_top += move_size;
168 ao_lisp_mark(const struct ao_lisp_type *type, void *addr)
170 if (mark_object(ao_lisp_busy, addr, type->size(addr)))
176 ao_lisp_mark_memory(void *addr, int size)
178 return mark_object(ao_lisp_busy, addr, size);
182 check_move(void *addr, int size)
184 if (addr == move_old) {
185 memmove(move_new, move_old, size);
186 move_size = (size + 3) & ~3;
193 ao_lisp_move(const struct ao_lisp_type *type, void *addr)
195 int size = type->size(addr);
200 addr = check_move(addr, size);
201 if (mark_object(ao_lisp_moving, addr, size))
208 ao_lisp_move_memory(void *addr, int size)
213 addr = check_move(addr, size);
214 if (mark_object(ao_lisp_moving, addr, size))
220 ao_lisp_alloc(int size)
224 size = ao_lisp_mem_round(size);
225 #ifdef AO_LISP_MAKE_CONST
226 if (ao_lisp_top + size > AO_LISP_POOL_CONST) {
227 fprintf(stderr, "Too much constant data, increase AO_LISP_POOL_CONST\n");
230 addr = ao_lisp_const + ao_lisp_top;
232 if (ao_lisp_top + size > AO_LISP_POOL) {
234 if (ao_lisp_top + size > AO_LISP_POOL) {
235 ao_lisp_exception |= AO_LISP_OOM;
239 addr = ao_lisp_pool + ao_lisp_top;
246 ao_lisp_root_add(const struct ao_lisp_type *type, void *addr)
249 for (i = 0; i < AO_LISP_ROOT; i++) {
250 if (!ao_lisp_root[i].addr) {
251 ao_lisp_root[i].addr = addr;
252 ao_lisp_root[i].type = type;
260 ao_lisp_root_clear(void *addr)
263 for (i = 0; i < AO_LISP_ROOT; i++) {
264 if (ao_lisp_root[i].addr == addr) {
265 ao_lisp_root[i].addr = 0;
266 ao_lisp_root[i].type = 0;