205 lines
4.2 KiB
C
205 lines
4.2 KiB
C
#ifndef GC_H_6b8a27c99f2eb5eb5437e045fa4af1c3
|
|
#define GC_H_6b8a27c99f2eb5eb5437e045fa4af1c3
|
|
|
|
#include <assert.h>
|
|
#include <inttypes.h>
|
|
#include <stdbool.h>
|
|
#include <stdio.h>
|
|
|
|
#ifndef NDEBUG
|
|
# define debug(printf_args) ((void)printf printf_args)
|
|
#else
|
|
# define debug(printf_args) ((void)0)
|
|
#endif
|
|
|
|
typedef uintptr_t value_t;
|
|
|
|
/* NIL: 00000000 00000000 00000000 00000000 */
|
|
/* Object: aaaaaaaa aaaaaaaa aaaaaaaa aaaaaa00 (where aa... >= 1024) */
|
|
/* Pair: aaaaaaaa aaaaaaaa aaaaaaaa aaaaaa10 */
|
|
/* Fixnum: snnnnnnn nnnnnnnn nnnnnnnn nnnnnnn1 */
|
|
|
|
#define NIL ((value_t)0)
|
|
|
|
/* Special values (0 <= n < 1024) */
|
|
/* These correspond to objects within the first page of memory */
|
|
#define SPECIAL_VALUE(n) ((value_t)(4*n+2))
|
|
#define MAX_SPECIAL SPECIAL_VALUE(1023)
|
|
|
|
#define BROKEN_HEART SPECIAL_VALUE(0)
|
|
#define TYPE_TAG_BOX SPECIAL_VALUE(1)
|
|
#define TYPE_TAG_VECTOR SPECIAL_VALUE(2)
|
|
#define TYPE_TAG_BYTESTR SPECIAL_VALUE(3)
|
|
|
|
typedef struct object
|
|
{
|
|
value_t tag;
|
|
union {
|
|
value_t values[0];
|
|
char bytes[0];
|
|
} payload;
|
|
} object_t;
|
|
|
|
typedef struct box
|
|
{
|
|
value_t tag;
|
|
value_t value;
|
|
} box_t;
|
|
|
|
typedef struct pair
|
|
{
|
|
value_t car;
|
|
value_t cdr;
|
|
} pair_t;
|
|
|
|
typedef struct vector
|
|
{
|
|
value_t tag;
|
|
size_t size;
|
|
value_t elements[0];
|
|
} vector_t;
|
|
|
|
typedef struct byte_string
|
|
{
|
|
value_t tag;
|
|
size_t size;
|
|
uint8_t bytes[0];
|
|
} byte_string_t;
|
|
|
|
typedef struct gc_root
|
|
{
|
|
value_t value;
|
|
struct gc_root *prev;
|
|
struct gc_root *next;
|
|
} gc_root_t;
|
|
|
|
typedef struct gc_stats
|
|
{
|
|
int collections;
|
|
clock_t total_ticks;
|
|
size_t high_water;
|
|
} gc_stats_t;
|
|
|
|
extern gc_stats_t gc_stats;
|
|
|
|
object_t *get_object(value_t v);
|
|
|
|
pair_t *get_pair(value_t pair);
|
|
value_t cons(value_t car, value_t cdr);
|
|
|
|
value_t make_box(value_t initial_value);
|
|
box_t *get_box(value_t v);
|
|
|
|
value_t make_vector(size_t elements, value_t default_value);
|
|
vector_t *get_vector(value_t v);
|
|
|
|
value_t make_byte_string(size_t size, int default_value);
|
|
byte_string_t *get_byte_string(value_t v);
|
|
|
|
intptr_t get_fixnum(value_t v);
|
|
|
|
/****************************************************************************/
|
|
|
|
static inline value_t object_value(void *obj)
|
|
{
|
|
assert((uintptr_t)obj >= 4096);
|
|
assert(((uintptr_t)obj & 3) == 0);
|
|
return (value_t)obj;
|
|
}
|
|
|
|
static inline bool is_object(value_t v)
|
|
{
|
|
/* Neither pairs nor other objects can exist below (void*)4096. */
|
|
return ((v & 0x1) == 0) && (v > MAX_SPECIAL);
|
|
}
|
|
|
|
/* Pairs are a type of object, but the value representation is different */
|
|
static inline object_t *_get_object(value_t v)
|
|
{
|
|
return (object_t*)(v & ~(value_t)3);
|
|
}
|
|
|
|
static inline value_t pair_value(pair_t *p)
|
|
{
|
|
assert((uintptr_t)p >= 4096);
|
|
assert(((uintptr_t)p & 3) == 0);
|
|
return (value_t)p + 2;
|
|
}
|
|
|
|
static inline bool is_pair(value_t v)
|
|
{
|
|
return ((v & 0x3) == 2);
|
|
}
|
|
|
|
static inline pair_t *_get_pair(value_t v)
|
|
{
|
|
return (pair_t*)_get_object(v);
|
|
}
|
|
|
|
static inline bool is_box(value_t v)
|
|
{
|
|
return is_object(v) && (_get_object(v)->tag == TYPE_TAG_BOX);
|
|
}
|
|
|
|
static inline box_t *_get_box(value_t v)
|
|
{
|
|
return (box_t*)_get_object(v);
|
|
}
|
|
|
|
static inline bool is_vector(value_t v)
|
|
{
|
|
return is_object(v) && (_get_object(v)->tag == TYPE_TAG_VECTOR);
|
|
}
|
|
|
|
static inline vector_t *_get_vector(value_t v)
|
|
{
|
|
return (vector_t*)_get_object(v);
|
|
}
|
|
|
|
static inline size_t vector_size(value_t v)
|
|
{
|
|
return get_vector(v)->size;
|
|
}
|
|
|
|
static inline bool is_byte_string(value_t v)
|
|
{
|
|
return is_object(v) && (_get_object(v)->tag == TYPE_TAG_BYTESTR);
|
|
}
|
|
|
|
static inline byte_string_t *_get_byte_string(value_t v)
|
|
{
|
|
return (byte_string_t*)_get_object(v);
|
|
}
|
|
|
|
static inline size_t byte_string_size(value_t v)
|
|
{
|
|
return get_byte_string(v)->size;
|
|
}
|
|
|
|
static inline bool is_fixnum(value_t v)
|
|
{
|
|
return (v & 1) != 0;
|
|
}
|
|
|
|
static inline value_t make_fixnum(intptr_t n)
|
|
{
|
|
return (value_t)(n << 1) | 1;
|
|
}
|
|
|
|
static inline intptr_t _get_fixnum(value_t n)
|
|
{
|
|
return ((intptr_t)n) >> 1;
|
|
}
|
|
|
|
void gc_init(size_t min_size, size_t max_size);
|
|
void register_gc_root(gc_root_t *root, value_t v);
|
|
void unregister_gc_root(gc_root_t *root);
|
|
void *gc_alloc(size_t nbytes);
|
|
void collect_garbage(size_t min_free);
|
|
|
|
/* To be provided by the main application */
|
|
void out_of_memory(void) __attribute__ ((noreturn));
|
|
|
|
#endif
|
|
/* vim:set sw=2 expandtab: */
|