aboutsummaryrefslogtreecommitdiffstats
path: root/include/uns.h
blob: 0ea61cc75b8a626f9e3db19d0f0832e9ad773106 (plain) (blame)
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
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
#ifndef UNIVERSAL_SERVICE_H
#define UNIVERSAL_SERVICE_H
/* 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/>.
*/

#include <stddef.h>

/********************************
 * Compatability stuff.
 ********************************/
#if __STDC_VERSION__ >= 199101L
# define UNS_INLINE inline
# include <stdint.h>
#else
# define UNS_INLINE
# define SIZE_MAX ((size_t)0 - 1)
#endif

#if defined(__GNUC__)
# define UNS_UNUSED __attribute__((unused))
#else
# define UNS_UNUSED
#endif

#if !defined(UNS_WORD) && __STDC_VERSION__ >= 199101L
# include <stdint.h>
# include <limits.h>
# define UNS_WORD uintptr_t
# define UNS_SIGNED_WORD intptr_t
# define UNS_WORD_MAX UINTPTR_MAX
# define UNS_SWORD_MAX INTPTR_MAX
# define UNS_SWORD_MIN INTPTR_MIN
#elif !defined(UNS_WORD)
# include <limits.h>
# define UNS_WORD unsigned long
# define UNS_WORD_MAX ULONG_MAX
# define UNS_SIGNED_WORD long
# define UNS_SWORD_MAX LONG_MAX
# define UNS_SWORD_MIN LONG_MIN
#endif

typedef UNS_WORD uns_word;
typedef UNS_SIGNED_WORD uns_sword;

/** Type for a pointer to a region.
  *
  * This struct doesn't exist and is used to make a unique pointer for
  * type checking.
  *
  * This pointer must be what was returned from an allocation (i.e. it
  * points to the first byte but before any hidden header data).
 */
typedef struct uns_ptr *Uns_ptr;

/** Flags for bytes regions. */
enum uns_bytes_type {
	UNS_NOEXEC = 0
};

/** Flags for record regions. */
enum uns_record_type {
	UNS_POINTERS_ONLY = 0
};

/** Type of a value in a record. */
enum uns_fld_type {
	UNS_POINTER,
	UNS_INTEGER,

	/** Value is a weak pointer. */
	UNS_WEAK
};

/** Container that boxes pointers for the runtime.
  *
  * Used for
  *
  * 1) Store roots of the GC,
  * 2) Store GC pointers used in C and possibly not pointed-to anywhere
  *    else in GC space,
  * 3) Preserve the location of a pointer after it moves.
  */
struct uns_ctr {
	 /** Pointer to a region in the heap, or NULL.
	   *
	   * All roots must point into the same heap, or to NULL.
	   * Multiple roots are allowed to point to the same region.
	   */
	void *p;

	/** This field is managed by the library.
	  * This must be set to NULL when initializing the container and
	  * must not be touched while the container is in the root list.
	  */
	struct uns_ctr *prev; 

	/** This field is managed by the library.
	  * This must be set to NULL when initializing the container and
	  * must not be touched while the container is in the root list.
	  */
	struct uns_ctr *next;
};

/** Opaque struct that stores the state of a garbage collected heap.
  *
  * The only thing that is stable about the layout of this struct is
  * that the first field is ALWAYS a pointer to the collector context.
  *
  * The context pointer will always be the same pointer from init to
  * deinit.
  */
typedef struct uns_gc *Uns_GC;

/** Size of `struct uns_gc` for allocation. */
extern const size_t uns_gc_size;

/** Get the context pointer for the collector. */
UNS_UNUSED static UNS_INLINE void *uns_ctx(Uns_GC gc)
{
	return *((void **)gc);
}

/** Set the context pointer for the collector. */
UNS_UNUSED static UNS_INLINE void uns_set_ctx(Uns_GC gc, void *ctx)
{
	*((void **)gc) = ctx;
}

/** Zero the memory of the generic GC struct. This will leak
  * memory if a collector was initialized and not deinitialized
  * beforehand.
  *
  * This must be called when the structure is allocated.
  */
void uns_gc_zero(Uns_GC gc);

