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;
125 memset(ao_lisp_busy, '\0', sizeof (ao_lisp_busy));
126 for (i = 0; i < AO_LISP_ROOT; i++)
127 if (ao_lisp_root[i].addr)
128 ao_lisp_mark(ao_lisp_root[i].type, *ao_lisp_root[i].addr);
132 for (i = 0; i < AO_LISP_POOL; i += 4) {
133 if (!busy(ao_lisp_busy, i))
137 while(i < AO_LISP_POOL) {
138 if (busy(ao_lisp_busy, i)) {
139 move_old = &ao_lisp_pool[i];
140 move_new = &ao_lisp_pool[ao_lisp_top];
143 clear_object(ao_lisp_busy, move_old, move_size);
145 ao_lisp_top += move_size;
154 ao_lisp_mark(const struct ao_lisp_mem_type *type, void *addr)
156 if (mark_object(ao_lisp_busy, addr, type->size(addr)))
162 ao_lisp_mark_memory(void *addr, int size)
164 return mark_object(ao_lisp_busy, addr, size);
168 check_move(void *addr, int size)
170 if (addr == move_old) {
171 memmove(move_new, move_old, size);
172 move_size = (size + 3) & ~3;
179 ao_lisp_move(const struct ao_lisp_mem_type *type, void *addr)
181 int size = type->size(addr);
186 addr = check_move(addr, size);
187 if (mark_object(ao_lisp_moving, addr, size))
194 ao_lisp_move_memory(void *addr, int size)
199 addr = check_move(addr, size);
200 if (mark_object(ao_lisp_moving, addr, size))
206 ao_lisp_alloc(int size)
210 size = (size + 3) & ~3;
211 if (ao_lisp_top + size > AO_LISP_POOL) {
213 if (ao_lisp_top + size > AO_LISP_POOL)
216 addr = ao_lisp_pool + ao_lisp_top;
222 ao_lisp_root_add(const struct ao_lisp_mem_type *type, void *addr)
225 for (i = 0; i < AO_LISP_ROOT; i++) {
226 if (!ao_lisp_root[i].addr) {
227 ao_lisp_root[i].addr = addr;
228 ao_lisp_root[i].type = type;
236 ao_lisp_root_clear(void *addr)
239 for (i = 0; i < AO_LISP_ROOT; i++) {
240 if (ao_lisp_root[i].addr == addr) {
241 ao_lisp_root[i].addr = 0;
242 ao_lisp_root[i].type = 0;