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.
18 uint8_t ao_lisp_pool[AO_LISP_POOL];
22 const struct ao_lisp_mem_type *type;
25 static struct ao_lisp_root ao_lisp_root[AO_LISP_ROOT];
27 static uint8_t ao_lisp_busy[AO_LISP_POOL / 32];
29 static uint8_t ao_lisp_moving[AO_LISP_POOL / 32];
31 static uint16_t ao_lisp_top;
33 static inline void mark(uint8_t *tag, int offset) {
34 int byte = offset >> 5;
35 int bit = (offset >> 2) & 7;
36 tag[byte] |= (1 << bit);
39 static inline void clear(uint8_t *tag, int offset) {
40 int byte = offset >> 5;
41 int bit = (offset >> 2) & 7;
42 tag[byte] &= ~(1 << bit);
45 static inline int busy(uint8_t *tag, int offset) {
46 int byte = offset >> 5;
47 int bit = (offset >> 2) & 7;
48 return (tag[byte] >> bit) & 1;
51 static inline int min(int a, int b) { return a < b ? a : b; }
52 static inline int max(int a, int b) { return a > b ? a : b; }
54 static inline int limit(int offset) {
55 return min(AO_LISP_POOL, max(offset, 0));
59 mark_object(uint8_t *tag, void *addr, int size) {
65 base = (uint8_t *) addr - ao_lisp_pool;
72 while (base < bound) {
80 clear_object(uint8_t *tag, void *addr, int size) {
86 base = (uint8_t *) addr - ao_lisp_pool;
93 while (base < bound) {
100 static void *move_old, *move_new;
101 static int move_size;
108 memset(ao_lisp_moving, '\0', sizeof (ao_lisp_moving));
109 for (i = 0; i < AO_LISP_ROOT; i++)
110 if (ao_lisp_root[i].addr) {
112 new = ao_lisp_move(ao_lisp_root[i].type, *ao_lisp_root[i].addr);
114 *ao_lisp_root[i].addr = new;
124 memset(ao_lisp_busy, '\0', sizeof (ao_lisp_busy));
125 for (i = 0; i < AO_LISP_ROOT; i++)
126 if (ao_lisp_root[i].addr)
127 ao_lisp_mark(ao_lisp_root[i].type, *ao_lisp_root[i].addr);
131 for (i = 0; i < AO_LISP_POOL; i += 4) {
132 if (!busy(ao_lisp_busy, i))
136 while(i < AO_LISP_POOL) {
137 if (busy(ao_lisp_busy, i)) {
138 move_old = &ao_lisp_pool[i];
139 move_new = &ao_lisp_pool[ao_lisp_top];
142 clear_object(ao_lisp_busy, move_old, move_size);
144 ao_lisp_top += move_size;
153 ao_lisp_mark(const struct ao_lisp_mem_type *type, void *addr)
155 if (mark_object(ao_lisp_busy, addr, type->size(addr)))
161 ao_lisp_mark_memory(void *addr, int size)
163 return mark_object(ao_lisp_busy, addr, size);
167 check_move(void *addr, int size)
169 if (addr == move_old) {
170 memmove(move_new, move_old, size);
171 move_size = (size + 3) & ~3;
178 ao_lisp_move(const struct ao_lisp_mem_type *type, void *addr)
180 int size = type->size(addr);
185 addr = check_move(addr, size);
186 if (mark_object(ao_lisp_moving, addr, size))
193 ao_lisp_move_memory(void *addr, int size)
198 addr = check_move(addr, size);
199 if (mark_object(ao_lisp_moving, addr, size))
205 ao_lisp_alloc(int size)
209 size = (size + 3) & ~3;
210 if (ao_lisp_top + size > AO_LISP_POOL) {
212 if (ao_lisp_top + size > AO_LISP_POOL)
215 addr = ao_lisp_pool + ao_lisp_top;
221 ao_lisp_root_add(const struct ao_lisp_mem_type *type, void *addr)
224 for (i = 0; i < AO_LISP_ROOT; i++) {
225 if (!ao_lisp_root[i].addr) {
226 ao_lisp_root[i].addr = addr;
227 ao_lisp_root[i].type = type;
235 ao_lisp_root_clear(void *addr)
238 for (i = 0; i < AO_LISP_ROOT; i++) {
239 if (ao_lisp_root[i].addr == addr) {
240 ao_lisp_root[i].addr = 0;
241 ao_lisp_root[i].type = 0;