1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
|
/* Copyright (C) 2024 Peter McGoron
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this program. If not, see
* <https://www.gnu.org/licenses/>.
*/
/* TODO: add support for freestanding */
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include "uns.h"
/** Internal GC state.
*
* The exact structure is hidden from implementations. The function API
* is stable(r).
*/
struct uns_gc {
/** Context pointer used by specific collector implementations. */
void *ctx;
/** Head of the roots linked list. */
struct uns_ctr *roots;
/** Function called when OOM occurs. If not specified, the library
* will print to standard error and exit.
*/
void (*oom)(struct uns_gc *);
/** Implementations of allocator functions. */
void (*deinit)(Uns_GC);
int (*collect)(Uns_GC);
void *(*alloc)(Uns_GC, size_t, enum uns_bytes_type);
void *(*alloc_rec)(Uns_GC, size_t, enum uns_record_type);
void (*free)(Uns_GC, Uns_ptr);
/** Generic implementation of record access. Values in a record may
* have unused bits filled in so raw reads may not work correctly.
* Values may also not be aligned correctly. The `get` and `set`
* functions will handle all of this so the caller gets what is
* expected.
*/
void (*set)(Uns_ptr, size_t, enum uns_fld_type, void *);
void *(*get)(Uns_ptr, size_t, enum uns_fld_type *);
};
const size_t uns_gc_size = sizeof(struct uns_gc);
void uns_gc_zero(Uns_GC gc)
{
gc->ctx = NULL;
gc->roots = NULL;
gc->oom = NULL;
gc->deinit = NULL;
gc->collect = NULL;
gc->alloc = NULL;
gc->alloc_rec = NULL;
gc->free = NULL;
gc->set = NULL;
gc->get = NULL;
}
/** Wrapper to define a setter for the generic state struct. */
#define SETTER(name, arg) \
void uns_set_##name(Uns_GC gc, arg) {gc->name = name;}
SETTER(deinit, void(*deinit)(Uns_GC))
SETTER(oom, void(*oom)(Uns_GC))
SETTER(collect, int(*collect)(Uns_GC))
SETTER(alloc, void*(*alloc)(Uns_GC, size_t, enum uns_bytes_type))
SETTER(alloc_rec, void*(*alloc_rec)(Uns_GC, size_t, enum uns_record_type))
SETTER(free, void(*free)(Uns_GC, Uns_ptr))
SETTER(set, void(*set)(Uns_ptr, size_t, enum uns_fld_type, void*))
SETTER(get, void*(*get)(Uns_ptr, size_t, enum uns_fld_type *))
#undef SETTER
void uns_deinit(Uns_GC gc)
{
if (gc->deinit)
gc->deinit(gc);
uns_gc_zero(gc);
}
int uns_collect(Uns_GC gc)
{
if (gc->collect)
return gc->collect(gc);
abort();
}
void *uns_alloc(Uns_GC gc, size_t bytes, enum uns_bytes_type typ)
{
if (gc->alloc)
return gc->alloc(gc, bytes, typ);
abort();
}
void *uns_alloc_rec(Uns_GC gc, size_t bytes, enum uns_record_type typ)
{
if (gc->alloc_rec)
return gc->alloc_rec(gc, bytes, typ);
abort();
}
void uns_free(Uns_GC gc, Uns_ptr p)
{
if (gc->free)
gc->free(gc, p);
}
void *uns_get(Uns_GC gc, Uns_ptr rec, size_t ind, enum uns_fld_type *typ)
{
if (gc->get)
return gc->get(rec, ind, typ);
else
abort();
}
void uns_set(Uns_GC gc, Uns_ptr rec, size_t ind, enum uns_fld_type typ, void *val)
{
if (gc->set)
gc->set(rec, ind, typ, val);
else
abort();
}
void uns_on_oom(Uns_GC gc)
{
if (gc->oom) {
gc->oom(gc);
} else {
fprintf(stderr, "oom\n");
abort();
}
}
void uns_root_add(Uns_GC gc, struct uns_ctr *root)
{
root->prev = NULL;
root->next = gc->roots;
if (gc->roots)
gc->roots->prev = root;
gc->roots = root;
}
void uns_root_remove(Uns_GC gc, struct uns_ctr *root)
{
if (root->prev) {
root->prev->next = root->next;
}
if (root->next) {
root->next->prev = root->prev;
}
if (gc->roots == root) {
assert(!root->prev);
gc->roots = root->next;
}
root->prev = root->next = NULL;
}
struct uns_ctr *uns_roots(Uns_GC gc)
{
return gc->roots;
}
|