/** Free memory associated with the GC. It is OK to call this
  * with a GC that has not been initialized.
  */
void uns_deinit(Uns_GC gc);

/** Set deinit function. */
void uns_set_deinit(Uns_GC gc, void(*deinit)(Uns_GC));

/** Set OOM handler. */
void uns_set_oom(Uns_GC gc, void(*oom)(Uns_GC));

/** Call OOM handler. */
void uns_on_oom(Uns_GC gc);

/** Set garbage collection function. */
void uns_set_collect(Uns_GC gc, int(*collect)(Uns_GC));

/** Set allocation function. */
void uns_set_alloc(Uns_GC gc,
                   void*(*alloc)(Uns_GC, size_t, enum uns_bytes_type));

/** Set allocation function. */
void uns_set_alloc_rec(Uns_GC gc,
                       void*(*alloc_rec)(Uns_GC, size_t, enum uns_record_type));

/** Set record setter function. */
void uns_set_set(Uns_GC gc, void(*set)(Uns_ptr, size_t, enum uns_fld_type,
                                       void*));

/** Set record getter function. */
void uns_set_get(Uns_GC gc, void*(*get)(Uns_ptr, size_t,
                                        enum uns_fld_type *));

/** Force a collection. */
int uns_collect(Uns_GC gc);

/** Allocate a region of bytes.
  *
  * This function will only return NULL if:
  *
  * 1. The type of region requested in `typ` is not supported, or
  * 2. The collector ran out of memory and the out-of-memory handler
  *    did not exit the program.
  *
  * Results are undefined if the type is not supported, but all
  * allocators can be compiled with a mode to abort in those cases.
  */
void *uns_alloc(Uns_GC gc, size_t bytes, enum uns_bytes_type typ);

/** Allocate a record.
  *
  * This function will only return NULL if:
  *
  * 1. The type of region requested in `typ` is not supported, or
  * 2. The collector ran out of memory and the out-of-memory handler
  *    did not exit the program.
  *
  * `len` is the number of elements in the record.
  */
void *uns_alloc_rec(Uns_GC gc, size_t len, enum uns_record_type typ);

/** Free a region.
  *
  * This is a no-op if freeing is not supported by the collector, or
  * if `p` is NULL.
  */
void uns_free(Uns_GC gc, Uns_ptr p);

/** Get a field from a record.
  *
  * ## Parameters
  * - `notnull gc`: GC data.
  * - `notnull rec`: Pointer to a record.
  * - `ind`: Index of the field in the record. This is not the byte
  *   offset.
  * - `out typ`: What type of field (integer, weak, etc.) was contained
  *   in the field. May be NULL.
  */
void *uns_get(Uns_GC gc, Uns_ptr rec, size_t ind, enum uns_fld_type *typ);

/** Set a field in a record.
  *
  * ## Parameters
  * - `notnull gc`: GC Data.
  * - `notnull rec`: Pointer to a record.
  * - `ind`: Index of the field in the record. This is not the byte
  *   offset.
  * - `typ`: The type of record to store. Behavior is undefined if the
  *   field type is not supported, either by the record or by the heap.
  * - `val`: Value to store.
  */
void uns_set(Uns_GC gc, Uns_ptr rec, size_t ind, enum uns_fld_type typ, 
             void *val);

/** Add a root to the GC.
  *
  * ## Parameters
  * - `notnull gc`: GC data.
  * - `notnull in out root`: Pointer to the container containing the root.
  *   Do not modify any other field in the container, except for p, after
  *   this function returns.
  */
void uns_root_add(Uns_GC gc, struct uns_ctr *root);

/** Remove a root from the GC.
  *
  * ## Parameters
  * - `notnull gc`: GC data.
  * - `notnull in out root`: Pointer to the container containing the
  *    root to be removed. If the root is not a part of any heap (the
  *    prev and next pointers are NULL), then this function is a noop.
  *    This function does not modify p.
  */
void uns_root_remove(Uns_GC gc, struct uns_ctr *root);

/** Get the head of the roots list.
  */
struct uns_ctr *uns_roots(Uns_GC gc);

#endif